terminalhire 0.42.33 → 0.42.34
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/bin/capture/captureEntry.js +54 -49
- package/dist/bin/jpi-claim.js +531 -93
- package/dist/bin/jpi-dispatch.js +554 -116
- package/dist/bin/jpi-mcp.js +541 -103
- package/dist/bin/jpi-run.js +177 -56
- package/package.json +4 -3
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* repository's. The repository's code has already run: its build wrote files into the
|
|
7
7
|
* clone, or its serve script is listening in a container this one shares a network
|
|
8
8
|
* namespace with. This process serves or reaches that app over loopback, drives a
|
|
9
|
-
* headless Chromium through each
|
|
10
|
-
* plus `manifest.json` to /out.
|
|
9
|
+
* headless Chromium through each planned shot (with no spec, one per route: desktop,
|
|
10
|
+
* light), and writes PNGs plus `manifest.json` to /out.
|
|
11
11
|
*
|
|
12
12
|
* No network in either mode: static capture runs under `--network=none`, and server
|
|
13
13
|
* capture joins an app container that itself has `--network=none`. Whatever the page
|
|
@@ -27,7 +27,16 @@ export const VIEWPORTS = {
|
|
|
27
27
|
desktop: { width: 1280, height: 800, isMobile: false },
|
|
28
28
|
mobile: { width: 390, height: 844, isMobile: true },
|
|
29
29
|
};
|
|
30
|
-
const SCHEMES = ['light', 'dark'];
|
|
30
|
+
export const SCHEMES = ['light', 'dark'];
|
|
31
|
+
/**
|
|
32
|
+
* What gets shot. With no spec, one picture per route at desktop size in light mode
|
|
33
|
+
* (TERM-1272). The desktop/mobile × light/dark matrix this replaces suited one claim
|
|
34
|
+
* and cost every other one three more renders of the same screen, most often a
|
|
35
|
+
* loading state; mobile and dark are for a spec to ask for, shot by shot.
|
|
36
|
+
*/
|
|
37
|
+
export function plannedShots(req) {
|
|
38
|
+
return req.routes.map((route) => ({ route, viewport: 'desktop', scheme: 'light' }));
|
|
39
|
+
}
|
|
31
40
|
// ---- which directory is the site -------------------------------------------
|
|
32
41
|
/**
|
|
33
42
|
* When the build started, read off the marker the build step wrote. Taken from the
|
|
@@ -287,53 +296,49 @@ async function shoot(origin, basePath, req, out) {
|
|
|
287
296
|
const items = [];
|
|
288
297
|
const failures = [];
|
|
289
298
|
try {
|
|
290
|
-
for (const route of req
|
|
299
|
+
for (const { route, viewport, scheme } of plannedShots(req)) {
|
|
291
300
|
const url = `${origin}${basePath.replace(/\/$/, '')}${route.startsWith('/') ? route : `/${route}`}`;
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
finally {
|
|
334
|
-
await context.close();
|
|
335
|
-
}
|
|
336
|
-
}
|
|
301
|
+
const v = VIEWPORTS[viewport];
|
|
302
|
+
const context = await browser.newContext({
|
|
303
|
+
viewport: { width: v.width, height: v.height },
|
|
304
|
+
isMobile: v.isMobile,
|
|
305
|
+
hasTouch: v.isMobile,
|
|
306
|
+
colorScheme: scheme,
|
|
307
|
+
deviceScaleFactor: 1,
|
|
308
|
+
});
|
|
309
|
+
try {
|
|
310
|
+
const page = await context.newPage();
|
|
311
|
+
await page.goto(url, { waitUntil: 'load', timeout: 20_000 });
|
|
312
|
+
// A page with no backend may keep retrying forever, so idle is
|
|
313
|
+
// waited for briefly and never required.
|
|
314
|
+
await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => undefined);
|
|
315
|
+
await page.waitForTimeout(300);
|
|
316
|
+
// Frozen, so two shots of the same page are the same bytes: a spinner
|
|
317
|
+
// caught on different frames would otherwise hide that light and dark
|
|
318
|
+
// render identically, which is the one comparison the notes rely on.
|
|
319
|
+
const png = await page.screenshot({ animations: 'disabled', caret: 'hide' });
|
|
320
|
+
const file = shotName(route, viewport, scheme);
|
|
321
|
+
writeFileSync(join(out, file), png);
|
|
322
|
+
items.push({
|
|
323
|
+
route,
|
|
324
|
+
viewport,
|
|
325
|
+
scheme,
|
|
326
|
+
file,
|
|
327
|
+
sha256: createHash('sha256').update(png).digest('hex'),
|
|
328
|
+
bytes: png.length,
|
|
329
|
+
...PNG_SIZE(png),
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
failures.push({
|
|
334
|
+
route,
|
|
335
|
+
viewport,
|
|
336
|
+
scheme,
|
|
337
|
+
error: String(err?.message ?? err).slice(0, 300),
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
finally {
|
|
341
|
+
await context.close();
|
|
337
342
|
}
|
|
338
343
|
}
|
|
339
344
|
}
|