@scelar/nodepod 1.0.5 → 1.0.6

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.
@@ -1,64 +1,64 @@
1
- import type { VolumeSnapshot } from "../engine-types";
2
- import type { MemoryHandlerOptions } from "../memory-handler";
3
- export interface NodepodOptions {
4
- files?: Record<string, string | Uint8Array>;
5
- env?: Record<string, string>;
6
- workdir?: string;
7
- swUrl?: string;
8
- onServerReady?: (port: number, url: string) => void;
9
- /** Show a small "nodepod" watermark link in preview iframes. Defaults to true. */
10
- watermark?: boolean;
11
- /** Memory optimization settings. Omit to use defaults. */
12
- memory?: MemoryHandlerOptions;
13
- /** Cache installed node_modules in IndexedDB for faster re-boots. Default: true. */
14
- enableSnapshotCache?: boolean;
15
- }
16
- export interface TerminalTheme {
17
- background?: string;
18
- foreground?: string;
19
- cursor?: string;
20
- selectionBackground?: string;
21
- black?: string;
22
- red?: string;
23
- green?: string;
24
- yellow?: string;
25
- blue?: string;
26
- magenta?: string;
27
- cyan?: string;
28
- white?: string;
29
- brightBlack?: string;
30
- brightRed?: string;
31
- brightGreen?: string;
32
- brightYellow?: string;
33
- brightBlue?: string;
34
- brightMagenta?: string;
35
- brightCyan?: string;
36
- brightWhite?: string;
37
- }
38
- export interface TerminalOptions {
39
- Terminal: any;
40
- FitAddon?: any;
41
- WebglAddon?: any;
42
- theme?: TerminalTheme;
43
- fontSize?: number;
44
- fontFamily?: string;
45
- prompt?: (cwd: string) => string;
46
- }
47
- export interface StatResult {
48
- isFile: boolean;
49
- isDirectory: boolean;
50
- size: number;
51
- mtime: number;
52
- }
53
- export type Snapshot = VolumeSnapshot;
54
- export interface SnapshotOptions {
55
- /** Exclude node_modules and other auto-installable dirs. Default: true */
56
- shallow?: boolean;
57
- /** Auto-install deps from package.json after restoring a shallow snapshot. Default: true */
58
- autoInstall?: boolean;
59
- }
60
- export interface SpawnOptions {
61
- cwd?: string;
62
- env?: Record<string, string>;
63
- signal?: AbortSignal;
64
- }
1
+ import type { VolumeSnapshot } from "../engine-types";
2
+ import type { MemoryHandlerOptions } from "../memory-handler";
3
+ export interface NodepodOptions {
4
+ files?: Record<string, string | Uint8Array>;
5
+ env?: Record<string, string>;
6
+ workdir?: string;
7
+ swUrl?: string;
8
+ onServerReady?: (port: number, url: string) => void;
9
+ /** Show a small "nodepod" watermark link in preview iframes. Defaults to true. */
10
+ watermark?: boolean;
11
+ /** Memory optimization settings. Omit to use defaults. */
12
+ memory?: MemoryHandlerOptions;
13
+ /** Cache installed node_modules in IndexedDB for faster re-boots. Default: true. */
14
+ enableSnapshotCache?: boolean;
15
+ }
16
+ export interface TerminalTheme {
17
+ background?: string;
18
+ foreground?: string;
19
+ cursor?: string;
20
+ selectionBackground?: string;
21
+ black?: string;
22
+ red?: string;
23
+ green?: string;
24
+ yellow?: string;
25
+ blue?: string;
26
+ magenta?: string;
27
+ cyan?: string;
28
+ white?: string;
29
+ brightBlack?: string;
30
+ brightRed?: string;
31
+ brightGreen?: string;
32
+ brightYellow?: string;
33
+ brightBlue?: string;
34
+ brightMagenta?: string;
35
+ brightCyan?: string;
36
+ brightWhite?: string;
37
+ }
38
+ export interface TerminalOptions {
39
+ Terminal: any;
40
+ FitAddon?: any;
41
+ WebglAddon?: any;
42
+ theme?: TerminalTheme;
43
+ fontSize?: number;
44
+ fontFamily?: string;
45
+ prompt?: (cwd: string) => string;
46
+ }
47
+ export interface StatResult {
48
+ isFile: boolean;
49
+ isDirectory: boolean;
50
+ size: number;
51
+ mtime: number;
52
+ }
53
+ export type Snapshot = VolumeSnapshot;
54
+ export interface SnapshotOptions {
55
+ /** Exclude node_modules and other auto-installable dirs. Default: true */
56
+ shallow?: boolean;
57
+ /** Auto-install deps from package.json after restoring a shallow snapshot. Default: true */
58
+ autoInstall?: boolean;
59
+ }
60
+ export interface SpawnOptions {
61
+ cwd?: string;
62
+ env?: Record<string, string>;
63
+ signal?: AbortSignal;
64
+ }
package/package.json CHANGED
@@ -1,97 +1,97 @@
1
- {
2
- "name": "@scelar/nodepod",
3
- "version": "1.0.5",
4
- "description": "Browser-native Node.js runtime environment",
5
- "type": "module",
6
- "license": "MIT WITH Commons-Clause",
7
- "author": "R1ck404 (https://github.com/R1ck404)",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/ScelarOrg/Nodepod.git"
11
- },
12
- "bugs": {
13
- "url": "https://github.com/ScelarOrg/Nodepod/issues"
14
- },
15
- "homepage": "https://github.com/ScelarOrg/Nodepod#readme",
16
- "keywords": [
17
- "node",
18
- "browser",
19
- "runtime",
20
- "sandbox",
21
- "typescript",
22
- "virtual-filesystem",
23
- "polyfill",
24
- "webcontainer",
25
- "in-browser",
26
- "nodejs"
27
- ],
28
- "engines": {
29
- "node": ">=20.0.0"
30
- },
31
- "main": "./dist/index.cjs",
32
- "module": "./dist/index.mjs",
33
- "types": "./dist/index.d.ts",
34
- "exports": {
35
- ".": {
36
- "import": {
37
- "types": "./dist/index.d.ts",
38
- "default": "./dist/index.mjs"
39
- },
40
- "require": {
41
- "types": "./dist/index.d.ts",
42
- "default": "./dist/index.cjs"
43
- }
44
- }
45
- },
46
- "files": [
47
- "src",
48
- "dist"
49
- ],
50
- "sideEffects": false,
51
- "scripts": {
52
- "build:lib": "vite build --config vite.lib.config.js && node -e \"require('fs').copyFileSync('static/__sw__.js','dist/__sw__.js')\"",
53
- "build:types": "tsc --project tsconfig.build.json",
54
- "build:publish": "npm run build:lib && npm run build:types",
55
- "type-check": "tsc --noEmit",
56
- "test": "vitest run",
57
- "test:watch": "vitest",
58
- "bench": "vitest bench",
59
- "bench:run": "vitest bench --run"
60
- },
61
- "dependencies": {
62
- "acorn": "^8.15.0",
63
- "acorn-jsx": "^5.3.2",
64
- "brotli": "^1.3.3",
65
- "brotli-wasm": "^3.0.1",
66
- "comlink": "^4.4.2",
67
- "pako": "^2.1.0",
68
- "resolve.exports": "^2.0.3",
69
- "zod": "^4.3.6"
70
- },
71
- "peerDependencies": {
72
- "@xterm/xterm": "^6.0.0",
73
- "@xterm/addon-fit": "^0.11.0",
74
- "@xterm/addon-webgl": "^0.19.0"
75
- },
76
- "peerDependenciesMeta": {
77
- "@xterm/xterm": {
78
- "optional": true
79
- },
80
- "@xterm/addon-fit": {
81
- "optional": true
82
- },
83
- "@xterm/addon-webgl": {
84
- "optional": true
85
- }
86
- },
87
- "devDependencies": {
88
- "@types/node": "^25.0.10",
89
- "@types/pako": "^2.0.4",
90
- "esbuild": "^0.27.2",
91
- "typescript": "^5.9.3",
92
- "vite": "^5.4.0",
93
- "vite-plugin-top-level-await": "^1.6.0",
94
- "vite-plugin-wasm": "^3.5.0",
95
- "vitest": "^4.0.18"
96
- }
97
- }
1
+ {
2
+ "name": "@scelar/nodepod",
3
+ "version": "1.0.6",
4
+ "description": "Browser-native Node.js runtime environment",
5
+ "type": "module",
6
+ "license": "MIT WITH Commons-Clause",
7
+ "author": "R1ck404 (https://github.com/R1ck404)",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/ScelarOrg/Nodepod.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/ScelarOrg/Nodepod/issues"
14
+ },
15
+ "homepage": "https://github.com/ScelarOrg/Nodepod#readme",
16
+ "keywords": [
17
+ "node",
18
+ "browser",
19
+ "runtime",
20
+ "sandbox",
21
+ "typescript",
22
+ "virtual-filesystem",
23
+ "polyfill",
24
+ "webcontainer",
25
+ "in-browser",
26
+ "nodejs"
27
+ ],
28
+ "engines": {
29
+ "node": ">=20.0.0"
30
+ },
31
+ "main": "./dist/index.cjs",
32
+ "module": "./dist/index.mjs",
33
+ "types": "./dist/index.d.ts",
34
+ "exports": {
35
+ ".": {
36
+ "import": {
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.mjs"
39
+ },
40
+ "require": {
41
+ "types": "./dist/index.d.ts",
42
+ "default": "./dist/index.cjs"
43
+ }
44
+ }
45
+ },
46
+ "files": [
47
+ "src",
48
+ "dist"
49
+ ],
50
+ "sideEffects": false,
51
+ "scripts": {
52
+ "build:lib": "vite build --config vite.lib.config.js && node -e \"require('fs').copyFileSync('static/__sw__.js','dist/__sw__.js')\"",
53
+ "build:types": "tsc --project tsconfig.build.json",
54
+ "build:publish": "npm run build:lib && npm run build:types",
55
+ "type-check": "tsc --noEmit",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest",
58
+ "bench": "vitest bench",
59
+ "bench:run": "vitest bench --run"
60
+ },
61
+ "dependencies": {
62
+ "acorn": "^8.15.0",
63
+ "acorn-jsx": "^5.3.2",
64
+ "brotli": "^1.3.3",
65
+ "brotli-wasm": "^3.0.1",
66
+ "comlink": "^4.4.2",
67
+ "pako": "^2.1.0",
68
+ "resolve.exports": "^2.0.3",
69
+ "zod": "^4.3.6"
70
+ },
71
+ "peerDependencies": {
72
+ "@xterm/xterm": "^6.0.0",
73
+ "@xterm/addon-fit": "^0.11.0",
74
+ "@xterm/addon-webgl": "^0.19.0"
75
+ },
76
+ "peerDependenciesMeta": {
77
+ "@xterm/xterm": {
78
+ "optional": true
79
+ },
80
+ "@xterm/addon-fit": {
81
+ "optional": true
82
+ },
83
+ "@xterm/addon-webgl": {
84
+ "optional": true
85
+ }
86
+ },
87
+ "devDependencies": {
88
+ "@types/node": "^25.0.10",
89
+ "@types/pako": "^2.0.4",
90
+ "esbuild": "^0.27.2",
91
+ "typescript": "^5.9.3",
92
+ "vite": "^5.4.0",
93
+ "vite-plugin-top-level-await": "^1.6.0",
94
+ "vite-plugin-wasm": "^3.5.0",
95
+ "vitest": "^4.0.18"
96
+ }
97
+ }
@@ -1986,6 +1986,9 @@ export function spawn(
1986
1986
  }, 0);
