Skip to content

Commit 701bc5e

Browse files
committed
Add pipeline for linting and formatting
1 parent 946b44e commit 701bc5e

16 files changed

Lines changed: 1030 additions & 160 deletions

File tree

.eslintrc.cjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = {
2+
env: {
3+
node: true,
4+
browser: true,
5+
es6: true,
6+
},
7+
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
8+
parser: '@typescript-eslint/parser',
9+
parserOptions: {
10+
ecmaVersion: 'latest',
11+
sourceType: 'module',
12+
},
13+
ignorePatterns: ['dist/', 'node_modules/', '*.gen.ts'],
14+
plugins: ['@typescript-eslint', 'unused-imports', '@stylistic/ts'],
15+
rules: {
16+
'@typescript-eslint/member-ordering': 'error',
17+
'@typescript-eslint/ban-ts-comment': 'off', // "move fast" mode
18+
'@typescript-eslint/no-explicit-any': 'off', // "move fast" mode
19+
'linebreak-style': ['error', 'unix'],
20+
'unused-imports/no-unused-imports': 'error',
21+
// No double quotes
22+
quotes: ['error', 'single', { avoidEscape: true }],
23+
// No extra semicolon
24+
'@stylistic/ts/semi': ['error', 'never'],
25+
},
26+
}

.github/workflows/lint.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: Lint
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
lint:
8+
name: Lint
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout Repo
13+
uses: actions/checkout@v4
14+
15+
- uses: pnpm/action-setup@v4
16+
with:
17+
version: 9.15.5
18+
19+
- name: Setup Node.js 20
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: '20.x'
23+
cache: pnpm
24+
25+
- name: Configure pnpm
26+
run: |
27+
pnpm config set auto-install-peers true
28+
pnpm config set exclude-links-from-lockfile true
29+
30+
- name: Install dependencies
31+
run: pnpm install --frozen-lockfile
32+
33+
- name: Set up Python
34+
uses: actions/setup-python@v4
35+
with:
36+
python-version: '3.9'
37+
38+
- name: Install and configure Poetry
39+
uses: snok/install-poetry@v1
40+
with:
41+
version: 1.5.1
42+
virtualenvs-create: true
43+
virtualenvs-in-project: true
44+
installer-parallel: true
45+
46+
- name: Install Python dependencies
47+
working-directory: python
48+
run: |
49+
poetry install --with dev
50+
51+
- name: Run linting
52+
run: |
53+
pnpm run lint
54+
55+
- name: Run formatting
56+
run: |
57+
pnpm run format
58+
59+
- name: Check for uncommitted changes
60+
run: |
61+
if [[ -n $(git status --porcelain) ]]; then
62+
echo "❌ Files are not formatted properly:"
63+
git status --short
64+
git diff
65+
exit 1
66+
else
67+
echo "✅ No changes detected."
68+
fi

package.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@
44
"scripts": {
55
"version": "changeset version && pnpm run -r postVersion",
66
"publish": "changeset publish && pnpm run -r postPublish",
7-
"rm-node-modules": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +"
7+
"rm-node-modules": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +",
8+
"lint": "pnpm --if-present --recursive run lint",
9+
"format": "pnpm --if-present --recursive run format"
810
},
9-
"packageManager": "pnpm@8.7.6",
11+
"packageManager": "pnpm@9.15.5",
1012
"devDependencies": {
1113
"@changesets/cli": "^2.26.2",
1214
"@changesets/read": "^0.6.5",
13-
"changeset": "^0.2.6"
15+
"changeset": "^0.2.6",
16+
"@typescript-eslint/eslint-plugin": "^6.7.2",
17+
"@typescript-eslint/parser": "^6.7.2",
18+
"eslint": "^8.57.1",
19+
"eslint-plugin-unused-imports": "^3.0.0",
20+
"@stylistic/eslint-plugin-ts": "^1.6.2"
1421
}
1522
}

packages/js-sdk/.eslintrc.cjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
root: true,
3+
extends: '../../.eslintrc.cjs',
4+
}

packages/js-sdk/example.mts

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,44 @@ import { config } from 'dotenv'
22

33
config()
44
import { Sandbox } from './dist'
5-
import { writeFileSync } from 'fs';
5+
import { writeFileSync } from 'fs'
66

7+
console.log('Starting desktop sandbox...')
78

8-
console.log("Starting desktop sandbox...")
9+
console.time('--> Sandbox creation time')
10+
const desktop = await Sandbox.create()
11+
console.timeEnd('--> Sandbox creation time')
912

