@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 +97 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +142 -0
- package/package.json +25 -0
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
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|