autokap 1.0.8 → 1.1.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/assets/skill/OPCODE-REFERENCE.md +29 -1
- package/assets/skill/SKILL.md +2 -1
- package/dist/auth-capture.js +35 -2
- package/dist/billing-operation-logging.d.ts +4 -3
- package/dist/billing-operation-logging.js +3 -2
- package/dist/browser.d.ts +10 -10
- package/dist/browser.js +32 -28
- package/dist/capture-encryption.d.ts +3 -1
- package/dist/capture-encryption.js +21 -6
- package/dist/capture-strategy.js +3 -2
- package/dist/cli-config.d.ts +2 -1
- package/dist/cli-config.js +51 -2
- package/dist/cli-contract.d.ts +5 -1
- package/dist/cli-contract.js +7 -1
- package/dist/cli-runner-local.js +16 -3
- package/dist/cli-runner.js +165 -18
- package/dist/cli.js +25 -19
- package/dist/clip-begin-frame-recorder.d.ts +44 -0
- package/dist/clip-begin-frame-recorder.js +250 -0
- package/dist/clip-capture-backend.d.ts +25 -0
- package/dist/clip-capture-backend.js +189 -0
- package/dist/clip-capture-loop.d.ts +61 -0
- package/dist/clip-capture-loop.js +111 -0
- package/dist/clip-frame-recorder.d.ts +63 -0
- package/dist/clip-frame-recorder.js +305 -0
- package/dist/clip-postprocess.d.ts +31 -2
- package/dist/clip-postprocess.js +174 -57
- package/dist/clip-runtime.d.ts +18 -0
- package/dist/clip-runtime.js +67 -0
- package/dist/clip-scale.d.ts +10 -0
- package/dist/clip-scale.js +21 -0
- package/dist/clip-screencast-recorder.d.ts +42 -0
- package/dist/clip-screencast-recorder.js +242 -0
- package/dist/clip-sidecar.d.ts +54 -0
- package/dist/clip-sidecar.js +208 -0
- package/dist/cost-logging.d.ts +1 -1
- package/dist/env-validation.js +38 -4
- package/dist/execution-schema.d.ts +690 -360
- package/dist/execution-schema.js +98 -42
- package/dist/execution-types.d.ts +53 -3
- package/dist/execution-types.js +2 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/llm-healer.d.ts +2 -10
- package/dist/llm-healer.js +109 -62
- package/dist/llm-provider.js +3 -0
- package/dist/opcode-actions.js +13 -0
- package/dist/opcode-runner.js +21 -12
- package/dist/program-signing.d.ts +1094 -0
- package/dist/program-signing.js +140 -0
- package/dist/provider-config.d.ts +5 -0
- package/dist/provider-config.js +28 -1
- package/dist/recovery-chain.js +40 -16
- package/dist/server-credit-usage.d.ts +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/web-playwright-local.d.ts +31 -1
- package/dist/web-playwright-local.js +207 -37
- package/package.json +12 -2
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { BeginFrameClipRecorder } from './clip-begin-frame-recorder.js';
|
|
5
|
+
import { FrameSequenceClipRecorder } from './clip-frame-recorder.js';
|
|
6
|
+
import { postProcessClipRecording, } from './clip-postprocess.js';
|
|
7
|
+
import { resolvePhysicalCaptureSize } from './clip-scale.js';
|
|
8
|
+
const DEFAULT_PLAYWRIGHT_VIDEO_FPS = 30;
|
|
9
|
+
function applyFallbackReason(result, fallbackReason) {
|
|
10
|
+
if (!fallbackReason || !result.clipPackage) {
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
...result,
|
|
15
|
+
clipPackage: {
|
|
16
|
+
...result.clipPackage,
|
|
17
|
+
fallbackReason,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async function loadPackagedClipResult(output, packagedClip) {
|
|
22
|
+
if (!output.mp4Path || !output.thumbnailPath) {
|
|
23
|
+
throw new Error('clip packaging failed: missing MP4 or thumbnail output');
|
|
24
|
+
}
|
|
25
|
+
const [mp4Buffer, gifBuffer, thumbnailBuffer] = await Promise.all([
|
|
26
|
+
fs.readFile(output.mp4Path),
|
|
27
|
+
output.gifPath ? fs.readFile(output.gifPath) : Promise.resolve(null),
|
|
28
|
+
fs.readFile(output.thumbnailPath),
|
|
29
|
+
]);
|
|
30
|
+
return {
|
|
31
|
+
buffer: mp4Buffer,
|
|
32
|
+
mimeType: 'video/mp4',
|
|
33
|
+
durationMs: output.durationMs,
|
|
34
|
+
trimStartMs: 0,
|
|
35
|
+
clipPackage: {
|
|
36
|
+
...packagedClip,
|
|
37
|
+
mp4: {
|
|
38
|
+
buffer: mp4Buffer,
|
|
39
|
+
mimeType: 'video/mp4',
|
|
40
|
+
},
|
|
41
|
+
...(gifBuffer
|
|
42
|
+
? {
|
|
43
|
+
gif: {
|
|
44
|
+
buffer: gifBuffer,
|
|
45
|
+
mimeType: 'image/gif',
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
: {}),
|
|
49
|
+
thumbnail: {
|
|
50
|
+
buffer: thumbnailBuffer,
|
|
51
|
+
mimeType: 'image/png',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function waitForFile(filePath, timeoutMs = 15_000) {
|
|
57
|
+
const deadline = Date.now() + timeoutMs;
|
|
58
|
+
while (Date.now() < deadline) {
|
|
59
|
+
try {
|
|
60
|
+
await fs.stat(filePath);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
throw new Error(`timed out waiting for clip artifact ${filePath}`);
|
|
68
|
+
}
|
|
69
|
+
class FrameSequenceClipCaptureBackend {
|
|
70
|
+
options;
|
|
71
|
+
captureMethod = 'frame_sequence';
|
|
72
|
+
recorder;
|
|
73
|
+
constructor(options) {
|
|
74
|
+
this.options = options;
|
|
75
|
+
this.recorder = new FrameSequenceClipRecorder(options.page, {
|
|
76
|
+
baseDir: options.recordingDir,
|
|
77
|
+
viewport: options.viewport,
|
|
78
|
+
requestedScale: options.requestedScale,
|
|
79
|
+
effectiveScale: options.effectiveScale,
|
|
80
|
+
clipOptions: options.clipOptions,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async start() {
|
|
84
|
+
await this.recorder.start();
|
|
85
|
+
}
|
|
86
|
+
async stop() {
|
|
87
|
+
const result = await this.recorder.stop();
|
|
88
|
+
return applyFallbackReason(result, this.options.fallbackReason);
|
|
89
|
+
}
|
|
90
|
+
async abort() {
|
|
91
|
+
await this.recorder.abort();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
class BeginFrameClipCaptureBackend {
|
|
95
|
+
options;
|
|
96
|
+
captureMethod = 'begin_frame';
|
|
97
|
+
recorder;
|
|
98
|
+
constructor(options) {
|
|
99
|
+
this.options = options;
|
|
100
|
+
this.recorder = new BeginFrameClipRecorder(options.page, {
|
|
101
|
+
baseDir: options.recordingDir,
|
|
102
|
+
viewport: options.viewport,
|
|
103
|
+
requestedScale: options.requestedScale,
|
|
104
|
+
effectiveScale: options.effectiveScale,
|
|
105
|
+
clipOptions: options.clipOptions,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async start() {
|
|
109
|
+
await this.recorder.start();
|
|
110
|
+
}
|
|
111
|
+
async stop() {
|
|
112
|
+
const result = await this.recorder.stop();
|
|
113
|
+
return applyFallbackReason(result, this.options.fallbackReason);
|
|
114
|
+
}
|
|
115
|
+
async abort() {
|
|
116
|
+
await this.recorder.abort();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
class PlaywrightVideoClipCaptureBackend {
|
|
120
|
+
options;
|
|
121
|
+
captureMethod = 'playwright_video';
|
|
122
|
+
startedAtMs = null;
|
|
123
|
+
workingDirPromise;
|
|
124
|
+
outputDimensions;
|
|
125
|
+
constructor(options) {
|
|
126
|
+
this.options = options;
|
|
127
|
+
this.workingDirPromise = options.recordingDir
|
|
128
|
+
? Promise.resolve(options.recordingDir)
|
|
129
|
+
: fs.mkdtemp(path.join(os.tmpdir(), 'autokap-clip-webm-'));
|
|
130
|
+
this.outputDimensions = resolvePhysicalCaptureSize(options.viewport, options.effectiveScale)
|
|
131
|
+
?? options.viewport;
|
|
132
|
+
}
|
|
133
|
+
async start() {
|
|
134
|
+
this.startedAtMs = Date.now();
|
|
135
|
+
}
|
|
136
|
+
async stop() {
|
|
137
|
+
const page = this.options.browser.currentPage;
|
|
138
|
+
const video = page.video();
|
|
139
|
+
if (!video) {
|
|
140
|
+
throw new Error('playwright video recording is not available on this browser context');
|
|
141
|
+
}
|
|
142
|
+
const workingDir = await this.workingDirPromise;
|
|
143
|
+
await fs.mkdir(workingDir, { recursive: true });
|
|
144
|
+
const browserStartedAtMs = this.options.browser.launchedAtMs ?? this.startedAtMs ?? Date.now();
|
|
145
|
+
const trimStartSec = this.startedAtMs
|
|
146
|
+
? Math.max(0, (this.startedAtMs - browserStartedAtMs) / 1000)
|
|
147
|
+
: 0;
|
|
148
|
+
try {
|
|
149
|
+
await this.options.browser.closeContext();
|
|
150
|
+
const webmPath = await video.path();
|
|
151
|
+
await waitForFile(webmPath);
|
|
152
|
+
const packaged = await postProcessClipRecording(webmPath, workingDir, 'clip', {
|
|
153
|
+
...this.options.clipOptions,
|
|
154
|
+
trimStartSec,
|
|
155
|
+
mp4Width: this.outputDimensions.width,
|
|
156
|
+
mp4Height: this.outputDimensions.height,
|
|
157
|
+
});
|
|
158
|
+
const result = await loadPackagedClipResult(packaged, {
|
|
159
|
+
captureMethod: 'playwright_video',
|
|
160
|
+
requestedScale: this.options.requestedScale,
|
|
161
|
+
effectiveScale: this.options.effectiveScale,
|
|
162
|
+
sourceFps: DEFAULT_PLAYWRIGHT_VIDEO_FPS,
|
|
163
|
+
outputFps: DEFAULT_PLAYWRIGHT_VIDEO_FPS,
|
|
164
|
+
dimensions: this.outputDimensions,
|
|
165
|
+
fallbackReason: this.options.fallbackReason,
|
|
166
|
+
});
|
|
167
|
+
return applyFallbackReason(result, this.options.fallbackReason);
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
await fs.rm(workingDir, { recursive: true, force: true }).catch(() => undefined);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async abort() {
|
|
174
|
+
const workingDir = await this.workingDirPromise;
|
|
175
|
+
await fs.rm(workingDir, { recursive: true, force: true }).catch(() => undefined);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
export function createClipCaptureBackend(options) {
|
|
179
|
+
switch (options.captureMethod) {
|
|
180
|
+
case 'begin_frame':
|
|
181
|
+
return new BeginFrameClipCaptureBackend(options);
|
|
182
|
+
case 'playwright_video':
|
|
183
|
+
return new PlaywrightVideoClipCaptureBackend(options);
|
|
184
|
+
case 'frame_sequence':
|
|
185
|
+
default:
|
|
186
|
+
return new FrameSequenceClipCaptureBackend(options);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=clip-capture-backend.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClipCaptureLoop — custom CDP Page.captureScreenshot loop.
|
|
3
|
+
*
|
|
4
|
+
* Pulls HiDPI-fidel frames from the Chromium compositor via
|
|
5
|
+
* `Page.captureScreenshot` with `optimizeForSpeed: true` and `fromSurface: true`.
|
|
6
|
+
* Produces crisp screenshot-grade JPEGs (not the downsampled/compressed
|
|
7
|
+
* `Page.startScreencast` stream that DevTools uses for remote debugging).
|
|
8
|
+
*
|
|
9
|
+
* Frames are buffered in memory during capture (raw base64), then flushed to
|
|
10
|
+
* disk in parallel at `stop()`. `assembleMp4FromFrames` reads the per-frame
|
|
11
|
+
* timestamps and encodes VFR via the concat demuxer so playback matches the
|
|
12
|
+
* real capture cadence — essential when the compositor is CPU-bound on heavy
|
|
13
|
+
* React UIs (frames arrive in bursts + gaps, not uniformly).
|
|
14
|
+
*/
|
|
15
|
+
import type { Page } from 'playwright';
|
|
16
|
+
export interface ClipCaptureLoopOptions {
|
|
17
|
+
/** Playwright page used to derive the CDP session. */
|
|
18
|
+
page: Page;
|
|
19
|
+
/** Absolute path to an existing directory where frames will be written. */
|
|
20
|
+
framesDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* JPEG quality (0-100). Default 80. On 2880×1800, q=80 sustains ~40 FPS on
|
|
23
|
+
* a modern Mac (vs 30 FPS at q=90) — the quality drop is invisible on screen
|
|
24
|
+
* content (high-contrast text, flat colors) but unlocks a 33% fluidity gain.
|
|
25
|
+
*/
|
|
26
|
+
jpegQuality?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ClipCaptureLoopResult {
|
|
29
|
+
framesDir: string;
|
|
30
|
+
frameCount: number;
|
|
31
|
+
/** (frameCount - 1) * 1000 / (lastTs - firstTs); 0 if < 2 frames. */
|
|
32
|
+
measuredFps: number;
|
|
33
|
+
actualDurationMs: number;
|
|
34
|
+
/** Delay between start() returning and the first frame being written. */
|
|
35
|
+
trimStartMs: number;
|
|
36
|
+
/**
|
|
37
|
+
* Wall-clock offset in milliseconds from the first frame, one entry per
|
|
38
|
+
* captured frame. Used by assembleMp4FromFrames to preserve real timing
|
|
39
|
+
* (VFR) instead of encoding at a uniform CFR — critical when capture
|
|
40
|
+
* throughput varies (heavy page renders pause the compositor while the
|
|
41
|
+
* loop keeps trying, producing bursts and gaps).
|
|
42
|
+
*/
|
|
43
|
+
frameOffsetsMs: number[];
|
|
44
|
+
}
|
|
45
|
+
export declare class ClipCaptureLoop {
|
|
46
|
+
private readonly page;
|
|
47
|
+
private readonly framesDir;
|
|
48
|
+
private readonly jpegQuality;
|
|
49
|
+
private cdp;
|
|
50
|
+
private running;
|
|
51
|
+
private loopPromise;
|
|
52
|
+
private frames;
|
|
53
|
+
private frameTimestamps;
|
|
54
|
+
private startedAt;
|
|
55
|
+
private firstFrameAt;
|
|
56
|
+
private lastFrameAt;
|
|
57
|
+
constructor(opts: ClipCaptureLoopOptions);
|
|
58
|
+
start(): Promise<void>;
|
|
59
|
+
stop(): Promise<ClipCaptureLoopResult>;
|
|
60
|
+
private loop;
|
|
61
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClipCaptureLoop — custom CDP Page.captureScreenshot loop.
|
|
3
|
+
*
|
|
4
|
+
* Pulls HiDPI-fidel frames from the Chromium compositor via
|
|
5
|
+
* `Page.captureScreenshot` with `optimizeForSpeed: true` and `fromSurface: true`.
|
|
6
|
+
* Produces crisp screenshot-grade JPEGs (not the downsampled/compressed
|
|
7
|
+
* `Page.startScreencast` stream that DevTools uses for remote debugging).
|
|
8
|
+
*
|
|
9
|
+
* Frames are buffered in memory during capture (raw base64), then flushed to
|
|
10
|
+
* disk in parallel at `stop()`. `assembleMp4FromFrames` reads the per-frame
|
|
11
|
+
* timestamps and encodes VFR via the concat demuxer so playback matches the
|
|
12
|
+
* real capture cadence — essential when the compositor is CPU-bound on heavy
|
|
13
|
+
* React UIs (frames arrive in bursts + gaps, not uniformly).
|
|
14
|
+
*/
|
|
15
|
+
import fs from 'node:fs/promises';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
export class ClipCaptureLoop {
|
|
18
|
+
page;
|
|
19
|
+
framesDir;
|
|
20
|
+
jpegQuality;
|
|
21
|
+
cdp = null;
|
|
22
|
+
running = false;
|
|
23
|
+
loopPromise = null;
|
|
24
|
+
frames = [];
|
|
25
|
+
frameTimestamps = [];
|
|
26
|
+
startedAt = 0;
|
|
27
|
+
firstFrameAt = 0;
|
|
28
|
+
lastFrameAt = 0;
|
|
29
|
+
constructor(opts) {
|
|
30
|
+
this.page = opts.page;
|
|
31
|
+
this.framesDir = opts.framesDir;
|
|
32
|
+
this.jpegQuality = opts.jpegQuality ?? 80;
|
|
33
|
+
}
|
|
34
|
+
async start() {
|
|
35
|
+
this.cdp = await this.page.context().newCDPSession(this.page);
|
|
36
|
+
this.startedAt = performance.now();
|
|
37
|
+
this.running = true;
|
|
38
|
+
this.loopPromise = this.loop();
|
|
39
|
+
}
|
|
40
|
+
async stop() {
|
|
41
|
+
this.running = false;
|
|
42
|
+
if (this.loopPromise) {
|
|
43
|
+
await this.loopPromise;
|
|
44
|
+
this.loopPromise = null;
|
|
45
|
+
}
|
|
46
|
+
if (this.cdp) {
|
|
47
|
+
try {
|
|
48
|
+
await this.cdp.detach();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// page/context may already be closed
|
|
52
|
+
}
|
|
53
|
+
this.cdp = null;
|
|
54
|
+
}
|
|
55
|
+
// Flush all captured base64 frames to disk in parallel now that the loop
|
|
56
|
+
// has stopped. Doing this during capture would bottleneck the loop on
|
|
57
|
+
// Buffer.from decoding; deferring gets us the full CDP throughput.
|
|
58
|
+
const writes = this.frames.map((data, i) => fs.writeFile(path.join(this.framesDir, `frame_${String(i).padStart(6, '0')}.jpg`), data, 'base64'));
|
|
59
|
+
await Promise.all(writes);
|
|
60
|
+
const frameCount = this.frames.length;
|
|
61
|
+
const span = this.lastFrameAt - this.firstFrameAt;
|
|
62
|
+
const measuredFps = frameCount > 1 && span > 0 ? ((frameCount - 1) * 1000) / span : 0;
|
|
63
|
+
const actualDurationMs = span > 0 ? span : 0;
|
|
64
|
+
const trimStartMs = this.firstFrameAt > 0 ? Math.max(0, this.firstFrameAt - this.startedAt) : 0;
|
|
65
|
+
// Snapshot offsets (ms from first frame) for VFR encoding downstream.
|
|
66
|
+
const frameOffsetsMs = this.frameTimestamps.map(ts => ts - this.firstFrameAt);
|
|
67
|
+
// Release memory — the caller owns framesDir from here on.
|
|
68
|
+
this.frames = [];
|
|
69
|
+
this.frameTimestamps = [];
|
|
70
|
+
return {
|
|
71
|
+
framesDir: this.framesDir,
|
|
72
|
+
frameCount,
|
|
73
|
+
measuredFps,
|
|
74
|
+
actualDurationMs,
|
|
75
|
+
trimStartMs,
|
|
76
|
+
frameOffsetsMs,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async loop() {
|
|
80
|
+
while (this.running) {
|
|
81
|
+
if (!this.cdp)
|
|
82
|
+
return;
|
|
83
|
+
let data;
|
|
84
|
+
try {
|
|
85
|
+
const r = await this.cdp.send('Page.captureScreenshot', {
|
|
86
|
+
format: 'jpeg',
|
|
87
|
+
quality: this.jpegQuality,
|
|
88
|
+
fromSurface: true,
|
|
89
|
+
optimizeForSpeed: true,
|
|
90
|
+
});
|
|
91
|
+
data = r.data;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Page may have navigated or context closing. If we're still running,
|
|
95
|
+
// skip this iteration and retry on next tick. If we're stopping, exit.
|
|
96
|
+
if (!this.running)
|
|
97
|
+
return;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const ts = performance.now();
|
|
101
|
+
if (this.firstFrameAt === 0)
|
|
102
|
+
this.firstFrameAt = ts;
|
|
103
|
+
this.lastFrameAt = ts;
|
|
104
|
+
// Push raw base64 — no decode, no I/O. Keeps the capture loop tight.
|
|
105
|
+
// Decode+write happens in stop().
|
|
106
|
+
this.frames.push(data);
|
|
107
|
+
this.frameTimestamps.push(ts);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=clip-capture-loop.js.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import type { RecordingResult } from './execution-types.js';
|
|
3
|
+
import type { ClipOptions } from './types.js';
|
|
4
|
+
interface ScrollOffset {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function buildCdpViewportClip(viewport: {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
}, effectiveScale: number, scrollOffset: ScrollOffset): {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
scale: number;
|
|
17
|
+
};
|
|
18
|
+
export interface FrameSequenceClipRecorderOptions {
|
|
19
|
+
baseDir?: string;
|
|
20
|
+
viewport: {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
requestedScale?: number;
|
|
25
|
+
effectiveScale: number;
|
|
26
|
+
clipOptions?: ClipOptions;
|
|
27
|
+
sourceFps?: number;
|
|
28
|
+
outputFps?: number;
|
|
29
|
+
}
|
|
30
|
+
export declare class FrameSequenceClipRecorder {
|
|
31
|
+
private readonly page;
|
|
32
|
+
private readonly options;
|
|
33
|
+
private readonly sourceFps;
|
|
34
|
+
private readonly outputFps;
|
|
35
|
+
private readonly workingDirPromise;
|
|
36
|
+
private readonly startedAt;
|
|
37
|
+
private readonly frames;
|
|
38
|
+
private stopRequested;
|
|
39
|
+
private loopPromise;
|
|
40
|
+
private finalResult;
|
|
41
|
+
private frameDimensions;
|
|
42
|
+
private lastCaptureError;
|
|
43
|
+
private readonly pendingWrites;
|
|
44
|
+
private pendingWriteError;
|
|
45
|
+
private cdpSession;
|
|
46
|
+
private cdpSessionPromise;
|
|
47
|
+
private cdpCaptureDisabled;
|
|
48
|
+
constructor(page: Page, options: FrameSequenceClipRecorderOptions);
|
|
49
|
+
start(): Promise<void>;
|
|
50
|
+
stop(): Promise<RecordingResult>;
|
|
51
|
+
abort(): Promise<void>;
|
|
52
|
+
private runCaptureLoop;
|
|
53
|
+
private captureFrame;
|
|
54
|
+
private captureFrameBuffer;
|
|
55
|
+
private readScrollOffset;
|
|
56
|
+
private captureFrameViaCdp;
|
|
57
|
+
private getCdpSession;
|
|
58
|
+
private disableCdpCapture;
|
|
59
|
+
private queueFrameWrite;
|
|
60
|
+
private waitForPendingWriteCapacity;
|
|
61
|
+
private flushPendingWrites;
|
|
62
|
+
}
|
|
63
|
+
export {};
|