10-
console.time('--> Sandbox creation time');
11-
const desktop = await Sandbox.create();
12-
console.timeEnd('--> Sandbox creation time');
13-
14-
console.log("Desktop Sandbox started, ID:", desktop.sandboxId)
15-
console.log("Screen size:", await desktop.getScreenSize())
13+
console.log('Desktop Sandbox started, ID:', desktop.sandboxId)
14+
console.log('Screen size:', await desktop.getScreenSize())
1615

1716
await desktop.stream.start({
18-
requireAuth: true
17+
requireAuth: true,
1918
})
2019

2120
const authKey = await desktop.stream.getAuthKey()
22-
console.log("Stream URL:", desktop.stream.getUrl({ authKey }))
21+
console.log('Stream URL:', desktop.stream.getUrl({ authKey }))
2322

24-
await new Promise(resolve => setTimeout(resolve, 5000));
23+
await new Promise((resolve) => setTimeout(resolve, 5000))
2524

2625
console.log("Moving mouse to 'Applications' and clicking...")
2726
await desktop.moveMouse(100, 100)
2827
await desktop.leftClick()
29-
console.log("Cursor position:", await desktop.getCursorPosition())
30-
31-
await new Promise(resolve => setTimeout(resolve, 1000));
28+
console.log('Cursor position:', await desktop.getCursorPosition())
3229

33-
const screenshot = await desktop.screenshot("bytes")
34-
writeFileSync('1.png', Buffer.from(screenshot));
30+
await new Promise((resolve) => setTimeout(resolve, 1000))
3531

32+
const screenshot = await desktop.screenshot('bytes')
33+
writeFileSync('1.png', Buffer.from(screenshot))
3634

3735
for (let i = 0; i < 20; i++) {
38-
const x = Math.floor(Math.random() * 1024);
39-
const y = Math.floor(Math.random() * 768);
40-
await desktop.moveMouse(x, y);
41-
await new Promise(resolve => setTimeout(resolve, 2000));
42-
await desktop.rightClick();
36+
const x = Math.floor(Math.random() * 1024)
37+
const y = Math.floor(Math.random() * 768)
38+
await desktop.moveMouse(x, y)
39+
await new Promise((resolve) => setTimeout(resolve, 2000))
40+
await desktop.rightClick()
4341
console.log('right clicked', i)
4442
}
4543

46-
4744
await desktop.stream.stop()
4845
await desktop.kill()

