@mearl/client 2.17.0 → 2.18.0

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.
@@ -48,6 +48,43 @@ export const APP_PROFILE_NAMES = [
48
48
  'didi',
49
49
  'easybike',
50
50
  ];
51
+ export const TAB_ID_REQUIRED_ACTIONS = [
52
+ 'page_screenshot',
53
+ 'tab_close',
54
+ 'page_click',
55
+ 'page_drag',
56
+ 'page_type',
57
+ 'page_scroll',
58
+ 'page_hover',
59
+ 'page_eval',
60
+ 'page_inspect',
61
+ 'page_snapshot',
62
+ 'page_press',
63
+ 'page_wait',
64
+ 'page_navigate',
65
+ 'page_upload',
66
+ 'page_frames',
67
+ 'set_device_emulation',
68
+ 'set_app_profile',
69
+ 'set_timezone',
70
+ 'get_cookie',
71
+ 'set_cookie',
72
+ 'run_actions',
73
+ ];
74
+ const TAB_ID_REQUIRED_ACTION_SET = new Set(TAB_ID_REQUIRED_ACTIONS);
75
+ export function actionRequiresTabId(action) {
76
+ return typeof action === 'string' && TAB_ID_REQUIRED_ACTION_SET.has(action);
77
+ }
78
+ export function validateRequiredActionTabId(action, data) {
79
+ if (!actionRequiresTabId(action))
80
+ return;
81
+ const tabId = data && typeof data === 'object' && !Array.isArray(data)
82
+ ? data.tabId
83
+ : undefined;
84
+ if (typeof tabId !== 'number' || !Number.isSafeInteger(tabId) || tabId < 0) {
85
+ throw new Error(`${action} requires a numeric tabId. Call tab_open or tab_list to obtain a tabId.`);
86
+ }
87
+ }
51
88
  export const PAGE_ACT_ACTIONS = [
52
89
  'page_click',
53
90
  'page_drag',
@@ -76,7 +113,6 @@ export const BROWSER_ACTIONS = {
76
113
  browser_launch: true,
77
114
  browser_close: true,
78
115
  page_screenshot: true,
79
- page_selected_element: true,
80
116
  tab_open: true,
81
117
  tab_close: true,
82
118
  tab_list: true,
@@ -86,6 +122,7 @@ export const BROWSER_ACTIONS = {
86
122
  page_scroll: true,
87
123
  page_hover: true,
88
124
  page_eval: true,
125
+ page_inspect: true,
89
126
  page_snapshot: true,
90
127
  page_press: true,
91
128
  page_wait: true,
@@ -117,7 +154,6 @@ export const BROWSER_COMMAND_ACTIONS = {
117
154
  browser_launch: true,
118
155
  browser_close: true,
119
156
  page_screenshot: true,
120
- page_selected_element: true,
121
157
  tab_open: true,
122
158
  tab_close: true,
123
159
  tab_list: true,
@@ -127,6 +163,7 @@ export const BROWSER_COMMAND_ACTIONS = {
127
163
  page_scroll: true,
128
164
  page_hover: true,
129
165
  page_eval: true,
166
+ page_inspect: true,
130
167
  page_snapshot: true,
131
168
  page_press: true,
132
169
  page_wait: true,
@@ -155,7 +192,6 @@ export const EXTENSION_BROWSER_ACTIONS = {
155
192
  send_mtop_request: true,
156
193
  browser_release: true,
157
194
  page_screenshot: true,
158
- page_selected_element: true,
159
195
  tab_open: true,
160
196
  tab_close: true,
161
197
  tab_list: true,
@@ -165,6 +201,7 @@ export const EXTENSION_BROWSER_ACTIONS = {
165
201
  page_scroll: true,
166
202
  page_hover: true,
167
203
  page_eval: true,
204
+ page_inspect: true,
168
205
  page_snapshot: true,
169
206
  page_press: true,
170
207
  page_wait: true,
package/dist/index.d.ts CHANGED
@@ -6,9 +6,9 @@
6
6
  */
7
7
  export { UnifiedClient, UnifiedClient as MearlClient, decodeBrowserTarget, invoke, invokePlugin, listCloudConnectors, } from './unified.js';
8
8
  export type { UnifiedClientOptions, UnifiedInvokeOptions, UnifiedInvokeOptions as InvokeOptions, } from './unified.js';
9
- export type { PluginInvocation, PluginInvokeOptions } from './plugin.js';
9
+ export type { PluginInvocation, PluginInvokeOptions, PluginProgress, StructuredPluginProgress, } from './plugin.js';
10
10
  export { APP_PROFILE_NAMES, BROWSER_DEVICE_PRESET_NAMES, BROWSER_ACTIONS, BROWSER_COMMAND_ACTIONS, EXTENSION_BROWSER_ACTIONS, PAGE_ACT_ACTIONS, SEND_REQUEST_MAX_FILES, SEND_REQUEST_MAX_TOTAL_BASE64_FILE_BYTES, SEND_REQUEST_MAX_TOTAL_FILE_BYTES, isBrowserAction, isBrowserCapabilityAction, isBrowserCommandAction, isExtensionBrowserAction, } from './generated-browser-action-protocol.js';
11
- export type { ActionStep, AppProfileName, BrowserAction, BrowserActionMap, BrowserActionRequest, BrowserActionResponse, BrowserCapabilities, BrowserCapabilityAction, BrowserCloseParams, BrowserCommandAction, BrowserInfo, BrowserInfoBase, BrowserJsonValue, BrowserLaunchParams, BrowserProviderOperation, BrowserListResult, BrowserPairingInfo, BrowserReleaseFailure, BrowserReleaseResult, BrowserProviderDefinition, BrowserProviderIdentity, BrowserProviderInputSchema, BrowserProviderListResult, BrowserReference, BrowserDetails, BrowserSource, BrowserStatus, BrowserScreenshotKind, BrowserTransport, CaptureCheckpointParams, CaptureCheckpointResult, BrowserDevicePresetName, BrowserEmulationOptions, ExtensionBrowserAction, GetCookieParams, GetCookieResult, GetEventsParams, GetLogsParams, GetMocksParams, GetRequestsParams, ManagedBrowserInfo, PageClickParams, PageDragEndpoint, PageDragParams, PageDragPoint, PageActAction, PageDiagnosticsOptions, PageDiagnosticsSetting, PageEvalParams, PageFramesParams, PageHoverParams, PageNavigateParams, PageObservationWaitOptions, PagePressParams, PageScreenshotParams, PageScrollParams, PageSelectedElementParams, PageSnapshotParams, PageSnapshotQuery, PageTypeParams, PageUploadParams, PageWaitParams, RegularBrowserInfo, RequestDomainPermissionParams, RulesResult, RunActionName, RunActionsParams, SelectBrowserParams, SelectBrowserResult, SendRequestFile, SendRequestFormValue, SendMtopRequestParams, SendRequestParams, SetAppProfileParams, SetCookieParams, SetCookieResult, SetDeviceEmulationParams, SetMockParams, SetRuleParams, SetTimezoneParams, SetTimezoneResult, TabCloseParams, TabOpenParams, } from './generated-browser-action-protocol.js';
11
+ export type { ActionStep, AppProfileName, BrowserAction, BrowserActionMap, BrowserActionRequest, BrowserActionResponse, BrowserCapabilities, BrowserCapabilityAction, BrowserCloseParams, BrowserCommandAction, BrowserInfo, BrowserInfoBase, BrowserJsonValue, BrowserLaunchParams, BrowserProviderOperation, BrowserListResult, BrowserPairingInfo, BrowserReleaseFailure, BrowserReleaseResult, BrowserProviderDefinition, BrowserProviderIdentity, BrowserProviderInputSchema, BrowserProviderListResult, BrowserReference, BrowserDetails, BrowserSource, BrowserStatus, BrowserScreenshotKind, BrowserTransport, CaptureCheckpointParams, CaptureCheckpointResult, BrowserDevicePresetName, BrowserEmulationOptions, ExtensionBrowserAction, GetCookieParams, GetCookieResult, GetEventsParams, GetLogsParams, GetMocksParams, GetRequestsParams, ManagedBrowserInfo, PageClickParams, PageDragEndpoint, PageDragParams, PageDragPoint, PageActAction, PageDiagnosticsOptions, PageDiagnosticsSetting, PageEvalParams, PageFramesParams, PageHoverParams, PageInspectFilter, PageInspectParams, PageNavigateParams, PageObservationWaitOptions, PagePressParams, PageScreenshotParams, PageScrollParams, PageSnapshotParams, PageSnapshotQuery, PageTypeParams, PageUploadParams, PageWaitParams, RegularBrowserInfo, RequestDomainPermissionParams, RulesResult, RunActionName, RunActionsParams, SelectBrowserParams, SelectBrowserResult, SendRequestFile, SendRequestFormValue, SendMtopRequestParams, SendRequestParams, SetAppProfileParams, SetCookieParams, SetCookieResult, SetDeviceEmulationParams, SetMockParams, SetRuleParams, SetTimezoneParams, SetTimezoneResult, TabCloseParams, TabOpenParams, } from './generated-browser-action-protocol.js';
12
12
  import { type UnifiedInvokeOptions } from './unified.js';
13
13
  import type * as Protocol from './generated-browser-action-protocol.js';
14
14
  export declare function tabCheckpoint(params?: Protocol.CaptureCheckpointParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_checkpoint'>>;
@@ -29,7 +29,6 @@ export declare function browserClose(params: Protocol.BrowserCloseParams, option
29
29
  export declare function setRule(params: Protocol.SetRuleParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'set_rule'>>;
30
30
  export declare function getRules(options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_rules'>>;
31
31
  export declare function pageScreenshot(params: Protocol.PageScreenshotParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_screenshot'>>;
32
- export declare function pageSelectedElement(params: Protocol.PageSelectedElementParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_selected_element'>>;
33
32
  export declare function tabOpen(params: Protocol.TabOpenParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_open'>>;
34
33
  export declare function tabClose(params: Protocol.TabCloseParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_close'>>;
35
34
  export declare function tabList(options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_list'>>;
@@ -39,6 +38,7 @@ export declare function pageType(params: Protocol.PageTypeParams, options?: Unif
39
38
  export declare function pageScroll(params: Protocol.PageScrollParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_scroll'>>;
40
39
  export declare function pageHover(params: Protocol.PageHoverParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_hover'>>;
41
40
  export declare function pageEval(params: Protocol.PageEvalParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_eval'>>;
41
+ export declare function pageInspect(params: Protocol.PageInspectParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_inspect'>>;
42
42
  export declare function pageSnapshot(params: Protocol.PageSnapshotParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_snapshot'>>;
43
43
  export declare function pagePress(params: Protocol.PagePressParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_press'>>;
44
44
  export declare function pageWait(params: Protocol.PageWaitParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_wait'>>;
package/dist/index.js CHANGED
@@ -59,9 +59,6 @@ export function getRules(options) {
59
59
  export function pageScreenshot(params, options) {
60
60
  return invoke('page_screenshot', params, options);
61
61
  }
62
- export function pageSelectedElement(params, options) {
63
- return invoke('page_selected_element', params, options);
64
- }
65
62
  export function tabOpen(params, options) {
66
63
  return invoke('tab_open', params, options);
67
64
  }
@@ -89,6 +86,9 @@ export function pageHover(params, options) {
89
86
  export function pageEval(params, options) {
90
87
  return invoke('page_eval', params, options);
91
88
  }
89
+ export function pageInspect(params, options) {
90
+ return invoke('page_inspect', params, options);
91
+ }
92
92
  export function pageSnapshot(params, options) {
93
93
  return invoke('page_snapshot', params, options);
94
94
  }
package/dist/plugin.d.ts CHANGED
@@ -1,14 +1,20 @@
1
1
  import { type OfficialPluginInstaller } from './officialPluginInstaller.js';
2
+ import { type PluginToolboxContribution } from './pluginRegistry.js';
2
3
  import type { UnifiedInvokeOptions } from './unified.js';
3
- export { assertPluginName, findPluginDirectoryEntry, findPluginEntry, findPluginRegistration, listPluginNames, registerPlugin, resolvePluginEntry, unregisterPlugin, PluginError, type PluginRegistration, type PluginRegistrationOptions, } from './pluginRegistry.js';
4
+ export { assertPluginName, findPluginDirectoryEntry, findPluginEntry, findPluginRegistration, listPluginNames, registerPlugin, resolvePluginEntry, unregisterPlugin, PluginError, readPluginPageBundleChunk, type PluginRegistration, type PluginRegistrationOptions, type PluginToolboxAgentConfig, type PluginPageBundleRegistration, type PluginToolboxContribution, type PluginToolboxLocale, type PluginToolboxSandboxPage, } from './pluginRegistry.js';
4
5
  export { findOfficialPlugin, listOfficialPluginNames, OFFICIAL_PLUGIN_MANAGER, OFFICIAL_PLUGINS, type OfficialPluginDefinition, type OfficialPluginName, } from './officialPluginCatalog.js';
5
6
  export type PluginOptions = UnifiedInvokeOptions;
7
+ export interface StructuredPluginProgress {
8
+ message: string;
9
+ data?: Record<string, unknown>;
10
+ }
11
+ export type PluginProgress = string | StructuredPluginProgress;
6
12
  export interface PluginInvocation {
7
13
  command: string;
8
14
  input: Record<string, any>;
9
15
  }
10
16
  export interface PluginInvokeOptions extends UnifiedInvokeOptions {
11
- onProgress?: (message: string) => void;
17
+ onProgress?: (progress: PluginProgress) => void;
12
18
  }
13
19
  export interface PluginExecutionContext {
14
20
  ensurePlugin?: OfficialPluginInstaller;
@@ -18,13 +24,14 @@ export interface PluginApp {
18
24
  readonly options: Readonly<PluginOptions>;
19
25
  command(signature: string, handler: PluginHandler, description?: string): void;
20
26
  invoke(action: string, payload?: Record<string, any>, options?: UnifiedInvokeOptions): Promise<any>;
21
- progress(message: string): void;
27
+ progress(progress: PluginProgress): void;
22
28
  }
23
29
  export type PluginHandler = (input: Record<string, any>) => unknown | Promise<unknown>;
24
30
  /** 注册和执行复用同一宿主能力边界;仅 handler 执行期间开放浏览器调用。 */
25
31
  export declare function loadPlugin(entry: string, context: Pick<PluginApp, 'invoke' | 'options' | 'progress'>, pluginName?: string): Promise<{
26
32
  name: string | undefined;
27
33
  description: string | undefined;
34
+ toolbox: PluginToolboxContribution | undefined;
28
35
  version: string | undefined;
29
36
  commandHelp(namespace: string): string;
30
37
  help(namespace: string, name?: string): string;
@@ -33,6 +40,7 @@ export declare function loadPlugin(entry: string, context: Pick<PluginApp, 'invo
33
40
  export declare function loadRegisteredPlugin(name: string, context: PluginExecutionContext, options?: PluginInvokeOptions): Promise<{
34
41
  name: string | undefined;
35
42
  description: string | undefined;
43
+ toolbox: PluginToolboxContribution | undefined;
36
44
  version: string | undefined;
37
45
  commandHelp(namespace: string): string;
38
46
  help(namespace: string, name?: string): string;
package/dist/plugin.js CHANGED
@@ -5,9 +5,9 @@ import { Command } from 'commander';
5
5
  import { COMMAND_MAP } from './commands.js';
6
6
  import { findOfficialPlugin } from './officialPluginCatalog.js';
7
7
  import { ensureOfficialPluginRegistered, } from './officialPluginInstaller.js';
8
- import { findPluginRegistration, PluginError } from './pluginRegistry.js';
8
+ import { findPluginRegistration, normalizePluginToolboxContribution, PluginError, } from './pluginRegistry.js';
9
9
  import { describePythonPlugin, runPythonPluginCommand } from './pythonPlugin.js';
10
- export { assertPluginName, findPluginDirectoryEntry, findPluginEntry, findPluginRegistration, listPluginNames, registerPlugin, resolvePluginEntry, unregisterPlugin, PluginError, } from './pluginRegistry.js';
10
+ export { assertPluginName, findPluginDirectoryEntry, findPluginEntry, findPluginRegistration, listPluginNames, registerPlugin, resolvePluginEntry, unregisterPlugin, PluginError, readPluginPageBundleChunk, } from './pluginRegistry.js';
11
11
  export { findOfficialPlugin, listOfficialPluginNames, OFFICIAL_PLUGIN_MANAGER, OFFICIAL_PLUGINS, } from './officialPluginCatalog.js';
12
12
  function readPluginVersion(entry) {
13
13
  try {
@@ -26,6 +26,36 @@ function isObject(value) {
26
26
  function isPluginInvocation(value) {
27
27
  return isObject(value) && typeof value.command === 'string' && isObject(value.input);
28
28
  }
29
+ function normalizePluginProgress(progress) {
30
+ if (typeof progress === 'string') {
31
+ if (!progress)
32
+ throw new Error('app.progress 需要非空消息');
33
+ return progress;
34
+ }
35
+ if (!isObject(progress) || typeof progress.message !== 'string' || !progress.message) {
36
+ throw new Error('app.progress 需要非空消息');
37
+ }
38
+ if (progress.data !== undefined && !isObject(progress.data)) {
39
+ throw new Error('app.progress data 必须是对象');
40
+ }
41
+ let data;
42
+ if (progress.data) {
43
+ try {
44
+ const serialized = JSON.stringify(progress.data);
45
+ const parsed = serialized === undefined ? undefined : JSON.parse(serialized);
46
+ if (!isObject(parsed))
47
+ throw new Error('invalid object');
48
+ data = Object.freeze(parsed);
49
+ }
50
+ catch {
51
+ throw new Error('app.progress data 必须是可 JSON 序列化的对象');
52
+ }
53
+ }
54
+ return Object.freeze({
55
+ message: progress.message,
56
+ ...(data ? { data } : {}),
57
+ });
58
+ }
29
59
  function missingPluginEntryMessage(entry, pluginName) {
30
60
  const name = pluginName ?? '<name>';
31
61
  return [
@@ -54,6 +84,7 @@ export async function loadPlugin(entry, context, pluginName) {
54
84
  let registering = true;
55
85
  let name;
56
86
  let description;
87
+ let toolbox;
57
88
  const app = Object.freeze({
58
89
  options: Object.freeze({ ...context.options }),
59
90
  command(signature, handler, description = '') {
@@ -80,12 +111,10 @@ export async function loadPlugin(entry, context, pluginName) {
80
111
  throw new Error('app.invoke 只能在命令执行期间调用');
81
112
  return context.invoke(action, payload, options);
82
113
  },
83
- progress(message) {
114
+ progress(progress) {
84
115
  if (!executing)
85
116
  throw new Error('app.progress 只能在命令执行期间调用');
86
- if (typeof message !== 'string' || !message)
87
- throw new Error('app.progress 需要非空字符串');
88
- context.progress(message);
117
+ context.progress(normalizePluginProgress(progress));
89
118
  },
90
119
  });
91
120
  try {
@@ -93,6 +122,7 @@ export async function loadPlugin(entry, context, pluginName) {
93
122
  const descriptor = await describePythonPlugin(entry, app.options);
94
123
  name = descriptor.name;
95
124
  description = descriptor.description;
125
+ toolbox = normalizePluginToolboxContribution(descriptor.toolbox);
96
126
  for (const command of descriptor.commands) {
97
127
  const commandName = command.signature.trim().split(/\s+/)[0];
98
128
  app.command(command.signature, input => runPythonPluginCommand(entry, commandName, input, app), command.description);
@@ -108,12 +138,18 @@ export async function loadPlugin(entry, context, pluginName) {
108
138
  if (module.description !== undefined && typeof module.description !== 'string')
109
139
  throw new Error('入口的 description 导出必须为字符串');
110
140
  description = module.description;
141
+ toolbox = normalizePluginToolboxContribution(module.toolbox);
111
142
  if (typeof module.default !== 'function')
112
143
  throw new Error('入口必须默认导出 register(app) 函数');
113
144
  await module.default(app);
114
145
  }
115
146
  if (commands.size === 0)
116
147
  throw new Error('入口未注册任何命令');
148
+ const toolboxCommands = toolbox?.page.commands ?? [];
149
+ for (const command of toolboxCommands) {
150
+ if (!commands.has(command))
151
+ throw new Error(`toolbox 命令未注册: ${command}`);
152
+ }
117
153
  }
118
154
  catch (error) {
119
155
  throw new PluginError('PLUGIN_LOAD_FAILED', `${entry}: ${error instanceof Error ? error.message : String(error)}`);
@@ -130,6 +166,7 @@ export async function loadPlugin(entry, context, pluginName) {
130
166
  return {
131
167
  name,
132
168
  description,
169
+ toolbox,
133
170
  version: readPluginVersion(entry),
134
171
  commandHelp(namespace) {
135
172
  return [...commands.values()]
@@ -215,7 +252,7 @@ async function loadRegisteredPluginWithState(name, context, options = {}, state
215
252
  }
216
253
  let registration = findPluginRegistration(name);
217
254
  if (!registration && findOfficialPlugin(name)) {
218
- await (context.ensurePlugin ?? ensureOfficialPluginRegistered)(name, options.onProgress);
255
+ await (context.ensurePlugin ?? ensureOfficialPluginRegistered)(name, options.onProgress ? message => options.onProgress?.(message) : undefined);
219
256
  registration = findPluginRegistration(name);
220
257
  }
221
258
  if (!registration) {
@@ -0,0 +1,8 @@
1
+ export declare const PLUGIN_PAGE_CHUNK_BYTES: number;
2
+ export interface BuiltPluginPageBundle {
3
+ content: string;
4
+ hash: string;
5
+ size: number;
6
+ chunks: number;
7
+ }
8
+ export declare function buildPluginPageBundle(entry: string, pageEntry: string): BuiltPluginPageBundle;