@design.estate/wcctools 6.2.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.
- package/changelog.md +21 -0
- package/dist_shell/bundle.js +4 -4
- package/dist_shell/bundle.js.map +1 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/capture/classes.capturebrowser.d.ts +65 -0
- package/dist_ts/capture/classes.capturebrowser.js +251 -0
- package/dist_ts/capture/classes.captureservice.d.ts +39 -0
- package/dist_ts/capture/classes.captureservice.js +119 -0
- package/dist_ts/capture/classes.screencast.d.ts +47 -0
- package/dist_ts/capture/classes.screencast.js +127 -0
- package/dist_ts/capture/errors.d.ts +14 -0
- package/dist_ts/capture/errors.js +23 -0
- package/dist_ts/capture/images.d.ts +3 -0
- package/dist_ts/capture/images.js +58 -0
- package/dist_ts/capture/index.d.ts +4 -0
- package/dist_ts/capture/index.js +5 -0
- package/dist_ts/capture/interaction.d.ts +11 -0
- package/dist_ts/capture/interaction.js +138 -0
- package/dist_ts/capture/navigationguard.d.ts +44 -0
- package/dist_ts/capture/navigationguard.js +129 -0
- package/dist_ts/capture/previewpage.d.ts +29 -0
- package/dist_ts/capture/previewpage.js +96 -0
- package/dist_ts/capture/request.d.ts +69 -0
- package/dist_ts/capture/request.js +239 -0
- package/dist_ts/classes.devserver.d.ts +25 -9
- package/dist_ts/classes.devserver.js +45 -14
- package/dist_ts/classes.hostpolicy.d.ts +63 -0
- package/dist_ts/classes.hostpolicy.js +171 -0
- package/dist_ts/cli.js +25 -3
- package/dist_ts/cli.screenshot.d.ts +6 -0
- package/dist_ts/cli.screenshot.js +89 -0
- package/dist_ts/plugins.d.ts +6 -2
- package/dist_ts/plugins.js +8 -3
- package/dist_ts_interfaces/capture.d.ts +151 -0
- package/dist_ts_interfaces/capture.js +2 -0
- package/dist_ts_interfaces/index.d.ts +1 -0
- package/dist_ts_interfaces/index.js +2 -1
- package/dist_ts_interfaces/requests.d.ts +24 -0
- package/dist_ts_shell/elements/wcc-recording-panel.d.ts +9 -0
- package/dist_ts_shell/elements/wcc-recording-panel.js +12 -1
- package/dist_ts_shell/services/framesampler.service.d.ts +23 -0
- package/dist_ts_shell/services/framesampler.service.js +101 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/package.json +2 -1
- package/readme.md +104 -6
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/capture/classes.capturebrowser.ts +290 -0
- package/ts/capture/classes.captureservice.ts +152 -0
- package/ts/capture/classes.screencast.ts +152 -0
- package/ts/capture/errors.ts +25 -0
- package/ts/capture/images.ts +61 -0
- package/ts/capture/index.ts +4 -0
- package/ts/capture/interaction.ts +146 -0
- package/ts/capture/navigationguard.ts +147 -0
- package/ts/capture/previewpage.ts +130 -0
- package/ts/capture/request.ts +304 -0
- package/ts/classes.devserver.ts +55 -13
- package/ts/classes.hostpolicy.ts +201 -0
- package/ts/cli.screenshot.ts +95 -0
- package/ts/cli.ts +25 -2
- package/ts/plugins.ts +9 -2
- package/ts_interfaces/capture.ts +144 -0
- package/ts_interfaces/index.ts +1 -0
- package/ts_interfaces/requests.ts +39 -0
- package/ts_shell/elements/wcc-recording-panel.ts +12 -0
- package/ts_shell/services/framesampler.service.ts +112 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/wcctools',
|
|
6
|
-
version: '
|
|
6
|
+
version: '7.0.0',
|
|
7
7
|
description: 'A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLG1KQUFtSjtDQUNqSyxDQUFBIn0=
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
type TBrowserContext = plugins.smartbrowser.puppeteer.BrowserContext;
|
|
3
|
+
export interface IWccCaptureBrowserOptions {
|
|
4
|
+
/** Captures that run at once; default 2. */
|
|
5
|
+
maxConcurrent?: number;
|
|
6
|
+
/** Captures that wait for a slot; more are refused as busy. Default 8. */
|
|
7
|
+
maxQueued?: number;
|
|
8
|
+
/** The browser closes after this long without captures; default 60 s. */
|
|
9
|
+
idleCloseMs?: number;
|
|
10
|
+
/** How long closing the browser may take before its process is killed; default 5 s. */
|
|
11
|
+
closeTimeoutMs?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const captureBrowserClosedMessage = "wcctools: the dev server is not serving captures.";
|
|
14
|
+
/**
|
|
15
|
+
* The headless browser of a dev server's captures: launched on the first capture, shared by the
|
|
16
|
+
* captures that follow and closed after a while without one, or when the server stops. Each
|
|
17
|
+
* capture runs in its own browser context, closed when it ends; a bounded number run at once and a
|
|
18
|
+
* bounded number wait for a slot. The browser leaves process signals to the application: the dev
|
|
19
|
+
* server's shutdown closes it.
|
|
20
|
+
*/
|
|
21
|
+
export declare class WccCaptureBrowser {
|
|
22
|
+
private readonly maxConcurrent;
|
|
23
|
+
private readonly maxQueued;
|
|
24
|
+
private readonly idleCloseMs;
|
|
25
|
+
private readonly closeTimeoutMs;
|
|
26
|
+
private isOpen;
|
|
27
|
+
private launching;
|
|
28
|
+
private readonly closingBrowsers;
|
|
29
|
+
private readonly contexts;
|
|
30
|
+
private readonly running;
|
|
31
|
+
private readonly queue;
|
|
32
|
+
private activeCount;
|
|
33
|
+
private idleTimer;
|
|
34
|
+
private launchCount;
|
|
35
|
+
constructor(optionsArg?: IWccCaptureBrowserOptions);
|
|
36
|
+
/** How often a browser was launched; one browser serves every capture while it runs. */
|
|
37
|
+
getLaunchCount(): number;
|
|
38
|
+
/** The process id of the running browser, or null while none runs. */
|
|
39
|
+
getProcessId(): Promise<number | null>;
|
|
40
|
+
/** Takes captures from now on. */
|
|
41
|
+
open(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Refuses new captures and the waiting ones, ends the running ones by closing their contexts,
|
|
44
|
+
* closes the browser and resolves once all of it has settled.
|
|
45
|
+
*/
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Runs a capture in a browser context of its own, once a slot is free. The context closes when
|
|
49
|
+
* the capture ends, and at once when `abortSignalArg` aborts, which ends the capture with the
|
|
50
|
+
* signal's reason.
|
|
51
|
+
*/
|
|
52
|
+
withContext<T>(abortSignalArg: AbortSignal, captureArg: (contextArg: TBrowserContext) => Promise<T>): Promise<T>;
|
|
53
|
+
private runInContext;
|
|
54
|
+
private acquireSlot;
|
|
55
|
+
private releaseSlot;
|
|
56
|
+
private clearIdleTimer;
|
|
57
|
+
/** The running browser, launched when none runs; refused once close() ran, so it never outlives it. */
|
|
58
|
+
private getBrowser;
|
|
59
|
+
private launch;
|
|
60
|
+
/** Closes the current browser, if one runs or launches; the next capture launches another. */
|
|
61
|
+
private closeBrowser;
|
|
62
|
+
/** Closes a browser, and kills its process when closing takes longer than allowed. */
|
|
63
|
+
private closeWithin;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { WccCaptureError, getErrorMessage } from './errors.js';
|
|
3
|
+
export const captureBrowserClosedMessage = 'wcctools: the dev server is not serving captures.';
|
|
4
|
+
/**
|
|
5
|
+
* The headless browser of a dev server's captures: launched on the first capture, shared by the
|
|
6
|
+
* captures that follow and closed after a while without one, or when the server stops. Each
|
|
7
|
+
* capture runs in its own browser context, closed when it ends; a bounded number run at once and a
|
|
8
|
+
* bounded number wait for a slot. The browser leaves process signals to the application: the dev
|
|
9
|
+
* server's shutdown closes it.
|
|
10
|
+
*/
|
|
11
|
+
export class WccCaptureBrowser {
|
|
12
|
+
maxConcurrent;
|
|
13
|
+
maxQueued;
|
|
14
|
+
idleCloseMs;
|
|
15
|
+
closeTimeoutMs;
|
|
16
|
+
isOpen = false;
|
|
17
|
+
launching = null;
|
|
18
|
+
closingBrowsers = new Set();
|
|
19
|
+
contexts = new Set();
|
|
20
|
+
running = new Set();
|
|
21
|
+
queue = [];
|
|
22
|
+
activeCount = 0;
|
|
23
|
+
idleTimer = null;
|
|
24
|
+
launchCount = 0;
|
|
25
|
+
constructor(optionsArg = {}) {
|
|
26
|
+
this.maxConcurrent = optionsArg.maxConcurrent ?? 2;
|
|
27
|
+
this.maxQueued = optionsArg.maxQueued ?? 8;
|
|
28
|
+
this.idleCloseMs = optionsArg.idleCloseMs ?? 60_000;
|
|
29
|
+
this.closeTimeoutMs = optionsArg.closeTimeoutMs ?? 5_000;
|
|
30
|
+
}
|
|
31
|
+
/** How often a browser was launched; one browser serves every capture while it runs. */
|
|
32
|
+
getLaunchCount() {
|
|
33
|
+
return this.launchCount;
|
|
34
|
+
}
|
|
35
|
+
/** The process id of the running browser, or null while none runs. */
|
|
36
|
+
async getProcessId() {
|
|
37
|
+
const launching = this.launching;
|
|
38
|
+
if (!launching) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const browser = await launching.catch(() => null);
|
|
42
|
+
return browser?.process()?.pid ?? null;
|
|
43
|
+
}
|
|
44
|
+
/** Takes captures from now on. */
|
|
45
|
+
open() {
|
|
46
|
+
this.isOpen = true;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Refuses new captures and the waiting ones, ends the running ones by closing their contexts,
|
|
50
|
+
* closes the browser and resolves once all of it has settled.
|
|
51
|
+
*/
|
|
52
|
+
async close() {
|
|
53
|
+
this.isOpen = false;
|
|
54
|
+
this.clearIdleTimer();
|
|
55
|
+
const refusal = new WccCaptureError(captureBrowserClosedMessage);
|
|
56
|
+
for (const queued of this.queue.splice(0)) {
|
|
57
|
+
queued.refuse(refusal);
|
|
58
|
+
}
|
|
59
|
+
await Promise.allSettled([...this.contexts].map((contextArg) => contextArg.close()));
|
|
60
|
+
await Promise.allSettled([...this.running]);
|
|
61
|
+
this.closeBrowser();
|
|
62
|
+
await Promise.allSettled([...this.closingBrowsers]);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Runs a capture in a browser context of its own, once a slot is free. The context closes when
|
|
66
|
+
* the capture ends, and at once when `abortSignalArg` aborts, which ends the capture with the
|
|
67
|
+
* signal's reason.
|
|
68
|
+
*/
|
|
69
|
+
async withContext(abortSignalArg, captureArg) {
|
|
70
|
+
await this.acquireSlot(abortSignalArg);
|
|
71
|
+
const run = this.runInContext(abortSignalArg, captureArg);
|
|
72
|
+
this.running.add(run);
|
|
73
|
+
try {
|
|
74
|
+
return await run;
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
this.running.delete(run);
|
|
78
|
+
this.releaseSlot();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async runInContext(abortSignalArg, captureArg) {
|
|
82
|
+
let context = null;
|
|
83
|
+
const closeContext = () => {
|
|
84
|
+
void context?.close().catch(() => {
|
|
85
|
+
// The context is gone already: its browser closed or disconnected
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
abortSignalArg.addEventListener('abort', closeContext, { once: true });
|
|
89
|
+
try {
|
|
90
|
+
const browser = await this.getBrowser();
|
|
91
|
+
abortSignalArg.throwIfAborted();
|
|
92
|
+
context = await browser.createBrowserContext();
|
|
93
|
+
this.contexts.add(context);
|
|
94
|
+
abortSignalArg.throwIfAborted();
|
|
95
|
+
if (!this.isOpen) {
|
|
96
|
+
// close() ran while the browser launched; it does not wait for this capture's context
|
|
97
|
+
throw new WccCaptureError(captureBrowserClosedMessage);
|
|
98
|
+
}
|
|
99
|
+
return await captureArg(context);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (abortSignalArg.aborted) {
|
|
103
|
+
throw abortSignalArg.reason;
|
|
104
|
+
}
|
|
105
|
+
if (!this.isOpen) {
|
|
106
|
+
throw new WccCaptureError(captureBrowserClosedMessage);
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
abortSignalArg.removeEventListener('abort', closeContext);
|
|
112
|
+
if (context) {
|
|
113
|
+
this.contexts.delete(context);
|
|
114
|
+
if (context.browser().connected) {
|
|
115
|
+
await context.close().catch(() => {
|
|
116
|
+
// Closed meanwhile by an abort, or its browser disconnected
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
acquireSlot(abortSignalArg) {
|
|
123
|
+
if (!this.isOpen) {
|
|
124
|
+
return Promise.reject(new WccCaptureError(captureBrowserClosedMessage));
|
|
125
|
+
}
|
|
126
|
+
abortSignalArg.throwIfAborted();
|
|
127
|
+
this.clearIdleTimer();
|
|
128
|
+
if (this.activeCount < this.maxConcurrent) {
|
|
129
|
+
this.activeCount++;
|
|
130
|
+
return Promise.resolve();
|
|
131
|
+
}
|
|
132
|
+
if (this.queue.length >= this.maxQueued) {
|
|
133
|
+
return Promise.reject(new WccCaptureError(`wcctools: the capture browser is busy (${this.maxConcurrent} captures running, ${this.queue.length} waiting); try again later.`));
|
|
134
|
+
}
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
const queued = {
|
|
137
|
+
grant: () => {
|
|
138
|
+
abortSignalArg.removeEventListener('abort', onAbort);
|
|
139
|
+
resolve();
|
|
140
|
+
},
|
|
141
|
+
refuse: (errorArg) => {
|
|
142
|
+
abortSignalArg.removeEventListener('abort', onAbort);
|
|
143
|
+
reject(errorArg);
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
const onAbort = () => {
|
|
147
|
+
const index = this.queue.indexOf(queued);
|
|
148
|
+
if (index !== -1) {
|
|
149
|
+
this.queue.splice(index, 1);
|
|
150
|
+
}
|
|
151
|
+
queued.refuse(abortSignalArg.reason);
|
|
152
|
+
};
|
|
153
|
+
abortSignalArg.addEventListener('abort', onAbort, { once: true });
|
|
154
|
+
this.queue.push(queued);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
releaseSlot() {
|
|
158
|
+
const next = this.queue.shift();
|
|
159
|
+
if (next) {
|
|
160
|
+
// The slot passes to the next capture
|
|
161
|
+
next.grant();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
this.activeCount--;
|
|
165
|
+
if (this.activeCount === 0 && this.isOpen && this.launching) {
|
|
166
|
+
this.idleTimer = setTimeout(() => {
|
|
167
|
+
this.idleTimer = null;
|
|
168
|
+
if (this.activeCount === 0) {
|
|
169
|
+
this.closeBrowser();
|
|
170
|
+
}
|
|
171
|
+
}, this.idleCloseMs);
|
|
172
|
+
this.idleTimer.unref();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
clearIdleTimer() {
|
|
176
|
+
if (this.idleTimer) {
|
|
177
|
+
clearTimeout(this.idleTimer);
|
|
178
|
+
this.idleTimer = null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** The running browser, launched when none runs; refused once close() ran, so it never outlives it. */
|
|
182
|
+
getBrowser() {
|
|
183
|
+
if (!this.isOpen) {
|
|
184
|
+
return Promise.reject(new WccCaptureError(captureBrowserClosedMessage));
|
|
185
|
+
}
|
|
186
|
+
this.launching ??= this.launch();
|
|
187
|
+
return this.launching;
|
|
188
|
+
}
|
|
189
|
+
async launch() {
|
|
190
|
+
this.launchCount++;
|
|
191
|
+
let browser;
|
|
192
|
+
try {
|
|
193
|
+
browser = await plugins.smartbrowser.getEnvAwareBrowserInstance({
|
|
194
|
+
launchOptions: {
|
|
195
|
+
// The application owns process signals: the dev server's shutdown closes the browser
|
|
196
|
+
handleSIGINT: false,
|
|
197
|
+
handleSIGTERM: false,
|
|
198
|
+
handleSIGHUP: false,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
this.launching = null;
|
|
204
|
+
throw new WccCaptureError(`wcctools: the capture browser failed to start: ${getErrorMessage(error)}. Captures need Chrome or Chromium: install google-chrome or chromium on the PATH.`);
|
|
205
|
+
}
|
|
206
|
+
const launching = this.launching;
|
|
207
|
+
browser.once('disconnected', () => {
|
|
208
|
+
// A crashed or closed browser is replaced by the next capture
|
|
209
|
+
if (this.launching === launching) {
|
|
210
|
+
this.launching = null;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
return browser;
|
|
214
|
+
}
|
|
215
|
+
/** Closes the current browser, if one runs or launches; the next capture launches another. */
|
|
216
|
+
closeBrowser() {
|
|
217
|
+
this.clearIdleTimer();
|
|
218
|
+
const launching = this.launching;
|
|
219
|
+
if (!launching) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
this.launching = null;
|
|
223
|
+
const closing = launching
|
|
224
|
+
.then((browserArg) => this.closeWithin(browserArg), () => undefined)
|
|
225
|
+
.finally(() => {
|
|
226
|
+
this.closingBrowsers.delete(closing);
|
|
227
|
+
});
|
|
228
|
+
this.closingBrowsers.add(closing);
|
|
229
|
+
}
|
|
230
|
+
/** Closes a browser, and kills its process when closing takes longer than allowed. */
|
|
231
|
+
async closeWithin(browserArg) {
|
|
232
|
+
if (!browserArg.connected) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
let deadline = null;
|
|
236
|
+
const timedOut = new Promise((resolve) => {
|
|
237
|
+
deadline = setTimeout(() => resolve('timeout'), this.closeTimeoutMs);
|
|
238
|
+
});
|
|
239
|
+
const closed = browserArg.close().then(() => 'closed', () => 'failed');
|
|
240
|
+
try {
|
|
241
|
+
const result = await Promise.race([closed, timedOut]);
|
|
242
|
+
if (result !== 'closed') {
|
|
243
|
+
browserArg.process()?.kill('SIGKILL');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
clearTimeout(deadline);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jYXB0dXJlYnJvd3Nlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NhcHR1cmUvY2xhc3Nlcy5jYXB0dXJlYnJvd3Nlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQXFCL0QsTUFBTSxDQUFDLE1BQU0sMkJBQTJCLEdBQUcsbURBQW1ELENBQUM7QUFFL0Y7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQUNYLGFBQWEsQ0FBUztJQUN0QixTQUFTLENBQVM7SUFDbEIsV0FBVyxDQUFTO0lBQ3BCLGNBQWMsQ0FBUztJQUNoQyxNQUFNLEdBQUcsS0FBSyxDQUFDO0lBQ2YsU0FBUyxHQUE2QixJQUFJLENBQUM7SUFDbEMsZUFBZSxHQUFHLElBQUksR0FBRyxFQUFpQixDQUFDO0lBQzNDLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBbUIsQ0FBQztJQUN0QyxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQW9CLENBQUM7SUFDdEMsS0FBSyxHQUFxQixFQUFFLENBQUM7SUFDdEMsV0FBVyxHQUFHLENBQUMsQ0FBQztJQUNoQixTQUFTLEdBQXlDLElBQUksQ0FBQztJQUN2RCxXQUFXLEdBQUcsQ0FBQyxDQUFDO0lBRXhCLFlBQVksYUFBd0MsRUFBRTtRQUNwRCxJQUFJLENBQUMsYUFBYSxHQUFHLFVBQVUsQ0FBQyxhQUFhLElBQUksQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxTQUFTLEdBQUcsVUFBVSxDQUFDLFNBQVMsSUFBSSxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUMsV0FBVyxJQUFJLE1BQU0sQ0FBQztRQUNwRCxJQUFJLENBQUMsY0FBYyxHQUFHLFVBQVUsQ0FBQyxjQUFjLElBQUksS0FBSyxDQUFDO0lBQzNE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
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import type { WccBundleStatusBoard } from '../classes.bundlestatus.js';
|
|
3
|
+
import { type IWccCaptureBrowserOptions } from './classes.capturebrowser.js';
|
|
4
|
+
/** The longest a screenshot may take, from its request to its image. */
|
|
5
|
+
export declare const screenshotDeadlineMs = 30000;
|
|
6
|
+
/** The longest an interaction may take: its steps, its observation and the set-up around them. */
|
|
7
|
+
export declare const interactionDeadlineMs: number;
|
|
8
|
+
/**
|
|
9
|
+
* The captures of a dev server: screenshots and observed interactions of single demos, taken in a
|
|
10
|
+
* headless browser on the server's preview route. A capture waits while a catalog bundle builds,
|
|
11
|
+
* and is refused when one failed, so it never shows a stale or broken bundle. Every capture has a
|
|
12
|
+
* deadline and ends when its client goes away. The service registers `captureScreenshot` and
|
|
13
|
+
* `captureInteraction` on the dev server's typed API.
|
|
14
|
+
*/
|
|
15
|
+
export declare class WccCaptureService {
|
|
16
|
+
private readonly bundleStatus;
|
|
17
|
+
private readonly browser;
|
|
18
|
+
private origin;
|
|
19
|
+
constructor(bundleStatus: WccBundleStatusBoard, browserOptionsArg?: IWccCaptureBrowserOptions);
|
|
20
|
+
/** Registers the capture requests on a typed router. */
|
|
21
|
+
addTypedHandlers(typedrouterArg: plugins.typedrequest.TypedRouter): void;
|
|
22
|
+
/** How often the capture browser was launched. */
|
|
23
|
+
getBrowserLaunchCount(): number;
|
|
24
|
+
/** The process id of the capture browser while it runs. */
|
|
25
|
+
getBrowserProcessId(): Promise<number | null>;
|
|
26
|
+
/** Takes captures of the dev server serving at `originArg` (scheme, host and port). */
|
|
27
|
+
open(originArg: string): void;
|
|
28
|
+
/** Ends every capture and closes the browser. */
|
|
29
|
+
close(): Promise<void>;
|
|
30
|
+
captureScreenshot(requestArg: plugins.interfaces.IWccScreenshotRequest, abortSignalArg?: AbortSignal): Promise<plugins.interfaces.IWccScreenshotResult>;
|
|
31
|
+
captureInteraction(requestArg: plugins.interfaces.IWccInteractionRequest, abortSignalArg?: AbortSignal): Promise<plugins.interfaces.IWccInteractionResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Runs a capture within its deadline: waits for settled bundles, then runs it in a browser
|
|
34
|
+
* context of its own. The client's abort and the deadline both end it.
|
|
35
|
+
*/
|
|
36
|
+
private run;
|
|
37
|
+
/** Resolves once no bundle builds; refused while a bundle's latest run failed. */
|
|
38
|
+
private waitForSettledBundles;
|
|
39
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { WccCaptureBrowser, captureBrowserClosedMessage } from './classes.capturebrowser.js';
|
|
3
|
+
import { WccCaptureError } from './errors.js';
|
|
4
|
+
import { runInteraction } from './interaction.js';
|
|
5
|
+
import { renderPreview, screenshotPreview } from './previewpage.js';
|
|
6
|
+
import { captureLimits, resolveInteractionRequest, resolveScreenshotRequest } from './request.js';
|
|
7
|
+
/** The longest a screenshot may take, from its request to its image. */
|
|
8
|
+
export const screenshotDeadlineMs = 30_000;
|
|
9
|
+
/** The longest an interaction may take: its steps, its observation and the set-up around them. */
|
|
10
|
+
export const interactionDeadlineMs = 30_000
|
|
11
|
+
+ captureLimits.maxSteps * captureLimits.stepTimeoutMs
|
|
12
|
+
+ captureLimits.maxObserveMs;
|
|
13
|
+
/**
|
|
14
|
+
* The captures of a dev server: screenshots and observed interactions of single demos, taken in a
|
|
15
|
+
* headless browser on the server's preview route. A capture waits while a catalog bundle builds,
|
|
16
|
+
* and is refused when one failed, so it never shows a stale or broken bundle. Every capture has a
|
|
17
|
+
* deadline and ends when its client goes away. The service registers `captureScreenshot` and
|
|
18
|
+
* `captureInteraction` on the dev server's typed API.
|
|
19
|
+
*/
|
|
20
|
+
export class WccCaptureService {
|
|
21
|
+
bundleStatus;
|
|
22
|
+
browser;
|
|
23
|
+
origin = null;
|
|
24
|
+
constructor(bundleStatus, browserOptionsArg = {}) {
|
|
25
|
+
this.bundleStatus = bundleStatus;
|
|
26
|
+
this.browser = new WccCaptureBrowser(browserOptionsArg);
|
|
27
|
+
}
|
|
28
|
+
/** Registers the capture requests on a typed router. */
|
|
29
|
+
addTypedHandlers(typedrouterArg) {
|
|
30
|
+
typedrouterArg.addTypedHandler(new plugins.typedrequest.TypedHandler('captureScreenshot', async (requestArg, typedToolsArg) => {
|
|
31
|
+
return this.captureScreenshot(requestArg, typedToolsArg?.abortSignal);
|
|
32
|
+
}));
|
|
33
|
+
typedrouterArg.addTypedHandler(new plugins.typedrequest.TypedHandler('captureInteraction', async (requestArg, typedToolsArg) => {
|
|
34
|
+
return this.captureInteraction(requestArg, typedToolsArg?.abortSignal);
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
/** How often the capture browser was launched. */
|
|
38
|
+
getBrowserLaunchCount() {
|
|
39
|
+
return this.browser.getLaunchCount();
|
|
40
|
+
}
|
|
41
|
+
/** The process id of the capture browser while it runs. */
|
|
42
|
+
getBrowserProcessId() {
|
|
43
|
+
return this.browser.getProcessId();
|
|
44
|
+
}
|
|
45
|
+
/** Takes captures of the dev server serving at `originArg` (scheme, host and port). */
|
|
46
|
+
open(originArg) {
|
|
47
|
+
this.origin = originArg;
|
|
48
|
+
this.browser.open();
|
|
49
|
+
}
|
|
50
|
+
/** Ends every capture and closes the browser. */
|
|
51
|
+
async close() {
|
|
52
|
+
this.origin = null;
|
|
53
|
+
await this.browser.close();
|
|
54
|
+
}
|
|
55
|
+
async captureScreenshot(requestArg, abortSignalArg) {
|
|
56
|
+
const request = resolveScreenshotRequest(requestArg);
|
|
57
|
+
return this.run(screenshotDeadlineMs, abortSignalArg, async (contextArg, originArg) => {
|
|
58
|
+
const preview = await renderPreview(contextArg, originArg, request.view, request.subject);
|
|
59
|
+
const shot = await screenshotPreview(preview, request.view, request.image);
|
|
60
|
+
await preview.navigationGuard.assertStayed('being captured');
|
|
61
|
+
return { selection: preview.selection, ...shot };
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async captureInteraction(requestArg, abortSignalArg) {
|
|
65
|
+
const request = resolveInteractionRequest(requestArg);
|
|
66
|
+
return this.run(interactionDeadlineMs, abortSignalArg, async (contextArg, originArg, signalArg) => {
|
|
67
|
+
const preview = await renderPreview(contextArg, originArg, request.view, request.subject);
|
|
68
|
+
const observed = await runInteraction(preview, request, signalArg);
|
|
69
|
+
const result = { selection: preview.selection, ...observed };
|
|
70
|
+
if (request.finalScreenshot) {
|
|
71
|
+
result.finalImage = (await screenshotPreview(preview, request.view, request.finalScreenshot)).image;
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Runs a capture within its deadline: waits for settled bundles, then runs it in a browser
|
|
78
|
+
* context of its own. The client's abort and the deadline both end it.
|
|
79
|
+
*/
|
|
80
|
+
async run(deadlineMsArg, clientSignalArg, captureArg) {
|
|
81
|
+
const origin = this.origin;
|
|
82
|
+
if (!origin) {
|
|
83
|
+
throw new WccCaptureError(captureBrowserClosedMessage);
|
|
84
|
+
}
|
|
85
|
+
const controller = new AbortController();
|
|
86
|
+
const deadline = setTimeout(() => {
|
|
87
|
+
controller.abort(new WccCaptureError(`wcctools: the capture did not finish within ${deadlineMsArg / 1000} s.`));
|
|
88
|
+
}, deadlineMsArg);
|
|
89
|
+
const onClientAbort = () => controller.abort(new WccCaptureError('wcctools: the client went away; the capture ended.'));
|
|
90
|
+
clientSignalArg?.addEventListener('abort', onClientAbort, { once: true });
|
|
91
|
+
if (clientSignalArg?.aborted) {
|
|
92
|
+
onClientAbort();
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
await this.waitForSettledBundles(controller.signal);
|
|
96
|
+
return await this.browser.withContext(controller.signal, (contextArg) => captureArg(contextArg, origin, controller.signal));
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
clearTimeout(deadline);
|
|
100
|
+
clientSignalArg?.removeEventListener('abort', onClientAbort);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Resolves once no bundle builds; refused while a bundle's latest run failed. */
|
|
104
|
+
async waitForSettledBundles(abortSignalArg) {
|
|
105
|
+
for (;;) {
|
|
106
|
+
abortSignalArg.throwIfAborted();
|
|
107
|
+
const snapshot = this.bundleStatus.getSnapshot();
|
|
108
|
+
const failed = snapshot.bundles.filter((bundleArg) => bundleArg.state === 'failed');
|
|
109
|
+
if (failed.length > 0) {
|
|
110
|
+
throw new WccCaptureError(`wcctools: the catalog bundle failed, so there is nothing current to capture: ${failed.map((bundleArg) => `${bundleArg.name}: ${bundleArg.errorMessage ?? 'no message'}`).join('; ')}`);
|
|
111
|
+
}
|
|
112
|
+
if (!snapshot.bundles.some((bundleArg) => bundleArg.state === 'started')) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
await this.bundleStatus.waitForChange(snapshot.revision, abortSignalArg);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jYXB0dXJlc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NhcHR1cmUvY2xhc3Nlcy5jYXB0dXJlc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUV6QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsMkJBQTJCLEVBQWtDLE1BQU0sNkJBQTZCLENBQUM7QUFDN0gsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxhQUFhLEVBQUUseUJBQXlCLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFbEcsd0VBQXdFO0FBQ3hFLE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHLE1BQU0sQ0FBQztBQUUzQyxrR0FBa0c7QUFDbEcsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsTUFBTTtNQUN2QyxhQUFhLENBQUMsUUFBUSxHQUFHLGFBQWEsQ0FBQyxhQUFhO01BQ3BELGFBQWEsQ0FBQyxZQUFZLENBQUM7QUFFL0I7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQUtUO0lBSkYsT0FBTyxDQUFvQjtJQUNwQyxNQUFNLEdBQWtCLElBQUksQ0FBQztJQUVyQyxZQUNtQixZQUFrQyxFQUNuRCxvQkFBK0MsRUFBRTtRQURoQyxpQkFBWSxHQUFaLFlBQVksQ0FBc0I7UUFHbkQsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELHdEQUF3RDtJQUNqRCxnQkFBZ0IsQ0FBQyxjQUFnRDtRQUN0RSxjQUFjLENBQUMsZUFBZSxDQUM1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
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
type TPage = plugins.smartbrowser.puppeteer.Page;
|
|
3
|
+
export interface IWccScreencastOptions {
|
|
4
|
+
/** JPEG quality from 1 to 100. */
|
|
5
|
+
quality: number;
|
|
6
|
+
/** Frames are scaled down to fit these device pixels. */
|
|
7
|
+
maxWidth: number;
|
|
8
|
+
maxHeight: number;
|
|
9
|
+
/** At most this many frames per second are kept; default 10. */
|
|
10
|
+
maxFps?: number;
|
|
11
|
+
/** The most frames kept over a whole recording; older ones are thinned out. Default 200. */
|
|
12
|
+
maxKeptFrames?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Records a page's screencast (Chrome DevTools Protocol `Page.startScreencast`): JPEG frames the
|
|
16
|
+
* browser sends whenever the page paints, kept at a bounded rate and count. The page's last
|
|
17
|
+
* painted frame is always kept.
|
|
18
|
+
*/
|
|
19
|
+
export declare class WccScreencastRecorder {
|
|
20
|
+
private readonly page;
|
|
21
|
+
private readonly options;
|
|
22
|
+
private session;
|
|
23
|
+
private startedAt;
|
|
24
|
+
private readonly kept;
|
|
25
|
+
/** The newest frame that arrived too soon after the last kept one. */
|
|
26
|
+
private latest;
|
|
27
|
+
private stopped;
|
|
28
|
+
private ackFailure;
|
|
29
|
+
private readonly minFrameGapMs;
|
|
30
|
+
private readonly maxKeptFrames;
|
|
31
|
+
constructor(page: TPage, options: IWccScreencastOptions);
|
|
32
|
+
/** The time the recording started, as `Date.now()` read it. */
|
|
33
|
+
getStartedAt(): number;
|
|
34
|
+
start(): Promise<void>;
|
|
35
|
+
/** Stops the screencast, detaches from the page and answers the kept frames in time order. */
|
|
36
|
+
stop(): Promise<plugins.interfaces.IWccTimedFrame[]>;
|
|
37
|
+
private readonly onFrame;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Picks at most `maxFramesArg` frames spread evenly over the time the frames cover: for each of
|
|
41
|
+
* that many points in time, the frame on screen at that point. The first and the last frame are
|
|
42
|
+
* always among them.
|
|
43
|
+
*/
|
|
44
|
+
export declare const selectFrames: <T extends {
|
|
45
|
+
timestampMs: number;
|
|
46
|
+
}>(framesArg: T[], maxFramesArg: number) => T[];
|
|
47
|
+
export {};
|