playwriter 0.0.63 → 0.0.89
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/a11y-client.js +18 -8
- package/dist/aria-snapshot.d.ts +41 -3
- package/dist/aria-snapshot.d.ts.map +1 -1
- package/dist/aria-snapshot.js +134 -55
- package/dist/aria-snapshot.js.map +1 -1
- package/dist/aria-snapshot.test.js +5 -2
- package/dist/aria-snapshot.test.js.map +1 -1
- package/dist/aria-snapshot.unit.test.js +83 -41
- package/dist/aria-snapshot.unit.test.js.map +1 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +5 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +1 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +5 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +1 -0
- package/dist/bippy.js +1 -1
- package/dist/cdp-log.d.ts +1 -1
- package/dist/cdp-log.d.ts.map +1 -1
- package/dist/cdp-log.js +1 -1
- package/dist/cdp-log.js.map +1 -1
- package/dist/cdp-relay.d.ts.map +1 -1
- package/dist/cdp-relay.js +492 -298
- package/dist/cdp-relay.js.map +1 -1
- package/dist/cdp-session.d.ts.map +1 -1
- package/dist/cdp-session.js.map +1 -1
- package/dist/cdp-types.d.ts.map +1 -1
- package/dist/cdp-types.js +7 -7
- package/dist/cdp-types.js.map +1 -1
- package/dist/clean-html.d.ts.map +1 -1
- package/dist/clean-html.js +4 -5
- package/dist/clean-html.js.map +1 -1
- package/dist/cli.js +45 -27
- package/dist/cli.js.map +1 -1
- package/dist/create-logger.d.ts.map +1 -1
- package/dist/create-logger.js +3 -1
- package/dist/create-logger.js.map +1 -1
- package/dist/debugger-examples-types.d.ts.map +1 -1
- package/dist/debugger.d.ts.map +1 -1
- package/dist/debugger.js +1 -3
- package/dist/debugger.js.map +1 -1
- package/dist/diff-utils.d.ts.map +1 -1
- package/dist/diff-utils.js +1 -4
- package/dist/diff-utils.js.map +1 -1
- package/dist/editor-api.md +12 -2
- package/dist/editor-examples.d.ts +1 -1
- package/dist/editor-examples.d.ts.map +1 -1
- package/dist/editor-examples.js +1 -1
- package/dist/editor-examples.js.map +1 -1
- package/dist/editor.d.ts +1 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +1 -1
- package/dist/editor.js.map +1 -1
- package/dist/executor.d.ts +26 -3
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +297 -64
- package/dist/executor.js.map +1 -1
- package/dist/executor.unit.test.js +38 -1
- package/dist/executor.unit.test.js.map +1 -1
- package/dist/extension-connection.test.js +139 -36
- package/dist/extension-connection.test.js.map +1 -1
- package/dist/ffmpeg.d.ts +148 -0
- package/dist/ffmpeg.d.ts.map +1 -0
- package/dist/ffmpeg.js +523 -0
- package/dist/ffmpeg.js.map +1 -0
- package/dist/ghost-browser.d.ts.map +1 -1
- package/dist/ghost-browser.js.map +1 -1
- package/dist/ghost-cursor-client.js +287 -0
- package/dist/ghost-cursor.d.ts +27 -0
- package/dist/ghost-cursor.d.ts.map +1 -0
- package/dist/ghost-cursor.js +63 -0
- package/dist/ghost-cursor.js.map +1 -0
- package/dist/htmlrewrite.d.ts.map +1 -1
- package/dist/htmlrewrite.js +17 -55
- package/dist/htmlrewrite.js.map +1 -1
- package/dist/htmlrewrite.test.js.map +1 -1
- package/dist/kill-port.d.ts.map +1 -1
- package/dist/kill-port.js +1 -3
- package/dist/kill-port.js.map +1 -1
- package/dist/locator-selector.test.d.ts +2 -0
- package/dist/locator-selector.test.d.ts.map +1 -0
- package/dist/locator-selector.test.js +96 -0
- package/dist/locator-selector.test.js.map +1 -0
- package/dist/mcp-client.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +8 -3
- package/dist/mcp.js.map +1 -1
- package/dist/on-mouse-action.test.d.ts +2 -0
- package/dist/on-mouse-action.test.d.ts.map +1 -0
- package/dist/on-mouse-action.test.js +155 -0
- package/dist/on-mouse-action.test.js.map +1 -0
- package/dist/page-markdown.js +4 -4
- package/dist/page-markdown.js.map +1 -1
- package/dist/prompt.md +450 -377
- package/dist/protocol.d.ts +4 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/readability.js +16 -2
- package/dist/recording-ghost-cursor.d.ts +41 -0
- package/dist/recording-ghost-cursor.d.ts.map +1 -0
- package/dist/recording-ghost-cursor.js +79 -0
- package/dist/recording-ghost-cursor.js.map +1 -0
- package/dist/recording-relay.d.ts.map +1 -1
- package/dist/recording-relay.js +8 -8
- package/dist/recording-relay.js.map +1 -1
- package/dist/relay-client.d.ts +17 -4
- package/dist/relay-client.d.ts.map +1 -1
- package/dist/relay-client.js +45 -11
- package/dist/relay-client.js.map +1 -1
- package/dist/relay-core.test.d.ts.map +1 -1
- package/dist/relay-core.test.js +515 -26
- package/dist/relay-core.test.js.map +1 -1
- package/dist/relay-navigation.test.d.ts.map +1 -1
- package/dist/relay-navigation.test.js +169 -31
- package/dist/relay-navigation.test.js.map +1 -1
- package/dist/relay-session.test.d.ts.map +1 -1
- package/dist/relay-session.test.js +113 -65
- package/dist/relay-session.test.js.map +1 -1
- package/dist/relay-state.d.ts +158 -0
- package/dist/relay-state.d.ts.map +1 -0
- package/dist/relay-state.js +306 -0
- package/dist/relay-state.js.map +1 -0
- package/dist/relay-state.test.d.ts +2 -0
- package/dist/relay-state.test.d.ts.map +1 -0
- package/dist/relay-state.test.js +472 -0
- package/dist/relay-state.test.js.map +1 -0
- package/dist/scoped-fs.d.ts.map +1 -1
- package/dist/scoped-fs.js.map +1 -1
- package/dist/screen-recording.d.ts +66 -4
- package/dist/screen-recording.d.ts.map +1 -1
- package/dist/screen-recording.js +150 -13
- package/dist/screen-recording.js.map +1 -1
- package/dist/screen-recording.test.d.ts +2 -0
- package/dist/screen-recording.test.d.ts.map +1 -0
- package/dist/screen-recording.test.js +102 -0
- package/dist/screen-recording.test.js.map +1 -0
- package/dist/selector-generator.js +1 -1
- package/dist/snapshot-tools.test.js +71 -28
- package/dist/snapshot-tools.test.js.map +1 -1
- package/dist/start-relay-server.d.ts +1 -1
- package/dist/start-relay-server.d.ts.map +1 -1
- package/dist/start-relay-server.js +1 -1
- package/dist/start-relay-server.js.map +1 -1
- package/dist/styles-api.md +8 -1
- package/dist/styles-examples.d.ts +1 -1
- package/dist/styles-examples.d.ts.map +1 -1
- package/dist/styles-examples.js +1 -1
- package/dist/styles-examples.js.map +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +1 -3
- package/dist/styles.js.map +1 -1
- package/dist/test-declarations.d.ts.map +1 -1
- package/dist/test-utils.d.ts +1 -1
- package/dist/test-utils.d.ts.map +1 -1
- package/dist/test-utils.js +7 -5
- package/dist/test-utils.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js.map +1 -1
- package/dist/wait-for-page-load.d.ts.map +1 -1
- package/dist/wait-for-page-load.js +1 -1
- package/dist/wait-for-page-load.js.map +1 -1
- package/package.json +4 -3
- package/src/a11y-client.ts +5 -4
- package/src/aria-snapshot.test.ts +5 -2
- package/src/aria-snapshot.ts +306 -117
- package/src/aria-snapshot.unit.test.ts +199 -141
- package/src/aria-snapshots/github-interactive.txt +2 -0
- package/src/aria-snapshots/github-raw.txt +5 -1
- package/src/aria-snapshots/hackernews-interactive.txt +238 -241
- package/src/aria-snapshots/hackernews-raw.txt +265 -269
- package/src/assets/aria-labels-example.png +0 -0
- package/src/assets/aria-labels-github.png +0 -0
- package/src/assets/aria-labels-hacker-news.png +0 -0
- package/src/assets/aria-labels-old-reddit.png +0 -0
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +5 -0
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +18 -0
- package/src/cdp-log.ts +4 -1
- package/src/cdp-relay.ts +1059 -737
- package/src/cdp-session.ts +12 -3
- package/src/cdp-types.ts +51 -51
- package/src/clean-html.ts +4 -5
- package/src/cli.ts +82 -55
- package/src/create-logger.ts +5 -3
- package/src/debugger-examples-types.ts +4 -1
- package/src/debugger.ts +1 -5
- package/src/diff-utils.ts +2 -5
- package/src/editor-examples.ts +11 -1
- package/src/editor.ts +10 -2
- package/src/executor.ts +374 -73
- package/src/executor.unit.test.ts +48 -1
- package/src/extension-connection.test.ts +612 -488
- package/src/ffmpeg.ts +769 -0
- package/src/ghost-browser.ts +4 -6
- package/src/ghost-cursor-client.ts +369 -0
- package/src/ghost-cursor.ts +110 -0
- package/src/htmlrewrite.test.ts +6 -2
- package/src/htmlrewrite.ts +348 -386
- package/src/kill-port.ts +1 -3
- package/src/locator-selector.test.ts +115 -0
- package/src/mcp-client.ts +1 -1
- package/src/mcp.ts +21 -15
- package/src/on-mouse-action.test.ts +196 -0
- package/src/page-markdown.ts +7 -7
- package/src/protocol.ts +73 -57
- package/src/recording-ghost-cursor.ts +113 -0
- package/src/recording-relay.ts +20 -12
- package/src/relay-client.ts +85 -18
- package/src/relay-core.test.ts +1117 -578
- package/src/relay-navigation.test.ts +648 -483
- package/src/relay-session.test.ts +984 -929
- package/src/relay-state.test.ts +570 -0
- package/src/relay-state.ts +497 -0
- package/src/resource.md +21 -49
- package/src/scoped-fs.ts +9 -3
- package/src/screen-recording.test.ts +111 -0
- package/src/screen-recording.ts +256 -31
- package/src/skill.md +476 -396
- package/src/snapshot-tools.test.ts +580 -528
- package/src/snapshots/shadcn-ui-accessibility-full.md +8 -8
- package/src/snapshots/shadcn-ui-accessibility-interactive.md +8 -8
- package/src/start-relay-server.ts +14 -11
- package/src/styles-examples.ts +8 -1
- package/src/styles.ts +20 -21
- package/src/test-declarations.ts +6 -6
- package/src/test-utils.ts +104 -91
- package/src/utils.ts +2 -1
- package/src/wait-for-page-load.ts +6 -1
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Recording happens in the extension context, so it survives page navigation.
|
|
4
4
|
*
|
|
5
5
|
* This module communicates with the relay server which forwards commands to the extension.
|
|
6
|
-
*
|
|
6
|
+
* sessionId (pw-tab-* format) is used to identify which tab to record.
|
|
7
7
|
*/
|
|
8
|
-
import type { Page } from '@xmorse/playwright-core';
|
|
8
|
+
import type { BrowserContext, Page } from '@xmorse/playwright-core';
|
|
9
|
+
import { RecordingGhostCursorController } from './recording-ghost-cursor.js';
|
|
9
10
|
/**
|
|
10
11
|
* Generate a shell command to quit and restart Chrome with flags that allow automatic tab capture.
|
|
11
12
|
* This enables screen recording without user interaction (clicking extension icon).
|
|
@@ -15,10 +16,25 @@ import type { Page } from '@xmorse/playwright-core';
|
|
|
15
16
|
* - --auto-accept-this-tab-capture - auto-accepts tab capture permission requests
|
|
16
17
|
*/
|
|
17
18
|
export declare function getChromeRestartCommand(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Compute the largest viewport that fits inside `current` at the target aspect ratio.
|
|
21
|
+
* Never increases width or height beyond current values — only shrinks the
|
|
22
|
+
* dimension that's "too large" relative to the target ratio.
|
|
23
|
+
*/
|
|
24
|
+
export declare function fitToAspectRatio(current: {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
}, ratio?: {
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
}): {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|
|
18
34
|
export interface StartRecordingOptions {
|
|
19
35
|
/** Target page to record */
|
|
20
36
|
page: Page;
|
|
21
|
-
/**
|
|
37
|
+
/** CDP tab session ID (pw-tab-* format) to identify which tab to record */
|
|
22
38
|
sessionId?: string;
|
|
23
39
|
/** Frame rate (default: 30) */
|
|
24
40
|
frameRate?: number;
|
|
@@ -32,11 +48,20 @@ export interface StartRecordingOptions {
|
|
|
32
48
|
outputPath: string;
|
|
33
49
|
/** Relay server port (default: 19988) */
|
|
34
50
|
relayPort?: number;
|
|
51
|
+
/** Aspect ratio to fit viewport to before recording (default: { width: 16, height: 9 }).
|
|
52
|
+
* Set to null to skip viewport resizing. */
|
|
53
|
+
aspectRatio?: {
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
} | null;
|
|
57
|
+
/** Max recording duration in ms (default: 15 min = 900000). Auto-stops recording
|
|
58
|
+
* when exceeded to prevent accidentally filling disk. Set to 0 or Infinity to disable. */
|
|
59
|
+
maxDurationMs?: number;
|
|
35
60
|
}
|
|
36
61
|
export interface StopRecordingOptions {
|
|
37
62
|
/** Target page that is being recorded */
|
|
38
63
|
page: Page;
|
|
39
|
-
/**
|
|
64
|
+
/** CDP tab session ID (pw-tab-* format) to identify which tab to stop recording */
|
|
40
65
|
sessionId?: string;
|
|
41
66
|
/** Relay server port (default: 19988) */
|
|
42
67
|
relayPort?: number;
|
|
@@ -46,6 +71,42 @@ export interface RecordingState {
|
|
|
46
71
|
startedAt?: number;
|
|
47
72
|
tabId?: number;
|
|
48
73
|
}
|
|
74
|
+
export interface ExecutionTimestamp {
|
|
75
|
+
start: number;
|
|
76
|
+
end: number;
|
|
77
|
+
}
|
|
78
|
+
interface CreateRecordingApiOptions {
|
|
79
|
+
context: BrowserContext;
|
|
80
|
+
defaultPage: Page;
|
|
81
|
+
relayPort: number;
|
|
82
|
+
ghostCursorController: RecordingGhostCursorController;
|
|
83
|
+
onStart: () => void;
|
|
84
|
+
onFinish: () => void;
|
|
85
|
+
getExecutionTimestamps: () => ExecutionTimestamp[];
|
|
86
|
+
}
|
|
87
|
+
interface StartRecordingWithDefaultsOptions extends Omit<StartRecordingOptions, 'relayPort'> {
|
|
88
|
+
}
|
|
89
|
+
interface StopRecordingWithDefaultsOptions extends Omit<StopRecordingOptions, 'relayPort'> {
|
|
90
|
+
}
|
|
91
|
+
interface IsRecordingWithDefaultsOptions {
|
|
92
|
+
page?: Page;
|
|
93
|
+
sessionId?: string;
|
|
94
|
+
}
|
|
95
|
+
interface CancelRecordingWithDefaultsOptions {
|
|
96
|
+
page?: Page;
|
|
97
|
+
sessionId?: string;
|
|
98
|
+
}
|
|
99
|
+
export declare function createRecordingApi(options: CreateRecordingApiOptions): {
|
|
100
|
+
start: (opts?: StartRecordingWithDefaultsOptions) => Promise<RecordingState>;
|
|
101
|
+
stop: (opts?: StopRecordingWithDefaultsOptions) => Promise<{
|
|
102
|
+
path: string;
|
|
103
|
+
duration: number;
|
|
104
|
+
size: number;
|
|
105
|
+
executionTimestamps: ExecutionTimestamp[];
|
|
106
|
+
}>;
|
|
107
|
+
isRecording: (opts?: IsRecordingWithDefaultsOptions) => Promise<RecordingState>;
|
|
108
|
+
cancel: (opts?: CancelRecordingWithDefaultsOptions) => Promise<void>;
|
|
109
|
+
};
|
|
49
110
|
/**
|
|
50
111
|
* Start recording the page.
|
|
51
112
|
* The recording is handled by the extension, so it survives page navigation.
|
|
@@ -76,4 +137,5 @@ export declare function cancelRecording(options: {
|
|
|
76
137
|
sessionId?: string;
|
|
77
138
|
relayPort?: number;
|
|
78
139
|
}): Promise<void>;
|
|
140
|
+
export {};
|
|
79
141
|
//# sourceMappingURL=screen-recording.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen-recording.d.ts","sourceRoot":"","sources":["../src/screen-recording.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"screen-recording.d.ts","sourceRoot":"","sources":["../src/screen-recording.ts"],"names":[],"mappings":"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"}
|
package/dist/screen-recording.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Recording happens in the extension context, so it survives page navigation.
|
|
4
4
|
*
|
|
5
5
|
* This module communicates with the relay server which forwards commands to the extension.
|
|
6
|
-
*
|
|
6
|
+
* sessionId (pw-tab-* format) is used to identify which tab to record.
|
|
7
7
|
*/
|
|
8
8
|
import os from 'node:os';
|
|
9
9
|
import path from 'node:path';
|
|
@@ -18,7 +18,9 @@ import { EXTENSION_IDS } from './utils.js';
|
|
|
18
18
|
*/
|
|
19
19
|
export function getChromeRestartCommand() {
|
|
20
20
|
const platform = os.platform();
|
|
21
|
-
const
|
|
21
|
+
const extensionFlags = EXTENSION_IDS.map((id) => `--allowlisted-extension-id=${id}`).join(' ');
|
|
22
|
+
// --profile-directory=Default skips the profile picker on startup, preventing Chrome from hanging
|
|
23
|
+
const flags = `${extensionFlags} --auto-accept-this-tab-capture --profile-directory=Default`;
|
|
22
24
|
if (platform === 'darwin') {
|
|
23
25
|
return `osascript -e 'quit app "Google Chrome"' && sleep 1 && open -a "Google Chrome" --args ${flags}`;
|
|
24
26
|
}
|
|
@@ -28,13 +30,140 @@ export function getChromeRestartCommand() {
|
|
|
28
30
|
// Linux
|
|
29
31
|
return `pkill chrome; sleep 1; google-chrome ${flags}`;
|
|
30
32
|
}
|
|
33
|
+
const DEFAULT_ASPECT_RATIO = { width: 16, height: 9 };
|
|
34
|
+
/** Default max recording duration: 15 minutes in milliseconds */
|
|
35
|
+
const DEFAULT_MAX_DURATION_MS = 15 * 60 * 1000;
|
|
36
|
+
/**
|
|
37
|
+
* Compute the largest viewport that fits inside `current` at the target aspect ratio.
|
|
38
|
+
* Never increases width or height beyond current values — only shrinks the
|
|
39
|
+
* dimension that's "too large" relative to the target ratio.
|
|
40
|
+
*/
|
|
41
|
+
export function fitToAspectRatio(current, ratio = DEFAULT_ASPECT_RATIO) {
|
|
42
|
+
const targetRatio = ratio.width / ratio.height;
|
|
43
|
+
const currentRatio = current.width / current.height;
|
|
44
|
+
if (currentRatio > targetRatio) {
|
|
45
|
+
// Too wide — keep height, shrink width
|
|
46
|
+
return { width: Math.round(current.height * targetRatio), height: current.height };
|
|
47
|
+
}
|
|
48
|
+
// Too tall (or already exact) — keep width, shrink height
|
|
49
|
+
return { width: current.width, height: Math.round(current.width / targetRatio) };
|
|
50
|
+
}
|
|
31
51
|
/**
|
|
32
52
|
* Check if an error is related to missing activeTab permission for recording.
|
|
33
53
|
*/
|
|
34
54
|
function isActiveTabPermissionError(error) {
|
|
35
|
-
return error.includes('Extension has not been invoked') ||
|
|
55
|
+
return (error.includes('Extension has not been invoked') ||
|
|
36
56
|
error.includes('activeTab') ||
|
|
37
|
-
error.includes('enable recording');
|
|
57
|
+
error.includes('enable recording'));
|
|
58
|
+
}
|
|
59
|
+
function resolveRecordingTargetPage(options) {
|
|
60
|
+
return options.ghostCursorController.resolveRecordingTargetPage({
|
|
61
|
+
context: options.context,
|
|
62
|
+
defaultPage: options.defaultPage,
|
|
63
|
+
target: options.target,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function withRecordingDefaults(options) {
|
|
67
|
+
const { relayPort, defaultPage, fn } = options;
|
|
68
|
+
return async (input = {}) => {
|
|
69
|
+
const targetPage = input.page || defaultPage;
|
|
70
|
+
const sessionId = input.sessionId || targetPage.sessionId() || undefined;
|
|
71
|
+
return fn({ page: targetPage, sessionId, relayPort, ...input });
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function createRecordingApi(options) {
|
|
75
|
+
const { context, defaultPage, relayPort, ghostCursorController, onStart, onFinish, getExecutionTimestamps } = options;
|
|
76
|
+
// Stores the original viewport before aspect-ratio resize so we can restore on stop/cancel
|
|
77
|
+
let preRecordingViewport = null;
|
|
78
|
+
// Auto-stop timer to prevent unbounded recordings
|
|
79
|
+
let maxDurationTimer = null;
|
|
80
|
+
const startWithDefaults = withRecordingDefaults({
|
|
81
|
+
relayPort,
|
|
82
|
+
defaultPage,
|
|
83
|
+
fn: startRecording,
|
|
84
|
+
});
|
|
85
|
+
const stopWithDefaults = withRecordingDefaults({
|
|
86
|
+
relayPort,
|
|
87
|
+
defaultPage,
|
|
88
|
+
fn: stopRecording,
|
|
89
|
+
});
|
|
90
|
+
const isRecordingWithDefaults = async (opts = {}) => {
|
|
91
|
+
const targetPage = opts.page || defaultPage;
|
|
92
|
+
const sessionId = opts.sessionId || targetPage.sessionId() || undefined;
|
|
93
|
+
return isRecording({ page: targetPage, sessionId, relayPort });
|
|
94
|
+
};
|
|
95
|
+
const cancelWithDefaults = async (opts = {}) => {
|
|
96
|
+
const targetPage = opts.page || defaultPage;
|
|
97
|
+
const sessionId = opts.sessionId || targetPage.sessionId() || undefined;
|
|
98
|
+
await cancelRecording({ page: targetPage, sessionId, relayPort });
|
|
99
|
+
};
|
|
100
|
+
const start = async (opts) => {
|
|
101
|
+
const targetPage = resolveRecordingTargetPage({ context, defaultPage, ghostCursorController, target: opts });
|
|
102
|
+
// Resize viewport to target aspect ratio (default 16:9) before recording.
|
|
103
|
+
// Only shrinks — never increases width or height beyond current values.
|
|
104
|
+
const aspectRatio = opts?.aspectRatio === undefined ? DEFAULT_ASPECT_RATIO : opts.aspectRatio;
|
|
105
|
+
if (aspectRatio) {
|
|
106
|
+
const current = targetPage.viewportSize();
|
|
107
|
+
if (current) {
|
|
108
|
+
const fitted = fitToAspectRatio(current, aspectRatio);
|
|
109
|
+
if (fitted.width !== current.width || fitted.height !== current.height) {
|
|
110
|
+
preRecordingViewport = current;
|
|
111
|
+
await targetPage.setViewportSize(fitted);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const result = await startWithDefaults(opts);
|
|
116
|
+
onStart();
|
|
117
|
+
await ghostCursorController.enableForRecording({ page: targetPage });
|
|
118
|
+
// Schedule auto-stop to prevent unbounded recordings filling disk.
|
|
119
|
+
// Default 15 min. Set maxDurationMs to 0 or Infinity to disable.
|
|
120
|
+
const maxMs = opts?.maxDurationMs ?? DEFAULT_MAX_DURATION_MS;
|
|
121
|
+
if (maxMs > 0 && maxMs < Infinity) {
|
|
122
|
+
maxDurationTimer = setTimeout(() => {
|
|
123
|
+
maxDurationTimer = null;
|
|
124
|
+
stop(opts ? { page: opts.page, sessionId: opts.sessionId } : undefined).catch(() => { });
|
|
125
|
+
}, maxMs);
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
};
|
|
129
|
+
const clearMaxDurationTimer = () => {
|
|
130
|
+
if (maxDurationTimer) {
|
|
131
|
+
clearTimeout(maxDurationTimer);
|
|
132
|
+
maxDurationTimer = null;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const restoreViewport = async (targetPage) => {
|
|
136
|
+
if (!preRecordingViewport) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const saved = preRecordingViewport;
|
|
140
|
+
preRecordingViewport = null;
|
|
141
|
+
await targetPage.setViewportSize(saved);
|
|
142
|
+
};
|
|
143
|
+
const stop = async (opts) => {
|
|
144
|
+
clearMaxDurationTimer();
|
|
145
|
+
const targetPage = resolveRecordingTargetPage({ context, defaultPage, ghostCursorController, target: opts });
|
|
146
|
+
const result = await stopWithDefaults(opts);
|
|
147
|
+
const executionTimestamps = [...getExecutionTimestamps()];
|
|
148
|
+
onFinish();
|
|
149
|
+
await ghostCursorController.disableForRecording({ page: targetPage });
|
|
150
|
+
await restoreViewport(targetPage);
|
|
151
|
+
return { ...result, executionTimestamps };
|
|
152
|
+
};
|
|
153
|
+
const cancel = async (opts) => {
|
|
154
|
+
clearMaxDurationTimer();
|
|
155
|
+
const targetPage = resolveRecordingTargetPage({ context, defaultPage, ghostCursorController, target: opts });
|
|
156
|
+
await cancelWithDefaults(opts);
|
|
157
|
+
onFinish();
|
|
158
|
+
await ghostCursorController.disableForRecording({ page: targetPage });
|
|
159
|
+
await restoreViewport(targetPage);
|
|
160
|
+
};
|
|
161
|
+
return {
|
|
162
|
+
start,
|
|
163
|
+
stop,
|
|
164
|
+
isRecording: isRecordingWithDefaults,
|
|
165
|
+
cancel,
|
|
166
|
+
};
|
|
38
167
|
}
|
|
39
168
|
/**
|
|
40
169
|
* Start recording the page.
|
|
@@ -48,9 +177,16 @@ export async function startRecording(options) {
|
|
|
48
177
|
const response = await fetch(`http://127.0.0.1:${relayPort}/recording/start`, {
|
|
49
178
|
method: 'POST',
|
|
50
179
|
headers: { 'Content-Type': 'application/json' },
|
|
51
|
-
body: JSON.stringify({
|
|
180
|
+
body: JSON.stringify({
|
|
181
|
+
sessionId,
|
|
182
|
+
frameRate,
|
|
183
|
+
videoBitsPerSecond,
|
|
184
|
+
audioBitsPerSecond,
|
|
185
|
+
audio,
|
|
186
|
+
outputPath: absoluteOutputPath,
|
|
187
|
+
}),
|
|
52
188
|
});
|
|
53
|
-
const result = await response.json();
|
|
189
|
+
const result = (await response.json());
|
|
54
190
|
if (!result.success) {
|
|
55
191
|
const errorMsg = result.error || 'Unknown error';
|
|
56
192
|
// If the error is about missing activeTab permission, provide helpful guidance
|
|
@@ -81,7 +217,7 @@ export async function stopRecording(options) {
|
|
|
81
217
|
headers: { 'Content-Type': 'application/json' },
|
|
82
218
|
body: JSON.stringify({ sessionId }),
|
|
83
219
|
});
|
|
84
|
-
const result = await response.json();
|
|
220
|
+
const result = (await response.json());
|
|
85
221
|
if (!result.success) {
|
|
86
222
|
throw new Error(`Failed to stop recording: ${result.error}`);
|
|
87
223
|
}
|
|
@@ -92,11 +228,12 @@ export async function stopRecording(options) {
|
|
|
92
228
|
*/
|
|
93
229
|
export async function isRecording(options) {
|
|
94
230
|
const { sessionId, relayPort = 19988 } = options;
|
|
95
|
-
const url =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
231
|
+
const url = new URL(`http://127.0.0.1:${relayPort}/recording/status`);
|
|
232
|
+
if (sessionId) {
|
|
233
|
+
url.searchParams.set('sessionId', sessionId);
|
|
234
|
+
}
|
|
235
|
+
const response = await fetch(url.toString());
|
|
236
|
+
const result = (await response.json());
|
|
100
237
|
return { isRecording: result.isRecording, startedAt: result.startedAt, tabId: result.tabId };
|
|
101
238
|
}
|
|
102
239
|
/**
|
|
@@ -109,7 +246,7 @@ export async function cancelRecording(options) {
|
|
|
109
246
|
headers: { 'Content-Type': 'application/json' },
|
|
110
247
|
body: JSON.stringify({ sessionId }),
|
|
111
248
|
});
|
|
112
|
-
const result = await response.json();
|
|
249
|
+
const result = (await response.json());
|
|
113
250
|
if (!result.success) {
|
|
114
251
|
throw new Error(`Failed to cancel recording: ${result.error}`);
|
|
115
252
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen-recording.js","sourceRoot":"","sources":["../src/screen-recording.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAQ5B,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"screen-recording.js","sourceRoot":"","sources":["../src/screen-recording.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-recording.test.d.ts","sourceRoot":"","sources":["../src/screen-recording.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for fitToAspectRatio — verifies viewport shrink-to-fit
|
|
3
|
+
* for common screen sizes and aspect ratios.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, test, expect } from 'vitest';
|
|
6
|
+
import { fitToAspectRatio } from './screen-recording.js';
|
|
7
|
+
describe('fitToAspectRatio', () => {
|
|
8
|
+
test('common sizes → 16:9', () => {
|
|
9
|
+
const ratio = { width: 16, height: 9 };
|
|
10
|
+
// Already 16:9 — no change
|
|
11
|
+
expect(fitToAspectRatio({ width: 1920, height: 1080 }, ratio)).toMatchInlineSnapshot(`
|
|
12
|
+
{
|
|
13
|
+
"height": 1080,
|
|
14
|
+
"width": 1920,
|
|
15
|
+
}
|
|
16
|
+
`);
|
|
17
|
+
expect(fitToAspectRatio({ width: 1280, height: 720 }, ratio)).toMatchInlineSnapshot(`
|
|
18
|
+
{
|
|
19
|
+
"height": 720,
|
|
20
|
+
"width": 1280,
|
|
21
|
+
}
|
|
22
|
+
`);
|
|
23
|
+
// 16:10 (MacBook default) — too tall, shrink height
|
|
24
|
+
expect(fitToAspectRatio({ width: 1440, height: 900 }, ratio)).toMatchInlineSnapshot(`
|
|
25
|
+
{
|
|
26
|
+
"height": 810,
|
|
27
|
+
"width": 1440,
|
|
28
|
+
}
|
|
29
|
+
`);
|
|
30
|
+
expect(fitToAspectRatio({ width: 1680, height: 1050 }, ratio)).toMatchInlineSnapshot(`
|
|
31
|
+
{
|
|
32
|
+
"height": 945,
|
|
33
|
+
"width": 1680,
|
|
34
|
+
}
|
|
35
|
+
`);
|
|
36
|
+
// 4:3 — too tall, shrink height
|
|
37
|
+
expect(fitToAspectRatio({ width: 1024, height: 768 }, ratio)).toMatchInlineSnapshot(`
|
|
38
|
+
{
|
|
39
|
+
"height": 576,
|
|
40
|
+
"width": 1024,
|
|
41
|
+
}
|
|
42
|
+
`);
|
|
43
|
+
// Ultra-wide 21:9 — too wide, shrink width
|
|
44
|
+
expect(fitToAspectRatio({ width: 2560, height: 1080 }, ratio)).toMatchInlineSnapshot(`
|
|
45
|
+
{
|
|
46
|
+
"height": 1080,
|
|
47
|
+
"width": 1920,
|
|
48
|
+
}
|
|
49
|
+
`);
|
|
50
|
+
expect(fitToAspectRatio({ width: 3440, height: 1440 }, ratio)).toMatchInlineSnapshot(`
|
|
51
|
+
{
|
|
52
|
+
"height": 1440,
|
|
53
|
+
"width": 2560,
|
|
54
|
+
}
|
|
55
|
+
`);
|
|
56
|
+
// Square — too tall, shrink height
|
|
57
|
+
expect(fitToAspectRatio({ width: 1000, height: 1000 }, ratio)).toMatchInlineSnapshot(`
|
|
58
|
+
{
|
|
59
|
+
"height": 563,
|
|
60
|
+
"width": 1000,
|
|
61
|
+
}
|
|
62
|
+
`);
|
|
63
|
+
});
|
|
64
|
+
test('custom aspect ratios', () => {
|
|
65
|
+
// 4:3
|
|
66
|
+
expect(fitToAspectRatio({ width: 1920, height: 1080 }, { width: 4, height: 3 })).toMatchInlineSnapshot(`
|
|
67
|
+
{
|
|
68
|
+
"height": 1080,
|
|
69
|
+
"width": 1440,
|
|
70
|
+
}
|
|
71
|
+
`);
|
|
72
|
+
// 1:1
|
|
73
|
+
expect(fitToAspectRatio({ width: 1920, height: 1080 }, { width: 1, height: 1 })).toMatchInlineSnapshot(`
|
|
74
|
+
{
|
|
75
|
+
"height": 1080,
|
|
76
|
+
"width": 1080,
|
|
77
|
+
}
|
|
78
|
+
`);
|
|
79
|
+
// 9:16 vertical
|
|
80
|
+
expect(fitToAspectRatio({ width: 1920, height: 1080 }, { width: 9, height: 16 })).toMatchInlineSnapshot(`
|
|
81
|
+
{
|
|
82
|
+
"height": 1080,
|
|
83
|
+
"width": 608,
|
|
84
|
+
}
|
|
85
|
+
`);
|
|
86
|
+
});
|
|
87
|
+
test('never increases dimensions', () => {
|
|
88
|
+
const ratio = { width: 16, height: 9 };
|
|
89
|
+
const sizes = [
|
|
90
|
+
{ width: 800, height: 600 },
|
|
91
|
+
{ width: 1440, height: 900 },
|
|
92
|
+
{ width: 2560, height: 1080 },
|
|
93
|
+
{ width: 1000, height: 1000 },
|
|
94
|
+
];
|
|
95
|
+
for (const size of sizes) {
|
|
96
|
+
const result = fitToAspectRatio(size, ratio);
|
|
97
|
+
expect(result.width).toBeLessThanOrEqual(size.width);
|
|
98
|
+
expect(result.height).toBeLessThanOrEqual(size.height);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=screen-recording.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-recording.test.js","sourceRoot":"","sources":["../src/screen-recording.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7373,6 +7373,6 @@ x-locator-editor.does-not-match {
|
|
|
7373
7373
|
return asLocator2(lang, selector);
|
|
7374
7374
|
}
|
|
7375
7375
|
|
|
7376
|
-
// dist/_selector-generator-entry-
|
|
7376
|
+
// dist/_selector-generator-entry-64982-1773397884857.js
|
|
7377
7377
|
globalThis.__selectorGenerator = { createSelectorGenerator, toLocator };
|
|
7378
7378
|
})();
|