@vscode/component-explorer-cli 0.2.1-162 → 0.2.1-164
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 +90 -0
- package/dist/_virtual/_build-info.js +1 -1
- package/dist/commands/mcpCommand.js +6 -1
- package/dist/commands/mcpCommand.js.map +1 -1
- package/dist/commands/serveCommand.d.ts +4 -1
- package/dist/commands/serveCommand.d.ts.map +1 -1
- package/dist/commands/serveCommand.js +91 -25
- package/dist/commands/serveCommand.js.map +1 -1
- package/dist/daemon/DaemonService.d.ts +5 -208
- package/dist/daemon/DaemonService.d.ts.map +1 -1
- package/dist/daemon/DaemonService.js +228 -304
- package/dist/daemon/DaemonService.js.map +1 -1
- package/dist/daemon/client.d.ts +76 -5
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/daemonRpc.test.d.ts +2 -0
- package/dist/daemon/daemonRpc.test.d.ts.map +1 -0
- package/dist/daemon/endpointServer.d.ts +4 -0
- package/dist/daemon/endpointServer.d.ts.map +1 -0
- package/dist/daemon/endpointServer.js +24 -0
- package/dist/daemon/endpointServer.js.map +1 -0
- package/dist/daemon/inProcessClient.d.ts +3 -9
- package/dist/daemon/inProcessClient.d.ts.map +1 -1
- package/dist/daemon/inProcessClient.js +29 -30
- package/dist/daemon/inProcessClient.js.map +1 -1
- package/dist/daemon/lifecycle.d.ts +4 -5
- package/dist/daemon/lifecycle.d.ts.map +1 -1
- package/dist/daemon/lifecycle.js +3 -2
- package/dist/daemon/lifecycle.js.map +1 -1
- package/dist/daemon/pipeClient.d.ts +2 -3
- package/dist/daemon/pipeClient.d.ts.map +1 -1
- package/dist/daemon/pipeClient.js +93 -195
- package/dist/daemon/pipeClient.js.map +1 -1
- package/dist/daemon/pipeName.d.ts +2 -2
- package/dist/daemon/pipeName.d.ts.map +1 -1
- package/dist/daemon/pipeName.js +6 -4
- package/dist/daemon/pipeName.js.map +1 -1
- package/dist/daemon/pipeServer.d.ts +2 -2
- package/dist/daemon/pipeServer.d.ts.map +1 -1
- package/dist/daemon/pipeServer.js +79 -70
- package/dist/daemon/pipeServer.js.map +1 -1
- package/dist/daemon/registerDaemonConnection.d.ts +7 -0
- package/dist/daemon/registerDaemonConnection.d.ts.map +1 -0
- package/dist/daemon/registerDaemonConnection.js +37 -0
- package/dist/daemon/registerDaemonConnection.js.map +1 -0
- package/dist/daemon/transports.test.d.ts +2 -0
- package/dist/daemon/transports.test.d.ts.map +1 -0
- package/dist/daemon/types.d.ts +1655 -8
- package/dist/daemon/types.d.ts.map +1 -1
- package/dist/daemon/types.js +4 -0
- package/dist/daemon/types.js.map +1 -0
- package/dist/daemon/version.d.ts +1 -5
- package/dist/daemon/version.d.ts.map +1 -1
- package/dist/daemon/version.js +2 -6
- package/dist/daemon/version.js.map +1 -1
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/chunks/inspectionHost-BA6ZmC_P.js +2523 -0
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/chunks/inspectionHost-BA6ZmC_P.js.map +1 -0
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/chunks/src-DYVSK_tz.js +1871 -0
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/chunks/src-DYVSK_tz.js.map +1 -0
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/chunks/webSocketTransport-Ct4OIdG9.js +220 -0
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/chunks/webSocketTransport-Ct4OIdG9.js.map +1 -0
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/node.js +721 -0
- package/dist/external/linkrpc/typescript/packages/linkrpc/dist/node.js.map +1 -0
- package/dist/index.d.ts +0 -2
- package/dist/js-component-explorer/packages/common/dist/daemonRpc.js +165 -0
- package/dist/js-component-explorer/packages/common/dist/daemonRpc.js.map +1 -0
- package/dist/mcp/DaemonAccessor.d.ts +2 -3
- package/dist/mcp/DaemonAccessor.d.ts.map +1 -1
- package/dist/mcp/McpServer.d.ts +1 -1
- package/dist/mcp/McpServer.d.ts.map +1 -1
- package/dist/mcp/McpServer.js +69 -58
- package/dist/mcp/McpServer.js.map +1 -1
- package/dist/renderManifest.d.ts +70 -5
- package/dist/server/serverConfig.d.ts +0 -2
- package/dist/server/serverConfig.d.ts.map +1 -1
- package/dist/server/serverConfig.js.map +1 -1
- package/dist/server/viteServer.d.ts +0 -2
- package/dist/server/viteServer.d.ts.map +1 -1
- package/dist/server/viteServer.js.map +1 -1
- package/package.json +9 -8
- package/dist/formatValue.js +0 -96
- package/dist/formatValue.js.map +0 -1
- package/dist/js-component-explorer/packages/simple-api/dist/chunk-FJ7AVNQE.js +0 -138
- package/dist/js-component-explorer/packages/simple-api/dist/chunk-FJ7AVNQE.js.map +0 -1
- package/dist/js-component-explorer/packages/simple-api/dist/chunk-TTRCY65Z.js +0 -27
- package/dist/js-component-explorer/packages/simple-api/dist/chunk-TTRCY65Z.js.map +0 -1
- package/dist/js-component-explorer/packages/simple-api/dist/chunk-WNXMRXWV.js +0 -28
- package/dist/js-component-explorer/packages/simple-api/dist/chunk-WNXMRXWV.js.map +0 -1
- package/dist/js-component-explorer/packages/simple-api/dist/express.js +0 -104
- package/dist/js-component-explorer/packages/simple-api/dist/express.js.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import '../vscode-observables/observables/dist/observableInternal/index.js';
|
|
3
2
|
import { observableValue } from '../vscode-observables/observables/dist/observableInternal/observables/observableValue.js';
|
|
4
3
|
import '../vscode-observables/observables/dist/observableInternal/debugLocation.js';
|
|
@@ -7,8 +6,8 @@ import { derived } from '../vscode-observables/observables/dist/observableIntern
|
|
|
7
6
|
import { waitForState } from '../vscode-observables/observables/dist/observableInternal/utils/utilsCancellation.js';
|
|
8
7
|
import '../vscode-observables/observables/dist/observableInternal/utils/utils.js';
|
|
9
8
|
import '../vscode-observables/observables/dist/observableInternal/observables/observableFromEvent.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { nt as defaultInterfaceTarget } from '../external/linkrpc/typescript/packages/linkrpc/dist/chunks/src-DYVSK_tz.js';
|
|
10
|
+
import { daemonRpcInterface } from '../js-component-explorer/packages/common/dist/daemonRpc.js';
|
|
12
11
|
import { ExplorerSession } from '../explorerSession.js';
|
|
13
12
|
import '../config.js';
|
|
14
13
|
import { RelativePath } from '../path.js';
|
|
@@ -21,7 +20,6 @@ import { FileApprovalStore } from './approvalStore.js';
|
|
|
21
20
|
import { VisualCache } from '../visualCache.js';
|
|
22
21
|
import { contentHash } from '../screenshotCache.js';
|
|
23
22
|
import { WorktreePool } from '../WorktreePool.js';
|
|
24
|
-
import { pluginProtocolVersionText, daemonApiVersionText } from './version.js';
|
|
25
23
|
export { isCompatibleVersion, parseVersion } from './version.js';
|
|
26
24
|
import { ViteServerConfig } from '../server/serverConfig.js';
|
|
27
25
|
|
|
@@ -108,7 +106,6 @@ class DaemonService {
|
|
|
108
106
|
_worktreePool;
|
|
109
107
|
approvals;
|
|
110
108
|
visualCache;
|
|
111
|
-
api;
|
|
112
109
|
constructor(_config, _pipeName, _logger, _browserFactory, approvalStorePath, idleTimeoutMs) {
|
|
113
110
|
this._config = _config;
|
|
114
111
|
this._pipeName = _pipeName;
|
|
@@ -120,350 +117,265 @@ class DaemonService {
|
|
|
120
117
|
if (_config.worktreePool) {
|
|
121
118
|
this._worktreePool = new WorktreePool(_config.worktreePool.maxSlots, _config.repo.worktreeRootPath());
|
|
122
119
|
}
|
|
123
|
-
this.api = this._buildApi();
|
|
124
120
|
}
|
|
125
121
|
static async create(config, logger, pipeName, options) {
|
|
126
122
|
const browserFactory = new PlaywrightBrowserPageFactory(options?.headed ?? false, 30_000, logger);
|
|
127
123
|
const approvalStorePath = config.screenshotDir.join(new RelativePath('approvals.json'));
|
|
128
124
|
const idleTimeoutMs = options?.idleTimeoutMs ?? 5 * 60 * 1000; // 5 minutes default
|
|
129
125
|
const svc = new DaemonService(config, pipeName, logger, browserFactory, approvalStorePath, idleTimeoutMs);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
126
|
+
try {
|
|
127
|
+
for (const sessionConfig of config.sessions) {
|
|
128
|
+
svc._sessionConfigs.set(sessionConfig.name, sessionConfig);
|
|
129
|
+
await svc._setupSession(sessionConfig);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
await svc.dispose();
|
|
134
|
+
throw error;
|
|
133
135
|
}
|
|
134
136
|
return svc;
|
|
135
137
|
}
|
|
136
138
|
// -- API definition ------------------------------------------------------
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}),
|
|
154
|
-
}),
|
|
155
|
-
screenshots: createApi({
|
|
156
|
-
take: createMethod({
|
|
157
|
-
args: {
|
|
158
|
-
fixtureId: z.string(),
|
|
159
|
-
sourceTreeId: z.string(),
|
|
160
|
-
sessionName: z.string(),
|
|
161
|
-
includeImage: z.boolean().optional(),
|
|
162
|
-
stabilityCheck: z.boolean().optional(),
|
|
163
|
-
reloadBeforeRender: z.boolean().optional(),
|
|
164
|
-
input: z.unknown().optional(),
|
|
165
|
-
disposeAfter: z.boolean().optional(),
|
|
166
|
-
},
|
|
167
|
-
}, async (args) => {
|
|
168
|
-
this._activityTracker.reportActivity();
|
|
169
|
-
const session = this.getSession(args.sessionName);
|
|
170
|
-
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
171
|
-
if (args.stabilityCheck) {
|
|
172
|
-
const result = await session.explorer.screenshotFixtureStabilityCheck(args.fixtureId, {
|
|
173
|
-
reloadBeforeRender: args.reloadBeforeRender,
|
|
174
|
-
input: args.input,
|
|
175
|
-
disposeAfter: args.disposeAfter,
|
|
176
|
-
});
|
|
177
|
-
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
178
|
-
const hashes = result.screenshots.map(s => contentHash(s.image));
|
|
179
|
-
const isStable = hashes[0] === hashes[1] && hashes[1] === hashes[2];
|
|
180
|
-
const stabilityScreenshots = result.screenshots.map((s, i) => ({
|
|
181
|
-
hash: hashes[i],
|
|
182
|
-
delayMs: s.delayMs,
|
|
183
|
-
image: (args.includeImage ?? true)
|
|
184
|
-
? Buffer.from(s.image).toString('base64')
|
|
185
|
-
: undefined,
|
|
186
|
-
}));
|
|
187
|
-
return {
|
|
188
|
-
hash: hashes[hashes.length - 1],
|
|
189
|
-
sourceTreeId: args.sourceTreeId,
|
|
190
|
-
image: (args.includeImage ?? true)
|
|
191
|
-
? Buffer.from(result.screenshots[result.screenshots.length - 1].image).toString('base64')
|
|
192
|
-
: undefined,
|
|
193
|
-
hasError: result.hasError,
|
|
194
|
-
error: result.error,
|
|
195
|
-
events: result.events.length > 0 ? result.events : undefined,
|
|
196
|
-
output: result.output,
|
|
197
|
-
isStable,
|
|
198
|
-
stabilityScreenshots,
|
|
199
|
-
previousDispose: result.previousDispose,
|
|
200
|
-
currentDispose: result.currentDispose,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
const result = await session.explorer.screenshotFixture(args.fixtureId, {
|
|
139
|
+
registerRpc(connection, context) {
|
|
140
|
+
const registration = connection.register(defaultInterfaceTarget(daemonRpcInterface), {
|
|
141
|
+
fixturesList: async (args) => {
|
|
142
|
+
this._activityTracker.reportActivity();
|
|
143
|
+
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
144
|
+
const session = this.getSession(args.sessionName);
|
|
145
|
+
const result = await session.explorer.listFixtures();
|
|
146
|
+
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
147
|
+
return result;
|
|
148
|
+
},
|
|
149
|
+
screenshotsTake: async (args) => {
|
|
150
|
+
this._activityTracker.reportActivity();
|
|
151
|
+
const session = this.getSession(args.sessionName);
|
|
152
|
+
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
153
|
+
if (args.stabilityCheck) {
|
|
154
|
+
const result = await session.explorer.screenshotFixtureStabilityCheck(args.fixtureId, {
|
|
204
155
|
reloadBeforeRender: args.reloadBeforeRender,
|
|
205
156
|
input: args.input,
|
|
206
157
|
disposeAfter: args.disposeAfter,
|
|
207
158
|
});
|
|
208
159
|
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
160
|
+
const hashes = result.screenshots.map(s => contentHash(s.image));
|
|
161
|
+
const isStable = hashes[0] === hashes[1] && hashes[1] === hashes[2];
|
|
162
|
+
const stabilityScreenshots = result.screenshots.map((s, i) => ({
|
|
163
|
+
hash: hashes[i],
|
|
164
|
+
delayMs: s.delayMs,
|
|
165
|
+
image: (args.includeImage ?? true)
|
|
166
|
+
? Buffer.from(s.image).toString('base64')
|
|
167
|
+
: undefined,
|
|
168
|
+
}));
|
|
209
169
|
return {
|
|
210
|
-
hash:
|
|
170
|
+
hash: hashes[hashes.length - 1],
|
|
211
171
|
sourceTreeId: args.sourceTreeId,
|
|
212
|
-
image: (args.includeImage ?? true)
|
|
213
|
-
? Buffer.from(result.image).toString('base64')
|
|
172
|
+
image: (args.includeImage ?? true)
|
|
173
|
+
? Buffer.from(result.screenshots[result.screenshots.length - 1].image).toString('base64')
|
|
214
174
|
: undefined,
|
|
215
175
|
hasError: result.hasError,
|
|
216
176
|
error: result.error,
|
|
217
|
-
events: result.events
|
|
177
|
+
events: result.events.length > 0 ? result.events : undefined,
|
|
218
178
|
output: result.output,
|
|
179
|
+
isStable,
|
|
180
|
+
stabilityScreenshots,
|
|
219
181
|
previousDispose: result.previousDispose,
|
|
220
182
|
currentDispose: result.currentDispose,
|
|
221
183
|
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
184
|
+
}
|
|
185
|
+
const result = await session.explorer.screenshotFixture(args.fixtureId, {
|
|
186
|
+
reloadBeforeRender: args.reloadBeforeRender,
|
|
187
|
+
input: args.input,
|
|
188
|
+
disposeAfter: args.disposeAfter,
|
|
189
|
+
});
|
|
190
|
+
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
191
|
+
return {
|
|
192
|
+
hash: result.image ? contentHash(result.image) : undefined,
|
|
193
|
+
sourceTreeId: args.sourceTreeId,
|
|
194
|
+
image: (args.includeImage ?? true) && result.image
|
|
195
|
+
? Buffer.from(result.image).toString('base64')
|
|
196
|
+
: undefined,
|
|
197
|
+
hasError: result.hasError,
|
|
198
|
+
error: result.error,
|
|
199
|
+
events: result.events?.length > 0 ? result.events : undefined,
|
|
200
|
+
output: result.output,
|
|
201
|
+
previousDispose: result.previousDispose,
|
|
202
|
+
currentDispose: result.currentDispose,
|
|
203
|
+
};
|
|
204
|
+
},
|
|
205
|
+
screenshotsTakeBatch: async (args) => {
|
|
206
|
+
this._activityTracker.reportActivity();
|
|
207
|
+
const session = this.getSession(args.sessionName);
|
|
208
|
+
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
209
|
+
const includeImages = args.includeImages ?? false;
|
|
210
|
+
this._logger.trace(`takeBatch: ${args.fixtureIds.length} fixtures, session=${args.sessionName}`);
|
|
211
|
+
const startTime = Date.now();
|
|
212
|
+
const screenshots = [];
|
|
213
|
+
for (let i = 0; i < args.fixtureIds.length; i++) {
|
|
214
|
+
const fixtureId = args.fixtureIds[i];
|
|
215
|
+
const result = await session.explorer.screenshotFixture(fixtureId, {
|
|
216
|
+
reloadOnError: true,
|
|
217
|
+
// Reload between fixtures (skip before the first one — the page is already fresh)
|
|
218
|
+
reloadBeforeRender: args.reloadBetweenFixtures && i > 0,
|
|
219
|
+
input: args.input,
|
|
220
|
+
});
|
|
235
221
|
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const fixtureId = args.fixtureIds[i];
|
|
242
|
-
const result = await session.explorer.screenshotFixture(fixtureId, {
|
|
243
|
-
reloadOnError: true,
|
|
244
|
-
// Reload between fixtures (skip before the first one — the page is already fresh)
|
|
245
|
-
reloadBeforeRender: args.reloadBetweenFixtures && i > 0,
|
|
246
|
-
input: args.input,
|
|
247
|
-
});
|
|
248
|
-
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
249
|
-
screenshots.push({
|
|
250
|
-
fixtureId,
|
|
251
|
-
hash: result.image ? contentHash(result.image) : undefined,
|
|
252
|
-
image: includeImages && result.image
|
|
253
|
-
? Buffer.from(result.image).toString('base64')
|
|
254
|
-
: undefined,
|
|
255
|
-
hasError: result.hasError,
|
|
256
|
-
error: result.error,
|
|
257
|
-
events: result.events.length > 0 ? result.events : undefined,
|
|
258
|
-
output: result.output,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
this._logger.trace(`takeBatch: done in ${Date.now() - startTime}ms`);
|
|
262
|
-
return { sourceTreeId: args.sourceTreeId, screenshots };
|
|
263
|
-
}),
|
|
264
|
-
compare: createMethod({
|
|
265
|
-
args: {
|
|
266
|
-
fixtureId: z.string(),
|
|
267
|
-
baselineSessionName: z.string(),
|
|
268
|
-
baselineSourceTreeId: z.string(),
|
|
269
|
-
currentSessionName: z.string(),
|
|
270
|
-
currentSourceTreeId: z.string(),
|
|
271
|
-
includeImages: z.boolean().optional(),
|
|
272
|
-
},
|
|
273
|
-
}, async (args) => {
|
|
274
|
-
this._activityTracker.reportActivity();
|
|
275
|
-
const baselineSession = this.getSession(args.baselineSessionName);
|
|
276
|
-
const currentSession = this.getSession(args.currentSessionName);
|
|
277
|
-
this.assertSourceTreeId(args.baselineSessionName, args.baselineSourceTreeId);
|
|
278
|
-
this.assertSourceTreeId(args.currentSessionName, args.currentSourceTreeId);
|
|
279
|
-
const [baselineResult, baselineListResult] = await Promise.all([
|
|
280
|
-
baselineSession.explorer.screenshotFixture(args.fixtureId),
|
|
281
|
-
baselineSession.explorer.listFixtures(),
|
|
282
|
-
]);
|
|
283
|
-
this.assertSourceTreeId(args.baselineSessionName, args.baselineSourceTreeId);
|
|
284
|
-
const [currentResult, currentListResult] = await Promise.all([
|
|
285
|
-
currentSession.explorer.screenshotFixture(args.fixtureId),
|
|
286
|
-
currentSession.explorer.listFixtures(),
|
|
287
|
-
]);
|
|
288
|
-
this.assertSourceTreeId(args.currentSessionName, args.currentSourceTreeId);
|
|
289
|
-
const baselineHash = baselineResult.image ? contentHash(baselineResult.image) : undefined;
|
|
290
|
-
const currentHash = currentResult.image ? contentHash(currentResult.image) : undefined;
|
|
291
|
-
const includeImages = args.includeImages ?? false;
|
|
292
|
-
const currentFixture = currentListResult.fixtures.find(f => f.fixtureId === args.fixtureId);
|
|
293
|
-
const baselineFixture = baselineListResult.fixtures.find(f => f.fixtureId === args.fixtureId);
|
|
294
|
-
const labels = currentFixture?.labels;
|
|
295
|
-
const labelsChanged = baselineFixture && !arraysEqual(baselineFixture.labels, currentFixture?.labels ?? []);
|
|
296
|
-
return {
|
|
297
|
-
match: baselineHash === currentHash,
|
|
298
|
-
baselineHash,
|
|
299
|
-
currentHash,
|
|
300
|
-
baselineImage: includeImages && baselineResult.image
|
|
301
|
-
? Buffer.from(baselineResult.image).toString('base64') : undefined,
|
|
302
|
-
currentImage: includeImages && currentResult.image
|
|
303
|
-
? Buffer.from(currentResult.image).toString('base64') : undefined,
|
|
304
|
-
baselineHasError: baselineResult.hasError,
|
|
305
|
-
baselineError: baselineResult.error,
|
|
306
|
-
baselineEvents: baselineResult.events.length > 0 ? baselineResult.events : undefined,
|
|
307
|
-
baselineOutput: baselineResult.output,
|
|
308
|
-
currentHasError: currentResult.hasError,
|
|
309
|
-
currentError: currentResult.error,
|
|
310
|
-
currentEvents: currentResult.events.length > 0 ? currentResult.events : undefined,
|
|
311
|
-
currentOutput: currentResult.output,
|
|
312
|
-
labels,
|
|
313
|
-
labelsBefore: labelsChanged ? baselineFixture.labels : undefined,
|
|
314
|
-
approval: (baselineHash !== undefined && currentHash !== undefined && baselineHash !== currentHash)
|
|
315
|
-
? this.approvals.lookup({
|
|
316
|
-
fixtureId: args.fixtureId,
|
|
317
|
-
originalHash: baselineHash,
|
|
318
|
-
modifiedHash: currentHash,
|
|
319
|
-
}) ?? undefined
|
|
222
|
+
screenshots.push({
|
|
223
|
+
fixtureId,
|
|
224
|
+
hash: result.image ? contentHash(result.image) : undefined,
|
|
225
|
+
image: includeImages && result.image
|
|
226
|
+
? Buffer.from(result.image).toString('base64')
|
|
320
227
|
: undefined,
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
args
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
228
|
+
hasError: result.hasError,
|
|
229
|
+
error: result.error,
|
|
230
|
+
events: result.events.length > 0 ? result.events : undefined,
|
|
231
|
+
output: result.output,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
this._logger.trace(`takeBatch: done in ${Date.now() - startTime}ms`);
|
|
235
|
+
return { sourceTreeId: args.sourceTreeId, screenshots };
|
|
236
|
+
},
|
|
237
|
+
screenshotsCompare: async (args) => {
|
|
238
|
+
this._activityTracker.reportActivity();
|
|
239
|
+
const baselineSession = this.getSession(args.baselineSessionName);
|
|
240
|
+
const currentSession = this.getSession(args.currentSessionName);
|
|
241
|
+
this.assertSourceTreeId(args.baselineSessionName, args.baselineSourceTreeId);
|
|
242
|
+
this.assertSourceTreeId(args.currentSessionName, args.currentSourceTreeId);
|
|
243
|
+
const [baselineResult, baselineListResult] = await Promise.all([
|
|
244
|
+
baselineSession.explorer.screenshotFixture(args.fixtureId),
|
|
245
|
+
baselineSession.explorer.listFixtures(),
|
|
246
|
+
]);
|
|
247
|
+
this.assertSourceTreeId(args.baselineSessionName, args.baselineSourceTreeId);
|
|
248
|
+
const [currentResult, currentListResult] = await Promise.all([
|
|
249
|
+
currentSession.explorer.screenshotFixture(args.fixtureId),
|
|
250
|
+
currentSession.explorer.listFixtures(),
|
|
251
|
+
]);
|
|
252
|
+
this.assertSourceTreeId(args.currentSessionName, args.currentSourceTreeId);
|
|
253
|
+
const baselineHash = baselineResult.image ? contentHash(baselineResult.image) : undefined;
|
|
254
|
+
const currentHash = currentResult.image ? contentHash(currentResult.image) : undefined;
|
|
255
|
+
const includeImages = args.includeImages ?? false;
|
|
256
|
+
const currentFixture = currentListResult.fixtures.find(f => f.fixtureId === args.fixtureId);
|
|
257
|
+
const baselineFixture = baselineListResult.fixtures.find(f => f.fixtureId === args.fixtureId);
|
|
258
|
+
const labels = currentFixture?.labels;
|
|
259
|
+
const labelsChanged = baselineFixture && !arraysEqual(baselineFixture.labels, currentFixture?.labels ?? []);
|
|
260
|
+
return {
|
|
261
|
+
match: baselineHash === currentHash,
|
|
262
|
+
baselineHash,
|
|
263
|
+
currentHash,
|
|
264
|
+
baselineImage: includeImages && baselineResult.image
|
|
265
|
+
? Buffer.from(baselineResult.image).toString('base64') : undefined,
|
|
266
|
+
currentImage: includeImages && currentResult.image
|
|
267
|
+
? Buffer.from(currentResult.image).toString('base64') : undefined,
|
|
268
|
+
baselineHasError: baselineResult.hasError,
|
|
269
|
+
baselineError: baselineResult.error,
|
|
270
|
+
baselineEvents: baselineResult.events.length > 0 ? baselineResult.events : undefined,
|
|
271
|
+
baselineOutput: baselineResult.output,
|
|
272
|
+
currentHasError: currentResult.hasError,
|
|
273
|
+
currentError: currentResult.error,
|
|
274
|
+
currentEvents: currentResult.events.length > 0 ? currentResult.events : undefined,
|
|
275
|
+
currentOutput: currentResult.output,
|
|
276
|
+
labels,
|
|
277
|
+
labelsBefore: labelsChanged ? baselineFixture.labels : undefined,
|
|
278
|
+
approval: (baselineHash !== undefined && currentHash !== undefined && baselineHash !== currentHash)
|
|
279
|
+
? this.approvals.lookup({
|
|
280
|
+
fixtureId: args.fixtureId,
|
|
281
|
+
originalHash: baselineHash,
|
|
282
|
+
modifiedHash: currentHash,
|
|
283
|
+
}) ?? undefined
|
|
284
|
+
: undefined,
|
|
285
|
+
};
|
|
286
|
+
},
|
|
287
|
+
approvalsApprove: async (args) => {
|
|
288
|
+
this._activityTracker.reportActivity();
|
|
289
|
+
this.approvals.approve(args);
|
|
290
|
+
},
|
|
291
|
+
approvalsRevoke: async (args) => {
|
|
292
|
+
this._activityTracker.reportActivity();
|
|
293
|
+
this.approvals.revoke(args);
|
|
294
|
+
},
|
|
295
|
+
approvalsList: async (args) => {
|
|
296
|
+
this._activityTracker.reportActivity();
|
|
297
|
+
return this.approvals.list(args.fixtureId);
|
|
298
|
+
},
|
|
299
|
+
approvalsLookup: async (args) => {
|
|
300
|
+
this._activityTracker.reportActivity();
|
|
301
|
+
return this.approvals.lookup(args) ?? null;
|
|
302
|
+
},
|
|
303
|
+
visualReviewGetStatus: async (args) => {
|
|
304
|
+
this._activityTracker.reportActivity();
|
|
305
|
+
return this.visualCache.getReviewStatus(args.fixtureId, args.expectedVisualDescriptions, args.screenshotHash);
|
|
306
|
+
},
|
|
307
|
+
visualReviewApprove: async (args) => {
|
|
308
|
+
this._activityTracker.reportActivity();
|
|
309
|
+
this.visualCache.approve(args.fixtureId, args.expectedVisualDescriptions, args.screenshotHash, args.comment);
|
|
310
|
+
},
|
|
311
|
+
evaluate: async (args) => {
|
|
394
312
|
this._activityTracker.reportActivity();
|
|
395
313
|
const session = this.getSession(args.sessionName);
|
|
396
314
|
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
397
315
|
const result = await session.explorer.evaluateJs(args.expression, args.fixtureId);
|
|
398
316
|
this.assertSourceTreeId(args.sessionName, args.sourceTreeId);
|
|
399
317
|
return { result };
|
|
400
|
-
}
|
|
401
|
-
setBrowserVisibility:
|
|
402
|
-
args: { visible: z.boolean() },
|
|
403
|
-
}, async (args, ctx) => {
|
|
318
|
+
},
|
|
319
|
+
setBrowserVisibility: async (args) => {
|
|
404
320
|
this._activityTracker.reportActivity();
|
|
405
|
-
this._logger.debug(`Set browser visibility: ${args.visible} (client=${
|
|
321
|
+
this._logger.debug(`Set browser visibility: ${args.visible} (client=${context.clientName})`);
|
|
406
322
|
await this._browserFactory.setHeaded(args.visible);
|
|
407
323
|
for (const session of this._sessions.values()) {
|
|
408
324
|
session.explorer.closePage();
|
|
409
325
|
}
|
|
410
326
|
return { visible: args.visible };
|
|
411
|
-
}
|
|
412
|
-
events:
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
327
|
+
},
|
|
328
|
+
events: async (_args, _ctx, stream) => {
|
|
329
|
+
const iterator = this.eventStream()[Symbol.asyncIterator]();
|
|
330
|
+
const onAbort = () => { void iterator.return?.(); };
|
|
331
|
+
stream.signal.addEventListener('abort', onAbort, { once: true });
|
|
332
|
+
try {
|
|
333
|
+
while (!stream.signal.aborted) {
|
|
334
|
+
const next = await iterator.next();
|
|
335
|
+
if (next.done) {
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
await stream.send(next.value);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
finally {
|
|
342
|
+
stream.signal.removeEventListener('abort', onAbort);
|
|
343
|
+
await iterator.return?.();
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
sessions: async () => {
|
|
416
347
|
this._activityTracker.reportActivity();
|
|
417
|
-
this._logger.trace(`API: sessions (client=${
|
|
348
|
+
this._logger.trace(`API: sessions (client=${context.clientName}, eventListeners=${this._eventListeners.size})`);
|
|
418
349
|
return this.getSessionInfos();
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
this._activityTracker.reportActivity();
|
|
422
|
-
return {
|
|
423
|
-
daemonApiVersion: daemonApiVersionText,
|
|
424
|
-
pluginProtocolVersion: pluginProtocolVersionText,
|
|
425
|
-
};
|
|
426
|
-
}),
|
|
427
|
-
restartSession: createMethod({
|
|
428
|
-
args: { sessionName: z.string() },
|
|
429
|
-
}, async (args, ctx) => {
|
|
350
|
+
},
|
|
351
|
+
restartSession: async (args) => {
|
|
430
352
|
this._activityTracker.reportActivity();
|
|
431
|
-
this._logger.debug(`Restart session "${args.sessionName}" requested (client=${
|
|
353
|
+
this._logger.debug(`Restart session "${args.sessionName}" requested (client=${context.clientName})`);
|
|
432
354
|
await this._restartSession(args.sessionName);
|
|
433
355
|
return this.getSessionInfos();
|
|
434
|
-
}
|
|
435
|
-
openSession:
|
|
436
|
-
args: {
|
|
437
|
-
name: z.string(),
|
|
438
|
-
ref: z.string(),
|
|
439
|
-
},
|
|
440
|
-
}, async (args, ctx) => {
|
|
356
|
+
},
|
|
357
|
+
openSession: async (args) => {
|
|
441
358
|
this._activityTracker.reportActivity();
|
|
442
|
-
this._logger.log(`Open session "${args.name}" @ ${args.ref} requested (client=${
|
|
359
|
+
this._logger.log(`Open session "${args.name}" @ ${args.ref} requested (client=${context.clientName})`);
|
|
443
360
|
return this._openDynamicSession(args.name, args.ref);
|
|
444
|
-
}
|
|
445
|
-
closeSession:
|
|
446
|
-
args: { name: z.string() },
|
|
447
|
-
}, async (args, ctx) => {
|
|
361
|
+
},
|
|
362
|
+
closeSession: async (args) => {
|
|
448
363
|
this._activityTracker.reportActivity();
|
|
449
|
-
this._logger.log(`Close session "${args.name}" requested (client=${
|
|
364
|
+
this._logger.log(`Close session "${args.name}" requested (client=${context.clientName})`);
|
|
450
365
|
return this._closeDynamicSession(args.name);
|
|
451
|
-
}
|
|
452
|
-
updateSessionRef:
|
|
453
|
-
args: {
|
|
454
|
-
name: z.string(),
|
|
455
|
-
ref: z.string(),
|
|
456
|
-
},
|
|
457
|
-
}, async (args, ctx) => {
|
|
366
|
+
},
|
|
367
|
+
updateSessionRef: async (args) => {
|
|
458
368
|
this._activityTracker.reportActivity();
|
|
459
|
-
this._logger.log(`Update session ref "${args.name}" → ${args.ref} requested (client=${
|
|
369
|
+
this._logger.log(`Update session ref "${args.name}" → ${args.ref} requested (client=${context.clientName})`);
|
|
460
370
|
return this._updateDynamicSessionRef(args.name, args.ref);
|
|
461
|
-
}
|
|
462
|
-
shutdown:
|
|
463
|
-
this._logger.debug(`Shutdown requested via API (client=${
|
|
464
|
-
|
|
465
|
-
|
|
371
|
+
},
|
|
372
|
+
shutdown: async () => {
|
|
373
|
+
this._logger.debug(`Shutdown requested via API (client=${context.clientName})`);
|
|
374
|
+
// Let LinkRPC serialize the reply before shutting down its transport.
|
|
375
|
+
setImmediate(() => this.requestShutdown());
|
|
376
|
+
},
|
|
466
377
|
});
|
|
378
|
+
return registration;
|
|
467
379
|
}
|
|
468
380
|
// -- Session access ------------------------------------------------------
|
|
469
381
|
getSession(name) {
|
|
@@ -551,6 +463,9 @@ class DaemonService {
|
|
|
551
463
|
let resolve;
|
|
552
464
|
let done = false;
|
|
553
465
|
const listener = (event) => {
|
|
466
|
+
if (done) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
554
469
|
if (event.type !== 'log') {
|
|
555
470
|
self._logger.trace(`Event stream: ${event.type}`);
|
|
556
471
|
}
|
|
@@ -568,6 +483,9 @@ class DaemonService {
|
|
|
568
483
|
self._activityTracker.setActive(true);
|
|
569
484
|
self._logger.debug(`Event stream opened (listeners: ${self._eventListeners.size})`);
|
|
570
485
|
const onShutdown = () => {
|
|
486
|
+
if (done) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
571
489
|
done = true;
|
|
572
490
|
cleanup();
|
|
573
491
|
if (resolve) {
|
|
@@ -578,9 +496,16 @@ class DaemonService {
|
|
|
578
496
|
};
|
|
579
497
|
self._shutdownResolvers.push(onShutdown);
|
|
580
498
|
const cleanup = () => {
|
|
499
|
+
if (!self._eventListeners.has(listener)) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
581
502
|
self._eventListeners.delete(listener);
|
|
582
503
|
self._eventListenerCount.set(self._eventListeners.size, undefined);
|
|
583
504
|
self._activityTracker.setActive(false);
|
|
505
|
+
const shutdownIndex = self._shutdownResolvers.indexOf(onShutdown);
|
|
506
|
+
if (shutdownIndex >= 0) {
|
|
507
|
+
self._shutdownResolvers.splice(shutdownIndex, 1);
|
|
508
|
+
}
|
|
584
509
|
self._logger.debug(`Event stream closed (listeners: ${self._eventListeners.size})`);
|
|
585
510
|
};
|
|
586
511
|
return {
|
|
@@ -676,10 +601,11 @@ class DaemonService {
|
|
|
676
601
|
// -- Shutdown ------------------------------------------------------------
|
|
677
602
|
requestShutdown() {
|
|
678
603
|
this._shutdownRequested = true;
|
|
679
|
-
|
|
604
|
+
const resolvers = this._shutdownResolvers;
|
|
605
|
+
this._shutdownResolvers = [];
|
|
606
|
+
for (const resolve of resolvers) {
|
|
680
607
|
resolve();
|
|
681
608
|
}
|
|
682
|
-
this._shutdownResolvers = [];
|
|
683
609
|
}
|
|
684
610
|
async dispose() {
|
|
685
611
|
this.requestShutdown();
|
|
@@ -733,8 +659,6 @@ class DaemonService {
|
|
|
733
659
|
daemonConfig: this._pipeName ? {
|
|
734
660
|
pipeName: this._pipeName,
|
|
735
661
|
sessionName,
|
|
736
|
-
daemonApiVersion: daemonApiVersionText,
|
|
737
|
-
pluginProtocolVersion: pluginProtocolVersionText,
|
|
738
662
|
} : undefined,
|
|
739
663
|
};
|
|
740
664
|
}
|
|
@@ -991,5 +915,5 @@ function arraysEqual(a, b) {
|
|
|
991
915
|
return true;
|
|
992
916
|
}
|
|
993
917
|
|
|
994
|
-
export { ActivityTracker, DaemonService, SourceTreeChangedError
|
|
918
|
+
export { ActivityTracker, DaemonService, SourceTreeChangedError };
|
|
995
919
|
//# sourceMappingURL=DaemonService.js.map
|