@freestyle-sh/with-nodejs 0.2.0 → 0.2.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,98 @@
1
+ # @freestyle-sh/with-nodejs
2
+
3
+ Node.js runtime via [NVM](https://github.com/nvm-sh/nvm) for [Freestyle](https://freestyle.sh) VMs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @freestyle-sh/with-nodejs freestyle-sandboxes
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { freestyle } from "freestyle-sandboxes";
15
+ import { VmNodeJs } from "@freestyle-sh/with-nodejs";
16
+
17
+ const { vm } = await freestyle.vms.create({
18
+ with: {
19
+ node: new VmNodeJs(),
20
+ },
21
+ });
22
+
23
+ const res = await vm.node.runCode({
24
+ code: "console.log(JSON.stringify({ hello: 'world' }));"
25
+ });
26
+
27
+ console.log(res);
28
+ // { result: { hello: 'world' }, stdout: '{"hello":"world"}\n', statusCode: 0 }
29
+ ```
30
+
31
+ ## Options
32
+
33
+ ```typescript
34
+ new VmNodeJs({
35
+ version: "22", // Optional: Node.js version (default: "24")
36
+ })
37
+ ```
38
+
39
+ | Option | Type | Default | Description |
40
+ |--------|------|---------|-------------|
41
+ | `version` | `string` | `"24"` | Node.js version to install via NVM. |
42
+
43
+ ## API
44
+
45
+ ### `vm.node.runCode({ code: string })`
46
+
47
+ Executes JavaScript code in the Node.js runtime.
48
+
49
+ **Returns:** `Promise<RunCodeResponse>`
50
+
51
+ ```typescript
52
+ type RunCodeResponse<Result> = {
53
+ result: Result; // Parsed JSON from stdout (if valid JSON)
54
+ stdout?: string; // Raw stdout output
55
+ stderr?: string; // Raw stderr output
56
+ statusCode?: number; // Exit code
57
+ };
58
+ ```
59
+
60
+ ### `vm.node.install(options?)`
61
+
62
+ Installs npm packages.
63
+
64
+ ```typescript
65
+ // Install from package.json in current directory
66
+ await vm.node.install();
67
+
68
+ // Install from package.json in specific directory
69
+ await vm.node.install({ directory: "/app" });
70
+
71
+ // Install specific packages
72
+ await vm.node.install({ deps: ["lodash", "express"] });
73
+
74
+ // Install with specific versions
75
+ await vm.node.install({ deps: { "lodash": "^4.0.0", "express": "~5.0.0" } });
76
+
77
+ // Install as dev dependencies
78
+ await vm.node.install({ deps: ["typescript"], dev: true });
79
+
80
+ // Install globally
81
+ await vm.node.install({ global: true, deps: ["typescript"] });
82
+ ```
83
+
84
+ **Returns:** `Promise<InstallResult>`
85
+
86
+ ```typescript
87
+ type InstallResult = {
88
+ success: boolean;
89
+ stdout?: string;
90
+ stderr?: string;
91
+ };
92
+ ```
93
+
94
+ ## Documentation
95
+
96
+ - [Freestyle Documentation](https://docs.freestyle.sh)
97
+ - [Node.js Documentation](https://nodejs.org/docs)
98
+ - [NVM Documentation](https://github.com/nvm-sh/nvm)
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { VmWith, VmWithInstance, CreateVmOptions } from 'freestyle-sandboxes';
2
- import { VmJavaScriptRuntimeInstance, JSONValue, RunCodeResponse, VmJavaScriptRuntime } from '@freestyle-sh/with-type-js';
1
+ import { VmWith, VmWithInstance, VmSpec } from 'freestyle-sandboxes';
2
+ import { VmJavaScriptRuntimeInstance, JSONValue, RunCodeResponse, InstallOptions, InstallResult, VmJavaScriptRuntime } from '@freestyle-sh/with-type-js';
3
3
 
4
4
  type NodeJsOptions = {
5
5
  version?: string;
@@ -12,16 +12,17 @@ type NodeJsResolvedOptions = {
12
12
  declare class VmNodeJs extends VmWith<NodeJsRuntimeInstance> implements VmJavaScriptRuntime<VmJavaScriptRuntimeInstance> {
13
13
  options: NodeJsResolvedOptions;
14
14
  constructor(options?: NodeJsOptions);
15
- configure(existingConfig: CreateVmOptions): CreateVmOptions | Promise<CreateVmOptions>;
15
+ configureSnapshotSpec(spec: VmSpec): VmSpec;
16
16
  createInstance(): NodeJsRuntimeInstance;
17
17
  installServiceName(): string;
18
18
  }
19
19
  declare class NodeJsRuntimeInstance extends VmWithInstance implements VmJavaScriptRuntimeInstance {
20
20
  builder: VmNodeJs;
21
21
  constructor(builder: VmNodeJs);
22
- runCode<Result extends JSONValue = any>({ code, }: {
22
+ runCode<Result extends JSONValue = any>(args: string | {
23
23
  code: string;
24
24
  }): Promise<RunCodeResponse<Result>>;
25
+ install(options?: InstallOptions): Promise<InstallResult>;
25
26
  }
26
27
 
27
28
  export { VmNodeJs };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { VmWith, VmTemplate, VmWithInstance } from 'freestyle-sandboxes';
1
+ import { VmWith, VmSpec, VmWithInstance } from 'freestyle-sandboxes';
2
2
 
3
3
  class VmNodeJs extends VmWith {
4
4
  options;
@@ -9,7 +9,7 @@ class VmNodeJs extends VmWith {
9
9
  workdir: options?.workdir
10
10
  };
11
11
  }
12
- configure(existingConfig) {
12
+ configureSnapshotSpec(spec) {
13
13
  const installScript = `#!/bin/bash
14
14
  set -e
15
15
  export NVM_DIR="/opt/nvm"
@@ -25,8 +25,9 @@ npm -v
25
25
  [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
26
26
  [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
27
27
  `;
28
- const nodeJsConfig = {
29
- template: new VmTemplate({
28
+ return this.composeSpecs(
29
+ spec,
30
+ new VmSpec({
30
31
  additionalFiles: {
31
32
  "/opt/install-nodejs.sh": {
32
33
  content: installScript
@@ -47,8 +48,7 @@ npm -v
47
48
  ]
48
49
  }
49
50
  })
50
- };
51
- return this.compose(existingConfig, nodeJsConfig);
51
+ );
52
52
  }
53
53
  createInstance() {
54
54
  return new NodeJsRuntimeInstance(this);
@@ -63,9 +63,8 @@ class NodeJsRuntimeInstance extends VmWithInstance {
63
63
  super();
64
64
  this.builder = builder;
65
65
  }
66
- async runCode({
67
- code
68
- }) {
66
+ async runCode(args) {
67
+ const code = typeof args === "string" ? args : args.code;
69
68
  const result = await this.vm.exec({
70
69
  command: `node -e "${code.replace(/"/g, '\\"')}"`
71
70
  });
