diff --git a/packages/cli/package.json b/packages/cli/package.json index 2084850..d110a64 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@mobile-reality/mdma-cli", - "version": "0.1.0", + "version": "0.1.3", "type": "module", "bin": { "mdma": "./dist/bin/mdma.js" diff --git a/packages/cli/src/server/dev-server.ts b/packages/cli/src/server/dev-server.ts index 3e7c2b2..4e04449 100644 --- a/packages/cli/src/server/dev-server.ts +++ b/packages/cli/src/server/dev-server.ts @@ -1,21 +1,61 @@ -import { createServer } from 'vite'; +import { createServer as createHttpServer } from 'node:http'; +import { readFile } from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import path from 'node:path'; +import open from 'open'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const MIME_TYPES: Record = { + '.html': 'text/html', + '.js': 'application/javascript', + '.css': 'text/css', + '.json': 'application/json', + '.png': 'image/png', + '.svg': 'image/svg+xml', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2': 'font/woff2', +}; + export async function startDevServer(port: number): Promise { - const appRoot = path.resolve(__dirname, '../../app'); - - const server = await createServer({ - root: appRoot, - configFile: path.resolve(appRoot, 'vite.config.ts'), - server: { - port, - open: true, - }, + const appRoot = path.resolve(__dirname, '../../app-dist'); + + const server = createHttpServer(async (req, res) => { + let urlPath = req.url?.split('?')[0] ?? '/'; + if (urlPath === '/') urlPath = '/index.html'; + + const filePath = path.join(appRoot, urlPath); + + // Prevent path traversal + if (!filePath.startsWith(appRoot + path.sep)) { + res.writeHead(403); + res.end('Forbidden'); + return; + } + + try { + const data = await readFile(filePath); + const ext = path.extname(filePath); + res.writeHead(200, { 'Content-Type': MIME_TYPES[ext] || 'application/octet-stream' }); + res.end(data); + } catch { + // SPA fallback — serve index.html for unknown routes + try { + const index = await readFile(path.join(appRoot, 'index.html')); + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(index); + } catch { + res.writeHead(404); + res.end('Not found'); + } + } }); - await server.listen(); - server.printUrls(); + await new Promise((resolve) => { + server.listen(port, () => { + open(`http://localhost:${port}`); + resolve(); + }); + }); }