@freestyle-sh/with-playwright 0.2.8

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/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # @freestyle-sh/with-playwright
2
+
3
+ Playwright runtime for [Freestyle](https://freestyle.sh) VMs, including browser installs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @freestyle-sh/with-playwright freestyle-sandboxes
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { freestyle } from "freestyle-sandboxes";
15
+ import { VmPlaywright } from "@freestyle-sh/with-playwright";
16
+
17
+ const { vm } = await freestyle.vms.create({
18
+ with: {
19
+ playwright: new VmPlaywright(),
20
+ },
21
+ });
22
+
23
+ const res = await vm.playwright.runCode({
24
+ code: `
25
+ const { chromium } = require("playwright");
26
+ (async () => {
27
+ const browser = await chromium.launch();
28
+ const page = await browser.newPage();
29
+ await page.goto("https://example.com");
30
+ const title = await page.title();
31
+ await browser.close();
32
+ console.log(JSON.stringify({ title }));
33
+ })();
34
+ `,
35
+ });
36
+
37
+ console.log(res);
38
+ ```
39
+
40
+ ## Options
41
+
42
+ ```typescript
43
+ new VmPlaywright({
44
+ nodeVersion: "24",
45
+ playwrightVersion: "1.47.0",
46
+ installDeps: true,
47
+ browsers: ["chromium"],
48
+ })
49
+ ```
50
+
51
+ | Option | Type | Default | Description |
52
+ |--------|------|---------|-------------|
53
+ | `nodeVersion` | `string` | `"24"` | Node.js version to install via NVM. |
54
+ | `playwrightVersion` | `string` | `undefined` | Playwright version to install. |
55
+ | `installDeps` | `boolean` | `true` | Install Playwright system dependencies via `--with-deps`. |
56
+ | `browsers` | `("chromium" \| "firefox" \| "webkit")[]` | `undefined` | Limit browser installs; default installs all. |
57
+
58
+ ## API
59
+
60
+ ### `vm.playwright.runCode({ code: string })`
61
+
62
+ Executes JavaScript code in the Playwright-ready Node.js runtime.
63
+
64
+ **Returns:** `Promise<RunCodeResponse>`
65
+
66
+ ```typescript
67
+ type RunCodeResponse<Result> = {
68
+ result: Result;
69
+ stdout?: string;
70
+ stderr?: string;
71
+ statusCode?: number;
72
+ };
73
+ ```
74
+
75
+ ### `vm.playwright.install(options?)`
76
+
77
+ Installs npm packages with `npm install`.
78
+
79
+ ```typescript
80
+ await vm.playwright.install({ deps: ["@playwright/test"] });
81
+ ```
82
+
83
+ **Returns:** `Promise<InstallResult>`
84
+
85
+ ```typescript
86
+ type InstallResult = {
87
+ success: boolean;
88
+ stdout?: string;
89
+ stderr?: string;
90
+ };
91
+ ```
92
+
93
+ ## Documentation
94
+
95
+ - [Freestyle Documentation](https://docs.freestyle.sh)
96
+ - [Playwright Documentation](https://playwright.dev)
97
+ ```
@@ -0,0 +1,35 @@
1
+ import { VmWith, VmWithInstance, VmSpec } from 'freestyle-sandboxes';
2
+ import { VmJavaScriptRuntimeInstance, JSONValue, RunCodeResponse, InstallOptions, InstallResult, VmJavaScriptRuntime } from '@freestyle-sh/with-type-js';
3
+
4
+ type PlaywrightOptions = {
5
+ nodeVersion?: string;
6
+ playwrightVersion?: string;
7
+ installDeps?: boolean;
8
+ browsers?: Array<"chromium" | "firefox" | "webkit">;
9
+ };
10
+ type PlaywrightResolvedOptions = {
11
+ nodeVersion: string;
12
+ playwrightVersion?: string;
13
+ installDeps: boolean;
14
+ browsers?: Array<"chromium" | "firefox" | "webkit">;
15
+ };
16
+ declare class VmPlaywright extends VmWith<PlaywrightRuntimeInstance> implements VmJavaScriptRuntime<VmJavaScriptRuntimeInstance> {
17
+ options: PlaywrightResolvedOptions;
18
+ constructor(options?: PlaywrightOptions);
19
+ configureSnapshotSpec(spec: VmSpec): VmSpec;
20
+ createInstance(): PlaywrightRuntimeInstance;
21
+ installServiceName(): string;
22
+ }
23
+ declare class PlaywrightRuntimeInstance extends VmWithInstance implements VmJavaScriptRuntimeInstance {
24
+ builder: VmPlaywright;
25
+ constructor(builder: VmPlaywright);
26
+ runCode<Result extends JSONValue = any>(args: string | {
27
+ code: string;
28
+ argv?: string[];
29
+ env?: Record<string, string>;
30
+ workdir?: string;
31
+ }): Promise<RunCodeResponse<Result>>;
32
+ install(options?: InstallOptions): Promise<InstallResult>;
33
+ }
34
+
35
+ export { VmPlaywright };
package/dist/index.js ADDED
@@ -0,0 +1,142 @@
1
+ import { VmWith, VmSpec, VmWithInstance } from 'freestyle-sandboxes';
2
+
3
+ class VmPlaywright extends VmWith {
4
+ options;
5
+ constructor(options) {
6
+ super();
7
+ this.options = {
8
+ nodeVersion: options?.nodeVersion ?? "24",
9
+ playwrightVersion: options?.playwrightVersion,
10
+ installDeps: options?.installDeps ?? true,
11
+ browsers: options?.browsers
12
+ };
13
+ }
14
+ configureSnapshotSpec(spec) {
15
+ const playwrightVersionArg = this.options.playwrightVersion ? `@${this.options.playwrightVersion}` : "";
16
+ const browserArgs = this.options.browsers?.length ? ` ${this.options.browsers.join(" ")}` : "";
17
+ const depsFlag = this.options.installDeps ? " --with-deps" : "";
18
+ const installScript = `#!/bin/bash
19
+ set -e
20
+ export NVM_DIR="/opt/nvm"
21
+ mkdir -p "$NVM_DIR"
22
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
23
+ source "$NVM_DIR/nvm.sh"
24
+ nvm install ${this.options.nodeVersion}
25
+ nvm alias default ${this.options.nodeVersion}
26
+ node -v
27
+ npm -v
28
+
29
+ export PLAYWRIGHT_BROWSERS_PATH="/opt/playwright-browsers"
30
+ mkdir -p /opt/playwright-browsers
31
+ mkdir -p /opt/playwright
32
+ cd /opt/playwright
33
+ npm init -y
34
+ npm install playwright${playwrightVersionArg}
35
+ npx playwright install${depsFlag}${browserArgs}
36
+ `;
37
+ const nvmInit = `export NVM_DIR="/opt/nvm"
38
+ [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
39
+ [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
40
+ `;
41
+ const playwrightEnv = `export PLAYWRIGHT_BROWSERS_PATH="/opt/playwright-browsers"
42
+ export NODE_PATH="/opt/playwright/node_modules"
43
+ `;
44
+ return this.composeSpecs(
45
+ spec,
46
+ new VmSpec({
47
+ additionalFiles: {
48
+ "/opt/install-playwright.sh": {
49
+ content: installScript
50
+ },
51
+ "/etc/profile.d/nvm.sh": {
52
+ content: nvmInit
53
+ },
54
+ "/etc/profile.d/playwright.sh": {
55
+ content: playwrightEnv
56
+ }
57
+ },
58
+ systemd: {
59
+ services: [
60
+ {
61
+ name: "install-playwright",
62
+ mode: "oneshot",
63
+ deleteAfterSuccess: true,
64
+ exec: ["bash /opt/install-playwright.sh"],
65
+ timeoutSec: 600
66
+ }
67
+ ]
68
+ }
69
+ })
70
+ );
71
+ }
72
+ createInstance() {
73
+ return new PlaywrightRuntimeInstance(this);
74
+ }
75
+ installServiceName() {
76
+ return "install-playwright.service";
77
+ }
78
+ }
79
+ class PlaywrightRuntimeInstance extends VmWithInstance {
80
+ builder;
81
+ constructor(builder) {
82
+ super();
83
+ this.builder = builder;
84
+ }
85
+ async runCode(args) {
86
+ const options = typeof args === "string" ? { code: args } : args;
87
+ const { code, argv, env, workdir } = options;
88
+ const shellEscape = (value) => `'${value.replace(/'/g, "'\\''")}'`;
89
+ const argvArgs = argv?.map(shellEscape).join(" ");
90
+ const mergedEnv = {
91
+ NODE_PATH: "/opt/playwright/node_modules",
92
+ PLAYWRIGHT_BROWSERS_PATH: "/opt/playwright-browsers",
93
+ ...env ?? {}
94
+ };
95
+ const envPrefix = Object.entries(mergedEnv).map(([key, value]) => `${key}=${shellEscape(value)}`).join(" ");
96
+ const cdPrefix = workdir ? `cd ${shellEscape(workdir)} && ` : "";
97
+ const command = `${cdPrefix}${envPrefix ? `${envPrefix} ` : ""}node -e "${code.replace(/"/g, '\\"')}"${argvArgs ? ` -- ${argvArgs}` : ""}`;
98
+ const result = await this.vm.exec({
99
+ command
100
+ });
101
+ let parsedResult = void 0;
102
+ if (result.stdout) {
103
+ const lines = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
104
+ const lastLine = lines[lines.length - 1];
105
+ if (lastLine) {
106
+ try {
107
+ parsedResult = JSON.parse(lastLine);
108
+ } catch (e) {
109
+ }
110
+ }
111
+ }
112
+ return {
113
+ result: parsedResult,
114
+ stdout: result.stdout ?? void 0,
115
+ stderr: result.stderr ?? void 0,
116
+ statusCode: result.statusCode ?? -1
117
+ };
118
+ }
119
+ async install(options) {
120
+ let command;
121
+ if (options?.global) {
122
+ command = `npm install -g ${options.deps.join(" ")}`;
123
+ } else {
124
+ const cdPrefix = options?.directory ? `cd ${options.directory} && ` : "";
125
+ if (!options?.deps) {
126
+ command = `${cdPrefix}npm install`;
127
+ } else {
128
+ const deps = Array.isArray(options.deps) ? options.deps : Object.entries(options.deps).map(([pkg, ver]) => `${pkg}@${ver}`);
129
+ const devFlag = options.dev ? " --save-dev" : "";
130
+ command = `${cdPrefix}npm install${devFlag} ${deps.join(" ")}`;
131
+ }
132
+ }
133
+ const result = await this.vm.exec({ command });
134
+ return {
135
+ success: result.statusCode === 0,
136
+ stdout: result.stdout ?? void 0,
137
+ stderr: result.stderr ?? void 0
138
+ };
139
+ }
140
+ }
141
+
142
+ export { VmPlaywright };
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@freestyle-sh/with-playwright",
3
+ "version": "0.2.8",
4
+ "private": false,
5
+ "dependencies": {
6
+ "freestyle-sandboxes": "^0.1.28",
7
+ "@freestyle-sh/with-type-js": "^0.2.8"
8
+ },
9
+ "type": "module",
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "source": "./src/index.ts",
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "build": "pkgroll"
24
+ }
25
+ }