@@ -86,6 +85,27 @@ class NodeJsRuntimeInstance extends VmWithInstance {
86
85
  statusCode: result.statusCode ?? -1
87
86
  };
88
87
  }
88
+ async install(options) {
89
+ let command;
90
+ if (options?.global) {
91
+ command = `npm install -g ${options.deps.join(" ")}`;
92
+ } else {
93
+ const cdPrefix = options?.directory ? `cd ${options.directory} && ` : "";
94
+ if (!options?.deps) {
95
+ command = `${cdPrefix}npm install`;
96
+ } else {
97
+ const deps = Array.isArray(options.deps) ? options.deps : Object.entries(options.deps).map(([pkg, ver]) => `${pkg}@${ver}`);
98
+ const devFlag = options.dev ? " --save-dev" : "";
99
+ command = `${cdPrefix}npm install${devFlag} ${deps.join(" ")}`;
100
+ }
101
+ }
102
+ const result = await this.vm.exec({ command });
103
+ return {
104
+ success: result.statusCode === 0,
105
+ stdout: result.stdout ?? void 0,
106
+ stderr: result.stderr ?? void 0
107
+ };
108
+ }
89
109
  }
90
110
 
91
111
  export { VmNodeJs };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@freestyle-sh/with-nodejs",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "dependencies": {
6
- "freestyle-sandboxes": "^0.1.2",
7
- "@freestyle-sh/with-type-js": "^0.2.0"
6
+ "freestyle-sandboxes": "^0.1.8",
7
+ "@freestyle-sh/with-type-js": "^0.2.1"
8
8
  },
9
9
  "type": "module",
10
10
  "main": "./dist/index.js",