@design.estate/wcctools 6.1.0 → 7.0.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.
Files changed (112) hide show
  1. package/changelog.md +41 -0
  2. package/dist_shell/bundle.js +405 -368
  3. package/dist_shell/bundle.js.map +1 -1
  4. package/dist_shell/bundle.js.third-party-notices.json +52 -0
  5. package/dist_shell/bundle.js.third-party-notices.txt +107 -1
  6. package/dist_shell/index.html +1 -1
  7. package/dist_ts/00_commitinfo_data.js +1 -1
  8. package/dist_ts/capture/classes.capturebrowser.d.ts +65 -0
  9. package/dist_ts/capture/classes.capturebrowser.js +251 -0
  10. package/dist_ts/capture/classes.captureservice.d.ts +39 -0
  11. package/dist_ts/capture/classes.captureservice.js +119 -0
  12. package/dist_ts/capture/classes.screencast.d.ts +47 -0
  13. package/dist_ts/capture/classes.screencast.js +127 -0
  14. package/dist_ts/capture/errors.d.ts +14 -0
  15. package/dist_ts/capture/errors.js +23 -0
  16. package/dist_ts/capture/images.d.ts +3 -0
  17. package/dist_ts/capture/images.js +58 -0
  18. package/dist_ts/capture/index.d.ts +4 -0
  19. package/dist_ts/capture/index.js +5 -0
  20. package/dist_ts/capture/interaction.d.ts +11 -0
  21. package/dist_ts/capture/interaction.js +138 -0
  22. package/dist_ts/capture/navigationguard.d.ts +44 -0
  23. package/dist_ts/capture/navigationguard.js +129 -0
  24. package/dist_ts/capture/previewpage.d.ts +29 -0
  25. package/dist_ts/capture/previewpage.js +96 -0
  26. package/dist_ts/capture/request.d.ts +69 -0
  27. package/dist_ts/capture/request.js +239 -0
  28. package/dist_ts/classes.bundlestatus.d.ts +36 -0
  29. package/dist_ts/classes.bundlestatus.js +110 -0
  30. package/dist_ts/classes.devapi.d.ts +3 -0
  31. package/dist_ts/classes.devapi.js +8 -1
  32. package/dist_ts/classes.devserver.d.ts +65 -14
  33. package/dist_ts/classes.devserver.js +157 -52
  34. package/dist_ts/classes.hostpolicy.d.ts +63 -0
  35. package/dist_ts/classes.hostpolicy.js +171 -0
  36. package/dist_ts/cli.js +28 -3
  37. package/dist_ts/cli.screenshot.d.ts +6 -0
  38. package/dist_ts/cli.screenshot.js +89 -0
  39. package/dist_ts/index.d.ts +0 -2
  40. package/dist_ts/index.js +1 -3
  41. package/dist_ts/plugins.d.ts +6 -2
  42. package/dist_ts/plugins.js +8 -3
  43. package/dist_ts_interfaces/capture.d.ts +151 -0
  44. package/dist_ts_interfaces/capture.js +2 -0
  45. package/dist_ts_interfaces/index.d.ts +1 -0
  46. package/dist_ts_interfaces/index.js +2 -1
  47. package/dist_ts_interfaces/requests.d.ts +59 -0
  48. package/dist_ts_shell/bundlestatus.d.ts +15 -0
  49. package/dist_ts_shell/bundlestatus.js +64 -0
  50. package/dist_ts_shell/elements/wcc-contextmenu.d.ts +3 -0
  51. package/dist_ts_shell/elements/wcc-contextmenu.js +18 -3
  52. package/dist_ts_shell/elements/wcc-preview-frame.d.ts +6 -0
  53. package/dist_ts_shell/elements/wcc-preview-frame.js +50 -2
  54. package/dist_ts_shell/elements/wcc-recording-panel.d.ts +9 -0
  55. package/dist_ts_shell/elements/wcc-recording-panel.js +12 -1
  56. package/dist_ts_shell/elements/wcc-shell.d.ts +15 -0
  57. package/dist_ts_shell/elements/wcc-shell.js +45 -3
  58. package/dist_ts_shell/plugins.d.ts +2 -1
  59. package/dist_ts_shell/plugins.js +3 -2
  60. package/dist_ts_shell/services/framesampler.service.d.ts +23 -0
  61. package/dist_ts_shell/services/framesampler.service.js +101 -0
  62. package/dist_ts_web/00_commitinfo_data.js +1 -1
  63. package/package.json +6 -2
  64. package/readme.md +108 -6
  65. package/ts/00_commitinfo_data.ts +1 -1
  66. package/ts/capture/classes.capturebrowser.ts +290 -0
  67. package/ts/capture/classes.captureservice.ts +152 -0
  68. package/ts/capture/classes.screencast.ts +152 -0
  69. package/ts/capture/errors.ts +25 -0
  70. package/ts/capture/images.ts +61 -0
  71. package/ts/capture/index.ts +4 -0
  72. package/ts/capture/interaction.ts +146 -0
  73. package/ts/capture/navigationguard.ts +147 -0
  74. package/ts/capture/previewpage.ts +130 -0
  75. package/ts/capture/request.ts +304 -0
  76. package/ts/classes.bundlestatus.ts +123 -0
  77. package/ts/classes.devapi.ts +9 -0
  78. package/ts/classes.devserver.ts +172 -50
  79. package/ts/classes.hostpolicy.ts +201 -0
  80. package/ts/cli.screenshot.ts +95 -0
  81. package/ts/cli.ts +28 -2
  82. package/ts/index.ts +0 -2
  83. package/ts/plugins.ts +9 -2
  84. package/ts_interfaces/bridge.ts +95 -0
  85. package/ts_interfaces/capture.ts +144 -0
  86. package/ts_interfaces/catalog.ts +37 -0
  87. package/ts_interfaces/index.ts +5 -0
  88. package/ts_interfaces/plugins.ts +3 -0
  89. package/ts_interfaces/requests.ts +104 -0
  90. package/ts_interfaces/standard.ts +103 -0
  91. package/ts_shared/index.ts +1 -0
  92. package/ts_shared/plugins.ts +3 -0
  93. package/ts_shared/previewroute.ts +58 -0
  94. package/ts_shell/bundlestatus.ts +68 -0
  95. package/ts_shell/elements/wcc-contextmenu.ts +306 -0
  96. package/ts_shell/elements/wcc-preview-frame.ts +167 -0
  97. package/ts_shell/elements/wcc-properties.ts +998 -0
  98. package/ts_shell/elements/wcc-record-button.ts +108 -0
  99. package/ts_shell/elements/wcc-recording-panel.ts +1017 -0
  100. package/ts_shell/elements/wcc-shell.ts +485 -0
  101. package/ts_shell/elements/wcc-sidebar.ts +1419 -0
  102. package/ts_shell/index.html +21 -0
  103. package/ts_shell/index.ts +4 -0
  104. package/ts_shell/plugins.ts +12 -0
  105. package/ts_shell/previewconnection.ts +103 -0
  106. package/ts_shell/services/framesampler.service.ts +112 -0
  107. package/ts_shell/services/recorder.service.ts +451 -0
  108. package/ts_shell/types/dom-mediacapture-stub/index.d.ts +12 -0
  109. package/ts_shell/types/dom-mediacapture-stub/package.json +6 -0
  110. package/ts_shell/types/dom-webcodecs-stub/index.d.ts +2 -0
  111. package/ts_shell/types/dom-webcodecs-stub/package.json +6 -0
  112. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -0,0 +1,129 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { WccCaptureError, getErrorMessage } from './errors.js';
