almostnode 0.1.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.
Files changed (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +731 -0
  3. package/dist/__sw__.js +394 -0
  4. package/dist/ai-chatbot-demo-entry.d.ts +6 -0
  5. package/dist/ai-chatbot-demo-entry.d.ts.map +1 -0
  6. package/dist/ai-chatbot-demo.d.ts +42 -0
  7. package/dist/ai-chatbot-demo.d.ts.map +1 -0
  8. package/dist/assets/runtime-worker-D9x_Ddwz.js +60543 -0
  9. package/dist/assets/runtime-worker-D9x_Ddwz.js.map +1 -0
  10. package/dist/convex-app-demo-entry.d.ts +6 -0
  11. package/dist/convex-app-demo-entry.d.ts.map +1 -0
  12. package/dist/convex-app-demo.d.ts +68 -0
  13. package/dist/convex-app-demo.d.ts.map +1 -0
  14. package/dist/cors-proxy.d.ts +46 -0
  15. package/dist/cors-proxy.d.ts.map +1 -0
  16. package/dist/create-runtime.d.ts +42 -0
  17. package/dist/create-runtime.d.ts.map +1 -0
  18. package/dist/demo.d.ts +6 -0
  19. package/dist/demo.d.ts.map +1 -0
  20. package/dist/dev-server.d.ts +97 -0
  21. package/dist/dev-server.d.ts.map +1 -0
  22. package/dist/frameworks/next-dev-server.d.ts +202 -0
  23. package/dist/frameworks/next-dev-server.d.ts.map +1 -0
  24. package/dist/frameworks/vite-dev-server.d.ts +85 -0
  25. package/dist/frameworks/vite-dev-server.d.ts.map +1 -0
  26. package/dist/index.cjs +14965 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.d.ts +71 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.mjs +14867 -0
  31. package/dist/index.mjs.map +1 -0
  32. package/dist/next-demo.d.ts +49 -0
  33. package/dist/next-demo.d.ts.map +1 -0
  34. package/dist/npm/index.d.ts +71 -0
  35. package/dist/npm/index.d.ts.map +1 -0
  36. package/dist/npm/registry.d.ts +66 -0
  37. package/dist/npm/registry.d.ts.map +1 -0
  38. package/dist/npm/resolver.d.ts +52 -0
  39. package/dist/npm/resolver.d.ts.map +1 -0
  40. package/dist/npm/tarball.d.ts +29 -0
  41. package/dist/npm/tarball.d.ts.map +1 -0
  42. package/dist/runtime-interface.d.ts +90 -0
  43. package/dist/runtime-interface.d.ts.map +1 -0
  44. package/dist/runtime.d.ts +103 -0
  45. package/dist/runtime.d.ts.map +1 -0
  46. package/dist/sandbox-helpers.d.ts +43 -0
  47. package/dist/sandbox-helpers.d.ts.map +1 -0
  48. package/dist/sandbox-runtime.d.ts +65 -0
  49. package/dist/sandbox-runtime.d.ts.map +1 -0
  50. package/dist/server-bridge.d.ts +89 -0
  51. package/dist/server-bridge.d.ts.map +1 -0
  52. package/dist/shims/assert.d.ts +51 -0
  53. package/dist/shims/assert.d.ts.map +1 -0
  54. package/dist/shims/async_hooks.d.ts +37 -0
  55. package/dist/shims/async_hooks.d.ts.map +1 -0
  56. package/dist/shims/buffer.d.ts +20 -0
  57. package/dist/shims/buffer.d.ts.map +1 -0
  58. package/dist/shims/child_process-browser.d.ts +92 -0
  59. package/dist/shims/child_process-browser.d.ts.map +1 -0
  60. package/dist/shims/child_process.d.ts +93 -0
  61. package/dist/shims/child_process.d.ts.map +1 -0
  62. package/dist/shims/chokidar.d.ts +55 -0
  63. package/dist/shims/chokidar.d.ts.map +1 -0
  64. package/dist/shims/cluster.d.ts +52 -0
  65. package/dist/shims/cluster.d.ts.map +1 -0
  66. package/dist/shims/crypto.d.ts +122 -0
  67. package/dist/shims/crypto.d.ts.map +1 -0
  68. package/dist/shims/dgram.d.ts +34 -0
  69. package/dist/shims/dgram.d.ts.map +1 -0
  70. package/dist/shims/diagnostics_channel.d.ts +80 -0
  71. package/dist/shims/diagnostics_channel.d.ts.map +1 -0
  72. package/dist/shims/dns.d.ts +87 -0
  73. package/dist/shims/dns.d.ts.map +1 -0
  74. package/dist/shims/domain.d.ts +25 -0
  75. package/dist/shims/domain.d.ts.map +1 -0
  76. package/dist/shims/esbuild.d.ts +105 -0
  77. package/dist/shims/esbuild.d.ts.map +1 -0
  78. package/dist/shims/events.d.ts +37 -0
  79. package/dist/shims/events.d.ts.map +1 -0
  80. package/dist/shims/fs.d.ts +115 -0
  81. package/dist/shims/fs.d.ts.map +1 -0
  82. package/dist/shims/fsevents.d.ts +67 -0
  83. package/dist/shims/fsevents.d.ts.map +1 -0
  84. package/dist/shims/http.d.ts +217 -0
  85. package/dist/shims/http.d.ts.map +1 -0
  86. package/dist/shims/http2.d.ts +81 -0
  87. package/dist/shims/http2.d.ts.map +1 -0
  88. package/dist/shims/https.d.ts +36 -0
  89. package/dist/shims/https.d.ts.map +1 -0
  90. package/dist/shims/inspector.d.ts +25 -0
  91. package/dist/shims/inspector.d.ts.map +1 -0
  92. package/dist/shims/module.d.ts +22 -0
  93. package/dist/shims/module.d.ts.map +1 -0
  94. package/dist/shims/net.d.ts +100 -0
  95. package/dist/shims/net.d.ts.map +1 -0
  96. package/dist/shims/os.d.ts +159 -0
  97. package/dist/shims/os.d.ts.map +1 -0
  98. package/dist/shims/path.d.ts +72 -0
  99. package/dist/shims/path.d.ts.map +1 -0
  100. package/dist/shims/perf_hooks.d.ts +50 -0
  101. package/dist/shims/perf_hooks.d.ts.map +1 -0
  102. package/dist/shims/process.d.ts +93 -0
  103. package/dist/shims/process.d.ts.map +1 -0
  104. package/dist/shims/querystring.d.ts +23 -0
  105. package/dist/shims/querystring.d.ts.map +1 -0
  106. package/dist/shims/readdirp.d.ts +52 -0
  107. package/dist/shims/readdirp.d.ts.map +1 -0
  108. package/dist/shims/readline.d.ts +62 -0
  109. package/dist/shims/readline.d.ts.map +1 -0
  110. package/dist/shims/rollup.d.ts +34 -0
  111. package/dist/shims/rollup.d.ts.map +1 -0
  112. package/dist/shims/sentry.d.ts +163 -0
  113. package/dist/shims/sentry.d.ts.map +1 -0
  114. package/dist/shims/stream.d.ts +181 -0
  115. package/dist/shims/stream.d.ts.map +1 -0
  116. package/dist/shims/tls.d.ts +53 -0
  117. package/dist/shims/tls.d.ts.map +1 -0
  118. package/dist/shims/tty.d.ts +30 -0
  119. package/dist/shims/tty.d.ts.map +1 -0
  120. package/dist/shims/url.d.ts +64 -0
  121. package/dist/shims/url.d.ts.map +1 -0
  122. package/dist/shims/util.d.ts +106 -0
  123. package/dist/shims/util.d.ts.map +1 -0
  124. package/dist/shims/v8.d.ts +73 -0
  125. package/dist/shims/v8.d.ts.map +1 -0
  126. package/dist/shims/vfs-adapter.d.ts +126 -0
  127. package/dist/shims/vfs-adapter.d.ts.map +1 -0
  128. package/dist/shims/vm.d.ts +45 -0
  129. package/dist/shims/vm.d.ts.map +1 -0
  130. package/dist/shims/worker_threads.d.ts +66 -0
  131. package/dist/shims/worker_threads.d.ts.map +1 -0
  132. package/dist/shims/ws.d.ts +66 -0
  133. package/dist/shims/ws.d.ts.map +1 -0
  134. package/dist/shims/zlib.d.ts +161 -0
  135. package/dist/shims/zlib.d.ts.map +1 -0
  136. package/dist/transform.d.ts +24 -0
  137. package/dist/transform.d.ts.map +1 -0
  138. package/dist/virtual-fs.d.ts +226 -0
  139. package/dist/virtual-fs.d.ts.map +1 -0
  140. package/dist/vite-demo.d.ts +35 -0
  141. package/dist/vite-demo.d.ts.map +1 -0
  142. package/dist/vite-sw.js +132 -0
  143. package/dist/worker/runtime-worker.d.ts +8 -0
  144. package/dist/worker/runtime-worker.d.ts.map +1 -0
  145. package/dist/worker-runtime.d.ts +50 -0
  146. package/dist/worker-runtime.d.ts.map +1 -0
  147. package/package.json +85 -0
  148. package/src/ai-chatbot-demo-entry.ts +244 -0
  149. package/src/ai-chatbot-demo.ts +509 -0
  150. package/src/convex-app-demo-entry.ts +1107 -0
  151. package/src/convex-app-demo.ts +1316 -0
  152. package/src/cors-proxy.ts +81 -0
  153. package/src/create-runtime.ts +147 -0
  154. package/src/demo.ts +304 -0
  155. package/src/dev-server.ts +274 -0
  156. package/src/frameworks/next-dev-server.ts +2224 -0
  157. package/src/frameworks/vite-dev-server.ts +702 -0
  158. package/src/index.ts +101 -0
  159. package/src/next-demo.ts +1784 -0
  160. package/src/npm/index.ts +347 -0
  161. package/src/npm/registry.ts +152 -0
  162. package/src/npm/resolver.ts +385 -0
  163. package/src/npm/tarball.ts +209 -0
  164. package/src/runtime-interface.ts +103 -0
  165. package/src/runtime.ts +1046 -0
  166. package/src/sandbox-helpers.ts +173 -0
  167. package/src/sandbox-runtime.ts +252 -0
  168. package/src/server-bridge.ts +426 -0
  169. package/src/shims/assert.ts +664 -0
  170. package/src/shims/async_hooks.ts +86 -0
  171. package/src/shims/buffer.ts +75 -0
  172. package/src/shims/child_process-browser.ts +217 -0
  173. package/src/shims/child_process.ts +463 -0
  174. package/src/shims/chokidar.ts +313 -0
  175. package/src/shims/cluster.ts +67 -0
  176. package/src/shims/crypto.ts +830 -0
  177. package/src/shims/dgram.ts +47 -0
  178. package/src/shims/diagnostics_channel.ts +196 -0
  179. package/src/shims/dns.ts +172 -0
  180. package/src/shims/domain.ts +58 -0
  181. package/src/shims/esbuild.ts +805 -0
  182. package/src/shims/events.ts +195 -0
  183. package/src/shims/fs.ts +803 -0
  184. package/src/shims/fsevents.ts +63 -0
  185. package/src/shims/http.ts +904 -0
  186. package/src/shims/http2.ts +96 -0
  187. package/src/shims/https.ts +86 -0
  188. package/src/shims/inspector.ts +30 -0
  189. package/src/shims/module.ts +82 -0
  190. package/src/shims/net.ts +359 -0
  191. package/src/shims/os.ts +195 -0
  192. package/src/shims/path.ts +199 -0
  193. package/src/shims/perf_hooks.ts +92 -0
  194. package/src/shims/process.ts +346 -0
  195. package/src/shims/querystring.ts +97 -0
  196. package/src/shims/readdirp.ts +228 -0
  197. package/src/shims/readline.ts +110 -0
  198. package/src/shims/rollup.ts +80 -0
  199. package/src/shims/sentry.ts +133 -0
  200. package/src/shims/stream.ts +1126 -0
  201. package/src/shims/tls.ts +95 -0
  202. package/src/shims/tty.ts +64 -0
  203. package/src/shims/url.ts +171 -0
  204. package/src/shims/util.ts +312 -0
  205. package/src/shims/v8.ts +113 -0
  206. package/src/shims/vfs-adapter.ts +402 -0
  207. package/src/shims/vm.ts +83 -0
  208. package/src/shims/worker_threads.ts +111 -0
  209. package/src/shims/ws.ts +382 -0
  210. package/src/shims/zlib.ts +289 -0
  211. package/src/transform.ts +313 -0
  212. package/src/types/external.d.ts +67 -0
  213. package/src/virtual-fs.ts +903 -0
  214. package/src/vite-demo.ts +577 -0
  215. package/src/worker/runtime-worker.ts +128 -0
  216. package/src/worker-runtime.ts +145 -0
@@ -0,0 +1,577 @@
1
+ /**
2
+ * Vite Demo - Running Vite in the browser using our Node.js shims
3
+ */
4
+
5
+ import { VirtualFS } from './virtual-fs';
6
+ import { Runtime } from './runtime';
7
+ import { PackageManager } from './npm';
8
+ import { ViteDevServer } from './frameworks/vite-dev-server';
9
+ import { getServerBridge } from './server-bridge';
10
+ import { Buffer } from './shims/stream';
11
+
12
+ // Create a simple Vite project in the virtual filesystem
13
+ export function createViteProject(vfs: VirtualFS): void {
14
+ // Create package.json
15
+ vfs.writeFileSync(
16
+ '/package.json',
17
+ JSON.stringify(
18
+ {
19
+ name: 'react-vite-browser-demo',
20
+ version: '1.0.0',
21
+ type: 'module',
22
+ scripts: {
23
+ dev: 'vite',
24
+ build: 'vite build',
25
+ preview: 'vite preview',
26
+ },
27
+ dependencies: {
28
+ react: '^18.2.0',
29
+ 'react-dom': '^18.2.0',
30
+ },
31
+ devDependencies: {
32
+ vite: '^5.0.0',
33
+ '@vitejs/plugin-react': '^4.2.0',
34
+ },
35
+ },
36
+ null,
37
+ 2
38
+ )
39
+ );
40
+
41
+ // Create vite.config.js with React plugin
42
+ vfs.writeFileSync(
43
+ '/vite.config.js',
44
+ `
45
+ import { defineConfig } from 'vite';
46
+ import react from '@vitejs/plugin-react';
47
+
48
+ export default defineConfig({
49
+ root: '/',
50
+ plugins: [react()],
51
+ server: {
52
+ port: 3000,
53
+ strictPort: true,
54
+ },
55
+ build: {
56
+ outDir: 'dist',
57
+ },
58
+ });
59
+ `
60
+ );
61
+
62
+ // Create index.html for React app
63
+ // Note: Use relative paths (./src/) so they work with /__virtual__/port/ URLs
64
+ // Import map resolves bare imports (react, react-dom) to CDN URLs
65
+ // IMPORTANT: Use ?dev to get development builds with DevTools/React Refresh support
66
+ vfs.writeFileSync(
67
+ '/index.html',
68
+ `<!DOCTYPE html>
69
+ <html lang="en">
70
+ <head>
71
+ <meta charset="UTF-8">
72
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
73
+ <title>React + Vite Browser Demo</title>
74
+ <script type="importmap">
75
+ {
76
+ "imports": {
77
+ "react": "https://esm.sh/react@18.2.0?dev",
78
+ "react/": "https://esm.sh/react@18.2.0&dev/",
79
+ "react-dom": "https://esm.sh/react-dom@18.2.0?dev",
80
+ "react-dom/": "https://esm.sh/react-dom@18.2.0&dev/"
81
+ }
82
+ }
83
+ </script>
84
+ </head>
85
+ <body>
86
+ <div id="root"></div>
87
+ <script type="module" src="./src/main.jsx"></script>
88
+ </body>
89
+ </html>
90
+ `
91
+ );
92
+
93
+ // Create src directory and main.jsx
94
+ vfs.mkdirSync('/src', { recursive: true });
95
+ vfs.writeFileSync(
96
+ '/src/main.jsx',
97
+ `
98
+ import React from 'react';
99
+ import ReactDOM from 'react-dom/client';
100
+ import App from './App.jsx';
101
+ import './style.css';
102
+
103
+ ReactDOM.createRoot(document.getElementById('root')).render(
104
+ <React.StrictMode>
105
+ <App />
106
+ </React.StrictMode>
107
+ );
108
+ `
109
+ );
110
+
111
+ // Create App.jsx
112
+ vfs.writeFileSync(
113
+ '/src/App.jsx',
114
+ `
115
+ import React, { useState } from 'react';
116
+ import Counter from './Counter.jsx';
117
+
118
+ function App() {
119
+ const [theme, setTheme] = useState('light');
120
+
121
+ const toggleTheme = () => {
122
+ setTheme(theme === 'light' ? 'dark' : 'light');
123
+ };
124
+
125
+ return (
126
+ <div className={\`app \${theme}\`}>
127
+ <header>
128
+ <h1>⚡ React + Vite in Browser</h1>
129
+ <p>Running with shimmed Node.js APIs</p>
130
+ </header>
131
+
132
+ <main>
133
+ <Counter />
134
+
135
+ <div className="theme-toggle">
136
+ <button onClick={toggleTheme}>
137
+ {theme === 'light' ? '🌙 Dark Mode' : '☀️ Light Mode'}
138
+ </button>
139
+ </div>
140
+
141
+ <div className="info-card">
142
+ <h3>How it works</h3>
143
+ <ul>
144
+ <li>VirtualFS stores all files in memory</li>
145
+ <li>Node.js APIs are shimmed for the browser</li>
146
+ <li>Edit files on the left to see HMR updates</li>
147
+ </ul>
148
+ </div>
149
+ </main>
150
+
151
+ <footer>
152
+ Made with 💜 WebContainers
153
+ </footer>
154
+ </div>
155
+ );
156
+ }
157
+
158
+ export default App;
159
+ `
160
+ );
161
+
162
+ // Create Counter.jsx
163
+ vfs.writeFileSync(
164
+ '/src/Counter.jsx',
165
+ `
166
+ import React, { useState } from 'react';
167
+
168
+ function Counter() {
169
+ const [count, setCount] = useState(0);
170
+
171
+ return (
172
+ <div className="counter-card">
173
+ <h2>Interactive Counter</h2>
174
+ <div className="counter-display">{count}</div>
175
+ <div className="counter-buttons">
176
+ <button onClick={() => setCount(c => c - 1)}>➖</button>
177
+ <button onClick={() => setCount(0)}>Reset</button>
178
+ <button onClick={() => setCount(c => c + 1)}>➕</button>
179
+ </div>
180
+ </div>
181
+ );
182
+ }
183
+
184
+ export default Counter;
185
+ `
186
+ );
187
+
188
+ // Create style.css for React app
189
+ vfs.writeFileSync(
190
+ '/src/style.css',
191
+ `
192
+ * {
193
+ box-sizing: border-box;
194
+ }
195
+
196
+ :root {
197
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
198
+ line-height: 1.5;
199
+ }
200
+
201
+ body {
202
+ margin: 0;
203
+ min-height: 100vh;
204
+ }
205
+
206
+ .app {
207
+ min-height: 100vh;
208
+ display: flex;
209
+ flex-direction: column;
210
+ transition: all 0.3s ease;
211
+ }
212
+
213
+ .app.light {
214
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
215
+ color: white;
216
+ }
217
+
218
+ .app.dark {
219
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
220
+ color: #eee;
221
+ }
222
+
223
+ header {
224
+ text-align: center;
225
+ padding: 2rem;
226
+ }
227
+
228
+ header h1 {
229
+ font-size: 2.5rem;
230
+ margin: 0 0 0.5rem 0;
231
+ }
232
+
233
+ header p {
234
+ opacity: 0.8;
235
+ margin: 0;
236
+ }
237
+
238
+ main {
239
+ flex: 1;
240
+ display: flex;
241
+ flex-direction: column;
242
+ align-items: center;
243
+ gap: 1.5rem;
244
+ padding: 1rem;
245
+ }
246
+
247
+ .counter-card {
248
+ background: rgba(255, 255, 255, 0.15);
249
+ backdrop-filter: blur(10px);
250
+ border-radius: 16px;
251
+ padding: 2rem;
252
+ text-align: center;
253
+ min-width: 280px;
254
+ }
255
+
256
+ .counter-card h2 {
257
+ margin: 0 0 1rem 0;
258
+ }
259
+
260
+ .counter-display {
261
+ font-size: 4rem;
262
+ font-weight: bold;
263
+ margin: 1rem 0;
264
+ }
265
+
266
+ .counter-buttons {
267
+ display: flex;
268
+ gap: 0.5rem;
269
+ justify-content: center;
270
+ }
271
+
272
+ button {
273
+ padding: 0.75rem 1.5rem;
274
+ font-size: 1rem;
275
+ font-weight: 500;
276
+ border: none;
277
+ border-radius: 8px;
278
+ background: rgba(255, 255, 255, 0.2);
279
+ color: inherit;
280
+ cursor: pointer;
281
+ transition: all 0.2s ease;
282
+ }
283
+
284
+ button:hover {
285
+ background: rgba(255, 255, 255, 0.3);
286
+ transform: translateY(-2px);
287
+ }
288
+
289
+ button:active {
290
+ transform: translateY(0);
291
+ }
292
+
293
+ .theme-toggle button {
294
+ background: rgba(0, 0, 0, 0.2);
295
+ }
296
+
297
+ .info-card {
298
+ background: rgba(255, 255, 255, 0.1);
299
+ border-radius: 12px;
300
+ padding: 1.5rem;
301
+ max-width: 400px;
302
+ }
303
+
304
+ .info-card h3 {
305
+ margin: 0 0 1rem 0;
306
+ }
307
+
308
+ .info-card ul {
309
+ margin: 0;
310
+ padding-left: 1.5rem;
311
+ }
312
+
313
+ .info-card li {
314
+ margin: 0.5rem 0;
315
+ opacity: 0.9;
316
+ }
317
+
318
+ footer {
319
+ text-align: center;
320
+ padding: 1.5rem;
321
+ opacity: 0.7;
322
+ }
323
+ `
324
+ );
325
+ }
326
+
327
+ // Initialize the demo
328
+ export async function initViteDemo(
329
+ outputElement: HTMLElement,
330
+ iframeElement: HTMLIFrameElement | null
331
+ ): Promise<{ vfs: VirtualFS; runtime: Runtime; npm: PackageManager }> {
332
+ const log = (message: string) => {
333
+ const line = document.createElement('div');
334
+ line.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
335
+ outputElement.appendChild(line);
336
+ outputElement.scrollTop = outputElement.scrollHeight;
337
+ };
338
+
339
+ log('Creating virtual file system...');
340
+ const vfs = new VirtualFS();
341
+
342
+ log('Creating Vite project structure...');
343
+ createViteProject(vfs);
344
+
345
+ log('Initializing runtime...');
346
+ const runtime = new Runtime(vfs, {
347
+ cwd: '/',
348
+ env: {
349
+ NODE_ENV: 'development',
350
+ },
351
+ onConsole: (method, args) => {
352
+ const prefix = method === 'error' ? '[ERROR]' : method === 'warn' ? '[WARN]' : '';
353
+ log(`${prefix} ${args.map((a) => String(a)).join(' ')}`);
354
+ },
355
+ });
356
+
357
+ // Initialize package manager
358
+ const npm = new PackageManager(vfs, { cwd: '/' });
359
+
360
+ // Set up file watcher demo
361
+ log('Setting up file watcher...');
362
+ vfs.watch('/src', { recursive: true }, (eventType, filename) => {
363
+ log(`File ${eventType}: ${filename}`);
364
+ });
365
+
366
+ log('Vite demo initialized!');
367
+ log('');
368
+ log('Virtual FS contents:');
369
+ listFiles(vfs, '/', log, ' ');
370
+
371
+ return { vfs, runtime, npm };
372
+ }
373
+
374
+ /**
375
+ * Install Vite into the virtual file system
376
+ */
377
+ export async function installVite(
378
+ npm: PackageManager,
379
+ log: (message: string) => void
380
+ ): Promise<void> {
381
+ log('');
382
+ log('=== Installing Vite ===');
383
+ log('This will download Vite and its dependencies from npm...');
384
+
385
+ try {
386
+ const result = await npm.install('vite@5.0.12', {
387
+ onProgress: (msg) => log(` ${msg}`),
388
+ });
389
+
390
+ log(`Installed ${result.added.length} packages`);
391
+ log('Vite installation complete!');
392
+ } catch (error) {
393
+ log(`ERROR installing Vite: ${error}`);
394
+ throw error;
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Try to run Vite's createServer
400
+ */
401
+ export async function runVite(
402
+ runtime: Runtime,
403
+ log: (message: string) => void
404
+ ): Promise<unknown> {
405
+ log('');
406
+ log('=== Starting Vite ===');
407
+
408
+ try {
409
+ // ESM packages are pre-transformed to CJS during npm install
410
+ // Try to require vite
411
+ log('Loading Vite module...');
412
+
413
+ const code = `
414
+ const vite = require('vite');
415
+ console.log('Vite loaded:', typeof vite);
416
+ console.log('Vite exports:', Object.keys(vite));
417
+
418
+ // Try to call createServer
419
+ async function start() {
420
+ try {
421
+ console.log('Creating Vite dev server...');
422
+ const server = await vite.createServer({
423
+ root: '/',
424
+ configFile: false,
425
+ server: {
426
+ port: 3000,
427
+ strictPort: true,
428
+ hmr: false, // Disable HMR for initial test
429
+ },
430
+ logLevel: 'info',
431
+ });
432
+ console.log('Vite server created!');
433
+ return server;
434
+ } catch (err) {
435
+ console.error('Failed to create Vite server:', err.message);
436
+ console.error(err.stack);
437
+ throw err;
438
+ }
439
+ }
440
+
441
+ module.exports = { start };
442
+ `;
443
+
444
+ const { exports } = runtime.execute(code, '/run-vite.js');
445
+ const { start } = exports as { start: () => Promise<unknown> };
446
+
447
+ log('Executing Vite createServer...');
448
+ const server = await start();
449
+ log('Vite server started successfully!');
450
+
451
+ return server;
452
+ } catch (error) {
453
+ log(`ERROR running Vite: ${error}`);
454
+ if (error instanceof Error) {
455
+ log(`Stack: ${error.stack}`);
456
+ }
457
+ throw error;
458
+ }
459
+ }
460
+
461
+ function listFiles(
462
+ vfs: VirtualFS,
463
+ path: string,
464
+ log: (msg: string) => void,
465
+ indent: string
466
+ ): void {
467
+ try {
468
+ const entries = vfs.readdirSync(path);
469
+ for (const entry of entries) {
470
+ const fullPath = path === '/' ? '/' + entry : path + '/' + entry;
471
+ const stats = vfs.statSync(fullPath);
472
+ if (stats.isDirectory()) {
473
+ log(`${indent}📁 ${entry}/`);
474
+ listFiles(vfs, fullPath, log, indent + ' ');
475
+ } else {
476
+ log(`${indent}📄 ${entry}`);
477
+ }
478
+ }
479
+ } catch (e) {
480
+ log(`${indent}Error: ${e}`);
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Start the dev server using Service Worker approach
486
+ * This is the recommended way to run the preview - no npm install required!
487
+ */
488
+ export async function startDevServer(
489
+ vfs: VirtualFS,
490
+ options: {
491
+ port?: number;
492
+ log?: (message: string) => void;
493
+ } = {}
494
+ ): Promise<{
495
+ server: ViteDevServer;
496
+ url: string;
497
+ stop: () => void;
498
+ }> {
499
+ const port = options.port || 3000;
500
+ const log = options.log || console.log;
501
+
502
+ log('Starting dev server...');
503
+
504
+ // Create ViteDevServer
505
+ const server = new ViteDevServer(vfs, { port, root: '/' });
506
+
507
+ // Get the server bridge
508
+ const bridge = getServerBridge();
509
+
510
+ // Initialize Service Worker
511
+ try {
512
+ log('Initializing Service Worker...');
513
+ await bridge.initServiceWorker();
514
+ log('Service Worker ready');
515
+ } catch (error) {
516
+ log(`Warning: Service Worker failed to initialize: ${error}`);
517
+ log('Falling back to direct request handling...');
518
+ }
519
+
520
+ // Register the server with the bridge
521
+ // The bridge will route /__virtual__/{port}/* requests to this server
522
+ bridge.on('server-ready', (p: unknown, u: unknown) => {
523
+ log(`Server ready at ${u}`);
524
+ });
525
+
526
+ // Wire up the ViteDevServer to handle requests through the bridge
527
+ // We need to make the server compatible with the bridge's http.Server interface
528
+ const httpServer = createHttpServerWrapper(server);
529
+ bridge.registerServer(httpServer, port);
530
+
531
+ // Start watching for file changes
532
+ server.start();
533
+ log('File watcher started');
534
+
535
+ // Set up HMR event forwarding
536
+ server.on('hmr-update', (update: unknown) => {
537
+ log(`HMR update: ${JSON.stringify(update)}`);
538
+ });
539
+
540
+ const url = bridge.getServerUrl(port);
541
+ log(`Dev server running at: ${url}/`);
542
+
543
+ return {
544
+ server,
545
+ url: url + '/',
546
+ stop: () => {
547
+ server.stop();
548
+ bridge.unregisterServer(port);
549
+ },
550
+ };
551
+ }
552
+
553
+ /**
554
+ * Create an http.Server-compatible wrapper around ViteDevServer
555
+ */
556
+ function createHttpServerWrapper(devServer: ViteDevServer) {
557
+ return {
558
+ listening: true,
559
+ address: () => ({ port: devServer.getPort(), address: '0.0.0.0', family: 'IPv4' }),
560
+ async handleRequest(
561
+ method: string,
562
+ url: string,
563
+ headers: Record<string, string>,
564
+ body?: string | Buffer
565
+ ) {
566
+ const bodyBuffer = body
567
+ ? typeof body === 'string'
568
+ ? Buffer.from(body)
569
+ : body
570
+ : undefined;
571
+ return devServer.handleRequest(method, url, headers, bodyBuffer);
572
+ },
573
+ };
574
+ }
575
+
576
+ // Export for use in the demo page
577
+ export { VirtualFS, Runtime, PackageManager, ViteDevServer };
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Runtime Worker - Runs the Just Node runtime in a Web Worker
3
+ *
4
+ * This worker receives code execution requests from the main thread
5
+ * and runs them in isolation, preventing UI blocking.
6
+ */
7
+
8
+ import { expose } from 'comlink';
9
+ import { VirtualFS } from '../virtual-fs';
10
+ import { Runtime } from '../runtime';
11
+ import type { VFSSnapshot, IRuntimeOptions, IExecuteResult } from '../runtime-interface';
12
+
13
+ let runtime: Runtime | null = null;
14
+ let vfs: VirtualFS | null = null;
15
+ let consoleCallback: ((method: string, args: unknown[]) => void) | null = null;
16
+
17
+ /**
18
+ * Worker API exposed via Comlink
19
+ */
20
+ const workerApi = {
21
+ /**
22
+ * Initialize the worker with a VFS snapshot and runtime options
23
+ */
24
+ init(vfsSnapshot: VFSSnapshot, options: IRuntimeOptions): void {
25
+ console.log('[Worker] Initializing with', vfsSnapshot.files.length, 'files');
26
+
27
+ // Restore VFS from snapshot
28
+ vfs = VirtualFS.fromSnapshot(vfsSnapshot);
29
+
30
+ // Create runtime with console forwarding
31
+ const runtimeOptions: IRuntimeOptions = {
32
+ ...options,
33
+ onConsole: (method, args) => {
34
+ // Forward console output to main thread
35
+ if (consoleCallback) {
36
+ consoleCallback(method, args);
37
+ }
38
+ },
39
+ };
40
+
41
+ runtime = new Runtime(vfs, runtimeOptions);
42
+ console.log('[Worker] Runtime initialized');
43
+ },
44
+
45
+ /**
46
+ * Set the console callback for forwarding output to main thread
47
+ */
48
+ setConsoleCallback(callback: ((method: string, args: unknown[]) => void) | null): void {
49
+ consoleCallback = callback;
50
+ },
51
+
52
+ /**
53
+ * Sync a file change from the main thread
54
+ */
55
+ syncFile(path: string, content: string | null): void {
56
+ if (!vfs) {
57
+ console.warn('[Worker] VFS not initialized, cannot sync file:', path);
58
+ return;
59
+ }
60
+
61
+ if (content === null) {
62
+ // File was deleted
63
+ try {
64
+ vfs.unlinkSync(path);
65
+ console.log('[Worker] Deleted file:', path);
66
+ } catch (err) {
67
+ // File might not exist, that's ok
68
+ }
69
+ } else {
70
+ // File was created or modified
71
+ vfs.writeFileSync(path, content);
72
+ console.log('[Worker] Synced file:', path);
73
+ }
74
+
75
+ // Clear module cache for this file to pick up changes
76
+ if (runtime) {
77
+ runtime.clearCache();
78
+ }
79
+ },
80
+
81
+ /**
82
+ * Execute code in the worker
83
+ */
84
+ async execute(code: string, filename?: string): Promise<IExecuteResult> {
85
+ if (!runtime) {
86
+ throw new Error('Worker runtime not initialized. Call init() first.');
87
+ }
88
+
89
+ console.log('[Worker] Executing code in file:', filename);
90
+ return runtime.execute(code, filename);
91
+ },
92
+
93
+ /**
94
+ * Run a file from the VFS
95
+ */
96
+ async runFile(filename: string): Promise<IExecuteResult> {
97
+ if (!runtime) {
98
+ throw new Error('Worker runtime not initialized. Call init() first.');
99
+ }
100
+
101
+ console.log('[Worker] Running file:', filename);
102
+ return runtime.runFile(filename);
103
+ },
104
+
105
+ /**
106
+ * Clear the module cache
107
+ */
108
+ clearCache(): void {
109
+ if (runtime) {
110
+ runtime.clearCache();
111
+ console.log('[Worker] Cache cleared');
112
+ }
113
+ },
114
+
115
+ /**
116
+ * Get current VFS state (for debugging)
117
+ */
118
+ getVFSSnapshot(): VFSSnapshot | null {
119
+ if (!vfs) return null;
120
+ return vfs.toSnapshot();
121
+ },
122
+ };
123
+
124
+ // Expose the API via Comlink
125
+ expose(workerApi);
126
+
127
+ // Log that worker is ready
128
+ console.log('[Worker] Runtime worker loaded and ready');