sharjeenux 0.3.0 → 1.0.0
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 +148 -23
- package/compliance/buildroot.config +4 -4
- package/compliance/linux.config +5 -5
- package/index.d.ts +2 -0
- package/index.js +65 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,36 +4,57 @@ Sharjeenux is a headless, in-memory Buildroot Linux VM controlled from Node.js.
|
|
|
4
4
|
It boots an i686 Linux image through v86 and exposes one persistent serial shell
|
|
5
5
|
as an async JavaScript API.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Modular Architecture
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Sharjeenux uses a plugin-based architecture. The core package ships a minimal
|
|
10
|
+
Linux base system, and language runtimes are installed as separate packages:
|
|
11
|
+
|
|
12
|
+
| Package | What it adds | Install |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `sharjeenux` | Base Linux (BusyBox, networking, archive tools) | `npm install sharjeenux` |
|
|
15
|
+
| `@sharjeenux/node` | Node.js 20, npm, npx, TypeScript | `npm install @sharjeenux/node` |
|
|
16
|
+
| `@sharjeenux/python` | Python 3, pip | `npm install @sharjeenux/python` |
|
|
17
|
+
| `@sharjeenux/java` | OpenJDK 21, javac, Apache Maven | `npm install @sharjeenux/java` |
|
|
18
|
+
|
|
19
|
+
The base system always includes:
|
|
20
|
+
|
|
21
|
+
- BusyBox coreutils, shell, and init
|
|
12
22
|
- Git, curl, GNU wget, OpenSSL, and CA certificates
|
|
13
23
|
- Common archive tools: tar, gzip, bzip2, xz, zip, and unzip
|
|
24
|
+
- Outbound networking via v86's fetch transport or a Wisp relay
|
|
14
25
|
|
|
15
26
|
It has no desktop, display server, SSH server, or host port-forwarding layer.
|
|
16
27
|
|
|
17
|
-
##
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Minimal (base Linux only)
|
|
18
31
|
|
|
19
32
|
```sh
|
|
20
33
|
npm install sharjeenux
|
|
21
34
|
```
|
|
22
35
|
|
|
23
|
-
|
|
36
|
+
```js
|
|
37
|
+
import { initialize, send, shutdown } from "sharjeenux";
|
|
24
38
|
|
|
25
|
-
|
|
26
|
-
|
|
39
|
+
await initialize();
|
|
40
|
+
console.log(await send("uname -a"));
|
|
41
|
+
console.log(await send("ls -la"));
|
|
42
|
+
console.log(await send("curl --version"));
|
|
43
|
+
await shutdown();
|
|
27
44
|
```
|
|
28
45
|
|
|
29
|
-
|
|
46
|
+
### Full Stack (Node.js + Python + Java)
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
npm install sharjeenux @sharjeenux/node @sharjeenux/python @sharjeenux/java
|
|
50
|
+
```
|
|
30
51
|
|
|
31
52
|
```js
|
|
32
53
|
import { initialize, send, exec, shutdown } from "sharjeenux";
|
|
33
54
|
|
|
34
55
|
await initialize();
|
|
35
56
|
|
|
36
|
-
|
|
57
|
+
// All runtimes are available automatically
|
|
37
58
|
console.log(await send("node -e 'console.log(6 * 7)'"));
|
|
38
59
|
console.log(await send("python3 -c 'print(6 * 7)'"));
|
|
39
60
|
console.log(await send("java --version"));
|
|
@@ -45,7 +66,23 @@ console.log(result.output, result.exitCode, result.durationMs);
|
|
|
45
66
|
await shutdown();
|
|
46
67
|
```
|
|
47
68
|
|
|
48
|
-
|
|
69
|
+
### Pick Only What You Need
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
# Just Node.js
|
|
73
|
+
npm install sharjeenux @sharjeenux/node
|
|
74
|
+
|
|
75
|
+
# Just Python
|
|
76
|
+
npm install sharjeenux @sharjeenux/python
|
|
77
|
+
|
|
78
|
+
# Node.js + Java (no Python)
|
|
79
|
+
npm install sharjeenux @sharjeenux/node @sharjeenux/java
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Plugins are detected automatically from your `package.json` dependencies. No
|
|
83
|
+
extra configuration is needed — just install and go.
|
|
84
|
+
|
|
85
|
+
CommonJS is also supported:
|
|
49
86
|
|
|
50
87
|
```js
|
|
51
88
|
const { initialize, send, shutdown } = require("sharjeenux");
|
|
@@ -55,18 +92,93 @@ console.log(await send("uname -a"));
|
|
|
55
92
|
await shutdown();
|
|
56
93
|
```
|
|
57
94
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
95
|
+
## How It Works
|
|
96
|
+
|
|
97
|
+
Under the hood, Sharjeenux leverages Linux's **composite initramfs** feature.
|
|
98
|
+
Each plugin package ships a compressed CPIO archive containing its runtime
|
|
99
|
+
binaries. At boot, the base initrd and all plugin initrds are concatenated
|
|
100
|
+
into a single buffer. The Linux kernel extracts them sequentially, overlaying
|
|
101
|
+
each archive onto the root filesystem. The result is a unified system with all
|
|
102
|
+
your chosen runtimes available in `$PATH`.
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
sharjeenux (base) → /bin, /sbin, /usr (BusyBox, git, curl…)
|
|
106
|
+
@sharjeenux/node (plugin) → /usr/local/bin/node, /usr/local/bin/npm…
|
|
107
|
+
@sharjeenux/python (plugin)→ /usr/bin/python3, /usr/bin/pip3…
|
|
108
|
+
@sharjeenux/java (plugin) → /usr/lib/jvm/…, /opt/maven/…
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## API
|
|
61
112
|
|
|
62
|
-
|
|
113
|
+
### `initialize(options?)`
|
|
114
|
+
|
|
115
|
+
Boots the VM and returns the `Sharjeenux` instance. Subsequent calls return the
|
|
116
|
+
same instance.
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
const vm = await initialize({
|
|
120
|
+
memoryMB: 2048, // Guest RAM (power of 2, min 128)
|
|
121
|
+
bootTimeoutMs: 180_000, // Max time to wait for boot
|
|
122
|
+
commandTimeoutMs: 1_800_000, // Default per-command timeout
|
|
123
|
+
networking: true, // Enable outbound networking
|
|
124
|
+
networkRelayUrl: "fetch", // Or "wisps://your-relay.example/"
|
|
125
|
+
plugins: [], // Explicit plugin package names (auto-detected by default)
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### `send(command, options?)`
|
|
130
|
+
|
|
131
|
+
Runs a shell command and returns its stdout as a string.
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
const output = await send("ls -la");
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `exec(command, options?)`
|
|
138
|
+
|
|
139
|
+
Runs a shell command and returns a result object:
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
const { output, exitCode, durationMs } = await exec("npm install lodash");
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `spawn(command, options?)`
|
|
146
|
+
|
|
147
|
+
Starts a long-running command without waiting for it to exit:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
const dev = vm.spawn("npm run dev -- --host 0.0.0.0", {
|
|
151
|
+
timeoutMs: 0,
|
|
152
|
+
onOutput: chunk => process.stdout.write(chunk),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Later...
|
|
156
|
+
dev.kill();
|
|
157
|
+
await dev.exit;
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `shutdown()`
|
|
161
|
+
|
|
162
|
+
Destroys the VM and releases all resources.
|
|
163
|
+
|
|
164
|
+
### Streaming Output
|
|
165
|
+
|
|
166
|
+
Both `exec()` and `send()` accept an `onOutput` callback for real-time output:
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
await send("npm install express", {
|
|
170
|
+
onOutput: chunk => process.stdout.write(chunk),
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Package Managers
|
|
63
175
|
|
|
64
176
|
Use npm/npx for JavaScript and TypeScript, pip for Python, and Maven for Java:
|
|
65
177
|
|
|
66
178
|
```js
|
|
67
|
-
await send("npm install lodash");
|
|
68
|
-
await send("pip3 install requests");
|
|
69
|
-
await send("mvn --version");
|
|
179
|
+
await send("npm install lodash"); // requires @sharjeenux/node
|
|
180
|
+
await send("pip3 install requests"); // requires @sharjeenux/python
|
|
181
|
+
await send("mvn --version"); // requires @sharjeenux/java
|
|
70
182
|
```
|
|
71
183
|
|
|
72
184
|
Buildroot images are intentionally assembled at build time and do not have a
|
|
@@ -79,7 +191,7 @@ compile native C/C++ extensions inside the guest are not guaranteed because
|
|
|
79
191
|
this image does not ship an on-target C/C++ compiler toolchain. Java source is
|
|
80
192
|
supported through `javac`.
|
|
81
193
|
|
|
82
|
-
## Long-
|
|
194
|
+
## Long-Running Commands
|
|
83
195
|
|
|
84
196
|
`send()` resolves only when a command exits. Use `spawn()` for a development
|
|
85
197
|
server or another long-lived process:
|
|
@@ -109,7 +221,7 @@ Sharjeenux deliberately does not map guest listening ports to the host. A Vite
|
|
|
109
221
|
server can run inside Linux, but its URL is not exposed to the host, browser,
|
|
110
222
|
or public network.
|
|
111
223
|
|
|
112
|
-
## Outbound
|
|
224
|
+
## Outbound Networking
|
|
113
225
|
|
|
114
226
|
The default is v86's fetch transport:
|
|
115
227
|
|
|
@@ -136,7 +248,20 @@ The fetch transport is much slower and less reliable for large dependency
|
|
|
136
248
|
graphs than normal TCP. Sharjeenux configures npm retries and conservative
|
|
137
249
|
parallelism, but a trusted Wisp relay is recommended for large installs.
|
|
138
250
|
|
|
139
|
-
##
|
|
251
|
+
## Creating a Plugin Package
|
|
252
|
+
|
|
253
|
+
Want to add your own runtime to Sharjeenux? Create an npm package that ships a
|
|
254
|
+
CPIO archive:
|
|
255
|
+
|
|
256
|
+
1. Build a `plugin.cpio.xz` (or `.cpio.gz` / `.cpio`) containing the files you
|
|
257
|
+
want overlaid onto the root filesystem
|
|
258
|
+
2. Set `"main": "plugin.cpio.xz"` in your plugin's `package.json`
|
|
259
|
+
3. Include `plugin.cpio.xz` in the `"files"` array
|
|
260
|
+
4. Name your package `@sharjeenux/<name>` or `sharjeenux-<name>`
|
|
261
|
+
|
|
262
|
+
The archive will be automatically detected and loaded at boot.
|
|
263
|
+
|
|
264
|
+
## Sandbox Requirements
|
|
140
265
|
|
|
141
266
|
Sharjeenux works in Node.js sandboxes that permit:
|
|
142
267
|
|
|
@@ -150,7 +275,7 @@ It is not a browser package: its host wrapper imports Node.js APIs. Serverless
|
|
|
150
275
|
and edge runtimes with short CPU limits, no writable temporary storage, or no
|
|
151
276
|
WebAssembly support are not compatible.
|
|
152
277
|
|
|
153
|
-
## Performance and Base64
|
|
278
|
+
## Performance and Base64 Assets
|
|
154
279
|
|
|
155
280
|
Every embedded binary is stored as Base64 text files of at most 1 KiB each.
|
|
156
281
|
The first initialization must open and decode those files. Decoded images are
|
|
@@ -162,7 +287,7 @@ slower than native Node.js or StackBlitz WebContainers, whose architecture is
|
|
|
162
287
|
designed specifically around browser-native execution. Streaming output with
|
|
163
288
|
`onOutput` makes long installs observable but does not remove emulation cost.
|
|
164
289
|
|
|
165
|
-
## Licensing and
|
|
290
|
+
## Licensing and Corresponding Source
|
|
166
291
|
|
|
167
292
|
The JavaScript wrapper is MIT-licensed. The Linux image contains components
|
|
168
293
|
under their own licenses, including GPLv2 BusyBox and the Linux kernel. See
|
|
@@ -446,10 +446,10 @@ BR2_STRIP_EXCLUDE_FILES=""
|
|
|
446
446
|
BR2_STRIP_EXCLUDE_DIRS=""
|
|
447
447
|
# BR2_OPTIMIZE_0 is not set
|
|
448
448
|
# BR2_OPTIMIZE_1 is not set
|
|
449
|
-
BR2_OPTIMIZE_2
|
|
449
|
+
# BR2_OPTIMIZE_2 is not set
|
|
450
450
|
# BR2_OPTIMIZE_3 is not set
|
|
451
451
|
# BR2_OPTIMIZE_G is not set
|
|
452
|
-
|
|
452
|
+
BR2_OPTIMIZE_S=y
|
|
453
453
|
# BR2_OPTIMIZE_FAST is not set
|
|
454
454
|
# BR2_ENABLE_LTO is not set
|
|
455
455
|
# BR2_GOOGLE_BREAKPAD_ENABLE is not set
|
|
@@ -3811,12 +3811,12 @@ BR2_TARGET_ROOTFS_CPIO=y
|
|
|
3811
3811
|
BR2_TARGET_ROOTFS_CPIO_FULL=y
|
|
3812
3812
|
# BR2_TARGET_ROOTFS_CPIO_DRACUT is not set
|
|
3813
3813
|
# BR2_TARGET_ROOTFS_CPIO_NONE is not set
|
|
3814
|
-
BR2_TARGET_ROOTFS_CPIO_GZIP
|
|
3814
|
+
# BR2_TARGET_ROOTFS_CPIO_GZIP is not set
|
|
3815
3815
|
# BR2_TARGET_ROOTFS_CPIO_BZIP2 is not set
|
|
3816
3816
|
# BR2_TARGET_ROOTFS_CPIO_LZ4 is not set
|
|
3817
3817
|
# BR2_TARGET_ROOTFS_CPIO_LZMA is not set
|
|
3818
3818
|
# BR2_TARGET_ROOTFS_CPIO_LZO is not set
|
|
3819
|
-
|
|
3819
|
+
BR2_TARGET_ROOTFS_CPIO_XZ=y
|
|
3820
3820
|
# BR2_TARGET_ROOTFS_CPIO_ZSTD is not set
|
|
3821
3821
|
# BR2_TARGET_ROOTFS_CPIO_UIMAGE is not set
|
|
3822
3822
|
# BR2_TARGET_ROOTFS_CRAMFS is not set
|
package/compliance/linux.config
CHANGED
|
@@ -186,7 +186,7 @@ CONFIG_NET_NS=y
|
|
|
186
186
|
# CONFIG_SCHED_AUTOGROUP is not set
|
|
187
187
|
# CONFIG_RELAY is not set
|
|
188
188
|
CONFIG_BLK_DEV_INITRD=y
|
|
189
|
-
CONFIG_INITRAMFS_SOURCE="
|
|
189
|
+
CONFIG_INITRAMFS_SOURCE=""
|
|
190
190
|
CONFIG_INITRAMFS_ROOT_UID=0
|
|
191
191
|
CONFIG_INITRAMFS_ROOT_GID=0
|
|
192
192
|
CONFIG_RD_GZIP=y
|
|
@@ -196,18 +196,18 @@ CONFIG_RD_XZ=y
|
|
|
196
196
|
CONFIG_RD_LZO=y
|
|
197
197
|
CONFIG_RD_LZ4=y
|
|
198
198
|
CONFIG_RD_ZSTD=y
|
|
199
|
-
CONFIG_INITRAMFS_COMPRESSION_GZIP
|
|
199
|
+
# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
|
|
200
200
|
# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
|
|
201
201
|
# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
|
|
202
|
-
|
|
202
|
+
CONFIG_INITRAMFS_COMPRESSION_XZ=y
|
|
203
203
|
# CONFIG_INITRAMFS_COMPRESSION_LZO is not set
|
|
204
204
|
# CONFIG_INITRAMFS_COMPRESSION_LZ4 is not set
|
|
205
205
|
# CONFIG_INITRAMFS_COMPRESSION_ZSTD is not set
|
|
206
206
|
# CONFIG_INITRAMFS_COMPRESSION_NONE is not set
|
|
207
207
|
# CONFIG_BOOT_CONFIG is not set
|
|
208
208
|
CONFIG_INITRAMFS_PRESERVE_MTIME=y
|
|
209
|
-
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
|
|
210
|
-
|
|
209
|
+
# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
|
|
210
|
+
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
|
211
211
|
CONFIG_LD_ORPHAN_WARN=y
|
|
212
212
|
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
|
|
213
213
|
CONFIG_SYSCTL=y
|
package/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export interface SharjeenuxOptions {
|
|
|
11
11
|
networkRelayUrl?: string;
|
|
12
12
|
/** Hash-check decoded VM assets during initialization. Default: true. */
|
|
13
13
|
verifyAssets?: boolean;
|
|
14
|
+
/** Explicit list of plugin package names to load (e.g. ["@sharjeenux/node"]). By default, plugins are auto-detected from package.json dependencies. */
|
|
15
|
+
plugins?: string[];
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface CommandOptions {
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { createRequire } from "node:module";
|
|
7
8
|
import { V86 } from "v86";
|
|
8
9
|
|
|
9
10
|
const ASSETS_URL = new URL("./assets/", import.meta.url);
|
|
@@ -16,6 +17,7 @@ const DEFAULTS = Object.freeze({
|
|
|
16
17
|
networking: true,
|
|
17
18
|
networkRelayUrl: "fetch",
|
|
18
19
|
verifyAssets: true,
|
|
20
|
+
plugins: [],
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
let defaultInstance;
|
|
@@ -57,6 +59,56 @@ function toArrayBuffer(buffer) {
|
|
|
57
59
|
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
58
60
|
}
|
|
59
61
|
|
|
62
|
+
|
|
63
|
+
function concatArrayBuffers(buffers) {
|
|
64
|
+
const totalLength = buffers.reduce((acc, b) => acc + b.byteLength, 0);
|
|
65
|
+
const result = new Uint8Array(totalLength);
|
|
66
|
+
let offset = 0;
|
|
67
|
+
for (const b of buffers) {
|
|
68
|
+
result.set(new Uint8Array(b), offset);
|
|
69
|
+
offset += b.byteLength;
|
|
70
|
+
}
|
|
71
|
+
return result.buffer;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function loadPlugins(explicitPlugins = []) {
|
|
75
|
+
const plugins = [];
|
|
76
|
+
const require = createRequire(process.cwd() + "/");
|
|
77
|
+
const depsToTry = new Set(explicitPlugins);
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const pkgPath = path.resolve(process.cwd(), "package.json");
|
|
81
|
+
const pkgText = await readFile(pkgPath, "utf8");
|
|
82
|
+
const pkg = JSON.parse(pkgText);
|
|
83
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
84
|
+
for (const dep of Object.keys(deps)) {
|
|
85
|
+
if ((dep.startsWith("sharjeenux-") || dep.startsWith("@sharjeenux/")) && dep !== "sharjeenux") {
|
|
86
|
+
depsToTry.add(dep);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {}
|
|
90
|
+
|
|
91
|
+
for (const dep of depsToTry) {
|
|
92
|
+
try {
|
|
93
|
+
let depPath;
|
|
94
|
+
try {
|
|
95
|
+
depPath = require.resolve(`${dep}/plugin.cpio.xz`);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
try {
|
|
98
|
+
depPath = require.resolve(`${dep}/plugin.cpio.gz`);
|
|
99
|
+
} catch (e2) {
|
|
100
|
+
depPath = require.resolve(`${dep}/plugin.cpio`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const buffer = await readFile(depPath);
|
|
104
|
+
plugins.push(toArrayBuffer(buffer));
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.warn(`[Sharjeenux] Failed to load plugin ${dep}: ${e.message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return plugins;
|
|
110
|
+
}
|
|
111
|
+
|
|
60
112
|
async function getManifest() {
|
|
61
113
|
manifestPromise ||= readFile(new URL("manifest.json", ASSETS_URL), "utf8").then(JSON.parse);
|
|
62
114
|
return manifestPromise;
|
|
@@ -153,13 +205,23 @@ export class Sharjeenux extends EventEmitter {
|
|
|
153
205
|
globalThis.WebSocket = WebSocket;
|
|
154
206
|
}
|
|
155
207
|
const manifest = await getManifest();
|
|
156
|
-
const [bios, vgabios, kernel,
|
|
208
|
+
const [bios, vgabios, kernel, baseInitrd, plugins] = await Promise.all([
|
|
157
209
|
loadImage("bios", this.options.verifyAssets),
|
|
158
210
|
loadImage("vgabios", this.options.verifyAssets),
|
|
159
211
|
loadImage("kernel", this.options.verifyAssets),
|
|
160
|
-
manifest.images.initrd ? loadImage("initrd", this.options.verifyAssets) :
|
|
212
|
+
manifest.images.initrd ? loadImage("initrd", this.options.verifyAssets) : Promise.resolve(null),
|
|
213
|
+
loadPlugins(this.options.plugins)
|
|
161
214
|
]);
|
|
162
215
|
|
|
216
|
+
let finalInitrd;
|
|
217
|
+
const initrdBuffers = [];
|
|
218
|
+
if (baseInitrd) initrdBuffers.push(baseInitrd);
|
|
219
|
+
if (plugins.length > 0) initrdBuffers.push(...plugins);
|
|
220
|
+
|
|
221
|
+
if (initrdBuffers.length > 0) {
|
|
222
|
+
finalInitrd = concatArrayBuffers(initrdBuffers);
|
|
223
|
+
}
|
|
224
|
+
|
|
163
225
|
const wasmPath = fileURLToPath(import.meta.resolve("v86/build/v86.wasm"));
|
|
164
226
|
const boot = deferred();
|
|
165
227
|
this._boot = boot;
|
|
@@ -183,7 +245,7 @@ export class Sharjeenux extends EventEmitter {
|
|
|
183
245
|
disable_mouse: true,
|
|
184
246
|
disable_speaker: true,
|
|
185
247
|
};
|
|
186
|
-
if (
|
|
248
|
+
if (finalInitrd) emulatorOptions.initrd = { buffer: finalInitrd };
|
|
187
249
|
this._emulator = new V86(emulatorOptions);
|
|
188
250
|
this._emulator.add_listener("serial0-output-byte", this._serialListener);
|
|
189
251
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sharjeenux",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A headless Buildroot Linux VM
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A modular, headless Buildroot Linux VM controlled from JavaScript. Install language runtimes as plugins: @sharjeenux/node, @sharjeenux/python, @sharjeenux/java.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.cjs",
|
|
7
7
|
"module": "./index.js",
|