@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 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)
@@ -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
+ }