@run0/jiki 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.
- package/dist/browser-bundle.d.ts +40 -0
- package/dist/builtins.d.ts +22 -0
- package/dist/code-transform.d.ts +7 -0
- package/dist/config/cdn.d.ts +13 -0
- package/dist/container.d.ts +101 -0
- package/dist/dev-server.d.ts +69 -0
- package/dist/errors.d.ts +19 -0
- package/dist/frameworks/code-transforms.d.ts +32 -0
- package/dist/frameworks/next-api-handler.d.ts +72 -0
- package/dist/frameworks/next-dev-server.d.ts +141 -0
- package/dist/frameworks/next-html-generator.d.ts +36 -0
- package/dist/frameworks/next-route-resolver.d.ts +19 -0
- package/dist/frameworks/next-shims.d.ts +78 -0
- package/dist/frameworks/remix-dev-server.d.ts +47 -0
- package/dist/frameworks/sveltekit-dev-server.d.ts +43 -0
- package/dist/frameworks/vite-dev-server.d.ts +50 -0
- package/dist/fs-errors.d.ts +36 -0
- package/dist/index.cjs +14916 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.mjs +14898 -0
- package/dist/index.mjs.map +1 -0
- package/dist/kernel.d.ts +48 -0
- package/dist/memfs.d.ts +144 -0
- package/dist/metrics.d.ts +78 -0
- package/dist/module-resolver.d.ts +60 -0
- package/dist/network-interceptor.d.ts +71 -0
- package/dist/npm/cache.d.ts +76 -0
- package/dist/npm/index.d.ts +60 -0
- package/dist/npm/lockfile-reader.d.ts +32 -0
- package/dist/npm/pnpm.d.ts +18 -0
- package/dist/npm/registry.d.ts +45 -0
- package/dist/npm/resolver.d.ts +39 -0
- package/dist/npm/sync-installer.d.ts +18 -0
- package/dist/npm/tarball.d.ts +4 -0
- package/dist/npm/workspaces.d.ts +46 -0
- package/dist/persistence.d.ts +94 -0
- package/dist/plugin.d.ts +156 -0
- package/dist/polyfills/assert.d.ts +30 -0
- package/dist/polyfills/child_process.d.ts +116 -0
- package/dist/polyfills/chokidar.d.ts +18 -0
- package/dist/polyfills/crypto.d.ts +49 -0
- package/dist/polyfills/events.d.ts +28 -0
- package/dist/polyfills/fs.d.ts +82 -0
- package/dist/polyfills/http.d.ts +147 -0
- package/dist/polyfills/module.d.ts +29 -0
- package/dist/polyfills/net.d.ts +53 -0
- package/dist/polyfills/os.d.ts +91 -0
- package/dist/polyfills/path.d.ts +96 -0
- package/dist/polyfills/perf_hooks.d.ts +21 -0
- package/dist/polyfills/process.d.ts +99 -0
- package/dist/polyfills/querystring.d.ts +15 -0
- package/dist/polyfills/readdirp.d.ts +18 -0
- package/dist/polyfills/readline.d.ts +32 -0
- package/dist/polyfills/stream.d.ts +106 -0
- package/dist/polyfills/stubs.d.ts +737 -0
- package/dist/polyfills/tty.d.ts +25 -0
- package/dist/polyfills/url.d.ts +41 -0
- package/dist/polyfills/util.d.ts +61 -0
- package/dist/polyfills/v8.d.ts +43 -0
- package/dist/polyfills/vm.d.ts +76 -0
- package/dist/polyfills/worker-threads.d.ts +77 -0
- package/dist/polyfills/ws.d.ts +32 -0
- package/dist/polyfills/zlib.d.ts +87 -0
- package/dist/runtime-helpers.d.ts +4 -0
- package/dist/runtime-interface.d.ts +39 -0
- package/dist/sandbox.d.ts +69 -0
- package/dist/server-bridge.d.ts +55 -0
- package/dist/shell-commands.d.ts +2 -0
- package/dist/shell.d.ts +101 -0
- package/dist/transpiler.d.ts +47 -0
- package/dist/type-checker.d.ts +57 -0
- package/dist/types/package-json.d.ts +17 -0
- package/dist/utils/binary-encoding.d.ts +4 -0
- package/dist/utils/hash.d.ts +6 -0
- package/dist/utils/safe-path.d.ts +6 -0
- package/dist/worker-runtime.d.ts +34 -0
- package/package.json +59 -0
- package/src/browser-bundle.ts +498 -0
- package/src/builtins.ts +222 -0
- package/src/code-transform.ts +183 -0
- package/src/config/cdn.ts +17 -0
- package/src/container.ts +343 -0
- package/src/dev-server.ts +322 -0
- package/src/errors.ts +604 -0
- package/src/frameworks/code-transforms.ts +667 -0
- package/src/frameworks/next-api-handler.ts +366 -0
- package/src/frameworks/next-dev-server.ts +1252 -0
- package/src/frameworks/next-html-generator.ts +585 -0
- package/src/frameworks/next-route-resolver.ts +521 -0
- package/src/frameworks/next-shims.ts +1084 -0
- package/src/frameworks/remix-dev-server.ts +163 -0
- package/src/frameworks/sveltekit-dev-server.ts +197 -0
- package/src/frameworks/vite-dev-server.ts +370 -0
- package/src/fs-errors.ts +118 -0
- package/src/index.ts +188 -0
- package/src/kernel.ts +381 -0
- package/src/memfs.ts +1006 -0
- package/src/metrics.ts +140 -0
- package/src/module-resolver.ts +511 -0
- package/src/network-interceptor.ts +143 -0
- package/src/npm/cache.ts +172 -0
- package/src/npm/index.ts +377 -0
- package/src/npm/lockfile-reader.ts +105 -0
- package/src/npm/pnpm.ts +108 -0
- package/src/npm/registry.ts +120 -0
- package/src/npm/resolver.ts +339 -0
- package/src/npm/sync-installer.ts +217 -0
- package/src/npm/tarball.ts +136 -0
- package/src/npm/workspaces.ts +255 -0
- package/src/persistence.ts +235 -0
- package/src/plugin.ts +293 -0
- package/src/polyfills/assert.ts +164 -0
- package/src/polyfills/child_process.ts +535 -0
- package/src/polyfills/chokidar.ts +52 -0
- package/src/polyfills/crypto.ts +433 -0
- package/src/polyfills/events.ts +178 -0
- package/src/polyfills/fs.ts +297 -0
- package/src/polyfills/http.ts +478 -0
- package/src/polyfills/module.ts +97 -0
- package/src/polyfills/net.ts +123 -0
- package/src/polyfills/os.ts +108 -0
- package/src/polyfills/path.ts +169 -0
- package/src/polyfills/perf_hooks.ts +30 -0
- package/src/polyfills/process.ts +349 -0
- package/src/polyfills/querystring.ts +66 -0
- package/src/polyfills/readdirp.ts +72 -0
- package/src/polyfills/readline.ts +80 -0
- package/src/polyfills/stream.ts +610 -0
- package/src/polyfills/stubs.ts +600 -0
- package/src/polyfills/tty.ts +43 -0
- package/src/polyfills/url.ts +97 -0
- package/src/polyfills/util.ts +173 -0
- package/src/polyfills/v8.ts +62 -0
- package/src/polyfills/vm.ts +111 -0
- package/src/polyfills/worker-threads.ts +189 -0
- package/src/polyfills/ws.ts +73 -0
- package/src/polyfills/zlib.ts +244 -0
- package/src/runtime-helpers.ts +83 -0
- package/src/runtime-interface.ts +46 -0
- package/src/sandbox.ts +178 -0
- package/src/server-bridge.ts +473 -0
- package/src/service-worker.ts +153 -0
- package/src/shell-commands.ts +708 -0
- package/src/shell.ts +795 -0
- package/src/transpiler.ts +282 -0
- package/src/type-checker.ts +241 -0
- package/src/types/package-json.ts +17 -0
- package/src/utils/binary-encoding.ts +38 -0
- package/src/utils/hash.ts +24 -0
- package/src/utils/safe-path.ts +38 -0
- package/src/worker-runtime.ts +42 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite-compatible dev server for jiki.
|
|
3
|
+
*
|
|
4
|
+
* Serves files as ES modules with on-the-fly esbuild-wasm transpilation.
|
|
5
|
+
* Supports React, Vue, Svelte, and any Vite-compatible framework by
|
|
6
|
+
* transforming files before serving.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - ESM-based module serving (no bundling, fast per-module transforms)
|
|
10
|
+
* - `/@modules/<pkg>` for bare import resolution from node_modules
|
|
11
|
+
* - CSS → JS module injection (injects `<style>` tags at runtime)
|
|
12
|
+
* - HMR update emission on file changes
|
|
13
|
+
* - HTML generation with module script tags
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
DevServer,
|
|
18
|
+
type DevServerOptions,
|
|
19
|
+
type ResponseData,
|
|
20
|
+
type HMRUpdate,
|
|
21
|
+
} from "../dev-server";
|
|
22
|
+
import { MemFS } from "../memfs";
|
|
23
|
+
import { BufferImpl as Buffer } from "../polyfills/stream";
|
|
24
|
+
import * as pathShim from "../polyfills/path";
|
|
25
|
+
import { processSource, transformEsmToCjs } from "../code-transform";
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Options
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
export interface ViteDevServerOptions extends DevServerOptions {
|
|
32
|
+
/** Entry HTML file (default: `/index.html`). */
|
|
33
|
+
entry?: string;
|
|
34
|
+
/** Framework preset for transform hints. */
|
|
35
|
+
framework?: "react" | "vue" | "svelte" | "solid" | "vanilla";
|
|
36
|
+
/** JSX import source (default: `react` for react, `solid-js` for solid). */
|
|
37
|
+
jsxImportSource?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// ViteDevServer
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
export class ViteDevServer extends DevServer {
|
|
45
|
+
private entry: string;
|
|
46
|
+
private framework: string;
|
|
47
|
+
private jsxImportSource: string;
|
|
48
|
+
|
|
49
|
+
constructor(vfs: MemFS, options: ViteDevServerOptions) {
|
|
50
|
+
super(vfs, options);
|
|
51
|
+
this.entry = options.entry || "/index.html";
|
|
52
|
+
this.framework = options.framework || "react";
|
|
53
|
+
this.jsxImportSource =
|
|
54
|
+
options.jsxImportSource ||
|
|
55
|
+
(this.framework === "solid" ? "solid-js" : "react");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async handleRequest(
|
|
59
|
+
method: string,
|
|
60
|
+
url: string,
|
|
61
|
+
headers: Record<string, string>,
|
|
62
|
+
body?: Buffer,
|
|
63
|
+
): Promise<ResponseData> {
|
|
64
|
+
if (method === "OPTIONS") return this.handleOptionsRequest();
|
|
65
|
+
|
|
66
|
+
const parsed = new URL(url, "http://localhost");
|
|
67
|
+
const pathname = decodeURIComponent(parsed.pathname);
|
|
68
|
+
|
|
69
|
+
// Serve HMR client
|
|
70
|
+
if (pathname === "/@vite/client") {
|
|
71
|
+
return this.addCorsHeaders(this.serveHmrClient());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Resolve bare imports: /@modules/react → node_modules/react
|
|
75
|
+
if (pathname.startsWith("/@modules/")) {
|
|
76
|
+
const pkgPath = pathname.slice("/@modules/".length);
|
|
77
|
+
return this.addCorsHeaders(await this.serveBareImport(pkgPath));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Serve HTML
|
|
81
|
+
if (pathname === "/" || pathname.endsWith(".html")) {
|
|
82
|
+
const htmlPath =
|
|
83
|
+
pathname === "/" ? this.entry : pathShim.join(this.root, pathname);
|
|
84
|
+
return this.addCorsHeaders(this.serveHtml(htmlPath));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Serve and transform JS/TS/JSX/TSX
|
|
88
|
+
if (this.isTransformable(pathname)) {
|
|
89
|
+
return this.addCorsHeaders(await this.serveTransformed(pathname));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Serve CSS as JS module
|
|
93
|
+
if (pathname.endsWith(".css")) {
|
|
94
|
+
return this.addCorsHeaders(this.serveCssAsModule(pathname));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Serve static files as-is
|
|
98
|
+
return this.addCorsHeaders(this.serveFile(pathname));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
startWatching(): void {
|
|
102
|
+
this.vfs.on("change", (path: string) => {
|
|
103
|
+
if (this.isTransformable(path) || path.endsWith(".css")) {
|
|
104
|
+
this.broadcastChange({
|
|
105
|
+
type: "update",
|
|
106
|
+
path,
|
|
107
|
+
timestamp: Date.now(),
|
|
108
|
+
});
|
|
109
|
+
} else if (path.endsWith(".html")) {
|
|
110
|
+
this.broadcastChange({
|
|
111
|
+
type: "full-reload",
|
|
112
|
+
path,
|
|
113
|
+
timestamp: Date.now(),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// -- HTML serving ---------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
private serveHtml(htmlPath: string): ResponseData {
|
|
122
|
+
const resolved = this.resolvePath(htmlPath);
|
|
123
|
+
try {
|
|
124
|
+
let html = this.vfs.readFileSync(resolved, "utf8");
|
|
125
|
+
// Inject HMR client script
|
|
126
|
+
html = html.replace(
|
|
127
|
+
"</head>",
|
|
128
|
+
`<script type="module" src="/@vite/client"></script>\n</head>`,
|
|
129
|
+
);
|
|
130
|
+
const buf = Buffer.from(html);
|
|
131
|
+
return {
|
|
132
|
+
statusCode: 200,
|
|
133
|
+
statusMessage: "OK",
|
|
134
|
+
headers: {
|
|
135
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
136
|
+
"Content-Length": String(buf.length),
|
|
137
|
+
"Cache-Control": "no-cache",
|
|
138
|
+
},
|
|
139
|
+
body: buf,
|
|
140
|
+
};
|
|
141
|
+
} catch {
|
|
142
|
+
// If no index.html, generate a minimal one
|
|
143
|
+
return this.generateDefaultHtml();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private generateDefaultHtml(): ResponseData {
|
|
148
|
+
const html = `<!DOCTYPE html>
|
|
149
|
+
<html>
|
|
150
|
+
<head>
|
|
151
|
+
<meta charset="utf-8" />
|
|
152
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
153
|
+
<title>Vite App</title>
|
|
154
|
+
<script type="module" src="/@vite/client"></script>
|
|
155
|
+
</head>
|
|
156
|
+
<body>
|
|
157
|
+
<div id="root"></div>
|
|
158
|
+
<div id="app"></div>
|
|
159
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
160
|
+
<script type="module" src="/src/main.ts"></script>
|
|
161
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
162
|
+
<script type="module" src="/src/main.js"></script>
|
|
163
|
+
</body>
|
|
164
|
+
</html>`;
|
|
165
|
+
const buf = Buffer.from(html);
|
|
166
|
+
return {
|
|
167
|
+
statusCode: 200,
|
|
168
|
+
statusMessage: "OK",
|
|
169
|
+
headers: {
|
|
170
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
171
|
+
"Content-Length": String(buf.length),
|
|
172
|
+
"Cache-Control": "no-cache",
|
|
173
|
+
},
|
|
174
|
+
body: buf,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// -- Module transforms ----------------------------------------------------
|
|
179
|
+
|
|
180
|
+
private isTransformable(path: string): boolean {
|
|
181
|
+
return /\.(js|ts|tsx|jsx|mjs|cjs)$/.test(path);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private async serveTransformed(pathname: string): Promise<ResponseData> {
|
|
185
|
+
const filePath = this.resolvePath(pathname);
|
|
186
|
+
try {
|
|
187
|
+
const source = this.vfs.readFileSync(filePath, "utf8");
|
|
188
|
+
let code = this.transformModule(source, filePath);
|
|
189
|
+
// Rewrite bare imports to /@modules/ prefix
|
|
190
|
+
code = this.rewriteBareImports(code);
|
|
191
|
+
// Rewrite relative CSS imports to request path
|
|
192
|
+
code = this.rewriteCssImports(code, pathname);
|
|
193
|
+
|
|
194
|
+
const buf = Buffer.from(code);
|
|
195
|
+
return {
|
|
196
|
+
statusCode: 200,
|
|
197
|
+
statusMessage: "OK",
|
|
198
|
+
headers: {
|
|
199
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
200
|
+
"Content-Length": String(buf.length),
|
|
201
|
+
"Cache-Control": "no-cache",
|
|
202
|
+
},
|
|
203
|
+
body: buf,
|
|
204
|
+
};
|
|
205
|
+
} catch (err) {
|
|
206
|
+
return this.serverError(err);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private transformModule(source: string, filePath: string): string {
|
|
211
|
+
try {
|
|
212
|
+
return processSource(source, filePath);
|
|
213
|
+
} catch {
|
|
214
|
+
// If processSource fails (e.g. transpiler not initialised),
|
|
215
|
+
// return the source with basic ESM-to-CJS conversion
|
|
216
|
+
try {
|
|
217
|
+
return transformEsmToCjs(source, filePath);
|
|
218
|
+
} catch {
|
|
219
|
+
return source;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Rewrite bare import specifiers to /@modules/ URLs.
|
|
226
|
+
* e.g. `import React from "react"` → `import React from "/@modules/react"`
|
|
227
|
+
*/
|
|
228
|
+
private rewriteBareImports(code: string): string {
|
|
229
|
+
// Match: require("pkg"), require("@scope/pkg"), require("pkg/sub")
|
|
230
|
+
return code.replace(
|
|
231
|
+
/require\(["']([^./][^"']*)["']\)/g,
|
|
232
|
+
(match, specifier) => {
|
|
233
|
+
// Skip node: builtins
|
|
234
|
+
if (specifier.startsWith("node:")) return match;
|
|
235
|
+
return `require("/@modules/${specifier}")`;
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Rewrite CSS imports to use absolute paths.
|
|
242
|
+
*/
|
|
243
|
+
private rewriteCssImports(code: string, fromPath: string): string {
|
|
244
|
+
const dir = pathShim.dirname(fromPath);
|
|
245
|
+
return code.replace(
|
|
246
|
+
/require\(["'](\.\.?\/[^"']*\.css)["']\)/g,
|
|
247
|
+
(_match, relPath) => {
|
|
248
|
+
const abs = pathShim.resolve(dir, relPath);
|
|
249
|
+
return `require("${abs}")`;
|
|
250
|
+
},
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// -- CSS as JS module -----------------------------------------------------
|
|
255
|
+
|
|
256
|
+
private serveCssAsModule(pathname: string): ResponseData {
|
|
257
|
+
const filePath = this.resolvePath(pathname);
|
|
258
|
+
try {
|
|
259
|
+
const css = this.vfs.readFileSync(filePath, "utf8");
|
|
260
|
+
// Wrap CSS in a JS module that injects a <style> tag
|
|
261
|
+
const escaped = css
|
|
262
|
+
.replace(/\\/g, "\\\\")
|
|
263
|
+
.replace(/`/g, "\\`")
|
|
264
|
+
.replace(/\$/g, "\\$");
|
|
265
|
+
const code = [
|
|
266
|
+
`const css = \`${escaped}\`;`,
|
|
267
|
+
`if (typeof document !== 'undefined') {`,
|
|
268
|
+
` const style = document.createElement('style');`,
|
|
269
|
+
` style.setAttribute('data-vite-css', '${pathname}');`,
|
|
270
|
+
` style.textContent = css;`,
|
|
271
|
+
` document.head.appendChild(style);`,
|
|
272
|
+
`}`,
|
|
273
|
+
`module.exports = {};`,
|
|
274
|
+
].join("\n");
|
|
275
|
+
|
|
276
|
+
const buf = Buffer.from(code);
|
|
277
|
+
return {
|
|
278
|
+
statusCode: 200,
|
|
279
|
+
statusMessage: "OK",
|
|
280
|
+
headers: {
|
|
281
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
282
|
+
"Content-Length": String(buf.length),
|
|
283
|
+
"Cache-Control": "no-cache",
|
|
284
|
+
},
|
|
285
|
+
body: buf,
|
|
286
|
+
};
|
|
287
|
+
} catch {
|
|
288
|
+
return this.notFound(pathname);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// -- Bare import resolution -----------------------------------------------
|
|
293
|
+
|
|
294
|
+
private async serveBareImport(pkgPath: string): Promise<ResponseData> {
|
|
295
|
+
// Resolve from node_modules
|
|
296
|
+
const nmPath = pathShim.join(this.root, "node_modules", pkgPath);
|
|
297
|
+
|
|
298
|
+
// Check if it's a direct file
|
|
299
|
+
if (this.exists(nmPath) && !this.isDirectory(nmPath)) {
|
|
300
|
+
return this.serveTransformed(`/node_modules/${pkgPath}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Try to resolve via package.json main/module/exports
|
|
304
|
+
const pkgJsonPath = pathShim.join(nmPath, "package.json");
|
|
305
|
+
if (this.exists(pkgJsonPath)) {
|
|
306
|
+
try {
|
|
307
|
+
const pkg = JSON.parse(this.vfs.readFileSync(pkgJsonPath, "utf8"));
|
|
308
|
+
const entry = pkg.module || pkg.main || "index.js";
|
|
309
|
+
const entryPath = pathShim.join(nmPath, entry);
|
|
310
|
+
if (this.exists(entryPath)) {
|
|
311
|
+
return this.serveTransformed(`/node_modules/${pkgPath}/${entry}`);
|
|
312
|
+
}
|
|
313
|
+
} catch {}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Try common index files
|
|
317
|
+
for (const idx of ["index.js", "index.mjs", "index.ts"]) {
|
|
318
|
+
const idxPath = pathShim.join(nmPath, idx);
|
|
319
|
+
if (this.exists(idxPath)) {
|
|
320
|
+
return this.serveTransformed(`/node_modules/${pkgPath}/${idx}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return this.notFound(`/@modules/${pkgPath}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// -- HMR client -----------------------------------------------------------
|
|
328
|
+
|
|
329
|
+
private serveHmrClient(): ResponseData {
|
|
330
|
+
const code = `
|
|
331
|
+
// Minimal Vite HMR client for jiki
|
|
332
|
+
const listeners = new Map();
|
|
333
|
+
|
|
334
|
+
export function createHotContext(ownerPath) {
|
|
335
|
+
return {
|
|
336
|
+
accept(deps, callback) {
|
|
337
|
+
if (typeof deps === 'function') {
|
|
338
|
+
listeners.set(ownerPath, deps);
|
|
339
|
+
} else if (callback) {
|
|
340
|
+
listeners.set(ownerPath, callback);
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
dispose(cb) {},
|
|
344
|
+
prune(cb) {},
|
|
345
|
+
decline() {},
|
|
346
|
+
invalidate() {},
|
|
347
|
+
on(event, cb) {},
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export const hot = createHotContext('/');
|
|
352
|
+
|
|
353
|
+
// import.meta.hot compatibility
|
|
354
|
+
if (typeof window !== 'undefined') {
|
|
355
|
+
window.__vite_hot__ = { createHotContext, listeners };
|
|
356
|
+
}
|
|
357
|
+
`;
|
|
358
|
+
const buf = Buffer.from(code);
|
|
359
|
+
return {
|
|
360
|
+
statusCode: 200,
|
|
361
|
+
statusMessage: "OK",
|
|
362
|
+
headers: {
|
|
363
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
364
|
+
"Content-Length": String(buf.length),
|
|
365
|
+
"Cache-Control": "no-cache",
|
|
366
|
+
},
|
|
367
|
+
body: buf,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
}
|
package/src/fs-errors.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export interface NodeError extends Error {
|
|
2
|
+
code: string;
|
|
3
|
+
errno: number;
|
|
4
|
+
syscall: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ErrorCode =
|
|
9
|
+
| "ENOENT"
|
|
10
|
+
| "ENOTDIR"
|
|
11
|
+
| "EISDIR"
|
|
12
|
+
| "EEXIST"
|
|
13
|
+
| "ENOTEMPTY"
|
|
14
|
+
| "ELOOP"
|
|
15
|
+
| "EINVAL"
|
|
16
|
+
| "EPERM";
|
|
17
|
+
|
|
18
|
+
const ERRORS: Record<string, { errno: number; text: string }> = {
|
|
19
|
+
ENOENT: { errno: -2, text: "no such file or directory" },
|
|
20
|
+
ENOTDIR: { errno: -20, text: "not a directory" },
|
|
21
|
+
EISDIR: { errno: -21, text: "is a directory" },
|
|
22
|
+
EEXIST: { errno: -17, text: "file already exists" },
|
|
23
|
+
ENOTEMPTY: { errno: -39, text: "directory not empty" },
|
|
24
|
+
ELOOP: { errno: -40, text: "too many levels of symbolic links" },
|
|
25
|
+
EINVAL: { errno: -22, text: "invalid argument" },
|
|
26
|
+
EPERM: { errno: -1, text: "operation not permitted" },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function createNodeError(
|
|
30
|
+
code: ErrorCode,
|
|
31
|
+
syscall: string,
|
|
32
|
+
path: string,
|
|
33
|
+
message?: string,
|
|
34
|
+
): NodeError {
|
|
35
|
+
const info = ERRORS[code];
|
|
36
|
+
const e = new Error(
|
|
37
|
+
message || `[${code}] ${syscall}: ${info.text} (${path})`,
|
|
38
|
+
) as NodeError;
|
|
39
|
+
e.code = code;
|
|
40
|
+
e.errno = info.errno;
|
|
41
|
+
e.syscall = syscall;
|
|
42
|
+
e.path = path;
|
|
43
|
+
return e;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface Stats {
|
|
47
|
+
isFile(): boolean;
|
|
48
|
+
isDirectory(): boolean;
|
|
49
|
+
isSymbolicLink(): boolean;
|
|
50
|
+
isBlockDevice(): boolean;
|
|
51
|
+
isCharacterDevice(): boolean;
|
|
52
|
+
isFIFO(): boolean;
|
|
53
|
+
isSocket(): boolean;
|
|
54
|
+
size: number;
|
|
55
|
+
mode: number;
|
|
56
|
+
mtime: Date;
|
|
57
|
+
atime: Date;
|
|
58
|
+
ctime: Date;
|
|
59
|
+
birthtime: Date;
|
|
60
|
+
mtimeMs: number;
|
|
61
|
+
atimeMs: number;
|
|
62
|
+
ctimeMs: number;
|
|
63
|
+
birthtimeMs: number;
|
|
64
|
+
nlink: number;
|
|
65
|
+
uid: number;
|
|
66
|
+
gid: number;
|
|
67
|
+
dev: number;
|
|
68
|
+
ino: number;
|
|
69
|
+
rdev: number;
|
|
70
|
+
blksize: number;
|
|
71
|
+
blocks: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let inoSeq = 1;
|
|
75
|
+
|
|
76
|
+
function modeForType(type: "file" | "directory" | "symlink"): number {
|
|
77
|
+
if (type === "directory") return 0o755;
|
|
78
|
+
if (type === "symlink") return 0o777;
|
|
79
|
+
return 0o644;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function buildStats(
|
|
83
|
+
type: "file" | "directory" | "symlink",
|
|
84
|
+
size: number,
|
|
85
|
+
mtime: number,
|
|
86
|
+
ino?: number,
|
|
87
|
+
): Stats {
|
|
88
|
+
const ts = mtime;
|
|
89
|
+
const id = ino ?? inoSeq++;
|
|
90
|
+
const m = modeForType(type);
|
|
91
|
+
return {
|
|
92
|
+
isFile: () => type === "file",
|
|
93
|
+
isDirectory: () => type === "directory",
|
|
94
|
+
isSymbolicLink: () => type === "symlink",
|
|
95
|
+
isBlockDevice: () => false,
|
|
96
|
+
isCharacterDevice: () => false,
|
|
97
|
+
isFIFO: () => false,
|
|
98
|
+
isSocket: () => false,
|
|
99
|
+
size,
|
|
100
|
+
mode: m,
|
|
101
|
+
mtime: new Date(ts),
|
|
102
|
+
atime: new Date(ts),
|
|
103
|
+
ctime: new Date(ts),
|
|
104
|
+
birthtime: new Date(ts),
|
|
105
|
+
mtimeMs: ts,
|
|
106
|
+
atimeMs: ts,
|
|
107
|
+
ctimeMs: ts,
|
|
108
|
+
birthtimeMs: ts,
|
|
109
|
+
nlink: 1,
|
|
110
|
+
uid: 1000,
|
|
111
|
+
gid: 1000,
|
|
112
|
+
dev: 0,
|
|
113
|
+
ino: id,
|
|
114
|
+
rdev: 0,
|
|
115
|
+
blksize: 4096,
|
|
116
|
+
blocks: Math.ceil(size / 512),
|
|
117
|
+
};
|
|
118
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// jiki - Lightweight browser-based Node.js runtime (MIT)
|
|
2
|
+
|
|
3
|
+
export { MemFS } from "./memfs";
|
|
4
|
+
export { MemFS as VirtualFS } from "./memfs";
|
|
5
|
+
export type {
|
|
6
|
+
FSNode,
|
|
7
|
+
Stats,
|
|
8
|
+
WatchEventType,
|
|
9
|
+
WatchListener,
|
|
10
|
+
FSWatcher,
|
|
11
|
+
NodeError,
|
|
12
|
+
} from "./memfs";
|
|
13
|
+
export { createNodeError } from "./memfs";
|
|
14
|
+
|
|
15
|
+
export { Kernel, Runtime } from "./kernel";
|
|
16
|
+
export type { Module, RuntimeOptions, RequireFunction } from "./kernel";
|
|
17
|
+
export type { AutoInstallProvider } from "./module-resolver";
|
|
18
|
+
export type {
|
|
19
|
+
IRuntime,
|
|
20
|
+
IExecuteResult,
|
|
21
|
+
IRuntimeOptions,
|
|
22
|
+
VFSSnapshot,
|
|
23
|
+
VFSFileEntry,
|
|
24
|
+
} from "./runtime-interface";
|
|
25
|
+
|
|
26
|
+
export { Container, boot, createContainer, registerPlugin } from "./container";
|
|
27
|
+
export type { ContainerOptions, RunResult } from "./container";
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
registerBuiltin,
|
|
31
|
+
registerBuiltins,
|
|
32
|
+
unregisterBuiltin,
|
|
33
|
+
listBuiltins,
|
|
34
|
+
} from "./builtins";
|
|
35
|
+
|
|
36
|
+
export { PluginRegistry } from "./plugin";
|
|
37
|
+
|
|
38
|
+
export { IndexedDBAdapter, InMemoryAdapter } from "./persistence";
|
|
39
|
+
export type {
|
|
40
|
+
PersistenceAdapter,
|
|
41
|
+
PersistedEntry,
|
|
42
|
+
IndexedDBAdapterOptions,
|
|
43
|
+
} from "./persistence";
|
|
44
|
+
export type { MemFSOptions } from "./memfs";
|
|
45
|
+
export type {
|
|
46
|
+
JikiPlugin,
|
|
47
|
+
PluginHooks,
|
|
48
|
+
OnResolveArgs,
|
|
49
|
+
OnResolveResult,
|
|
50
|
+
OnResolveCallback,
|
|
51
|
+
OnLoadArgs,
|
|
52
|
+
OnLoadResult,
|
|
53
|
+
OnLoadCallback,
|
|
54
|
+
OnTransformArgs,
|
|
55
|
+
OnTransformResult,
|
|
56
|
+
OnTransformCallback,
|
|
57
|
+
OnInstallCallback,
|
|
58
|
+
OnBootCallback,
|
|
59
|
+
} from "./plugin";
|
|
60
|
+
|
|
61
|
+
export { PackageManager, NpmLayout } from "./npm/index";
|
|
62
|
+
export type {
|
|
63
|
+
LayoutStrategy,
|
|
64
|
+
InstallOptions,
|
|
65
|
+
InstallResult,
|
|
66
|
+
} from "./npm/index";
|
|
67
|
+
export { PnpmLayout } from "./npm/pnpm";
|
|
68
|
+
|
|
69
|
+
export { PackageCache } from "./npm/cache";
|
|
70
|
+
export type { PackageCacheOptions } from "./npm/cache";
|
|
71
|
+
|
|
72
|
+
export { shouldUseWorker } from "./worker-runtime";
|
|
73
|
+
export type { WorkerMode, WorkerRuntimeConfig } from "./worker-runtime";
|
|
74
|
+
|
|
75
|
+
export { SandboxGuard } from "./sandbox";
|
|
76
|
+
export type {
|
|
77
|
+
SandboxOptions,
|
|
78
|
+
SandboxLimits,
|
|
79
|
+
SandboxNetwork,
|
|
80
|
+
SandboxFs,
|
|
81
|
+
} from "./sandbox";
|
|
82
|
+
|
|
83
|
+
export { Metrics } from "./metrics";
|
|
84
|
+
export type { MetricsSnapshot } from "./metrics";
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
NetworkInterceptor,
|
|
88
|
+
mockResponseToFetchResponse,
|
|
89
|
+
} from "./network-interceptor";
|
|
90
|
+
export type { MockResponse, FetchHandler } from "./network-interceptor";
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
discoverWorkspaces,
|
|
94
|
+
resolveWorkspaceDep,
|
|
95
|
+
isWorkspaceProtocol,
|
|
96
|
+
linkWorkspaces,
|
|
97
|
+
} from "./npm/workspaces";
|
|
98
|
+
export type { WorkspacePackage } from "./npm/workspaces";
|
|
99
|
+
|
|
100
|
+
export { TypeChecker } from "./type-checker";
|
|
101
|
+
export type { Diagnostic, TypeCheckerOptions } from "./type-checker";
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
Worker as WorkerThread,
|
|
105
|
+
MessageChannel,
|
|
106
|
+
MessagePort,
|
|
107
|
+
} from "./polyfills/worker-threads";
|
|
108
|
+
|
|
109
|
+
export { Shell, ShellHistory, createShell } from "./shell";
|
|
110
|
+
export type {
|
|
111
|
+
ShellOptions,
|
|
112
|
+
ShellProcess,
|
|
113
|
+
ShellContext,
|
|
114
|
+
CommandHandler,
|
|
115
|
+
ShellResult,
|
|
116
|
+
} from "./shell";
|
|
117
|
+
|
|
118
|
+
export {
|
|
119
|
+
initTranspiler,
|
|
120
|
+
transpile,
|
|
121
|
+
transpileSync,
|
|
122
|
+
bundle,
|
|
123
|
+
stopTranspiler,
|
|
124
|
+
needsTranspilation,
|
|
125
|
+
setWasmURL,
|
|
126
|
+
hasSyncSupport,
|
|
127
|
+
} from "./transpiler";
|
|
128
|
+
export type {
|
|
129
|
+
TranspileOptions,
|
|
130
|
+
BundleOptions,
|
|
131
|
+
BundleResult,
|
|
132
|
+
InitOptions,
|
|
133
|
+
} from "./transpiler";
|
|
134
|
+
|
|
135
|
+
export { NextDevServer } from "./frameworks/next-dev-server";
|
|
136
|
+
export type { NextDevServerOptions } from "./frameworks/next-dev-server";
|
|
137
|
+
export { ViteDevServer } from "./frameworks/vite-dev-server";
|
|
138
|
+
export type { ViteDevServerOptions } from "./frameworks/vite-dev-server";
|
|
139
|
+
export { SvelteKitDevServer } from "./frameworks/sveltekit-dev-server";
|
|
140
|
+
export type { SvelteKitDevServerOptions } from "./frameworks/sveltekit-dev-server";
|
|
141
|
+
export { RemixDevServer } from "./frameworks/remix-dev-server";
|
|
142
|
+
export type {
|
|
143
|
+
RemixDevServerOptions,
|
|
144
|
+
RemixRoute,
|
|
145
|
+
} from "./frameworks/remix-dev-server";
|
|
146
|
+
export { DevServer } from "./dev-server";
|
|
147
|
+
export type { DevServerOptions, HMRUpdate, ResponseData } from "./dev-server";
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
ServerBridge,
|
|
151
|
+
getServerBridge,
|
|
152
|
+
resetServerBridge,
|
|
153
|
+
} from "./server-bridge";
|
|
154
|
+
export type {
|
|
155
|
+
IVirtualServer,
|
|
156
|
+
VirtualServer,
|
|
157
|
+
BridgeOptions,
|
|
158
|
+
InitServiceWorkerOptions,
|
|
159
|
+
} from "./server-bridge";
|
|
160
|
+
|
|
161
|
+
export {
|
|
162
|
+
setServerListenCallback,
|
|
163
|
+
setServerCloseCallback,
|
|
164
|
+
} from "./polyfills/http";
|
|
165
|
+
|
|
166
|
+
export {
|
|
167
|
+
bundlePackageForBrowser,
|
|
168
|
+
generateRequireScript,
|
|
169
|
+
scanBareImports,
|
|
170
|
+
preprocessImports,
|
|
171
|
+
extractPackageName,
|
|
172
|
+
} from "./browser-bundle";
|
|
173
|
+
export type { BrowserBundle, BundleError } from "./browser-bundle";
|
|
174
|
+
|
|
175
|
+
export {
|
|
176
|
+
parseError,
|
|
177
|
+
formatErrorText,
|
|
178
|
+
formatErrorHtml,
|
|
179
|
+
errorOverlayScript,
|
|
180
|
+
} from "./errors";
|
|
181
|
+
export type { ContainerError, ErrorCategory } from "./errors";
|
|
182
|
+
|
|
183
|
+
export * as pathShim from "./polyfills/path";
|
|
184
|
+
export { EventEmitter } from "./polyfills/events";
|
|
185
|
+
export { createProcess } from "./polyfills/process";
|
|
186
|
+
export type { Process, ProcessEnv } from "./polyfills/process";
|
|
187
|
+
export { createFsShim } from "./polyfills/fs";
|
|
188
|
+
export type { FsShim } from "./polyfills/fs";
|