1987
1987
  }
1988
1988
 
1989
+ // real Node emits this on next tick so listeners can attach first
1990
+ queueMicrotask(() => child.emit("spawn"));
1991
+
1989
1992
  return child;
1990
1993
  }
1991
1994
 
@@ -2,6 +2,8 @@
2
2
  // EventEmitter.call(this) and Object.create(EventEmitter.prototype) work.
3
3
  // ES6 classes forbid calling without `new`, which breaks tons of npm packages.
4
4
 
5
+ import { ref, unref } from "../helpers/event-loop";
6
+
5
7
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
8
  export type EventHandler = (...args: any[]) => void;
7
9
 
@@ -171,16 +173,28 @@ EventEmitter.prototype.emit = function emit(name: string, ...payload: unknown[])
171
173
  return false;
172
174
  }
173
175
 
176
+ // if a handler returns a promise, hold a ref so the process doesn't bail early
177
+ const trackResult = (result: unknown) => {
178
+ if (result && typeof (result as any).then === "function") {
179
+ ref();
180
+ (result as Promise<unknown>).then(() => unref(), () => unref());
181
+ }
182
+ };
183
+
174
184
  // Fast path: single listener — avoid slice() allocation
175
185
  if (slot.length === 1) {
176
- try { slot[0].apply(this, payload); } catch (_) { /* swallow */ }
186
+ try {
187
+ const r = slot[0].apply(this, payload);
188
+ trackResult(r);
189
+ } catch (_) { /* swallow */ }
177
190
  return true;
178
191
  }
179
192
 
180
193
  const snapshot = slot.slice();
181
194
  for (const handler of snapshot) {
182
195
  try {
183
- handler.apply(this, payload);
196
+ const r = handler.apply(this, payload);
197
+ trackResult(r);
184
198
  } catch (fault) {
185
199
  /* swallow handler errors */
186
200
  }