@mearl/provider 2.13.0 → 2.15.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/README.md +104 -83
- package/dist/generated-provider-actions.d.ts +1 -1
- package/dist/generated-provider-actions.js +0 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/provider-runtime.d.ts +5 -0
- package/dist/provider-runtime.js +527 -0
- package/dist/registry.d.ts +25 -11
- package/dist/registry.js +41 -25
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +1 -0
- package/dist/server.js +93 -123
- package/dist/types.d.ts +162 -29
- package/dist/types.js +1 -1
- package/package.json +3 -3
package/dist/registry.js
CHANGED
|
@@ -3,6 +3,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
4
|
import { claimRecord, ensureDir, hashKey, isAlive, keyedConfigFile, keyedDir, listRecordFiles, readLiveRecords, readRecord, removeInvalidRecord, removeRecordIfPid, writeRecord, writeRecordIfPid, } from '@mearl/daemon-core';
|
|
5
5
|
import { MEARL_PROVIDER_PROTOCOL_VERSION, } from './types.js';
|
|
6
|
+
import { isProviderInputSchema } from './provider-runtime.js';
|
|
6
7
|
export const INSTALLED_PROVIDERS_SUBDIR = 'providers/installed';
|
|
7
8
|
export const LIVE_PROVIDERS_SUBDIR = 'providers/live';
|
|
8
9
|
export const STARTING_PROVIDERS_SUBDIR = 'providers/starting';
|
|
@@ -10,8 +11,14 @@ export const PROVIDER_SOCKETS_SUBDIR = 'providers/sockets';
|
|
|
10
11
|
export const PROVIDER_DATA_SUBDIR = 'providers/data';
|
|
11
12
|
export const BROWSERS_SUBDIR = 'browsers';
|
|
12
13
|
export const PROVIDER_START_TOKEN_ENV = 'MEARL_PROVIDER_START_TOKEN';
|
|
14
|
+
const RESERVED_PROVIDER_IDS = new Set(['local']);
|
|
13
15
|
export function providerBrowserKey(providerId, browserId) {
|
|
14
|
-
|
|
16
|
+
const redundantPrefix = `managed:${providerId}:`;
|
|
17
|
+
const scopedBrowserId = browserId.toLowerCase().startsWith(redundantPrefix.toLowerCase())
|
|
18
|
+
? browserId.slice(redundantPrefix.length)
|
|
19
|
+
: browserId;
|
|
20
|
+
const encodedBrowserId = encodeURIComponent(scopedBrowserId).replace(/%3A/gi, ':');
|
|
21
|
+
return `provider:${encodeURIComponent(providerId)}:${encodedBrowserId}`;
|
|
15
22
|
}
|
|
16
23
|
export function providerSocketPath(providerId) {
|
|
17
24
|
const suffix = hashKey(providerId);
|
|
@@ -89,6 +96,9 @@ export function validateInstalledProviderManifest(manifest) {
|
|
|
89
96
|
if (manifest.protocolVersion !== MEARL_PROVIDER_PROTOCOL_VERSION) {
|
|
90
97
|
return `protocol ${manifest.protocolVersion} is unsupported`;
|
|
91
98
|
}
|
|
99
|
+
if (RESERVED_PROVIDER_IDS.has(manifest.providerId)) {
|
|
100
|
+
return `providerId ${manifest.providerId} is reserved for a built-in Provider`;
|
|
101
|
+
}
|
|
92
102
|
if (!isProviderBrowserType(manifest.browserType)) {
|
|
93
103
|
return 'browserType is invalid';
|
|
94
104
|
}
|
|
@@ -135,25 +145,23 @@ function isProviderBrowserType(value) {
|
|
|
135
145
|
const browserType = value;
|
|
136
146
|
if (typeof browserType.name !== 'string' || !browserType.name.trim())
|
|
137
147
|
return false;
|
|
138
|
-
if (
|
|
148
|
+
if (browserType.documentationUrl !== undefined &&
|
|
149
|
+
(typeof browserType.documentationUrl !== 'string' ||
|
|
150
|
+
!/^https?:\/\//.test(browserType.documentationUrl)))
|
|
139
151
|
return false;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
keys.add(parameter.key);
|
|
155
|
-
}
|
|
156
|
-
return true;
|
|
152
|
+
if (browserType.help !== undefined &&
|
|
153
|
+
(!Array.isArray(browserType.help) ||
|
|
154
|
+
browserType.help.some(item => typeof item !== 'string' || !item.trim())))
|
|
155
|
+
return false;
|
|
156
|
+
if (!isProviderObjectSchema(browserType.inputSchema))
|
|
157
|
+
return false;
|
|
158
|
+
return (browserType.configuration === undefined ||
|
|
159
|
+
(Boolean(browserType.configuration) &&
|
|
160
|
+
typeof browserType.configuration === 'object' &&
|
|
161
|
+
isProviderObjectSchema(browserType.configuration.inputSchema)));
|
|
162
|
+
}
|
|
163
|
+
function isProviderObjectSchema(value) {
|
|
164
|
+
return isProviderInputSchema(value) && value.type === 'object';
|
|
157
165
|
}
|
|
158
166
|
export function registerProviderPackage(packageRoot) {
|
|
159
167
|
if (!isAbsolute(packageRoot))
|
|
@@ -290,13 +298,21 @@ export function publishProviderBrowsers(descriptor, socketPath, browsers, previo
|
|
|
290
298
|
browserName: browser.name,
|
|
291
299
|
socketPath,
|
|
292
300
|
transport: 'provider',
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
301
|
+
provider: {
|
|
302
|
+
id: descriptor.providerId,
|
|
303
|
+
name: descriptor.name,
|
|
304
|
+
builtin: descriptor.builtin === true,
|
|
305
|
+
version: descriptor.version,
|
|
306
|
+
protocolVersion: descriptor.protocolVersion ?? MEARL_PROVIDER_PROTOCOL_VERSION,
|
|
307
|
+
},
|
|
308
|
+
capabilities: browser.control.kind === 'provider' ? browser.control.capabilities : undefined,
|
|
309
|
+
status: browser.status,
|
|
310
|
+
ownership: browser.ownership,
|
|
311
|
+
persistence: browser.persistence,
|
|
312
|
+
operations: browser.operations,
|
|
299
313
|
pairing: browser.pairing,
|
|
314
|
+
references: browser.references,
|
|
315
|
+
details: browser.details,
|
|
300
316
|
startedAt: previous?.startedAt ?? startedAt,
|
|
301
317
|
updatedAt: now,
|
|
302
318
|
lastFocusedAt: Math.max(browser.lastFocusedAt ?? 0, previous?.lastFocusedAt ?? 0),
|
package/dist/runtime.d.ts
CHANGED
|
@@ -2,3 +2,4 @@
|
|
|
2
2
|
export { ensureInstalledProvidersRunning } from './launcher.js';
|
|
3
3
|
export { providerBrowserKey, readLiveProvider } from './registry.js';
|
|
4
4
|
export type { LiveProviderRecord } from './registry.js';
|
|
5
|
+
export { createProviderRuntime, validateProviderBrowser, validateProviderInput, } from './provider-runtime.js';
|
package/dist/runtime.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
/** Mearl host integration; Provider implementations should use the package root API. */
|
|
2
2
|
export { ensureInstalledProvidersRunning } from './launcher.js';
|
|
3
3
|
export { providerBrowserKey, readLiveProvider } from './registry.js';
|
|
4
|
+
export { createProviderRuntime, validateProviderBrowser, validateProviderInput, } from './provider-runtime.js';
|
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;
|
|
@@ -11,6 +12,15 @@ const activeProviderIds = new Set();
|
|
|
11
12
|
function errorMessage(error) {
|
|
12
13
|
return error instanceof Error ? error.message : String(error);
|
|
13
14
|
}
|
|
15
|
+
function isProviderHostContextData(value) {
|
|
16
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
17
|
+
return false;
|
|
18
|
+
const host = value;
|
|
19
|
+
return ((host.userAgent === undefined || typeof host.userAgent === 'string') &&
|
|
20
|
+
(host.cookies === undefined ||
|
|
21
|
+
(Array.isArray(host.cookies) &&
|
|
22
|
+
host.cookies.every(cookie => cookie && typeof cookie === 'object' && !Array.isArray(cookie)))));
|
|
23
|
+
}
|
|
14
24
|
function isProviderActionRequest(value) {
|
|
15
25
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
16
26
|
return false;
|
|
@@ -25,156 +35,116 @@ function isProviderActionRequest(value) {
|
|
|
25
35
|
!Array.isArray(request.data))) &&
|
|
26
36
|
(request.browserId === undefined || typeof request.browserId === 'string') &&
|
|
27
37
|
(request.version === undefined || typeof request.version === 'string') &&
|
|
28
|
-
(request.controlSource === undefined || typeof request.controlSource === 'string')
|
|
38
|
+
(request.controlSource === undefined || typeof request.controlSource === 'string') &&
|
|
39
|
+
(request.host === undefined || isProviderHostContextData(request.host)));
|
|
40
|
+
}
|
|
41
|
+
function providerContext(request) {
|
|
42
|
+
const hostData = request.host;
|
|
43
|
+
return {
|
|
44
|
+
controlSource: request.controlSource,
|
|
45
|
+
...(hostData
|
|
46
|
+
? {
|
|
47
|
+
host: {
|
|
48
|
+
async request(method) {
|
|
49
|
+
if (method === 'export_cookies')
|
|
50
|
+
return (hostData.cookies ?? []);
|
|
51
|
+
if (method === 'get_browser_user_agent') {
|
|
52
|
+
if (!hostData.userAgent)
|
|
53
|
+
throw new Error('Host browser user agent is unavailable');
|
|
54
|
+
return hostData.userAgent;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`Unsupported Provider host service: ${method}`);
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
: {}),
|
|
61
|
+
};
|
|
29
62
|
}
|
|
30
63
|
export function createProviderServer(options) {
|
|
31
|
-
const
|
|
64
|
+
const runtime = createProviderRuntime(options.definition);
|
|
65
|
+
const descriptor = options.definition.descriptor;
|
|
66
|
+
const socketPath = options.socketPath ?? providerSocketPath(descriptor.providerId);
|
|
32
67
|
let server = null;
|
|
33
68
|
let browserIds = new Set();
|
|
34
69
|
let browsers = [];
|
|
35
70
|
let state = 'idle';
|
|
36
71
|
let stopPromise = null;
|
|
37
72
|
const connections = new Set();
|
|
38
|
-
function
|
|
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) {
|
|
73
|
+
async function providerBrowserId(requested) {
|
|
94
74
|
if (requested)
|
|
95
75
|
return requested;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
76
|
+
const available = await runtime.listBrowsers();
|
|
77
|
+
if (available.length === 1)
|
|
78
|
+
return available[0].browserId;
|
|
79
|
+
if (available.length === 0)
|
|
80
|
+
throw new Error('Provider has no browser instances');
|
|
100
81
|
throw new Error('browserId is required when the provider has multiple browsers');
|
|
101
82
|
}
|
|
102
83
|
async function dispatch(request) {
|
|
84
|
+
const context = providerContext(request);
|
|
103
85
|
if (request.action === 'browser_launch') {
|
|
104
86
|
if (request.browserId)
|
|
105
87
|
throw new Error('browser_launch does not accept browserId');
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
throw new Error('Provider returned an invalid browser creation result');
|
|
124
|
-
}
|
|
125
|
-
return created;
|
|
88
|
+
return runtime.launch(request.data ?? {}, context);
|
|
89
|
+
}
|
|
90
|
+
if (request.action === 'browser_provider_configure') {
|
|
91
|
+
if (request.browserId)
|
|
92
|
+
throw new Error('Provider configuration does not accept browserId');
|
|
93
|
+
return runtime.configure(request.data ?? {}, context);
|
|
94
|
+
}
|
|
95
|
+
if (request.action === 'browser_manager_start') {
|
|
96
|
+
return runtime.start({ browserId: await providerBrowserId(request.browserId) }, context);
|
|
97
|
+
}
|
|
98
|
+
if (request.action === 'browser_manager_sync_cookies') {
|
|
99
|
+
return runtime.syncCookies({
|
|
100
|
+
browserId: await providerBrowserId(request.browserId),
|
|
101
|
+
scope: request.data?.scope,
|
|
102
|
+
}, context);
|
|
126
103
|
}
|
|
127
104
|
if (request.action !== 'get_versions' &&
|
|
128
105
|
request.action !== 'browser_close' &&
|
|
106
|
+
request.action !== 'get_browser_access_url' &&
|
|
129
107
|
!isProviderAction(request.action)) {
|
|
130
108
|
throw new Error(`Unsupported provider action: ${String(request.action)}`);
|
|
131
109
|
}
|
|
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}`);
|
|
110
|
+
const browserId = await providerBrowserId(request.browserId);
|
|
136
111
|
if (request.action === 'browser_close') {
|
|
137
|
-
return
|
|
112
|
+
return runtime.close({ browserId, deleteData: request.data?.deleteProfile === true }, context);
|
|
113
|
+
}
|
|
114
|
+
if (request.action === 'get_browser_access_url') {
|
|
115
|
+
return {
|
|
116
|
+
browserAccess: await runtime.getAccess({ browserId }, context),
|
|
117
|
+
};
|
|
138
118
|
}
|
|
139
119
|
if (request.action === 'get_versions') {
|
|
120
|
+
const found = (await runtime.listBrowsers()).find(browser => browser.browserId === browserId);
|
|
121
|
+
if (!found)
|
|
122
|
+
throw new Error(`Provider browser not found: ${browserId}`);
|
|
140
123
|
return {
|
|
141
124
|
provider: {
|
|
142
|
-
|
|
143
|
-
name:
|
|
144
|
-
|
|
145
|
-
|
|
125
|
+
id: descriptor.providerId,
|
|
126
|
+
name: descriptor.name,
|
|
127
|
+
builtin: descriptor.builtin === true,
|
|
128
|
+
version: descriptor.version,
|
|
129
|
+
protocolVersion: descriptor.protocolVersion ?? MEARL_PROVIDER_PROTOCOL_VERSION,
|
|
146
130
|
},
|
|
147
|
-
capabilities: found.capabilities,
|
|
131
|
+
capabilities: found.control.kind === 'provider' ? found.control.capabilities : undefined,
|
|
148
132
|
};
|
|
149
133
|
}
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
134
|
+
if (request.action === 'browser_release') {
|
|
135
|
+
const found = (await runtime.listBrowsers()).find(browser => browser.browserId === browserId);
|
|
136
|
+
if (found?.operations.includes('detach')) {
|
|
137
|
+
return runtime.detach({ browserId }, context);
|
|
138
|
+
}
|
|
155
139
|
}
|
|
156
|
-
touchProviderBrowser(providerBrowserKey(
|
|
157
|
-
return
|
|
140
|
+
touchProviderBrowser(providerBrowserKey(descriptor.providerId, browserId));
|
|
141
|
+
return runtime.invokeAction({
|
|
158
142
|
browserId,
|
|
159
143
|
action: request.action,
|
|
160
144
|
data: request.data ?? {},
|
|
161
145
|
controlSource: request.controlSource,
|
|
162
146
|
});
|
|
163
147
|
}
|
|
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
148
|
function handleConnection(socket) {
|
|
179
149
|
connections.add(socket);
|
|
180
150
|
socket.once('close', () => connections.delete(socket));
|
|
@@ -216,22 +186,22 @@ export function createProviderServer(options) {
|
|
|
216
186
|
}
|
|
217
187
|
return {
|
|
218
188
|
socketPath,
|
|
189
|
+
runtime,
|
|
219
190
|
async start() {
|
|
220
191
|
if (state !== 'idle')
|
|
221
192
|
throw new Error(`Provider server is already ${state}`);
|
|
222
|
-
|
|
223
|
-
const providerId = options.descriptor.providerId;
|
|
193
|
+
const providerId = descriptor.providerId;
|
|
224
194
|
if (activeProviderIds.has(providerId)) {
|
|
225
195
|
throw new Error(`Provider ${providerId} is already running in this process`);
|
|
226
196
|
}
|
|
227
197
|
state = 'starting';
|
|
228
198
|
activeProviderIds.add(providerId);
|
|
229
199
|
const startToken = process.env[PROVIDER_START_TOKEN_ENV] || randomUUID();
|
|
230
|
-
const existing = readLiveProvider(
|
|
200
|
+
const existing = readLiveProvider(descriptor.providerId);
|
|
231
201
|
if (existing) {
|
|
232
202
|
state = 'idle';
|
|
233
203
|
activeProviderIds.delete(providerId);
|
|
234
|
-
throw new Error(`Provider ${
|
|
204
|
+
throw new Error(`Provider ${descriptor.providerId} is already running (pid ${existing.pid})`);
|
|
235
205
|
}
|
|
236
206
|
if (!claimProviderStart(providerId, startToken)) {
|
|
237
207
|
state = 'idle';
|
|
@@ -256,7 +226,7 @@ export function createProviderServer(options) {
|
|
|
256
226
|
});
|
|
257
227
|
if (process.platform !== 'win32')
|
|
258
228
|
chmodSync(socketPath, 0o600);
|
|
259
|
-
publishLiveProvider(
|
|
229
|
+
publishLiveProvider(descriptor, socketPath);
|
|
260
230
|
releaseProviderStart(providerId, startToken);
|
|
261
231
|
state = 'running';
|
|
262
232
|
}
|
|
@@ -281,9 +251,9 @@ export function createProviderServer(options) {
|
|
|
281
251
|
updateBrowsers(nextBrowsers) {
|
|
282
252
|
if (state !== 'running')
|
|
283
253
|
throw new Error('Provider server is not running');
|
|
284
|
-
|
|
254
|
+
runtime.updateBrowsers(nextBrowsers);
|
|
285
255
|
browsers = [...nextBrowsers];
|
|
286
|
-
browserIds = publishProviderBrowsers(
|
|
256
|
+
browserIds = publishProviderBrowsers(descriptor, socketPath, browsers, browserIds);
|
|
287
257
|
},
|
|
288
258
|
touchBrowser(browserId) {
|
|
289
259
|
if (state !== 'running')
|
|
@@ -291,7 +261,7 @@ export function createProviderServer(options) {
|
|
|
291
261
|
if (!browsers.some(browser => browser.browserId === browserId)) {
|
|
292
262
|
throw new Error(`Provider browser not found: ${browserId}`);
|
|
293
263
|
}
|
|
294
|
-
touchProviderBrowser(providerBrowserKey(
|
|
264
|
+
touchProviderBrowser(providerBrowserKey(descriptor.providerId, browserId));
|
|
295
265
|
},
|
|
296
266
|
async stop() {
|
|
297
267
|
if (state === 'idle')
|
|
@@ -314,9 +284,9 @@ export function createProviderServer(options) {
|
|
|
314
284
|
browsers = [];
|
|
315
285
|
if (process.platform !== 'win32')
|
|
316
286
|
rmSync(socketPath, { force: true });
|
|
317
|
-
unpublishLiveProvider(
|
|
287
|
+
unpublishLiveProvider(descriptor.providerId);
|
|
318
288
|
})().finally(() => {
|
|
319
|
-
activeProviderIds.delete(
|
|
289
|
+
activeProviderIds.delete(descriptor.providerId);
|
|
320
290
|
stopPromise = null;
|
|
321
291
|
state = 'idle';
|
|
322
292
|
});
|