@freestyle-sh/with-vscode 0.0.1
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 +102 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +134 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# @freestyle-sh/with-vscode
|
|
2
|
+
|
|
3
|
+
[VS Code](https://github.com/coder/code-server) in the browser for [Freestyle](https://freestyle.sh) VMs, powered by code-server.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @freestyle-sh/with-vscode freestyle-sandboxes
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { freestyle, VmSpec } from "freestyle-sandboxes";
|
|
15
|
+
import { VmVscode } from "@freestyle-sh/with-vscode";
|
|
16
|
+
|
|
17
|
+
const domain = `${crypto.randomUUID()}.style.dev`;
|
|
18
|
+
|
|
19
|
+
const { vm } = await freestyle.vms.create({
|
|
20
|
+
snapshot: new VmSpec({
|
|
21
|
+
with: {
|
|
22
|
+
vscode: new VmVscode(),
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
domains: [
|
|
26
|
+
{
|
|
27
|
+
domain,
|
|
28
|
+
vmPort: 8080,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log(`VS Code available at: https://${domain}`);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### With Extensions
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const { vm } = await freestyle.vms.create({
|
|
40
|
+
snapshot: new VmSpec({
|
|
41
|
+
with: {
|
|
42
|
+
vscode: new VmVscode({
|
|
43
|
+
workdir: "/root/project",
|
|
44
|
+
extensions: ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"],
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
domains: [
|
|
49
|
+
{
|
|
50
|
+
domain,
|
|
51
|
+
vmPort: 8080,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Options
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
new VmVscode({
|
|
61
|
+
port: 8080, // Optional: port to run on (default: 8080)
|
|
62
|
+
workdir: "/root", // Optional: folder to open (default: /root)
|
|
63
|
+
user: "root", // Optional: user to run as (default: root)
|
|
64
|
+
extensions: [], // Optional: VS Code extensions to pre-install
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
| Option | Type | Default | Description |
|
|
69
|
+
|--------|------|---------|-------------|
|
|
70
|
+
| `port` | `number` | `8080` | Port to run code-server on |
|
|
71
|
+
| `workdir` | `string` | `"/root"` | Folder to open in VS Code |
|
|
72
|
+
| `user` | `string` | `"root"` | User to run code-server as |
|
|
73
|
+
| `extensions` | `string[]` | `[]` | VS Code extensions to pre-install (e.g. `["esbenp.prettier-vscode"]`) |
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### `vm.vscode.route({ domain })`
|
|
78
|
+
|
|
79
|
+
Expose code-server publicly via Freestyle domain routing.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
await vm.vscode.route({ domain: "my-editor.example.com" });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `vm.vscode.port`
|
|
86
|
+
|
|
87
|
+
Returns the configured port number.
|
|
88
|
+
|
|
89
|
+
## How It Works
|
|
90
|
+
|
|
91
|
+
The package uses systemd services to install and run code-server during VM creation:
|
|
92
|
+
|
|
93
|
+
1. Downloads code-server v4.100.3 from GitHub releases
|
|
94
|
+
2. Installs any specified VS Code extensions
|
|
95
|
+
3. Starts code-server as a systemd service with auto-restart
|
|
96
|
+
|
|
97
|
+
Authentication is disabled by default. Code-server listens on all interfaces (0.0.0.0).
|
|
98
|
+
|
|
99
|
+
## Documentation
|
|
100
|
+
|
|
101
|
+
- [Freestyle Documentation](https://docs.freestyle.sh)
|
|
102
|
+
- [code-server Documentation](https://coder.com/docs/code-server)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { VmWith, VmWithInstance, VmSpec } from 'freestyle-sandboxes';
|
|
2
|
+
|
|
3
|
+
type VmVscodeOptions = {
|
|
4
|
+
/** Port to run code-server on (default: 8080) */
|
|
5
|
+
port?: number;
|
|
6
|
+
/** Folder to open in VS Code (default: /root) */
|
|
7
|
+
workdir?: string;
|
|
8
|
+
/** User to run code-server as (default: root) */
|
|
9
|
+
user?: string;
|
|
10
|
+
/** VS Code extensions to pre-install (e.g. ["esbenp.prettier-vscode"]) */
|
|
11
|
+
extensions?: string[];
|
|
12
|
+
};
|
|
13
|
+
type VmVscodeResolvedOptions = {
|
|
14
|
+
port: number;
|
|
15
|
+
workdir: string;
|
|
16
|
+
user: string;
|
|
17
|
+
extensions: string[];
|
|
18
|
+
};
|
|
19
|
+
declare class VmVscode extends VmWith<VmVscodeInstance> {
|
|
20
|
+
options: VmVscodeResolvedOptions;
|
|
21
|
+
constructor(options?: VmVscodeOptions);
|
|
22
|
+
configureSnapshotSpec(spec: VmSpec): VmSpec;
|
|
23
|
+
configureSpec(spec: VmSpec): VmSpec;
|
|
24
|
+
private composeCodeServerSpec;
|
|
25
|
+
createInstance(): VmVscodeInstance;
|
|
26
|
+
installServiceName(): string;
|
|
27
|
+
}
|
|
28
|
+
declare class VmVscodeInstance extends VmWithInstance {
|
|
29
|
+
builder: VmVscode;
|
|
30
|
+
readonly port: number;
|
|
31
|
+
constructor(builder: VmVscode);
|
|
32
|
+
/** Expose code-server publicly via Freestyle routing */
|
|
33
|
+
route({ domain }: {
|
|
34
|
+
domain: string;
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { VmVscode, VmVscodeInstance };
|
|
39
|
+
export type { VmVscodeOptions, VmVscodeResolvedOptions };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { VmWith, VmSpec, VmWithInstance } from 'freestyle-sandboxes';
|
|
2
|
+
|
|
3
|
+
const CODE_SERVER_VERSION = "4.100.3";
|
|
4
|
+
class VmVscode extends VmWith {
|
|
5
|
+
options;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super();
|
|
8
|
+
this.options = {
|
|
9
|
+
port: options?.port ?? 8080,
|
|
10
|
+
workdir: options?.workdir ?? "/root",
|
|
11
|
+
user: options?.user ?? "root",
|
|
12
|
+
extensions: options?.extensions ?? []
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
configureSnapshotSpec(spec) {
|
|
16
|
+
return this.composeCodeServerSpec(spec);
|
|
17
|
+
}
|
|
18
|
+
configureSpec(spec) {
|
|
19
|
+
return this.composeCodeServerSpec(spec);
|
|
20
|
+
}
|
|
21
|
+
composeCodeServerSpec(spec) {
|
|
22
|
+
const { port, workdir, user, extensions } = this.options;
|
|
23
|
+
const installScript = `#!/bin/bash
|
|
24
|
+
set -e
|
|
25
|
+
|
|
26
|
+
CODE_SERVER_VERSION="${CODE_SERVER_VERSION}"
|
|
27
|
+
mkdir -p /usr/local/bin /tmp/code-server-install
|
|
28
|
+
cd /tmp/code-server-install
|
|
29
|
+
curl -fsSL -o code-server.tar.gz "https://github.com/coder/code-server/releases/download/v\${CODE_SERVER_VERSION}/code-server-\${CODE_SERVER_VERSION}-linux-amd64.tar.gz"
|
|
30
|
+
tar -xzf code-server.tar.gz
|
|
31
|
+
cp code-server-\${CODE_SERVER_VERSION}-linux-amd64/bin/code-server /usr/local/bin/code-server
|
|
32
|
+
cp -r code-server-\${CODE_SERVER_VERSION}-linux-amd64/lib /usr/local/lib/code-server
|
|
33
|
+
chmod +x /usr/local/bin/code-server
|
|
34
|
+
rm -rf /tmp/code-server-install
|
|
35
|
+
code-server --version
|
|
36
|
+
`;
|
|
37
|
+
const installExtensionsScript = extensions.length > 0 ? `#!/bin/bash
|
|
38
|
+
set -e
|
|
39
|
+
${extensions.map((ext) => `/usr/local/bin/code-server --install-extension ${ext}`).join("\n")}
|
|
40
|
+
` : null;
|
|
41
|
+
const configYaml = [
|
|
42
|
+
`bind-addr: 0.0.0.0:${port}`,
|
|
43
|
+
`auth: none`,
|
|
44
|
+
`cert: false`,
|
|
45
|
+
`disable-telemetry: true`,
|
|
46
|
+
`disable-update-check: true`
|
|
47
|
+
].join("\n");
|
|
48
|
+
const args = [
|
|
49
|
+
`/usr/local/bin/code-server`,
|
|
50
|
+
`--config /etc/code-server/config.yaml`,
|
|
51
|
+
workdir
|
|
52
|
+
];
|
|
53
|
+
const serviceAfter = installExtensionsScript ? [
|
|
54
|
+
"install-code-server.service",
|
|
55
|
+
"install-code-server-extensions.service"
|
|
56
|
+
] : ["install-code-server.service"];
|
|
57
|
+
return this.composeSpecs(
|
|
58
|
+
spec,
|
|
59
|
+
new VmSpec({
|
|
60
|
+
additionalFiles: {
|
|
61
|
+
"/etc/code-server/config.yaml": { content: configYaml },
|
|
62
|
+
"/opt/install-code-server.sh": { content: installScript },
|
|
63
|
+
...installExtensionsScript ? {
|
|
64
|
+
"/opt/install-code-server-extensions.sh": {
|
|
65
|
+
content: installExtensionsScript
|
|
66
|
+
}
|
|
67
|
+
} : {}
|
|
68
|
+
},
|
|
69
|
+
systemd: {
|
|
70
|
+
services: [
|
|
71
|
+
{
|
|
72
|
+
name: "install-code-server",
|
|
73
|
+
mode: "oneshot",
|
|
74
|
+
deleteAfterSuccess: true,
|
|
75
|
+
exec: ["bash /opt/install-code-server.sh"],
|
|
76
|
+
timeoutSec: 120
|
|
77
|
+
},
|
|
78
|
+
...installExtensionsScript ? [
|
|
79
|
+
{
|
|
80
|
+
name: "install-code-server-extensions",
|
|
81
|
+
mode: "oneshot",
|
|
82
|
+
deleteAfterSuccess: true,
|
|
83
|
+
exec: ["bash /opt/install-code-server-extensions.sh"],
|
|
84
|
+
after: ["install-code-server.service"],
|
|
85
|
+
timeoutSec: 300
|
|
86
|
+
}
|
|
87
|
+
] : [],
|
|
88
|
+
{
|
|
89
|
+
name: "code-server",
|
|
90
|
+
mode: "service",
|
|
91
|
+
exec: [args.join(" ")],
|
|
92
|
+
user,
|
|
93
|
+
workdir,
|
|
94
|
+
restartPolicy: {
|
|
95
|
+
policy: "always",
|
|
96
|
+
restartSec: 2
|
|
97
|
+
},
|
|
98
|
+
after: serviceAfter
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
createInstance() {
|
|
106
|
+
return new VmVscodeInstance(this);
|
|
107
|
+
}
|
|
108
|
+
installServiceName() {
|
|
109
|
+
return "install-code-server.service";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
class VmVscodeInstance extends VmWithInstance {
|
|
113
|
+
builder;
|
|
114
|
+
port;
|
|
115
|
+
constructor(builder) {
|
|
116
|
+
super();
|
|
117
|
+
this.builder = builder;
|
|
118
|
+
this.port = builder.options.port;
|
|
119
|
+
}
|
|
120
|
+
/** Expose code-server publicly via Freestyle routing */
|
|
121
|
+
async route({ domain }) {
|
|
122
|
+
const freestyle = this.vm._freestyle;
|
|
123
|
+
console.log(
|
|
124
|
+
`Routing code-server on vm ${this.vm.vmId} at port ${this.port} to domain ${domain}`
|
|
125
|
+
);
|
|
126
|
+
await freestyle.domains.mappings.create({
|
|
127
|
+
domain,
|
|
128
|
+
vmId: this.vm.vmId,
|
|
129
|
+
vmPort: this.port
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export { VmVscode, VmVscodeInstance };
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@freestyle-sh/with-vscode",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"freestyle-sandboxes": "^0.1.14"
|
|
7
|
+
},
|
|
8
|
+
"devDependencies": {
|
|
9
|
+
"@types/node": "^22.0.0",
|
|
10
|
+
"pkgroll": "^2.11.2",
|
|
11
|
+
"typescript": "^5.8.3"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"source": "./src/index.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "pkgroll"
|
|
28
|
+
}
|
|
29
|
+
}
|