@freestyle-sh/with-bun 0.2.10 → 0.2.11

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 CHANGED
@@ -91,6 +91,83 @@ type InstallResult = {
91
91
  };
92
92
  ```
93
93
 
94
+ ## Workspaces and Tasks
95
+
96
+ Use the Bun builder to attach a workspace and run a package script as a managed systemd service.
97
+
98
+ ```typescript
99
+ import { freestyle, VmSpec } from "freestyle-sandboxes";
100
+ import { VmBun } from "@freestyle-sh/with-bun";
101
+
102
+ const SOURCE_REPO = "https://github.com/freestyle-sh/freestyle-next";
103
+
104
+ const bun = new VmBun();
105
+ const workspace = bun.workspace({ path: "/root/app", install: true });
106
+ const appTask = workspace.task("dev", {
107
+ env: {
108
+ HOST: "0.0.0.0",
109
+ PORT: "3000",
110
+ },
111
+ });
112
+
113
+ const spec = new VmSpec()
114
+ .with("bun", bun)
115
+ .repo(SOURCE_REPO, "/root/app")
116
+ .with("workspace", workspace)
117
+ .with("app", appTask)
118
+ .snapshot()
119
+ .waitFor("curl http://localhost:3000")
120
+ .snapshot();
121
+
122
+ const { repoId } = await freestyle.git.repos.create({
123
+ source: {
124
+ url: SOURCE_REPO,
125
+ },
126
+ });
127
+
128
+ const domain = `${repoId}.style.dev`;
129
+
130
+ const { vm } = await freestyle.vms.create({
131
+ spec,
132
+ domains: [{ domain, vmPort: 3000 }],
133
+ git: {
134
+ repos: [{ repo: repoId, path: "/root/app" }],
135
+ },
136
+ });
137
+
138
+ console.log(await vm.app.logs());
139
+ ```
140
+
141
+ ### Workspace API
142
+
143
+ ```typescript
144
+ const workspace = bun.workspace({
145
+ path: "/root/app",
146
+ install: true,
147
+ });
148
+ ```
149
+
150
+ - `path`: Working directory for `bun install` and task execution.
151
+ - `install`: When true, runs `bun install` in the workspace during VM startup.
152
+
153
+ ### Task API
154
+
155
+ ```typescript
156
+ const task = workspace.task("dev", {
157
+ env: {
158
+ HOST: "0.0.0.0",
159
+ PORT: "3000",
160
+ },
161
+ serviceName: "my-bun-app",
162
+ });
163
+ ```
164
+
165
+ - `name`: Script name from `package.json`.
166
+ - `env`: Optional environment variables for the task service.
167
+ - `serviceName`: Optional explicit systemd service name.
168
+
169
+ When added to the spec with `.with("app", task)`, you can access task logs with `vm.app.logs()`.
170
+
94
171
  ## Documentation
95
172
 
96
173
  - [Freestyle Documentation](https://docs.freestyle.sh)
package/dist/index.d.ts CHANGED
@@ -13,11 +13,55 @@ type BunJsResolvedOptions = {
13
13
  };
14
14
  declare class VmBun extends VmWith<VmBunInstance> implements VmJavaScriptRuntime<VmJavaScriptRuntimeInstance> {
15
15
  options: BunJsResolvedOptions;
16
+ workspaces: BunWorkspace[];
16
17
  constructor(options?: BunJsOptions);
17
18
  configureSnapshotSpec(spec: VmSpec): VmSpec;
18
19
  createInstance(): VmBunInstance;
20
+ workspace(options: {
21
+ path: string;
22
+ install?: boolean;
23
+ }): BunWorkspace;
19
24
  installServiceName(): string;
20
25
  }
26
+ declare class BunWorkspace extends VmWith<BunWorkspaceInstance> {
27
+ options: {
28
+ path: string;
29
+ install?: boolean;
30
+ };
31
+ env?: Record<string, string>;
32
+ constructor(options: {
33
+ path: string;
34
+ install?: boolean;
35
+ }, env?: Record<string, string>);
36
+ task(name: string, options?: {
37
+ env?: Record<string, string>;
38
+ serviceName?: string;
39
+ }): BunWorkspaceTask;
40
+ getInstallServiceName(): string;
41
+ configureSpec(spec: VmSpec): VmSpec;
42
+ createInstance(): BunWorkspaceInstance;
43
+ }
44
+ declare class BunWorkspaceInstance extends VmWithInstance {
45
+ }
46
+ declare class BunWorkspaceTask extends VmWith<BunWorkspaceTaskInstance> {
47
+ name: string;
48
+ workspace: BunWorkspace;
49
+ env?: Record<string, string>;
50
+ serviceName?: string;
51
+ constructor(name: string, workspace: BunWorkspace, env?: Record<string, string>, serviceName?: string);
52
+ getServiceName(): string;
53
+ configureSpec(spec: VmSpec): VmSpec;
54
+ createInstance(): BunWorkspaceTaskInstance;
55
+ }
56
+ declare class BunWorkspaceTaskInstance extends VmWithInstance {
57
+ name: string;
58
+ workspace: BunWorkspace;
59
+ env?: Record<string, string>;
60
+ serviceName?: string;
61
+ constructor(name: string, workspace: BunWorkspace, env?: Record<string, string>, serviceName?: string);
62
+ getServiceName(): string;
63
+ logs(): Promise<string[] | undefined>;
64
+ }
21
65
  declare class VmBunInstance extends VmWithInstance implements VmJavaScriptRuntimeInstance {
22
66
  builder: VmBun;
23
67
  constructor(builder: VmBun);
@@ -30,4 +74,4 @@ declare class VmBunInstance extends VmWithInstance implements VmJavaScriptRuntim
30
74
  install(options?: InstallOptions): Promise<InstallResult>;
31
75
  }
32
76
 
33
- export { VmBun };
77
+ export { BunWorkspace, BunWorkspaceInstance, BunWorkspaceTask, BunWorkspaceTaskInstance, VmBun };
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { VmWith, VmSpec, VmWithInstance } from 'freestyle-sandboxes';
2
2
 
3
3
  class VmBun extends VmWith {
4
4
  options;
5
+ workspaces = [];
5
6
  constructor(options) {
6
7
  super();
7
8
  this.options = {
@@ -52,10 +53,140 @@ export PATH="$BUN_INSTALL/bin:$PATH"
52
53
  createInstance() {
53
54
  return new VmBunInstance(this);
54
55
  }
56
+ workspace(options) {
57
+ const workspace = new BunWorkspace(options);
58
+ this.workspaces.push(workspace);
59
+ return workspace;
60
+ }
55
61
  installServiceName() {
56
62
  return "install-bun.service";
57
63
  }
58
64
  }
65
+ class BunWorkspace extends VmWith {
66
+ options;
67
+ env;
68
+ constructor(options, env) {
69
+ super();
70
+ this.options = options;
71
+ this.env = env;
72
+ }
73
+ task(name, options) {
74
+ return new BunWorkspaceTask(
75
+ name,
76
+ this,
77
+ {
78
+ ...this.env,
79
+ ...options?.env
80
+ },
81
+ options?.serviceName
82
+ );
83
+ }
84
+ getInstallServiceName() {
85
+ return `bun-install-${this.options.path.replace(/\//g, "-")}`;
86
+ }
87
+ configureSpec(spec) {
88
+ if (this.options.install) {
89
+ return this.composeSpecs(
90
+ spec,
91
+ new VmSpec({
92
+ systemd: {
93
+ services: [
94
+ {
95
+ name: this.getInstallServiceName(),
96
+ mode: "oneshot",
97
+ exec: ["/opt/bun/bin/bun install"],
98
+ workdir: this.options.path,
99
+ env: {
100
+ HOME: "/root",
101
+ BUN_INSTALL: "/opt/bun",
102
+ PATH: "/opt/bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
103
+ ...this.env
104
+ },
105
+ user: "root"
106
+ }
107
+ ]
108
+ }
109
+ })
110
+ );
111
+ }
112
+ return spec;
113
+ }
114
+ createInstance() {
115
+ return new BunWorkspaceInstance();
116
+ }
117
+ }
118
+ class BunWorkspaceInstance extends VmWithInstance {
119
+ }
120
+ class BunWorkspaceTask extends VmWith {
121
+ name;
122
+ workspace;
123
+ env;
124
+ serviceName;
125
+ constructor(name, workspace, env, serviceName) {
126
+ super();
127
+ this.name = name;
128
+ this.workspace = workspace;
129
+ this.env = env;
130
+ this.serviceName = serviceName;
131
+ }
132
+ getServiceName() {
133
+ return this.serviceName ?? `bun-workspace-${this.workspace.options.path.replace(/\//g, "-")}-task-${this.name}`;
134
+ }
135
+ configureSpec(spec) {
136
+ return this.composeSpecs(
137
+ spec,
138
+ new VmSpec({
139
+ systemd: {
140
+ services: [
141
+ {
142
+ name: this.getServiceName(),
143
+ exec: [`/opt/bun/bin/bun run ${this.name}`],
144
+ workdir: this.workspace.options.path,
145
+ after: this.workspace.options.install ? [this.workspace.getInstallServiceName()] : void 0,
146
+ requires: this.workspace.options.install ? [this.workspace.getInstallServiceName()] : void 0,
147
+ env: {
148
+ HOME: "/root",
149
+ BUN_INSTALL: "/opt/bun",
150
+ PATH: "/opt/bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
151
+ ...this.env
152
+ },
153
+ user: "root"
154
+ }
155
+ ]
156
+ }
157
+ })
158
+ );
159
+ }
160
+ createInstance() {
161
+ return new BunWorkspaceTaskInstance(
162
+ this.name,
163
+ this.workspace,
164
+ this.env,
165
+ this.serviceName
166
+ );
167
+ }
168
+ }
169
+ class BunWorkspaceTaskInstance extends VmWithInstance {
170
+ name;
171
+ workspace;
172
+ env;
173
+ serviceName;
174
+ constructor(name, workspace, env, serviceName) {
175
+ super();
176
+ this.name = name;
177
+ this.workspace = workspace;
178
+ this.env = env;
179
+ this.serviceName = serviceName;
180
+ }
181
+ getServiceName() {
182
+ return this.serviceName ?? `bun-workspace-${this.workspace.options.path.replace(/\//g, "-")}-task-${this.name}`;
183
+ }
184
+ logs() {
185
+ return this.vm.exec({
186
+ command: `journalctl -u ${this.getServiceName()} --no-pager -n 30`
187
+ }).then((result) => result.stdout?.trim().split("\n"));
188
+ }
189
+ }
59
190
  class VmBunInstance extends VmWithInstance {
60
191
  builder;
61
192
  constructor(builder) {
@@ -114,4 +245,4 @@ class VmBunInstance extends VmWithInstance {
114
245
  }
115
246
  }
116
247
 
117
- export { VmBun };
248
+ export { BunWorkspace, BunWorkspaceInstance, BunWorkspaceTask, BunWorkspaceTaskInstance, VmBun };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@freestyle-sh/with-bun",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "private": false,
5
5
  "dependencies": {
6
- "freestyle-sandboxes": "^0.1.28",
7
- "@freestyle-sh/with-type-js": "^0.2.8"
6
+ "freestyle-sandboxes": "^0.1.41",
7
+ "@freestyle-sh/with-type-js": "^0.2.9"
8
8
  },
9
9
  "type": "module",
10
10
  "main": "./dist/index.js",