3
+ /** The message of a navigation the capture blocked. */
4
+ export const formatBlockedNavigation = (urlArg) => {
5
+ return `navigation to ${urlArg} blocked: a capture stays on the rendered preview`;
6
+ };
7
+ /**
8
+ * Runs in the main frame before the preview's scripts, so its `navigate` listener is the first:
9
+ * cancels each navigation that would replace the document (a link, a form submission, a script
10
+ * assigning `location`, a reload, also to the same URL, to `about:blank` or a `blob:` URL) as it
11
+ * starts, and records its URL. Same-document navigations (`history.replaceState`, fragments) and
12
+ * downloads pass. Link clicks and scripts start their navigation while the step that caused it
13
+ * runs; form submissions in a task right after.
14
+ */
15
+ const cancelLeavingNavigations = () => {
16
+ if (window !== window.top) {
17
+ return;
18
+ }
19
+ const cancelled = [];
20
+ window.wccCancelledNavigations = cancelled;
21
+ navigation.addEventListener('navigate', (eventArg) => {
22
+ if (eventArg.destination.sameDocument || eventArg.downloadRequest !== null || !eventArg.cancelable) {
23
+ return;
24
+ }
25
+ eventArg.preventDefault();
26
+ cancelled.push(eventArg.destination.url);
27
+ });
28
+ };
29
+ /**
30
+ * Keeps a capture page on the preview. Its main frame loads the preview document once; after that,
31
+ * the page script above cancels every navigation that would replace the document before it starts.
32
+ * Request interception backs it up: a main-frame navigation request the page could not cancel is
33
+ * aborted before it leaves. The preview's history holds the preview alone, so there is no earlier
34
+ * document to go back to. Subframes and all other requests are left alone.
35
+ *
36
+ * `takeBlockedNavigation()` answers the navigation blocked since its last call, so each step of an
37
+ * interaction learns about the navigation it started.
38
+ */
39
+ export class WccNavigationGuard {
40
+ page;
41
+ /** Navigation requests aborted by the backstop since the last `takeBlockedNavigation()`. */
42
+ abortedUrls = [];
43
+ interceptionFailure = null;
44
+ previewUrl;
45
+ constructor(page, previewUrlArg) {
46
+ this.page = page;
47
+ this.previewUrl = new URL(previewUrlArg).href;
48
+ }
49
+ /**
50
+ * Installs the page script and intercepts the page's requests; the page's first main-frame
51
+ * navigation may load `previewUrlArg` only. Install before loading the preview.
52
+ */
53
+ static async install(pageArg, previewUrlArg) {
54
+ const guard = new WccNavigationGuard(pageArg, previewUrlArg);
55
+ pageArg.on('request', (requestArg) => guard.decide(requestArg));
56
+ await pageArg.setRequestInterception(true);
57
+ await pageArg.evaluateOnNewDocument(cancelLeavingNavigations);
58
+ return guard;
59
+ }
60
+ /** Drops the history entries before the loaded preview (the blank page it opened as), so going back leaves nothing. */
61
+ async forgetEarlierHistory() {
62
+ const session = await this.page.createCDPSession();
63
+ try {
64
+ await session.send('Page.resetNavigationHistory');
65
+ }
66
+ finally {
67
+ await session.detach();
68
+ }
69
+ }
70
+ /**
71
+ * Lets the page run the tasks queued so far (an animation frame, then a task), then answers the
72
+ * URL of the first navigation blocked since the last call, by the page script or the backstop,
73
+ * or null when none was.
74
+ */
75
+ async takeBlockedNavigation() {
76
+ const cancelledUrl = await this.page.evaluate(() => {
77
+ return new Promise((resolve) => {
78
+ requestAnimationFrame(() => {
79
+ setTimeout(() => {
80
+ const cancelled = window.wccCancelledNavigations ?? [];
81
+ resolve(cancelled[0] ?? null);
82
+ cancelled.length = 0;
83
+ }, 0);
84
+ });
85
+ });
86
+ });
87
+ if (this.interceptionFailure !== null) {
88
+ throw new WccCaptureError(`wcctools: the capture failed to handle a request of the preview: ${getErrorMessage(this.interceptionFailure)}`);
89
+ }
90
+ const abortedUrl = this.abortedUrls[0] ?? null;
91
+ this.abortedUrls = [];
92
+ return cancelledUrl ?? abortedUrl;
93
+ }
94
+ /** Throws when the page tried to leave the preview while `whileArg` (e.g. "rendering"). */
95
+ async assertStayed(whileArg) {
96
+ const blockedUrl = await this.takeBlockedNavigation();
97
+ if (blockedUrl !== null) {
98
+ throw new WccCaptureError(`wcctools: the demo tried to navigate away while ${whileArg}; ${formatBlockedNavigation(blockedUrl)}.`);
99
+ }
100
+ }
101
+ decide(requestArg) {
102
+ if (requestArg.isInterceptResolutionHandled()) {
103
+ return;
104
+ }
105
+ if (!requestArg.isNavigationRequest() || requestArg.frame() !== this.page.mainFrame()) {
106
+ this.settle(requestArg.continue());
107
+ return;
108
+ }
109
+ if (this.previewUrl !== null && requestArg.url() === this.previewUrl) {
110
+ // The preview document's own load, once
111
+ this.previewUrl = null;
112
+ this.settle(requestArg.continue());
113
+ return;
114
+ }
115
+ this.abortedUrls.push(requestArg.url());
116
+ // `aborted` drops the navigation without committing an error page, so the preview stays
117
+ this.settle(requestArg.abort('aborted'));
118
+ }
119
+ /**
120
+ * Keeps the first failure of an interception decision. Puppeteer itself tolerates a request
121
+ * that ended or a page that closed meanwhile; what reaches here fails the capture.
122
+ */
123
+ settle(decisionArg) {
124
+ decisionArg.catch((errorArg) => {
125
+ this.interceptionFailure ??= errorArg;
126
+ });
127
+ }
128
+ }
129
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF2aWdhdGlvbmd1YXJkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvY2FwdHVyZS9uYXZpZ2F0aW9uZ3VhcmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFLL0QsdURBQXVEO0FBQ3ZELE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLENBQUMsTUFBYyxFQUFVLEVBQUU7SUFDaEUsT0FBTyxpQkFBaUIsTUFBTSxtREFBbUQsQ0FBQztBQUNwRixDQUFDLENBQUM7QUFRRjs7Ozs7OztHQU9HO0FBQ0gsTUFBTSx3QkFBd0IsR0FBRyxHQUFHLEVBQUU7SUFDcEMsSUFBSSxNQUFNLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQzFCLE9BQU87SUFDVCxDQUFDO0lBQ0QsTUFBTSxTQUFTLEdBQWEsRUFBRSxDQUFDO0lBQzlCLE1BQStDLENBQUMsdUJBQXVCLEdBQUcsU0FBUyxDQUFDO0lBQ3JGLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRTtRQUNuRCxJQUFJLFFBQVEsQ0FBQyxXQUFXLENBQUMsWUFBWSxJQUFJLFFBQVEsQ0FBQyxlQUFlLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ25HLE9BQU87UUFDVCxDQUFDO1FBQ0QsUUFBUSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQzFCLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMzQyxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQztBQUVGOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sT0FBTyxrQkFBa0I7SUFPVjtJQU5uQiw0RkFBNEY7SUFDcEYsV0FBVyxHQUFh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
@@ -0,0 +1,29 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { WccNavigationGuard } from './navigationguard.js';
3
+ import { type IWccResolvedImageOptions, type IWccResolvedView } from './request.js';
4
+ type TBrowserContext = plugins.smartbrowser.puppeteer.BrowserContext;
5
+ type TPage = plugins.smartbrowser.puppeteer.Page;
6
+ /** A preview document in the capture browser that rendered one demo. */
7
+ export interface IWccRenderedPreview {
8
+ page: TPage;
9
+ /** Keeps the page on the preview and knows the navigation it blocked. */
10
+ navigationGuard: WccNavigationGuard;
11
+ selection: plugins.interfaces.IWccSelection;
12
+ /** What the demo rendered: an element demo or a page. */
13
+ type: 'element' | 'page';
14
+ }
15
+ /**
16
+ * Opens the preview route of the dev server at `originArg` in the context, waits for the preview
17
+ * runtime to install its bridge (it does once it rendered the route), resolves the subject against
18
+ * the catalog manifest and renders it. Waits only on the preview's own signals: the bridge, the
19
+ * render's completed updates and the document's fonts. The page stays on the preview: every
20
+ * later navigation of its main frame is blocked, and one blocked while rendering fails the capture.
21
+ */
22
+ export declare const renderPreview: (contextArg: TBrowserContext, originArg: string, viewArg: IWccResolvedView, subjectArg: plugins.interfaces.IWccCaptureSubject) => Promise<IWccRenderedPreview>;
23
+ /** Screenshots a rendered preview as framed. */
24
+ export declare const screenshotPreview: (previewArg: IWccRenderedPreview, viewArg: IWccResolvedView, optionsArg: IWccResolvedImageOptions) => Promise<{
25
+ framing: plugins.interfaces.TWccCaptureFraming;
26
+ image: plugins.interfaces.IWccImage;
27
+ truncated: boolean;
28
+ }>;
29
+ export {};
@@ -0,0 +1,96 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { WccCaptureError, WccCaptureRequestError, getErrorMessage } from './errors.js';
3
+ import { toWccImage } from './images.js';
4
+ import { WccNavigationGuard } from './navigationguard.js';
5
+ import { captureLimits, resolveSelection } from './request.js';
6
+ /** How long the preview document may take to load and render its demo. */
7
+ const previewStartTimeoutMs = 20_000;
8
+ const formatPageErrors = (errorsArg) => {
9
+ return errorsArg.length > 0 ? ` The preview reported: ${errorsArg.slice(0, 5).join(' | ')}` : '';
10
+ };
11
+ /**
12
+ * Opens the preview route of the dev server at `originArg` in the context, waits for the preview
13
+ * runtime to install its bridge (it does once it rendered the route), resolves the subject against
14
+ * the catalog manifest and renders it. Waits only on the preview's own signals: the bridge, the
15
+ * render's completed updates and the document's fonts. The page stays on the preview: every
16
+ * later navigation of its main frame is blocked, and one blocked while rendering fails the capture.
17
+ */
18
+ export const renderPreview = async (contextArg, originArg, viewArg, subjectArg) => {
19
+ const page = await contextArg.newPage();
20
+ const pageErrors = [];
21
+ page.on('pageerror', (errorArg) => {
22
+ pageErrors.push(getErrorMessage(errorArg));
23
+ });
24
+ page.on('console', (messageArg) => {
25
+ if (messageArg.type() === 'error') {
26
+ pageErrors.push(messageArg.text());
27
+ }
28
+ });
29
+ await page.setViewport({ width: viewArg.width, height: viewArg.height, deviceScaleFactor: viewArg.scale });
30
+ await page.emulateMediaFeatures([
31
+ { name: 'prefers-color-scheme', value: viewArg.theme === 'bright' ? 'light' : 'dark' },
32
+ ]);
33
+ const previewUrl = `${originArg}${plugins.shared.previewRoutePath}${plugins.shared.formatPreviewQuery({ selection: null, theme: viewArg.theme })}`;
34
+ const navigationGuard = await WccNavigationGuard.install(page, previewUrl);
35
+ const response = await page.goto(previewUrl, { waitUntil: 'load', timeout: previewStartTimeoutMs });
36
+ if (!response?.ok()) {
37
+ throw new WccCaptureError(`wcctools: the preview document answered ${response?.status() ?? 'nothing'}.${formatPageErrors(pageErrors)}`);
38
+ }
39
+ await navigationGuard.forgetEarlierHistory();
40
+ try {
41
+ await page.waitForFunction(() => window.wccPreview !== undefined, { polling: 'raf', timeout: previewStartTimeoutMs });
42
+ }
43
+ catch (error) {
44
+ throw new WccCaptureError(`wcctools: the preview did not start within ${previewStartTimeoutMs / 1000} s (${getErrorMessage(error)}).${formatPageErrors(pageErrors)}`);
45
+ }
46
+ const manifest = await page.evaluate(() => window.wccPreview.getManifest());
47
+ const selection = resolveSelection(manifest, subjectArg);
48
+ const outcome = await page.evaluate((selectionArg) => window.wccPreview.render(selectionArg), selection);
49
+ if (outcome.kind === 'empty') {
50
+ throw new WccCaptureError(`wcctools: ${selection.sectionName}/${selection.itemName} demo ${selection.demoIndex} did not render: ${outcome.emptyState.title}. ${outcome.emptyState.detail}${formatPageErrors(pageErrors)}`);
51
+ }
52
+ await page.evaluate(async () => {
53
+ await document.fonts.ready;
54
+ });
55
+ await navigationGuard.assertStayed('rendering');
56
+ return { page, navigationGuard, selection, type: outcome.type };
57
+ };
58
+ /** Screenshots a rendered preview as framed. */
59
+ export const screenshotPreview = async (previewArg, viewArg, optionsArg) => {
60
+ const { page } = previewArg;
61
+ const framing = optionsArg.framing ?? (previewArg.type === 'page' ? 'fullpage' : 'element');
62
+ const encoding = { type: optionsArg.format, ...(optionsArg.quality === undefined ? {} : { quality: optionsArg.quality }) };
63
+ if (framing === 'element') {
64
+ if (previewArg.type === 'page') {
65
+ throw new WccCaptureRequestError('wcctools: a page has no element to frame; use the viewport or fullpage framing.');
66
+ }
67
+ const handle = await page.evaluateHandle(() => window.wccPreview.findRenderedInstance());
68
+ try {
69
+ const element = handle.asElement();
70
+ if (!element) {
71
+ throw new WccCaptureError(`wcctools: the demo of ${previewArg.selection.itemName} renders no instance of its element; use the viewport framing.`);
72
+ }
73
+ const bytes = await element.screenshot(encoding);
74
+ return { framing, image: toWccImage(bytes, optionsArg.format), truncated: false };
75
+ }
76
+ finally {
77
+ await handle.dispose();
78
+ }
79
+ }
80
+ if (framing === 'viewport') {
81
+ const bytes = await page.screenshot(encoding);
82
+ return { framing, image: toWccImage(bytes, optionsArg.format), truncated: false };
83
+ }
84
+ const documentHeight = await page.evaluate(() => document.documentElement.scrollHeight);
85
+ if (documentHeight > captureLimits.maxFullPageHeight) {
86
+ const bytes = await page.screenshot({
87
+ ...encoding,
88
+ clip: { x: 0, y: 0, width: viewArg.width, height: captureLimits.maxFullPageHeight },
89
+ captureBeyondViewport: true,
90
+ });
91
+ return { framing, image: toWccImage(bytes, optionsArg.format), truncated: true };
92
+ }
93
+ const bytes = await page.screenshot({ ...encoding, fullPage: true });
94
+ return { framing, image: toWccImage(bytes, optionsArg.format), truncated: false };
95
+ };
96
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJldmlld3BhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jYXB0dXJlL3ByZXZpZXdwYWdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxlQUFlLEVBQUUsc0JBQXNCLEVBQUUsZUFBZSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3ZGLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDekMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxnQkFBZ0IsRUFBd0QsTUFBTSxjQUFjLENBQUM7QUFLckgsMEVBQTBFO0FBQzFFLE1BQU0scUJBQXFCLEdBQUcsTUFBTSxDQUFDO0FBWXJDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxTQUFtQixFQUFVLEVBQUU7SUFDdkQsT0FBTyxTQUFTLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsMEJBQTBCLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDbkcsQ0FBQyxDQUFDO0FBRUY7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLEtBQUssRUFDaEMsVUFBMkIsRUFDM0IsU0FBaUIsRUFDakIsT0FBeUIsRUFDekIsVUFBaUQsRUFDbkIsRUFBRTtJQUNoQyxNQUFNLElBQUksR0FBRyxNQUFNLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUN4QyxNQUFNLFVBQVUsR0FBYSxFQUFFLENBQUM7SUFDaEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRTtRQUNoQyxVQUFVLENBQUMsSUFBSSxDQUFDLGVBQWUs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
@@ -0,0 +1,69 @@
1
+ import * as plugins from '../plugins.js';
2
+ type IWccCaptureSubject = plugins.interfaces.IWccCaptureSubject;
3
+ type TWccCaptureFraming = plugins.interfaces.TWccCaptureFraming;
4
+ type TWccInteractionStep = plugins.interfaces.TWccInteractionStep;
5
+ /** The limits every capture request is held to. */
6
+ export declare const captureLimits: {
7
+ readonly minWidth: 200;
8
+ readonly maxWidth: 3840;
9
+ readonly minHeight: 200;
10
+ readonly maxHeight: 4320;
11
+ readonly defaultHeight: 800;
12
+ /** Full-page captures are cut at this height in CSS pixels. */
13
+ readonly maxFullPageHeight: 10000;
14
+ readonly defaultJpegQuality: 80;
15
+ readonly maxSteps: 20;
16
+ readonly stepTimeoutMs: 5000;
17
+ readonly maxWaitMs: 3000;
18
+ readonly defaultObserveMs: 500;
19
+ readonly maxObserveMs: 5000;
20
+ readonly defaultMaxFrames: 12;
21
+ readonly maxMaxFrames: 40;
22
+ readonly defaultFrameQuality: 70;
23
+ readonly maxSelectorLength: 500;
24
+ readonly maxTextLength: 2000;
25
+ readonly maxKeyLength: 32;
26
+ readonly maxSubjectLength: 200;
27
+ };
28
+ /** The capture widths of the named viewports: the dees-domtools breakpoints. */
29
+ export declare const captureViewportWidths: Readonly<Record<plugins.interfaces.TWccCaptureViewportPreset, number>>;
30
+ /** The preview set-up of a capture, validated and with its defaults applied. */
31
+ export interface IWccResolvedView {
32
+ width: number;
33
+ height: number;
34
+ theme: plugins.interfaces.TWccTheme;
35
+ scale: 1 | 2;
36
+ }
37
+ export interface IWccResolvedImageOptions {
38
+ /** Undefined: the default framing of what the demo rendered. */
39
+ framing?: TWccCaptureFraming;
40
+ format: 'png' | 'jpeg';
41
+ /** JPEG quality; undefined for PNG. */
42
+ quality?: number;
43
+ }
44
+ export interface IWccResolvedScreenshotRequest {
45
+ subject: IWccCaptureSubject;
46
+ view: IWccResolvedView;
47
+ image: IWccResolvedImageOptions;
48
+ }
49
+ export interface IWccResolvedInteractionRequest {
50
+ subject: IWccCaptureSubject;
51
+ view: IWccResolvedView;
52
+ steps: TWccInteractionStep[];
53
+ observeMs: number;
54
+ maxFrames: number;
55
+ frameQuality: number;
56
+ finalScreenshot: IWccResolvedImageOptions | null;
57
+ }
58
+ /** Reads a viewport: a named one, or a width in CSS pixels. */
59
+ export declare const resolveViewportWidth: (viewportArg: unknown) => number;
60
+ /** Validates a screenshot request and applies its defaults. */
61
+ export declare const resolveScreenshotRequest: (requestArg: plugins.interfaces.IWccScreenshotRequest) => IWccResolvedScreenshotRequest;
62
+ /** Validates an interaction request and applies its defaults. */
63
+ export declare const resolveInteractionRequest: (requestArg: plugins.interfaces.IWccInteractionRequest) => IWccResolvedInteractionRequest;
64
+ /**
65
+ * Resolves a subject to one demo of the catalog: an entry named by its name or its element's tag,
66
+ * in the named section or, without one, in exactly one section.
67
+ */
68
+ export declare const resolveSelection: (manifestArg: plugins.interfaces.IWccCatalogManifest, subjectArg: IWccCaptureSubject) => plugins.interfaces.IWccSelection;
69
+ export {};
@@ -0,0 +1,239 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { WccCaptureRequestError } from './errors.js';
3
+ /** The limits every capture request is held to. */
4
+ export const captureLimits = {
5
+ minWidth: 200,
6
+ maxWidth: 3840,
7
+ minHeight: 200,
8
+ maxHeight: 4320,
9
+ defaultHeight: 800,
10
+ /** Full-page captures are cut at this height in CSS pixels. */
11
+ maxFullPageHeight: 10_000,
12
+ defaultJpegQuality: 80,
13
+ maxSteps: 20,
14
+ stepTimeoutMs: 5_000,
15
+ maxWaitMs: 3_000,
16
+ defaultObserveMs: 500,
17
+ maxObserveMs: 5_000,
18
+ defaultMaxFrames: 12,
19
+ maxMaxFrames: 40,
20
+ defaultFrameQuality: 70,
21
+ maxSelectorLength: 500,
22
+ maxTextLength: 2_000,
23
+ maxKeyLength: 32,
24
+ maxSubjectLength: 200,
25
+ };
26
+ /** The capture widths of the named viewports: the dees-domtools breakpoints. */
27
+ export const captureViewportWidths = {
28
+ phone: plugins.deesDomtools.breakpoints.phone,
29
+ phablet: plugins.deesDomtools.breakpoints.phablet,
30
+ tablet: plugins.deesDomtools.breakpoints.tablet,
31
+ desktop: plugins.deesDomtools.breakpoints.desktop,
32
+ };
33
+ const isViewportPreset = (valueArg) => {
34
+ return typeof valueArg === 'string' && Object.hasOwn(captureViewportWidths, valueArg);
35
+ };
36
+ const framings = ['element', 'viewport', 'fullpage'];
37
+ const isInteger = (valueArg) => typeof valueArg === 'number' && Number.isInteger(valueArg);
38
+ const requireIntegerIn = (valueArg, minArg, maxArg, nameArg) => {
39
+ if (!isInteger(valueArg) || valueArg < minArg || valueArg > maxArg) {
40
+ throw new WccCaptureRequestError(`wcctools: ${nameArg} must be a whole number from ${minArg} to ${maxArg}.`);
41
+ }
42
+ return valueArg;
43
+ };
44
+ const requireText = (valueArg, maxLengthArg, nameArg, allowEmptyArg = false) => {
45
+ if (typeof valueArg !== 'string' || (!allowEmptyArg && valueArg.trim() === '') || valueArg.length > maxLengthArg) {
46
+ throw new WccCaptureRequestError(`wcctools: ${nameArg} must be ${allowEmptyArg ? 'a' : 'a non-empty'} string of at most ${maxLengthArg} characters.`);
47
+ }
48
+ return valueArg;
49
+ };
50
+ const resolveSubject = (subjectArg) => {
51
+ if (typeof subjectArg !== 'object' || subjectArg === null) {
52
+ throw new WccCaptureRequestError('wcctools: a capture needs a subject: the catalog entry to render.');
53
+ }
54
+ const subject = subjectArg;
55
+ const resolved = {
56
+ itemName: requireText(subject.itemName, captureLimits.maxSubjectLength, 'the subject\'s itemName'),
57
+ demoIndex: subject.demoIndex === undefined ? 0 : requireIntegerIn(subject.demoIndex, 0, 1_000, 'the demo index'),
58
+ };
59
+ if (subject.sectionName !== undefined) {
60
+ resolved.sectionName = requireText(subject.sectionName, captureLimits.maxSubjectLength, 'the subject\'s sectionName');
61
+ }
62
+ return resolved;
63
+ };
64
+ /** Reads a viewport: a named one, or a width in CSS pixels. */
65
+ export const resolveViewportWidth = (viewportArg) => {
66
+ if (viewportArg === undefined) {
67
+ return captureViewportWidths.desktop;
68
+ }
69
+ if (isViewportPreset(viewportArg)) {
70
+ return captureViewportWidths[viewportArg];
71
+ }
72
+ if (isInteger(viewportArg)) {
73
+ return requireIntegerIn(viewportArg, captureLimits.minWidth, captureLimits.maxWidth, 'the viewport width');
74
+ }
75
+ throw new WccCaptureRequestError(`wcctools: the viewport must be one of ${Object.keys(captureViewportWidths).join(', ')} or a width from ${captureLimits.minWidth} to ${captureLimits.maxWidth}.`);
76
+ };
77
+ const resolveView = (requestArg) => {
78
+ const theme = requestArg.theme ?? 'dark';
79
+ if (theme !== 'dark' && theme !== 'bright') {
80
+ throw new WccCaptureRequestError('wcctools: the theme must be dark or bright.');
81
+ }
82
+ const scale = requestArg.scale ?? 1;
83
+ if (scale !== 1 && scale !== 2) {
84
+ throw new WccCaptureRequestError('wcctools: the scale must be 1 or 2.');
85
+ }
86
+ return {
87
+ width: resolveViewportWidth(requestArg.viewport),
88
+ height: requestArg.height === undefined
89
+ ? captureLimits.defaultHeight
90
+ : requireIntegerIn(requestArg.height, captureLimits.minHeight, captureLimits.maxHeight, 'the height'),
91
+ theme,
92
+ scale,
93
+ };
94
+ };
95
+ const resolveImageOptions = (optionsArg) => {
96
+ const framing = optionsArg.framing;
97
+ if (framing !== undefined && !framings.includes(framing)) {
98
+ throw new WccCaptureRequestError(`wcctools: the framing must be one of ${framings.join(', ')}.`);
99
+ }
100
+ const format = optionsArg.format ?? 'png';
101
+ if (format !== 'png' && format !== 'jpeg') {
102
+ throw new WccCaptureRequestError('wcctools: the format must be png or jpeg.');
103
+ }
104
+ if (format === 'png' && optionsArg.quality !== undefined) {
105
+ throw new WccCaptureRequestError('wcctools: a quality applies to jpeg only.');
106
+ }
107
+ return {
108
+ framing: framing,
109
+ format,
110
+ quality: format === 'jpeg'
111
+ ? (optionsArg.quality === undefined ? captureLimits.defaultJpegQuality : requireIntegerIn(optionsArg.quality, 1, 100, 'the quality'))
112
+ : undefined,
113
+ };
114
+ };
115
+ /** Validates a screenshot request and applies its defaults. */
116
+ export const resolveScreenshotRequest = (requestArg) => {
117
+ if (typeof requestArg !== 'object' || requestArg === null) {
118
+ throw new WccCaptureRequestError('wcctools: the screenshot request is missing.');
119
+ }
120
+ return {
121
+ subject: resolveSubject(requestArg.subject),
122
+ view: resolveView(requestArg),
123
+ image: resolveImageOptions(requestArg),
124
+ };
125
+ };
126
+ const resolveStep = (stepArg, indexArg) => {
127
+ const name = `step ${indexArg}`;
128
+ if (typeof stepArg !== 'object' || stepArg === null) {
129
+ throw new WccCaptureRequestError(`wcctools: ${name} must be an object with an action.`);
130
+ }
131
+ const step = stepArg;
132
+ const selector = (requiredArg) => {
133
+ if (!requiredArg && step.selector === undefined) {
134
+ return undefined;
135
+ }
136
+ return requireText(step.selector, captureLimits.maxSelectorLength, `the selector of ${name}`);
137
+ };
138
+ switch (step.action) {
139
+ case 'click':
140
+ case 'hover':
141
+ return { action: step.action, selector: selector(true) };
142
+ case 'fill':
143
+ return {
144
+ action: 'fill',
145
+ selector: selector(true),
146
+ text: requireText(step.text, captureLimits.maxTextLength, `the text of ${name}`, true),
147
+ };
148
+ case 'press': {
149
+ const pressStep = {
150
+ action: 'press',
151
+ key: requireText(step.key, captureLimits.maxKeyLength, `the key of ${name}`),
152
+ };
153
+ const pressSelector = selector(false);
154
+ return pressSelector === undefined ? pressStep : { ...pressStep, selector: pressSelector };
155
+ }
156
+ case 'waitFor': {
157
+ const state = step.state ?? 'visible';
158
+ if (state !== 'visible' && state !== 'hidden') {
159
+ throw new WccCaptureRequestError(`wcctools: the state of ${name} must be visible or hidden.`);
160
+ }
161
+ return { action: 'waitFor', selector: selector(true), state };
162
+ }
163
+ case 'wait':
164
+ return { action: 'wait', ms: requireIntegerIn(step.ms, 0, captureLimits.maxWaitMs, `the time of ${name}`) };
165
+ default:
166
+ throw new WccCaptureRequestError(`wcctools: the action of ${name} must be one of click, hover, fill, press, waitFor, wait.`);
167
+ }
168
+ };
169
+ /** Validates an interaction request and applies its defaults. */
170
+ export const resolveInteractionRequest = (requestArg) => {
171
+ if (typeof requestArg !== 'object' || requestArg === null) {
172
+ throw new WccCaptureRequestError('wcctools: the interaction request is missing.');
173
+ }
174
+ if (!Array.isArray(requestArg.steps) || requestArg.steps.length > captureLimits.maxSteps) {
175
+ throw new WccCaptureRequestError(`wcctools: an interaction has a list of at most ${captureLimits.maxSteps} steps.`);
176
+ }
177
+ if (requestArg.finalScreenshot !== undefined && (typeof requestArg.finalScreenshot !== 'object' || requestArg.finalScreenshot === null)) {
178
+ throw new WccCaptureRequestError('wcctools: finalScreenshot must be an object.');
179
+ }
180
+ return {
181
+ subject: resolveSubject(requestArg.subject),
182
+ view: resolveView(requestArg),
183
+ steps: requestArg.steps.map((stepArg, indexArg) => resolveStep(stepArg, indexArg)),
184
+ observeMs: requestArg.observeMs === undefined
185
+ ? captureLimits.defaultObserveMs
186
+ : requireIntegerIn(requestArg.observeMs, 0, captureLimits.maxObserveMs, 'observeMs'),
187
+ maxFrames: requestArg.maxFrames === undefined
188
+ ? captureLimits.defaultMaxFrames
189
+ : requireIntegerIn(requestArg.maxFrames, 1, captureLimits.maxMaxFrames, 'maxFrames'),
190
+ frameQuality: requestArg.frameQuality === undefined
191
+ ? captureLimits.defaultFrameQuality
192
+ : requireIntegerIn(requestArg.frameQuality, 1, 100, 'frameQuality'),
193
+ finalScreenshot: requestArg.finalScreenshot ? resolveImageOptions(requestArg.finalScreenshot) : null,
194
+ };
195
+ };
196
+ const describeEntry = (sectionNameArg, entryNameArg) => `${sectionNameArg}/${entryNameArg}`;
197
+ const listSome = (namesArg) => {
198
+ const shown = namesArg.slice(0, 20).join(', ');
199
+ return namesArg.length > 20 ? `${shown}, … (${namesArg.length} in all)` : shown;
200
+ };
201
+ /**
202
+ * Resolves a subject to one demo of the catalog: an entry named by its name or its element's tag,
203
+ * in the named section or, without one, in exactly one section.
204
+ */
205
+ export const resolveSelection = (manifestArg, subjectArg) => {
206
+ const sections = subjectArg.sectionName === undefined
207
+ ? manifestArg.sections
208
+ : manifestArg.sections.filter((sectionArg) => sectionArg.name === subjectArg.sectionName);
209
+ if (sections.length === 0) {
210
+ throw new WccCaptureRequestError(`wcctools: the catalog has no section "${subjectArg.sectionName}". Sections: ${listSome(manifestArg.sections.map((sectionArg) => sectionArg.name))}.`);
211
+ }
212
+ const wanted = subjectArg.itemName;
213
+ const matchesName = (entryArg) => {
214
+ return entryArg.name === wanted || (entryArg.tagName !== null && entryArg.tagName === wanted.toLowerCase());
215
+ };
216
+ const matches = sections.flatMap((sectionArg) => sectionArg.entries
217
+ .filter(matchesName)
218
+ .map((entryArg) => ({ section: sectionArg, entry: entryArg })));
219
+ if (matches.length === 0) {
220
+ const withoutDemo = sections.flatMap((sectionArg) => sectionArg.entriesWithoutDemo
221
+ .filter(matchesName)
222
+ .map((entryArg) => describeEntry(sectionArg.name, entryArg.name)));
223
+ if (withoutDemo.length > 0) {
224
+ throw new WccCaptureRequestError(`wcctools: ${listSome(withoutDemo)} has no demo to capture.`);
225
+ }
226
+ const known = sections.flatMap((sectionArg) => sectionArg.entries.map((entryArg) => describeEntry(sectionArg.name, entryArg.name)));
227
+ throw new WccCaptureRequestError(`wcctools: the catalog has no entry "${wanted}". Entries: ${listSome(known)}.`);
228
+ }
229
+ if (matches.length > 1) {
230
+ throw new WccCaptureRequestError(`wcctools: "${wanted}" names ${matches.length} entries (${listSome(matches.map((matchArg) => describeEntry(matchArg.section.name, matchArg.entry.name)))}); name its section.`);
231
+ }
232
+ const [{ section, entry }] = matches;
233
+ const demoIndex = subjectArg.demoIndex ?? 0;
234
+ if (demoIndex >= entry.demoCount) {
235
+ throw new WccCaptureRequestError(`wcctools: ${describeEntry(section.name, entry.name)} has ${entry.demoCount} demo${entry.demoCount === 1 ? '' : 's'}; demo ${demoIndex} does not exist (demos count from 0).`);
236
+ }
237
+ return { sectionName: section.name, itemName: entry.name, demoIndex };
238
+ };
239
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NhcHR1cmUvcmVxdWVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFNckQsbURBQW1EO0FBQ25ELE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUMzQixRQUFRLEVBQUUsR0FBRztJQUNiLFFBQVEsRUFBRSxJQUFJO0lBQ2QsU0FBUyxFQUFFLEdBQUc7SUFDZCxTQUFTLEVBQUUsSUFBSTtJQUNmLGFBQWEsRUFBRSxHQUFHO0lBQ2xCLCtEQUErRDtJQUMvRCxpQkFBaUIsRUFBRSxNQUFNO0lBQ3pCLGtCQUFrQixFQUFFLEVBQUU7SUFDdEIsUUFBUSxFQUFFLEVBQUU7SUFDWixhQUFhLEVBQUUsS0FBSztJQUNwQixTQUFTLEVBQUUsS0FBSztJQUNoQixnQkFBZ0IsRUFBRSxHQUFHO0lBQ3JCLFlBQVksRUFBRSxLQUFLO0lBQ25CLGdCQUFnQixFQUFFLEVBQUU7SUFDcEIsWUFBWSxFQUFFLEVBQUU7SUFDaEIsbUJBQW1CLEVBQUUsRUFBRTtJQUN2QixpQkFBaUIsRUFBRSxHQUFHO0lBQ3RCLGFBQWEsRUFBRSxLQUFLO0lBQ3BCLFlBQVksRUFBRSxFQUFFO0lBQ2hCLGdCQUFnQixFQUFFLEdBQUc7Q0FDYixDQUFDO0FBRVgsZ0ZBQWdGO0FBQ2hGLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUEyRTtJQUMzRyxLQUFLLEVBQUUsT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsS0FBSztJQUM3QyxPQUFPLEVBQUUsT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsT0FBTztJQUNqRCxNQUFNLEVBQUUsT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsTUFBTTtJQUMvQyxPQUFPLEVBQUUsT0FBTyxDQUFDLFlBQVks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
@@ -0,0 +1,36 @@
1
+ import * as plugins from './plugins.js';
2
+ /** The longest time a status request waits for a change before it answers the unchanged status. */
3
+ export declare const bundleStatusWaitLimitMs = 25000;
4
+ /** What a status request answers while the board is closed: the server is not serving. */
5
+ export declare const bundleStatusClosedMessage = "wcctools: the dev server is not serving the bundle status.";
6
+ /**
7
+ * The status of the catalog bundles, as tswatch's bundle events report it, for the shell's
8
+ * `getBundleStatus` requests. Every event raises the revision and answers the requests waiting for
9
+ * a change. While closed (the server is not serving), requests are refused with a typed error, so
10
+ * a client backs off as it does for any failed request.
11
+ */
12
+ export declare class WccBundleStatusBoard {
13
+ private readonly bundles;
14
+ private revision;
15
+ private isOpen;
16
+ /** Settles one waiting request: answers the current snapshot, or refuses; each removes itself. */
17
+ private readonly waiters;
18
+ /** Starts a run of the server: the bundles of an earlier run are forgotten. */
19
+ open(): void;
20
+ /** Ends the run: every waiting request is refused now, later ones at once. */
21
+ close(): void;
22
+ /** The number of requests waiting for a change. */
23
+ getWaiterCount(): number;
24
+ record(eventArg: plugins.tswatch.TBundleEvent): void;
25
+ getSnapshot(): plugins.interfaces.IWccBundleStatusSnapshot;
26
+ /**
27
+ * The snapshot once it differs from `afterRevisionArg`, or after the wait limit; at once without
28
+ * a revision or for a revision that is no longer current. Refused while closed. When
29
+ * `abortSignalArg` aborts (the client went away), the wait ends at once and releases its timer;
30
+ * it answers the current snapshot, which the transport drops.
31
+ */
32
+ waitForChange(afterRevisionArg: number | undefined, abortSignalArg?: AbortSignal): Promise<plugins.interfaces.IWccBundleStatusSnapshot>;
33
+ private changed;
34
+ private answerWaiters;
35
+ private createClosedError;
36
+ }