@secure-exec/core 0.3.0-rc.1 → 0.3.0-rc.2

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.
@@ -76,6 +76,38 @@ export interface NodeRuntimeCreateOptions {
76
76
  * ```
77
77
  */
78
78
  mounts?: HostDirectoryMount[];
79
+ /**
80
+ * Mount a host `node_modules` directory into the VM in one call so guest
81
+ * `import`/`require` resolve real, host-installed npm packages.
82
+ *
83
+ * Pass the absolute host path to a `node_modules` directory (or an object
84
+ * with that path and an explicit guest location). The whole directory is
85
+ * projected lazily, Docker-style, at a guest `node_modules` on the resolution
86
+ * path, so any package inside it resolves the way Node would over a real
87
+ * filesystem (ancestor `node_modules` walk, `exports`/conditions, symlinks).
88
+ * This is the ergonomic alternative to wiring up individual `mounts` entries
89
+ * per package.
90
+ *
91
+ * By default the directory is mounted at `/tmp/node_modules`, which is where
92
+ * the resolution walk for a program run by {@link NodeRuntime.exec} /
93
+ * {@link NodeRuntime.run} begins (each program is written under `/tmp`). Pass
94
+ * the object form with `guestPath` to mount it elsewhere on a different
95
+ * module's resolution path.
96
+ *
97
+ * ```ts
98
+ * const rt = await NodeRuntime.create({
99
+ * nodeModules: "/abs/path/to/project/node_modules",
100
+ * });
101
+ * await rt.exec(`
102
+ * import isNumber from "is-number";
103
+ * console.log(isNumber(42));
104
+ * `);
105
+ * ```
106
+ *
107
+ * The host filesystem is never exposed beyond the mounted `node_modules`
108
+ * subtree. The mount is read-only.
109
+ */
110
+ nodeModules?: string | NodeModulesMount;
79
111
  /**
80
112
  * Host-side tools the guest can invoke as shell commands. Each entry is
81
113
  * registered as a named guest command; when the guest runs it, the
@@ -138,6 +170,21 @@ export interface HostDirectoryMount {
138
170
  /** Mount read-only (the default). Pass `false` to allow guest writes. */
139
171
  readOnly?: boolean;
140
172
  }
173
+ /**
174
+ * Object form of the `nodeModules` create option: a host `node_modules`
175
+ * directory to project, optionally at an explicit guest path. The string form
176
+ * (`nodeModules: "/abs/node_modules"`) is shorthand for `{ hostPath }`.
177
+ */
178
+ export interface NodeModulesMount {
179
+ /** Absolute host `node_modules` directory to project (read lazily). */
180
+ hostPath: string;
181
+ /**
182
+ * Absolute guest path to mount it at. Defaults to `/tmp/node_modules`, where
183
+ * the resolution walk for {@link NodeRuntime.exec} / {@link NodeRuntime.run}
184
+ * programs begins. Override to put it on a different module's resolution path.
185
+ */
186
+ guestPath?: string;
187
+ }
141
188
  /** Result of {@link NodeRuntime.exec}. */
142
189
  export interface NodeRuntimeExecResult {
143
190
  stdout: string;
@@ -45,6 +45,8 @@ const DEFAULT_PERMISSIONS = {
45
45
  env: "allow",
46
46
  network: "deny",
47
47
  };
48
+ /** Guest path a `nodeModules` mount is projected at by default. */
49
+ const DEFAULT_NODE_MODULES_GUEST_PATH = "/tmp/node_modules";
48
50
  let nextProgramId = 0;
49
51
  /**
50
52
  * Ergonomic, batteries-included runtime for executing guest JavaScript.
@@ -81,7 +83,21 @@ export class NodeRuntime {
81
83
  // Project host directories into the VM, Docker-style. NodeFileSystem
82
84
  // reads lazily through the VFS so large trees never traverse the
83
85
  // protocol frame as a single blob.
84
- const mounts = (options.mounts ?? []).map((mount) => ({
86
+ const hostMounts = [...(options.mounts ?? [])];
87
+ // The `nodeModules` helper is sugar over a single host directory mount:
88
+ // project the whole host `node_modules` at a guest `node_modules` on the
89
+ // resolution path so any package inside resolves like real Node would.
90
+ if (options.nodeModules !== undefined) {
91
+ const nodeModules = typeof options.nodeModules === "string"
92
+ ? { hostPath: options.nodeModules }
93
+ : options.nodeModules;
94
+ hostMounts.push({
95
+ guestPath: nodeModules.guestPath ?? DEFAULT_NODE_MODULES_GUEST_PATH,
96
+ hostPath: nodeModules.hostPath,
97
+ readOnly: true,
98
+ });
99
+ }
100
+ const mounts = hostMounts.map((mount) => ({
85
101
  path: mount.guestPath,
86
102
  fs: new NodeFileSystem({ root: mount.hostPath }),
87
103
  readOnly: mount.readOnly ?? true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secure-exec/core",
3
- "version": "0.3.0-rc.1",
3
+ "version": "0.3.0-rc.2",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
@@ -183,7 +183,7 @@
183
183
  "test": "vitest run"
184
184
  },
185
185
  "dependencies": {
186
- "@secure-exec/sidecar": "0.3.0-rc.1",
186
+ "@secure-exec/sidecar": "0.3.0-rc.2",
187
187
  "@rivetkit/bare-ts": "^0.6.2"
188
188
  },
189
189
  "devDependencies": {