@mearl/provider 2.13.0 → 2.14.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.
package/dist/server.js CHANGED
@@ -4,6 +4,7 @@ import { chmodSync, rmSync } from 'node:fs';
4
4
  import { dirname } from 'node:path';
5
5
  import { ensureDir } from '@mearl/daemon-core';
6
6
  import { isProviderAction } from './generated-provider-actions.js';
7
+ import { createProviderRuntime } from './provider-runtime.js';
7
8
  import { PROVIDER_START_TOKEN_ENV, claimProviderStart, providerBrowserKey, providerSocketPath, publishLiveProvider, publishProviderBrowsers, readLiveProvider, releaseProviderStart, removeStaleProviderSocket, touchProviderBrowser, unpublishLiveProvider, unpublishProviderBrowsers, } from './registry.js';
8
9
  import { MEARL_PROVIDER_PROTOCOL_VERSION } from './types.js';
9
10
  const MAX_REQUEST_BYTES = 16 * 1024 * 1024;
@@ -28,153 +29,89 @@ function isProviderActionRequest(value) {
28
29
  (request.controlSource === undefined || typeof request.controlSource === 'string'));
29
30
  }
30
31
  export function createProviderServer(options) {
31
- const socketPath = options.socketPath ?? providerSocketPath(options.descriptor.providerId);
32
+ const runtime = createProviderRuntime(options.definition);
33
+ const descriptor = options.definition.descriptor;
34
+ const socketPath = options.socketPath ?? providerSocketPath(descriptor.providerId);
32
35
  let server = null;
33
36
  let browserIds = new Set();
34
37
  let browsers = [];
35
38
  let state = 'idle';
36
39
  let stopPromise = null;
37
40
  const connections = new Set();
38
- function assertDescriptor() {
39
- const { providerId, name, version, protocolVersion } = options.descriptor;
40
- if (typeof providerId !== 'string' || !providerId.trim()) {
41
- throw new Error('providerId is required');
42
- }
43
- if (typeof name !== 'string' || !name.trim())
44
- throw new Error('provider name is required');
45
- if (typeof version !== 'string' || !version.trim()) {
46
- throw new Error('provider version is required');
47
- }
48
- if (protocolVersion !== undefined && protocolVersion !== MEARL_PROVIDER_PROTOCOL_VERSION) {
49
- throw new Error(`Unsupported provider protocol ${protocolVersion}; expected ${MEARL_PROVIDER_PROTOCOL_VERSION}`);
50
- }
51
- }
52
- function assertBrowsers(nextBrowsers) {
53
- const seen = new Set();
54
- for (const browser of nextBrowsers) {
55
- if (typeof browser.browserId !== 'string' || !browser.browserId.trim()) {
56
- throw new Error('provider browserId is required');
57
- }
58
- if (typeof browser.name !== 'string' || !browser.name.trim()) {
59
- throw new Error(`Provider browser ${browser.browserId} needs a name`);
60
- }
61
- if (seen.has(browser.browserId)) {
62
- throw new Error(`Duplicate provider browserId: ${browser.browserId}`);
63
- }
64
- seen.add(browser.browserId);
65
- if (!Array.isArray(browser.capabilities?.actions)) {
66
- throw new Error(`Provider browser ${browser.browserId} needs an actions capability list`);
67
- }
68
- for (const action of browser.capabilities.actions) {
69
- if (!isProviderAction(action)) {
70
- throw new Error(`Unsupported provider capability action: ${String(action)}`);
71
- }
72
- }
73
- if (new Set(browser.capabilities.actions).size !== browser.capabilities.actions.length) {
74
- throw new Error(`Provider browser ${browser.browserId} has duplicate capability actions`);
75
- }
76
- if (!['native', 'reconstructed', 'none'].includes(browser.capabilities.screenshot)) {
77
- throw new Error(`Unsupported screenshot capability: ${browser.capabilities.screenshot}`);
78
- }
79
- const supportsScreenshot = browser.capabilities.actions.includes('page_screenshot');
80
- if (supportsScreenshot === (browser.capabilities.screenshot === 'none')) {
81
- throw new Error(`Provider browser ${browser.browserId} has inconsistent screenshot capabilities`);
82
- }
83
- if (browser.status !== undefined && !['connected', 'pairing'].includes(browser.status)) {
84
- throw new Error(`Unsupported provider browser status: ${String(browser.status)}`);
85
- }
86
- assertPairing(browser.status, browser.pairing, browser.browserId);
87
- if (browser.lastFocusedAt !== undefined &&
88
- (!Number.isFinite(browser.lastFocusedAt) || browser.lastFocusedAt < 0)) {
89
- throw new Error(`Provider browser ${browser.browserId} has invalid lastFocusedAt`);
90
- }
91
- }
92
- }
93
- function providerBrowserId(requested) {
41
+ async function providerBrowserId(requested) {
94
42
  if (requested)
95
43
  return requested;
96
- if (browsers.length === 1)
97
- return browsers[0].browserId;
98
- if (browsers.length === 0)
99
- throw new Error('Provider has no connected browsers');
44
+ const available = await runtime.listBrowsers();
45
+ if (available.length === 1)
46
+ return available[0].browserId;
47
+ if (available.length === 0)
48
+ throw new Error('Provider has no browser instances');
100
49
  throw new Error('browserId is required when the provider has multiple browsers');
101
50
  }
102
51
  async function dispatch(request) {
103
52
  if (request.action === 'browser_launch') {
104
53
  if (request.browserId)
105
54
  throw new Error('browser_launch does not accept browserId');
106
- const parameters = request.data ?? {};
107
- if (Object.values(parameters).some(value => typeof value !== 'string')) {
108
- throw new Error('Provider browser parameters must be strings');
109
- }
110
- const created = await options.createBrowser(parameters);
111
- if (!created ||
112
- typeof created.browserId !== 'string' ||
113
- !created.browserId.trim() ||
114
- typeof created.name !== 'string' ||
115
- !created.name.trim() ||
116
- !['connected', 'pairing'].includes(created.status)) {
117
- throw new Error('Provider returned an invalid browser creation result');
118
- }
119
- try {
120
- assertPairing(created.status, created.pairing, created.browserId);
121
- }
122
- catch {
123
- throw new Error('Provider returned an invalid browser creation result');
124
- }
125
- return created;
55
+ return runtime.launch(request.data ?? {}, { controlSource: request.controlSource });
56
+ }
57
+ if (request.action === 'browser_provider_configure') {
58
+ if (request.browserId)
59
+ throw new Error('Provider configuration does not accept browserId');
60
+ return runtime.configure(request.data ?? {}, { controlSource: request.controlSource });
61
+ }
62
+ if (request.action === 'browser_manager_start') {
63
+ return runtime.start({ browserId: await providerBrowserId(request.browserId) }, { controlSource: request.controlSource });
64
+ }
65
+ if (request.action === 'browser_manager_sync_cookies') {
66
+ return runtime.syncCookies({
67
+ browserId: await providerBrowserId(request.browserId),
68
+ scope: request.data?.scope,
69
+ }, { controlSource: request.controlSource });
126
70
  }
127
71
  if (request.action !== 'get_versions' &&
128
72
  request.action !== 'browser_close' &&
73
+ request.action !== 'get_browser_access_url' &&
129
74
  !isProviderAction(request.action)) {
130
75
  throw new Error(`Unsupported provider action: ${String(request.action)}`);
131
76
  }
132
- const browserId = providerBrowserId(request.browserId);
133
- const found = browsers.find(browser => browser.browserId === browserId);
134
- if (!found)
135
- throw new Error(`Provider browser not found: ${browserId}`);
77
+ const browserId = await providerBrowserId(request.browserId);
136
78
  if (request.action === 'browser_close') {
137
- return options.deleteBrowser(browserId);
79
+ return runtime.close({ browserId, deleteData: request.data?.deleteProfile === true }, { controlSource: request.controlSource });
80
+ }
81
+ if (request.action === 'get_browser_access_url') {
82
+ return {
83
+ browserAccess: await runtime.getAccess({ browserId }, { controlSource: request.controlSource }),
84
+ };
138
85
  }
139
86
  if (request.action === 'get_versions') {
87
+ const found = (await runtime.listBrowsers()).find(browser => browser.browserId === browserId);
88
+ if (!found)
89
+ throw new Error(`Provider browser not found: ${browserId}`);
140
90
  return {
141
91
  provider: {
142
- providerId: options.descriptor.providerId,
143
- name: options.descriptor.name,
144
- version: options.descriptor.version,
145
- protocolVersion: options.descriptor.protocolVersion ?? MEARL_PROVIDER_PROTOCOL_VERSION,
92
+ id: descriptor.providerId,
93
+ name: descriptor.name,
94
+ builtin: descriptor.builtin === true,
95
+ version: descriptor.version,
96
+ protocolVersion: descriptor.protocolVersion ?? MEARL_PROVIDER_PROTOCOL_VERSION,
146
97
  },
147
- capabilities: found.capabilities,
98
+ capabilities: found.control.kind === 'provider' ? found.control.capabilities : undefined,
148
99
  };
149
100
  }
150
- if (found.status === 'pairing') {
151
- throw new Error(`Provider browser ${browserId} is waiting for device pairing`);
152
- }
153
- if (!found.capabilities.actions.includes(request.action)) {
154
- throw new Error(`Provider browser ${browserId} does not support ${request.action}`);
101
+ if (request.action === 'browser_release') {
102
+ const found = (await runtime.listBrowsers()).find(browser => browser.browserId === browserId);
103
+ if (found?.operations.includes('detach')) {
104
+ return runtime.detach({ browserId }, { controlSource: request.controlSource });
105
+ }
155
106
  }
156
- touchProviderBrowser(providerBrowserKey(options.descriptor.providerId, browserId));
157
- return options.handleAction({
107
+ touchProviderBrowser(providerBrowserKey(descriptor.providerId, browserId));
108
+ return runtime.invokeAction({
158
109
  browserId,
159
110
  action: request.action,
160
111
  data: request.data ?? {},
161
112
  controlSource: request.controlSource,
162
113
  });
163
114
  }
164
- function assertPairing(status, pairing, browserId) {
165
- if (status === 'pairing' &&
166
- (pairing?.kind !== 'qr' || typeof pairing.url !== 'string' || !pairing.url.trim())) {
167
- throw new Error(`Pairing browser ${browserId} needs a pairing URL`);
168
- }
169
- if (status !== 'pairing' && pairing) {
170
- throw new Error(`Pairing metadata requires status "pairing": ${browserId}`);
171
- }
172
- if (pairing &&
173
- ((pairing.code !== undefined && typeof pairing.code !== 'string') ||
174
- (pairing.label !== undefined && typeof pairing.label !== 'string'))) {
175
- throw new Error(`Provider browser ${browserId} has invalid pairing metadata`);
176
- }
177
- }
178
115
  function handleConnection(socket) {
179
116
  connections.add(socket);
180
117
  socket.once('close', () => connections.delete(socket));
@@ -216,22 +153,22 @@ export function createProviderServer(options) {
216
153
  }
217
154
  return {
218
155
  socketPath,
156
+ runtime,
219
157
  async start() {
220
158
  if (state !== 'idle')
221
159
  throw new Error(`Provider server is already ${state}`);
222
- assertDescriptor();
223
- const providerId = options.descriptor.providerId;
160
+ const providerId = descriptor.providerId;
224
161
  if (activeProviderIds.has(providerId)) {
225
162
  throw new Error(`Provider ${providerId} is already running in this process`);
226
163
  }
227
164
  state = 'starting';
228
165
  activeProviderIds.add(providerId);
229
166
  const startToken = process.env[PROVIDER_START_TOKEN_ENV] || randomUUID();
230
- const existing = readLiveProvider(options.descriptor.providerId);
167
+ const existing = readLiveProvider(descriptor.providerId);
231
168
  if (existing) {
232
169
  state = 'idle';
233
170
  activeProviderIds.delete(providerId);
234
- throw new Error(`Provider ${options.descriptor.providerId} is already running (pid ${existing.pid})`);
171
+ throw new Error(`Provider ${descriptor.providerId} is already running (pid ${existing.pid})`);
235
172
  }
236
173
  if (!claimProviderStart(providerId, startToken)) {
237
174
  state = 'idle';
@@ -256,7 +193,7 @@ export function createProviderServer(options) {
256
193
  });
257
194
  if (process.platform !== 'win32')
258
195
  chmodSync(socketPath, 0o600);
259
- publishLiveProvider(options.descriptor, socketPath);
196
+ publishLiveProvider(descriptor, socketPath);
260
197
  releaseProviderStart(providerId, startToken);
261
198
  state = 'running';
262
199
  }
@@ -281,9 +218,9 @@ export function createProviderServer(options) {
281
218
  updateBrowsers(nextBrowsers) {
282
219
  if (state !== 'running')
283
220
  throw new Error('Provider server is not running');
284
- assertBrowsers(nextBrowsers);
221
+ runtime.updateBrowsers(nextBrowsers);
285
222
  browsers = [...nextBrowsers];
286
- browserIds = publishProviderBrowsers(options.descriptor, socketPath, browsers, browserIds);
223
+ browserIds = publishProviderBrowsers(descriptor, socketPath, browsers, browserIds);
287
224
  },
288
225
  touchBrowser(browserId) {
289
226
  if (state !== 'running')
@@ -291,7 +228,7 @@ export function createProviderServer(options) {
291
228
  if (!browsers.some(browser => browser.browserId === browserId)) {
292
229
  throw new Error(`Provider browser not found: ${browserId}`);
293
230
  }
294
- touchProviderBrowser(providerBrowserKey(options.descriptor.providerId, browserId));
231
+ touchProviderBrowser(providerBrowserKey(descriptor.providerId, browserId));
295
232
  },
296
233
  async stop() {
297
234
  if (state === 'idle')
@@ -314,9 +251,9 @@ export function createProviderServer(options) {
314
251
  browsers = [];
315
252
  if (process.platform !== 'win32')
316
253
  rmSync(socketPath, { force: true });
317
- unpublishLiveProvider(options.descriptor.providerId);
254
+ unpublishLiveProvider(descriptor.providerId);
318
255
  })().finally(() => {
319
- activeProviderIds.delete(options.descriptor.providerId);
256
+ activeProviderIds.delete(descriptor.providerId);
320
257
  stopPromise = null;
321
258
  state = 'idle';
322
259
  });
package/dist/types.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import type { ProviderAction } from './generated-provider-actions.js';
2
- export declare const MEARL_PROVIDER_PROTOCOL_VERSION = 1;
2
+ export declare const MEARL_PROVIDER_PROTOCOL_VERSION = 2;
3
3
  export type { ProviderAction } from './generated-provider-actions.js';
4
+ export type JsonPrimitive = string | number | boolean | null;
5
+ export type JsonValue = JsonPrimitive | JsonValue[] | JsonObject;
6
+ export interface JsonObject {
7
+ [key: string]: JsonValue;
8
+ }
4
9
  export type ProviderScreenshotKind = 'native' | 'reconstructed' | 'none';
5
10
  export interface ProviderCapabilities {
6
11
  actions: ProviderAction[];
@@ -17,27 +22,104 @@ export interface ProviderDescriptor {
17
22
  name: string;
18
23
  version: string;
19
24
  protocolVersion?: number;
25
+ builtin?: boolean;
20
26
  }
21
- export interface ProviderBrowserParameter {
22
- key: string;
23
- label: string;
24
- required?: boolean;
25
- placeholder?: string;
27
+ interface ProviderSchemaBase {
28
+ title?: string;
26
29
  description?: string;
30
+ default?: JsonValue;
31
+ }
32
+ export interface ProviderStringSchema extends ProviderSchemaBase {
33
+ type: 'string';
34
+ secret?: boolean;
35
+ enum?: readonly string[];
36
+ minLength?: number;
37
+ maxLength?: number;
38
+ pattern?: string;
39
+ placeholder?: string;
40
+ }
41
+ export interface ProviderNumberSchema extends ProviderSchemaBase {
42
+ type: 'number';
43
+ integer?: boolean;
44
+ minimum?: number;
45
+ maximum?: number;
46
+ }
47
+ export interface ProviderBooleanSchema extends ProviderSchemaBase {
48
+ type: 'boolean';
49
+ }
50
+ export interface ProviderArraySchema extends ProviderSchemaBase {
51
+ type: 'array';
52
+ items: ProviderInputSchema;
53
+ minItems?: number;
54
+ maxItems?: number;
55
+ }
56
+ export interface ProviderObjectSchema extends ProviderSchemaBase {
57
+ type: 'object';
58
+ properties: Record<string, ProviderInputSchema>;
59
+ required?: readonly string[];
60
+ oneOf?: readonly ProviderObjectSchema[];
61
+ not?: ProviderObjectSchema;
62
+ additionalProperties?: boolean;
63
+ }
64
+ export type ProviderInputSchema = ProviderStringSchema | ProviderNumberSchema | ProviderBooleanSchema | ProviderArraySchema | ProviderObjectSchema;
65
+ export interface ProviderConfigurationDefinition {
66
+ inputSchema: ProviderObjectSchema;
27
67
  }
28
68
  export interface ProviderBrowserType {
29
69
  name: string;
30
- parameters: ProviderBrowserParameter[];
70
+ documentationUrl?: string;
71
+ inputSchema: ProviderObjectSchema;
72
+ configuration?: ProviderConfigurationDefinition;
73
+ }
74
+ export type ProviderBrowserStatus = 'connected' | 'pairing' | 'running_disconnected' | 'stopped';
75
+ export type ProviderOwnership = 'owned' | 'attached';
76
+ export type ProviderPersistence = 'ephemeral' | 'persistent';
77
+ export type ProviderBrowserOperation = 'start' | 'close' | 'detach' | 'deleteData' | 'access' | 'syncCookies';
78
+ export type ProviderBrowserControl = {
79
+ kind: 'provider';
80
+ capabilities: ProviderCapabilities;
81
+ } | {
82
+ kind: 'host';
83
+ transport: 'extension' | 'cdp';
84
+ browserId: string;
85
+ capabilities?: ProviderCapabilities;
86
+ } | {
87
+ kind: 'none';
88
+ };
89
+ /** Common safe metadata; additional Provider-specific keys must also be non-secret JSON. */
90
+ export type ProviderBrowserDetails = JsonObject & {
91
+ headless?: boolean;
92
+ createdAt?: string;
93
+ cdpPort?: number;
94
+ account?: {
95
+ nickname: string;
96
+ accountId?: string;
97
+ loginId?: string;
98
+ };
99
+ copiedCookies?: {
100
+ domains: string[];
101
+ count: number;
102
+ };
103
+ };
104
+ export interface ProviderBrowserReference {
105
+ kind: string;
106
+ id: string;
107
+ label?: string;
31
108
  }
32
109
  export interface ProviderBrowser {
33
- /** Stable within this provider. Mearl prefixes it with the provider id globally. */
110
+ /** Stable within this provider. Mearl adds the Provider namespace globally. */
34
111
  browserId: string;
35
112
  name: string;
36
- status?: 'connected' | 'pairing';
113
+ status: ProviderBrowserStatus;
114
+ control: ProviderBrowserControl;
115
+ ownership?: ProviderOwnership;
116
+ persistence: ProviderPersistence;
117
+ operations: ProviderBrowserOperation[];
37
118
  lastFocusedAt?: number;
38
- capabilities: ProviderCapabilities;
39
- /** Pairing metadata is valid only while status is pairing. */
40
119
  pairing?: ProviderPairingInfo;
120
+ references?: ProviderBrowserReference[];
121
+ /** Safe, non-secret metadata suitable for browser_list and remote connectors. */
122
+ details?: ProviderBrowserDetails;
41
123
  }
42
124
  export interface InstalledProviderManifest extends ProviderDescriptor {
43
125
  protocolVersion: number;
@@ -56,7 +138,7 @@ export interface ProviderPackageMetadata {
56
138
  export interface ProviderActionRequest {
57
139
  id: string;
58
140
  action: string;
59
- data?: Record<string, unknown>;
141
+ data?: JsonObject;
60
142
  /** Provider-local browser id selected by the Mearl client. */
61
143
  browserId?: string;
62
144
  version?: string;
@@ -65,32 +147,63 @@ export interface ProviderActionRequest {
65
147
  export interface ProviderActionContext {
66
148
  browserId: string;
67
149
  action: ProviderAction;
68
- data: Record<string, unknown>;
150
+ data: JsonObject;
69
151
  controlSource?: string;
70
152
  }
71
- export type ProviderActionHandler = (context: ProviderActionContext) => Promise<unknown>;
72
- interface ProviderBrowserCreateResultBase {
153
+ export interface ProviderHostServices {
154
+ request<T = JsonValue>(method: string, data?: JsonObject): Promise<T>;
155
+ }
156
+ export interface ProviderContext {
157
+ host?: ProviderHostServices;
158
+ controlSource?: string;
159
+ }
160
+ export interface ProviderInstanceRequest {
73
161
  browserId: string;
74
- name: string;
75
162
  }
76
- export type ProviderBrowserCreateResult = (ProviderBrowserCreateResultBase & {
77
- status: 'connected';
78
- pairing?: never;
79
- }) | (ProviderBrowserCreateResultBase & {
80
- status: 'pairing';
81
- pairing: ProviderPairingInfo;
82
- });
83
- export type ProviderBrowserCreateHandler = (parameters: Record<string, string>) => Promise<ProviderBrowserCreateResult>;
84
- export type ProviderBrowserDeleteHandler = (browserId: string) => Promise<unknown>;
85
- export interface ProviderServerOptions {
163
+ export interface ProviderCloseRequest extends ProviderInstanceRequest {
164
+ deleteData?: boolean;
165
+ }
166
+ export interface ProviderSyncCookiesRequest extends ProviderInstanceRequest {
167
+ scope: JsonObject;
168
+ }
169
+ export interface ProviderAccess {
170
+ kind: string;
171
+ url: string;
172
+ sensitive: true;
173
+ }
174
+ export interface BrowserProviderDefinition {
86
175
  descriptor: ProviderDescriptor;
87
- handleAction: ProviderActionHandler;
88
- createBrowser: ProviderBrowserCreateHandler;
89
- deleteBrowser: ProviderBrowserDeleteHandler;
176
+ browserType: ProviderBrowserType;
177
+ listBrowsers?: (context: ProviderContext) => ProviderBrowser[] | Promise<ProviderBrowser[]>;
178
+ launch: (options: JsonObject, context: ProviderContext) => Promise<ProviderBrowser>;
179
+ start?: (request: ProviderInstanceRequest, context: ProviderContext) => Promise<ProviderBrowser>;
180
+ close: (request: ProviderCloseRequest, context: ProviderContext) => Promise<unknown>;
181
+ detach?: (request: ProviderInstanceRequest, context: ProviderContext) => Promise<unknown>;
182
+ syncCookies?: (request: ProviderSyncCookiesRequest, context: ProviderContext) => Promise<unknown>;
183
+ getAccess?: (request: ProviderInstanceRequest, context: ProviderContext) => Promise<ProviderAccess>;
184
+ configure?: (options: JsonObject, context: ProviderContext) => Promise<unknown>;
185
+ handleAction?: (context: ProviderActionContext) => Promise<unknown>;
186
+ }
187
+ export interface ProviderRuntime {
188
+ readonly definition: BrowserProviderDefinition;
189
+ listBrowsers(context?: ProviderContext): Promise<ProviderBrowser[]>;
190
+ updateBrowsers(browsers: ProviderBrowser[]): void;
191
+ launch(options: JsonObject, context?: ProviderContext): Promise<ProviderBrowser>;
192
+ start(request: ProviderInstanceRequest, context?: ProviderContext): Promise<ProviderBrowser>;
193
+ close(request: ProviderCloseRequest, context?: ProviderContext): Promise<unknown>;
194
+ detach(request: ProviderInstanceRequest, context?: ProviderContext): Promise<unknown>;
195
+ syncCookies(request: ProviderSyncCookiesRequest, context?: ProviderContext): Promise<unknown>;
196
+ getAccess(request: ProviderInstanceRequest, context?: ProviderContext): Promise<ProviderAccess>;
197
+ configure(options: JsonObject, context?: ProviderContext): Promise<unknown>;
198
+ invokeAction(context: ProviderActionContext): Promise<unknown>;
199
+ }
200
+ export interface ProviderServerOptions {
201
+ definition: BrowserProviderDefinition;
90
202
  socketPath?: string;
91
203
  }
92
204
  export interface ProviderServer {
93
205
  readonly socketPath: string;
206
+ readonly runtime: ProviderRuntime;
94
207
  start(): Promise<void>;
95
208
  updateBrowsers(browsers: ProviderBrowser[]): void;
96
209
  touchBrowser(browserId: string): void;
package/dist/types.js CHANGED
@@ -1 +1 @@
1
- export const MEARL_PROVIDER_PROTOCOL_VERSION = 1;
1
+ export const MEARL_PROVIDER_PROTOCOL_VERSION = 2;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mearl/provider",
3
- "version": "2.13.0",
4
- "description": "Contracts and runtime utilities for external Mearl browser-control providers",
3
+ "version": "2.14.0",
4
+ "description": "Unified contracts and runtime utilities for built-in and external Mearl browser providers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  "registry": "https://registry.npmjs.org"
36
36
  },
37
37
  "dependencies": {
38
- "@mearl/daemon-core": "2.13.0"
38
+ "@mearl/daemon-core": "2.14.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^24.9.1",