packages/js-sdk/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
"dev": "tsup --watch",
5050
"test": "vitest run --disable-console-intercept",
5151
"example": "npx tsx example.mts",
52-
"generate-ref": "./scripts/generate_sdk_ref.sh"
52+
"generate-ref": "./scripts/generate_sdk_ref.sh",
53+
"lint": "eslint src/ tests/",
54+
"format": "prettier --write src/ tests/ example.mts"
5355
},
5456
"devDependencies": {
5557
"@types/node": "^22.13.9",

packages/js-sdk/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export * from 'e2b'
22

3-
export { Sandbox } from './sandbox'
3+
export { Sandbox } from './sandbox'

packages/js-sdk/src/sandbox.ts

Lines changed: 43 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ export interface SandboxBetaCreateOpts extends SandboxBetaCreateOptsBase {
143143

144144
export class Sandbox extends SandboxBase {
145145
protected static override readonly defaultTemplate: string = 'desktop'
146-
private lastXfce4Pid: number | null = null
147146
public display: string = ':0'
148147
public stream: VNCServer = new VNCServer(this)
148+
private lastXfce4Pid: number | null = null
149149

150150
/**
151151
* Use {@link Sandbox.create} to create a new Sandbox instead.
@@ -323,28 +323,6 @@ export class Sandbox extends SandboxBase {
323323
return false
324324
}
325325

326-
/**
327-
* Start xfce4 session if logged out or not running.
328-
*/
329-
private async startXfce4(): Promise<void> {
330-
if (
331-
this.lastXfce4Pid === null ||
332-
(
333-
await this.commands.run(
334-
`ps aux | grep ${this.lastXfce4Pid} | grep -v grep | head -n 1`
335-
)
336-
).stdout
337-
.trim()
338-
.includes('[xfce4-session] <defunct>')
339-
) {
340-
const result = await this.commands.run('startxfce4', {
341-
background: true,
342-
timeoutMs: 0,
343-
})
344-
this.lastXfce4Pid = result.pid
345-
}
346-
}
347-
348326
/**
349327
* Take a screenshot and save it to the given name.
350328
* @param format - The format of the screenshot.
@@ -507,26 +485,6 @@ export class Sandbox extends SandboxBase {
507485
}
508486
}
509487

510-
private *breakIntoChunks(text: string, n: number): Generator<string> {
511-
for (let i = 0; i < text.length; i += n) {
512-
yield text.slice(i, i + n)
513-
}
514-
}
515-
516-
private quoteString(s: string): string {
517-
if (!s) {
518-
return "''"
519-
}
520-
521-
if (!/[^\w@%+=:,./-]/.test(s)) {
522-
return s
523-
}
524-
525-
// use single quotes, and put single quotes into double quotes
526-
// the string $'b is then quoted as '$'"'"'b'
527-
return "'" + s.replace(/'/g, "'\"'\"'") + "'"
528-
}
529-
530488
/**
531489
* Write the given text at the current cursor position.
532490
* @param text - The text to write.
@@ -708,47 +666,6 @@ class VNCServer {
708666
return this.password
709667
}
710668

711-
/**
712-
* Set the VNC command to start the VNC server.
713-
*/
714-
private async getVNCCommand(windowId?: string): Promise<string> {
715-
let pwdFlag = '-nopw'
716-
if (this.novncAuthEnabled) {
717-
// Create .vnc directory if it doesn't exist
718-
await this.desktop.commands.run('mkdir -p ~/.vnc')
719-
await this.desktop.commands.run(
720-
`x11vnc -storepasswd ${this.password} ~/.vnc/passwd`
721-
)
722-
pwdFlag = '-usepw'
723-
}
724-
725-
return (
726-
`x11vnc -bg -display ${this.desktop.display} -forever -wait 50 -shared ` +
727-
`-rfbport ${this.vncPort} ${pwdFlag} 2>/tmp/x11vnc_stderr.log` +
728-
(windowId ? ` -id ${windowId}` : '')
729-
)
730-
}
731-
732-
private async waitForPort(port: number): Promise<boolean> {
733-
return await this.desktop.waitAndVerify(
734-
`netstat -tuln | grep ":${port} "`,
735-
(r: CommandResult) => r.stdout.trim() !== ''
736-
)
737-
}
738-
739-
/**
740-
* Check if the VNC server is running.
741-
* @returns Whether the VNC server is running.
742-
*/
743-
private async checkVNCRunning(): Promise<boolean> {
744-
try {
745-
const result = await this.desktop.commands.run('pgrep -x x11vnc')
746-
return result.stdout.trim() !== ''
747-
} catch (error) {
748-
return false
749-
}
750-
}
751-
752669
/**
753670
* Get the URL to a web page with a stream of the desktop sandbox.
754671
* @param autoConnect - Whether to automatically connect to the server after opening the URL.
@@ -767,7 +684,7 @@ class VNCServer {
767684
throw new Error('Server is not running')
768685
}
769686

770-
let url = new URL(this.url)
687+
const url = new URL(this.url)
771688
if (autoConnect) {
772689
url.searchParams.set('autoconnect', 'true')
773690
}
@@ -823,4 +740,45 @@ class VNCServer {
823740
this.novncHandle = null
824741
}
825742
}
743+
744+
/**
745+
* Set the VNC command to start the VNC server.
746+
*/
747+
private async getVNCCommand(windowId?: string): Promise<string> {
748+
let pwdFlag = '-nopw'
749+
if (this.novncAuthEnabled) {
750+
// Create .vnc directory if it doesn't exist
751+
await this.desktop.commands.run('mkdir -p ~/.vnc')
752+
await this.desktop.commands.run(
753+
`x11vnc -storepasswd ${this.password} ~/.vnc/passwd`
754+
)
755+
pwdFlag = '-usepw'
756+
}
757+
758+
return (
759+
`x11vnc -bg -display ${this.desktop.display} -forever -wait 50 -shared ` +
760+
`-rfbport ${this.vncPort} ${pwdFlag} 2>/tmp/x11vnc_stderr.log` +
761+
(windowId ? ` -id ${windowId}` : '')
762+
)
763+
}
764+
765+
private async waitForPort(port: number): Promise<boolean> {
766+
return await this.desktop.waitAndVerify(
767+
`netstat -tuln | grep ":${port} "`,
768+
(r: CommandResult) => r.stdout.trim() !== ''
769+
)
770+
}
771+
772+
/**
773+
* Check if the VNC server is running.
774+
* @returns Whether the VNC server is running.
775+
*/
776+
private async checkVNCRunning(): Promise<boolean> {
777+
try {
778+
const result = await this.desktop.commands.run('pgrep -x x11vnc')
779+
return result.stdout.trim() !== ''
780+
} catch (error) {
781+
return false
782+
}
783+
}
826784
}

0 commit comments

Comments
 (0)