@mantajs/host-nitro 0.2.0-beta.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.
@@ -0,0 +1,30 @@
1
+ export interface BuildOptions {
2
+ /** Working directory */
3
+ cwd: string;
4
+ /** Deployment preset (vercel, node, cloudflare, etc.) */
5
+ preset: string;
6
+ /** Output directory (default: .output) */
7
+ outputDir?: string;
8
+ }
9
+ export interface BuildResult {
10
+ /** Output directory path */
11
+ outputDir: string;
12
+ /** Preset used */
13
+ preset: string;
14
+ }
15
+ /**
16
+ * Build a Manta project for production using Nitro.
17
+ *
18
+ * Runs `nitropack build` with the specified preset. The resulting output
19
+ * includes the compiled server (catch-all route + Manta bootstrap) and
20
+ * any static assets (admin dashboard).
21
+ *
22
+ * ```ts
23
+ * import { buildForProduction } from '@mantajs/host-nitro'
24
+ *
25
+ * await buildForProduction({ cwd: '.', preset: 'node' })
26
+ * // .output/server/index.mjs ready to run
27
+ * ```
28
+ */
29
+ export declare function buildForProduction(options: BuildOptions): Promise<BuildResult>;
30
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAA;IACd,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAmHpF"}
package/dist/build.js ADDED
@@ -0,0 +1,128 @@
1
+ // SPEC-039 — Nitro production build for Manta
2
+ // Delegates to nitropack build (v2) or nitro build (v3 when stable).
3
+ /**
4
+ * Build a Manta project for production using Nitro.
5
+ *
6
+ * Runs `nitropack build` with the specified preset. The resulting output
7
+ * includes the compiled server (catch-all route + Manta bootstrap) and
8
+ * any static assets (admin dashboard).
9
+ *
10
+ * ```ts
11
+ * import { buildForProduction } from '@mantajs/host-nitro'
12
+ *
13
+ * await buildForProduction({ cwd: '.', preset: 'node' })
14
+ * // .output/server/index.mjs ready to run
15
+ * ```
16
+ */
17
+ export async function buildForProduction(options) {
18
+ const { cwd, preset, outputDir = '.output' } = options;
19
+ const { resolve, dirname } = await import('node:path');
20
+ const { execFileSync } = await import('node:child_process');
21
+ const { copyFileSync, mkdirSync, existsSync, writeFileSync } = await import('node:fs');
22
+ const { createRequire } = await import('node:module');
23
+ const { fileURLToPath } = await import('node:url');
24
+ // Copy framework server templates to .manta/server/ BEFORE running Nitro build.
25
+ // In dev mode, dev.ts handles this. In build mode, we must do it here because
26
+ // nitro.config.ts has `srcDir: '.manta/server'` — without these files, Nitro
27
+ // compiles an empty server with no routes and the deploy 404s on everything.
28
+ const __dirname = dirname(fileURLToPath(import.meta.url));
29
+ const templatesDir = resolve(__dirname, '..', 'templates', 'server');
30
+ const targetDir = resolve(cwd, '.manta', 'server');
31
+ const routesDir = resolve(targetDir, 'routes');
32
+ if (!existsSync(targetDir))
33
+ mkdirSync(targetDir, { recursive: true });
34
+ if (!existsSync(routesDir))
35
+ mkdirSync(routesDir, { recursive: true });
36
+ copyFileSync(resolve(templatesDir, 'routes', '[...].ts'), resolve(routesDir, '[...].ts'));
37
+ // Copy manta.config.ts
38
+ const configSrc = resolve(cwd, 'manta.config.ts');
39
+ if (existsSync(configSrc)) {
40
+ copyFileSync(configSrc, resolve(targetDir, 'manta.config.ts'));
41
+ }
42
+ // Generate a PRODUCTION bootstrap that statically imports the manifest.
43
+ // The dev template uses require('./manifest') which DOES NOT WORK in ESM bundles
44
+ // (require is a CommonJS thing, the Nitro bundle is ESM). The prod bootstrap uses
45
+ // a static `import ... from './manifest'` which Nitro/rolldown traces and bundles.
46
+ //
47
+ // If no manifest.ts exists (non-serverless preset), fall back to the dev template.
48
+ const manifestPath = resolve(targetDir, 'manifest.ts');
49
+ if (existsSync(manifestPath)) {
50
+ const deploymentPreset = preset === 'cloudflare' ? 'cloudflare' : preset === 'vercel' ? 'vercel' : '';
51
+ const prodBootstrap = `// @ts-nocheck — Auto-generated PRODUCTION bootstrap (manifest with lazy imports)
52
+ import { bootstrapApp } from '@mantajs/cli/bootstrap'
53
+ import { moduleImports, preloadedResources, preloadedPluginResources } from './manifest'
54
+
55
+ const deploymentPreset = ${JSON.stringify(deploymentPreset)}
56
+ let _bootstrapped: any = null
57
+ let _promise: Promise<any> | null = null
58
+
59
+ async function bootstrap() {
60
+ if (_bootstrapped) return _bootstrapped
61
+ const cwd = typeof process.cwd === 'function' ? process.cwd() : '/'
62
+
63
+ // Cloudflare exposes env during the request lifecycle. Do not read .env from
64
+ // the filesystem or include the load-env module in the Worker bundle.
65
+ ${deploymentPreset === 'cloudflare' ? " const cfEnv = (globalThis as any).__env__ as Record<string, unknown> | undefined\n if (cfEnv) {\n for (const [key, value] of Object.entries(cfEnv)) {\n if (process.env[key] === undefined && ['string', 'number', 'boolean'].includes(typeof value)) {\n process.env[key] = String(value)\n }\n }\n }\n" : " const { loadEnv } = await import('@mantajs/cli/env')\n loadEnv(cwd)\n"}
66
+ if (deploymentPreset) {
67
+ process.env.MANTA_DEPLOY_PRESET = deploymentPreset
68
+ }
69
+
70
+ const mantaConfigModule = await import('./manta.config')
71
+ const rawConfig = mantaConfigModule.default ?? mantaConfigModule
72
+ const config = deploymentPreset && !rawConfig.preset ? { ...rawConfig, preset: deploymentPreset } : rawConfig
73
+
74
+ // Resolve all lazy imports AFTER globals are registered inside bootstrapApp.
75
+ // The lazy imports are () => import('...') functions that only execute when called.
76
+ // bootstrapApp's importFn calls them on demand → user code runs AFTER
77
+ // defineModel/field/etc. are set on globalThis.
78
+ const importFn = async (path: string): Promise<Record<string, unknown>> => {
79
+ const lazyFn = moduleImports[path]
80
+ if (lazyFn) return lazyFn()
81
+ // Fallback: try without/with extension
82
+ const withoutExt = path.replace(/\\.tsx?$/, '')
83
+ for (const [key, fn] of Object.entries(moduleImports)) {
84
+ if (key.replace(/\\.tsx?$/, '') === withoutExt) return fn()
85
+ }
86
+ return {}
87
+ }
88
+
89
+ _bootstrapped = await bootstrapApp({
90
+ config,
91
+ cwd,
92
+ mode: 'dev',
93
+ preloadedResources: preloadedResources as any,
94
+ preloadedPluginResources: preloadedPluginResources as any,
95
+ importFn,
96
+ })
97
+ return _bootstrapped
98
+ }
99
+
100
+ function bootPromise() {
101
+ if (!_promise) _promise = bootstrap()
102
+ return _promise
103
+ }
104
+
105
+ export async function getMantaAdapter() { const { adapter } = await bootPromise(); return adapter }
106
+ export async function getMantaApp() { const { app } = await bootPromise(); return app }
107
+ `;
108
+ writeFileSync(resolve(targetDir, 'manta-bootstrap.ts'), prodBootstrap);
109
+ }
110
+ else {
111
+ // No manifest → use the dev template (jiti-based runtime discovery)
112
+ copyFileSync(resolve(templatesDir, 'manta-bootstrap.ts'), resolve(targetDir, 'manta-bootstrap.ts'));
113
+ }
114
+ const presetArg = preset === 'node' ? 'node-server' : preset === 'cloudflare' ? 'cloudflare_module' : preset;
115
+ const nodeRequire = createRequire(import.meta.url);
116
+ const nitroPkgPath = nodeRequire.resolve('nitro/package.json');
117
+ const nitroCliPath = resolve(dirname(nitroPkgPath), 'dist', 'cli', 'index.mjs');
118
+ execFileSync(process.execPath, [nitroCliPath, 'build', '--preset', presetArg], {
119
+ cwd,
120
+ stdio: 'inherit',
121
+ env: { ...process.env, NODE_ENV: 'production' },
122
+ });
123
+ return {
124
+ outputDir: resolve(cwd, outputDir),
125
+ preset,
126
+ };
127
+ }
128
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,qEAAqE;AAkBrE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAqB;IAC5D,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,OAAO,CAAA;IACtD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;IACtD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAC3D,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;IACtF,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IACrD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAA;IAElD,gFAAgF;IAChF,8EAA8E;IAC9E,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACzD,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAA;IACpE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IAE9C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACrE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAErE,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;IAEzF,uBAAuB;IACvB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAA;IACjD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAA;IAChE,CAAC;IAED,wEAAwE;IACxE,iFAAiF;IACjF,kFAAkF;IAClF,mFAAmF;IACnF,EAAE;IACF,mFAAmF;IACnF,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACtD,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,MAAM,gBAAgB,GAAG,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;QACrG,MAAM,aAAa,GAAG;;;;2BAIC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;;;;;;;;;;EAUzD,gBAAgB,KAAK,YAAY,CAAC,CAAC,CAAC,qUAAqU,CAAC,CAAC,CAAC,0EAA0E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Cvb,CAAA;QACG,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,aAAa,CAAC,CAAA;IACxE,CAAC;SAAM,CAAC;QACN,oEAAoE;QACpE,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAAA;IACrG,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAA;IAC5G,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClD,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAC9D,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAA;IAE/E,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE;QAC7E,GAAG;QACH,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE;KAChD,CAAC,CAAA;IAEF,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC;QAClC,MAAM;KACP,CAAA;AACH,CAAC"}
package/dist/dev.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ export interface SpaEntry {
2
+ /** SPA name (e.g. 'admin', 'vendor') — served on /{name} */
3
+ name: string;
4
+ /** Vite config path for this SPA */
5
+ viteConfigPath: string;
6
+ /** Vite dev server port */
7
+ vitePort: number;
8
+ }
9
+ export interface DevServerOptions {
10
+ /** Working directory */
11
+ cwd: string;
12
+ /** Dev server port */
13
+ port: number;
14
+ /** Vite config path for admin dashboard (starts Vite alongside Nitro) */
15
+ viteConfigPath?: string;
16
+ /** Vite dev server port (default: 5199) */
17
+ vitePort?: number;
18
+ /** V2: SPAs to serve (generalizes viteConfigPath for N SPAs) */
19
+ spas?: SpaEntry[];
20
+ }
21
+ export interface DevServerHandle {
22
+ /** Close the dev server and cleanup */
23
+ close(): Promise<void>;
24
+ /** The port the server is running on */
25
+ port: number;
26
+ }
27
+ /**
28
+ * Start a Nitro dev server programmatically.
29
+ *
30
+ * Copies framework templates to .manta/server/ then starts Nitro.
31
+ * The dev project has NO server/ directory — this is all framework.
32
+ */
33
+ export declare function startDevServer(options: DevServerOptions): Promise<DevServerHandle>;
34
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,QAAQ;IACvB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAA;IACtB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwJxF"}
package/dist/dev.js ADDED
@@ -0,0 +1,215 @@
1
+ // SPEC-039 — Programmatic Nitro dev server for Manta
2
+ // Copies framework-owned server templates to .manta/server/
3
+ // The dev project has NO server/ directory.
4
+ import { copyFileSync, mkdirSync } from 'node:fs';
5
+ import { dirname, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ /**
10
+ * Start a Nitro dev server programmatically.
11
+ *
12
+ * Copies framework templates to .manta/server/ then starts Nitro.
13
+ * The dev project has NO server/ directory — this is all framework.
14
+ */
15
+ export async function startDevServer(options) {
16
+ const { cwd, port, viteConfigPath, vitePort = 5199, spas = [] } = options;
17
+ // Collect all SPA entries (legacy viteConfigPath + V2 spas)
18
+ const allSpas = [...spas];
19
+ if (viteConfigPath && !allSpas.some((s) => s.name === 'admin')) {
20
+ allSpas.push({ name: 'admin', viteConfigPath, vitePort });
21
+ }
22
+ // Start Vite dev servers for each SPA
23
+ // biome-ignore lint/suspicious/noExplicitAny: child process handles
24
+ const viteProcesses = [];
25
+ for (const spa of allSpas) {
26
+ const proc = await startViteDev(cwd, spa.viteConfigPath, spa.vitePort);
27
+ viteProcesses.push(proc);
28
+ }
29
+ // Expose Vite port so the catch-all route handler can proxy SPA fallback in dev
30
+ if (allSpas.length > 0) {
31
+ process.env.__MANTA_VITE_PORT = String(allSpas[0].vitePort);
32
+ }
33
+ // Copy framework server templates to .manta/server/
34
+ copyServerTemplates(cwd);
35
+ // Build devProxy config for all SPAs
36
+ // Each SPA gets: /{name}, /{name}/, /{name}/** proxied to its Vite dev server
37
+ // Vite internals (/@vite, /@fs, /node_modules/.vite) also proxied for HMR
38
+ // ws: true enables WebSocket upgrade proxying (Vite HMR)
39
+ const devProxy = {};
40
+ for (const spa of allSpas) {
41
+ const target = `http://localhost:${spa.vitePort}`;
42
+ devProxy[`/${spa.name}/**`] = { target, ws: true };
43
+ devProxy[`/${spa.name}/`] = { target, ws: true };
44
+ devProxy[`/${spa.name}`] = { target, ws: true };
45
+ }
46
+ if (allSpas.length > 0) {
47
+ const target = `http://localhost:${allSpas[0].vitePort}`;
48
+ devProxy['/@vite/**'] = { target, ws: true };
49
+ devProxy['/@fs/**'] = { target, ws: true };
50
+ devProxy['/node_modules/.vite/**'] = { target, ws: true };
51
+ }
52
+ // Programmatic Nitro v3 dev server
53
+ const { createNitro, createDevServer, prepare, build } = await import('nitro/builder');
54
+ const nitro = await createNitro({
55
+ rootDir: cwd,
56
+ dev: true,
57
+ preset: 'nitro-dev',
58
+ scanDirs: [resolve(cwd, '.manta', 'server')],
59
+ // nitro-dev externalizes node_modules by default. Manta workspace packages
60
+ // intentionally expose TS source during development, so let Nitro bundle
61
+ // them instead of asking Node ESM to load directory-style source exports.
62
+ noExternals: [/@mantajs\//],
63
+ ...(Object.keys(devProxy).length > 0 ? { devProxy } : {}),
64
+ });
65
+ const server = createDevServer(nitro);
66
+ const listener = await server.listen({ port, hostname: 'localhost' });
67
+ // SPA fallback: intercept SPA sub-routes (e.g. /admin/paniers) at the raw HTTP
68
+ // level BEFORE Nitro's serveStatic. Proxy to Vite with Accept: text/html so
69
+ // Vite returns index.html for client-side routing.
70
+ // biome-ignore lint/suspicious/noExplicitAny: listhen internal
71
+ const httpServer = listener?.node?.server;
72
+ if (httpServer && allSpas.length > 0) {
73
+ const spaNames = allSpas.map((s) => s.name);
74
+ const originalListeners = httpServer.listeners('request').slice();
75
+ httpServer.removeAllListeners('request');
76
+ httpServer.on('request', async (req, res) => {
77
+ const url = req.url ?? '';
78
+ const matchedSpa = spaNames.find((name) => url.startsWith(`/${name}/`) || url === `/${name}`);
79
+ // Proxy ALL SPA requests to Vite (HTML pages, .tsx, .js, .css, assets)
80
+ // Only skip /api/* routes which are handled by Nitro
81
+ if (matchedSpa && !url.startsWith('/api/') && req.method === 'GET') {
82
+ const spaVitePort = allSpas.find((s) => s.name === matchedSpa)?.vitePort;
83
+ if (spaVitePort) {
84
+ try {
85
+ const isHtmlRoute = !url.match(/\.\w+(\?|$)/);
86
+ const headers = isHtmlRoute ? { Accept: 'text/html' } : {};
87
+ const viteRes = await fetch(`http://localhost:${spaVitePort}${url}`, { headers });
88
+ if (viteRes.ok) {
89
+ const contentType = viteRes.headers.get('content-type') ?? 'application/octet-stream';
90
+ const body = Buffer.from(await viteRes.arrayBuffer());
91
+ res.writeHead(200, { 'Content-Type': contentType });
92
+ res.end(body);
93
+ return;
94
+ }
95
+ }
96
+ catch {
97
+ // Vite not ready — fall through to Nitro
98
+ }
99
+ }
100
+ }
101
+ // Also proxy Vite internal paths (HMR, source maps, etc.)
102
+ if (url.startsWith('/@vite/') || url.startsWith('/@fs/') || url.startsWith('/node_modules/.vite/')) {
103
+ const spaVitePort = allSpas[0]?.vitePort;
104
+ if (spaVitePort) {
105
+ try {
106
+ const viteRes = await fetch(`http://localhost:${spaVitePort}${url}`);
107
+ if (viteRes.ok) {
108
+ const contentType = viteRes.headers.get('content-type') ?? 'application/javascript';
109
+ const body = Buffer.from(await viteRes.arrayBuffer());
110
+ res.writeHead(200, { 'Content-Type': contentType });
111
+ res.end(body);
112
+ return;
113
+ }
114
+ }
115
+ catch {
116
+ // fall through
117
+ }
118
+ }
119
+ }
120
+ // Fall through to original Nitro handlers
121
+ for (const listener of originalListeners) {
122
+ ;
123
+ listener.call(httpServer, req, res);
124
+ }
125
+ });
126
+ }
127
+ // Nitro's dev server always registers an `upgrade` handler (crossws) that routes
128
+ // WebSocket upgrades to the catch-all route handler — which crashes because our
129
+ // handler is HTTP-only. Replace it with a proper WS proxy to Vite for HMR.
130
+ if (httpServer && allSpas.length > 0) {
131
+ httpServer.removeAllListeners('upgrade');
132
+ const { createProxyServer } = await import('httpxy');
133
+ const wsProxy = createProxyServer({ ws: true });
134
+ wsProxy.on('error', () => { }); // swallow — Vite reconnects
135
+ httpServer.on('upgrade', (req, socket, head) => {
136
+ const spa = allSpas.find((s) => req.url?.startsWith(`/${s.name}`));
137
+ const target = `http://localhost:${(spa ?? allSpas[0]).vitePort}`;
138
+ // httpxy signature: (req, socket, opts, head?) — target goes in opts.
139
+ // Cast socket: Node's http 'upgrade' event yields a Duplex subtype; net.Socket is the expected type.
140
+ wsProxy.ws(req, socket, { target }, head);
141
+ });
142
+ }
143
+ await prepare(nitro);
144
+ await build(nitro);
145
+ return {
146
+ port,
147
+ async close() {
148
+ for (const proc of viteProcesses) {
149
+ if (proc)
150
+ proc.kill();
151
+ }
152
+ await server.close();
153
+ await nitro.close();
154
+ },
155
+ };
156
+ }
157
+ /**
158
+ * Copy framework server templates from packages/host-nitro/templates/ to .manta/server/
159
+ */
160
+ function copyServerTemplates(cwd) {
161
+ const templatesDir = resolve(__dirname, '..', 'templates', 'server');
162
+ const targetDir = resolve(cwd, '.manta', 'server');
163
+ mkdirSync(resolve(targetDir, 'routes'), { recursive: true });
164
+ mkdirSync(resolve(targetDir, 'middleware'), { recursive: true });
165
+ // Copy bootstrap
166
+ copyFileSync(resolve(templatesDir, 'manta-bootstrap.ts'), resolve(targetDir, 'manta-bootstrap.ts'));
167
+ // Copy catch-all route
168
+ copyFileSync(resolve(templatesDir, 'routes', '[...].ts'), resolve(targetDir, 'routes', '[...].ts'));
169
+ // Copy SPA fallback middleware (dev-only: proxies /admin/* to Vite for client-side routing)
170
+ copyFileSync(resolve(templatesDir, 'middleware', 'spa-fallback.ts'), resolve(targetDir, 'middleware', 'spa-fallback.ts'));
171
+ // Copy manta.config.ts so the bootstrap's static import resolves.
172
+ // In dev mode, the manifest doesn't exist → bootstrap falls back to jiti for
173
+ // module loading. But the config import is always static (no jiti needed for config).
174
+ const { existsSync } = require('node:fs');
175
+ const configSrc = resolve(cwd, 'manta.config.ts');
176
+ if (existsSync(configSrc)) {
177
+ copyFileSync(configSrc, resolve(targetDir, 'manta.config.ts'));
178
+ }
179
+ }
180
+ // biome-ignore lint/suspicious/noExplicitAny: child process return
181
+ async function startViteDev(cwd, viteConfigPath, vitePort) {
182
+ const { spawn } = await import('node:child_process');
183
+ console.log(` Starting Vite admin dashboard on port ${vitePort}...`);
184
+ const child = spawn('npx', ['vite', '--config', viteConfigPath, '--port', String(vitePort)], {
185
+ cwd,
186
+ stdio: ['ignore', 'pipe', 'pipe'],
187
+ env: { ...process.env, FORCE_COLOR: '1' },
188
+ });
189
+ child.stdout?.on('data', (data) => {
190
+ const msg = data.toString().trim();
191
+ if (msg)
192
+ console.log(`[vite] ${msg}`);
193
+ });
194
+ child.stderr?.on('data', (data) => {
195
+ const msg = data.toString().trim();
196
+ if (msg && !msg.includes('ExperimentalWarning'))
197
+ console.warn(`[vite] ${msg}`);
198
+ });
199
+ // Wait for Vite to be ready
200
+ for (let i = 0; i < 20; i++) {
201
+ await new Promise((r) => setTimeout(r, 500));
202
+ try {
203
+ const res = await fetch(`http://localhost:${vitePort}/admin/`);
204
+ if (res.ok) {
205
+ console.log(` Admin dashboard: http://localhost:${vitePort}/admin/`);
206
+ break;
207
+ }
208
+ }
209
+ catch {
210
+ /* not ready yet */
211
+ }
212
+ }
213
+ return child;
214
+ }
215
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { type BuildOptions, type BuildResult, buildForProduction } from './build';
2
+ export { type DevServerHandle, type DevServerOptions, startDevServer } from './dev';
3
+ export { type StartHandle, type StartOptions, startProduction } from './start';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AACjF,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AACnF,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // @mantajs/host-nitro — Nitro host integration for Manta
2
+ // Three commands: dev, build, start. That's it.
3
+ export { buildForProduction } from './build';
4
+ export { startDevServer } from './dev';
5
+ export { startProduction } from './start';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,gDAAgD;AAEhD,OAAO,EAAuC,kBAAkB,EAAE,MAAM,SAAS,CAAA;AACjF,OAAO,EAA+C,cAAc,EAAE,MAAM,OAAO,CAAA;AACnF,OAAO,EAAuC,eAAe,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,21 @@
1
+ export interface StartOptions {
2
+ /** Output directory (default: .output) */
3
+ outputDir?: string;
4
+ /** Port override (if supported by the preset) */
5
+ port?: number;
6
+ }
7
+ export interface StartHandle {
8
+ /** Close the production server */
9
+ close(): Promise<void>;
10
+ }
11
+ /**
12
+ * Start a production server from Nitro build output.
13
+ *
14
+ * ```ts
15
+ * import { startProduction } from '@mantajs/host-nitro'
16
+ *
17
+ * await startProduction({ outputDir: '.output' })
18
+ * ```
19
+ */
20
+ export declare function startProduction(options?: StartOptions): Promise<StartHandle>;
21
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CA2BtF"}
package/dist/start.js ADDED
@@ -0,0 +1,36 @@
1
+ // SPEC-039 — Start production Nitro output
2
+ // Runs the compiled .output/server/index.mjs from a Nitro build.
3
+ /**
4
+ * Start a production server from Nitro build output.
5
+ *
6
+ * ```ts
7
+ * import { startProduction } from '@mantajs/host-nitro'
8
+ *
9
+ * await startProduction({ outputDir: '.output' })
10
+ * ```
11
+ */
12
+ export async function startProduction(options = {}) {
13
+ const { outputDir = '.output', port } = options;
14
+ const { resolve } = await import('node:path');
15
+ const { existsSync } = await import('node:fs');
16
+ const { spawn } = await import('node:child_process');
17
+ const entryPath = resolve(outputDir, 'server', 'index.mjs');
18
+ if (!existsSync(entryPath)) {
19
+ throw new Error(`Production build not found at ${entryPath}. Run 'manta build' first.`);
20
+ }
21
+ const env = { ...process.env };
22
+ if (port) {
23
+ env.PORT = String(port);
24
+ env.NITRO_PORT = String(port);
25
+ }
26
+ const child = spawn('node', [entryPath], {
27
+ stdio: 'inherit',
28
+ env,
29
+ });
30
+ return {
31
+ async close() {
32
+ child.kill();
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,iEAAiE;AAcjE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAwB,EAAE;IAC9D,MAAM,EAAE,SAAS,GAAG,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;IAC7C,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;IAC9C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAEpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;IAC3D,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,4BAA4B,CAAC,CAAA;IACzF,CAAC;IAED,MAAM,GAAG,GAA2B,EAAE,GAAI,OAAO,CAAC,GAA8B,EAAE,CAAA;IAClF,IAAI,IAAI,EAAE,CAAC;QACT,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;QACvB,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE;QACvC,KAAK,EAAE,SAAS;QAChB,GAAG;KACJ,CAAC,CAAA;IAEF,OAAO;QACL,KAAK,CAAC,KAAK;YACT,KAAK,CAAC,IAAI,EAAE,CAAA;QACd,CAAC;KACF,CAAA;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@mantajs/host-nitro",
3
+ "version": "0.2.0-beta.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "nitro": "3.0.260311-beta",
16
+ "httpxy": "^0.5.3",
17
+ "jiti": "^2.6.0",
18
+ "vite": "^7.0.0",
19
+ "@vitejs/plugin-react": "^5.2.0"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "templates"
24
+ ]
25
+ }
@@ -0,0 +1,73 @@
1
+ // @ts-nocheck — Template file: deps (@mantajs/cli, jiti) are resolved in the target project
2
+ // Auto-generated by @mantajs/host-nitro — DO NOT EDIT
3
+ //
4
+ // Uses STATIC imports everywhere (bundled by Nitro at build time):
5
+ // - @mantajs/cli subpaths (not the barrel) to avoid pulling in dev tooling
6
+ // - manifest.ts (generated by manta build) with pre-imported user modules
7
+ // - No jiti, no readdirSync, no dynamic import of .ts files
8
+ //
9
+ // This is the serverless-safe bootstrap: all user code is statically traced
10
+ // and bundled by Nitro/rolldown. No filesystem access at runtime.
11
+
12
+ import { bootstrapApp } from '@mantajs/cli/bootstrap'
13
+ import { loadEnv } from '@mantajs/cli/env'
14
+ import mantaConfigModule from './manta.config'
15
+
16
+ // Build-time manifest: pre-discovered resources + pre-imported modules.
17
+ // Generated by `manta build --preset vercel` in packages/cli/src/build/generate-manifest.ts.
18
+ // If the manifest doesn't exist (dev mode), fallback to runtime discovery.
19
+ let manifest: {
20
+ moduleExports: Record<string, unknown>
21
+ preloadedResources: unknown
22
+ preloadedPluginResources: unknown[]
23
+ } | null = null
24
+ try {
25
+ manifest = require('./manifest')
26
+ } catch {
27
+ // Manifest not available (dev mode or non-serverless build) — runtime discovery will be used
28
+ }
29
+
30
+ // biome-ignore lint/suspicious/noExplicitAny: dynamic bootstrap result
31
+ let _bootstrapped: any = null
32
+
33
+ async function bootstrap() {
34
+ if (_bootstrapped) return _bootstrapped
35
+
36
+ const cwd = process.cwd()
37
+ loadEnv(cwd)
38
+
39
+ const config = mantaConfigModule.default ?? mantaConfigModule
40
+
41
+ if (manifest) {
42
+ // Serverless path: use build-time manifest (no filesystem access, no jiti)
43
+ _bootstrapped = await bootstrapApp({
44
+ config,
45
+ cwd,
46
+ mode: 'dev',
47
+ preloadedResources: manifest.preloadedResources as any,
48
+ preloadedImports: manifest.moduleExports as Record<string, Record<string, unknown>>,
49
+ })
50
+ } else {
51
+ // Dev path: use jiti for runtime .ts loading
52
+ const { createJiti } = await import('@mantajs/cli/jiti')
53
+ const jiti = createJiti(cwd)
54
+ // biome-ignore lint/suspicious/noExplicitAny: dynamic module import
55
+ const importFn = (path: string) => jiti.import(path) as Promise<any>
56
+
57
+ _bootstrapped = await bootstrapApp({ config, cwd, mode: 'dev', importFn })
58
+ }
59
+
60
+ return _bootstrapped
61
+ }
62
+
63
+ const _promise = bootstrap()
64
+
65
+ export async function getMantaAdapter() {
66
+ const { adapter } = await _promise
67
+ return adapter
68
+ }
69
+
70
+ export async function getMantaApp() {
71
+ const { app } = await _promise
72
+ return app
73
+ }
@@ -0,0 +1,32 @@
1
+ // SPA fallback middleware — runs BEFORE route handlers.
2
+ // In dev mode, proxies SPA routes (e.g. /admin/paniers) to Vite dev server
3
+ // with Accept: text/html so Vite returns index.html for client-side routing.
4
+
5
+ import { defineEventHandler, setResponseHeader } from '@mantajs/adapter-h3'
6
+
7
+ export default defineEventHandler(async (event) => {
8
+ const pathname = event.path ?? ''
9
+ const vitePort = process.env.__MANTA_VITE_PORT
10
+
11
+ // Only in dev (vitePort set), only GET, only SPA sub-routes (not root, not API, not files)
12
+ if (!vitePort) return
13
+ if (event.method !== 'GET') return
14
+ if (pathname === '/admin' || pathname === '/admin/') return // root is handled by devProxy
15
+ if (!pathname.startsWith('/admin/')) return
16
+ if (pathname.startsWith('/api/')) return
17
+ if (pathname.match(/\.\w{2,5}$/)) return // skip .js, .css, .png etc
18
+
19
+ // Fetch from Vite with Accept: text/html — triggers Vite's SPA fallback
20
+ try {
21
+ const viteRes = await fetch(`http://localhost:${vitePort}${pathname}`, {
22
+ headers: { Accept: 'text/html' },
23
+ })
24
+ if (viteRes.ok) {
25
+ const html = await viteRes.text()
26
+ setResponseHeader(event, 'content-type', 'text/html; charset=utf-8')
27
+ return html
28
+ }
29
+ } catch {
30
+ // Vite not ready yet — fall through
31
+ }
32
+ })
@@ -0,0 +1,45 @@
1
+ // Auto-generated by @mantajs/host-nitro — DO NOT EDIT
2
+ // Catch-all: every request goes through the Manta H3 adapter.
3
+ // SPA fallback: if the adapter returns 404 for a SPA path (e.g. /admin/paniers),
4
+ // fetch index.html from the Vite dev server for client-side routing.
5
+
6
+ import { defineEventHandler, getRequestHeaders, getRequestURL, readRawBody } from '@mantajs/adapter-h3'
7
+ import { getMantaAdapter } from '../manta-bootstrap'
8
+
9
+ export default defineEventHandler(async (event) => {
10
+ const adapter = await getMantaAdapter()
11
+
12
+ const url = getRequestURL(event)
13
+ const method = event.method ?? 'GET'
14
+ const headers = getRequestHeaders(event)
15
+
16
+ let body: Uint8Array | undefined
17
+ if (method !== 'GET' && method !== 'HEAD') {
18
+ body = ((await readRawBody(event, false)) as Uint8Array | undefined) ?? undefined
19
+ }
20
+
21
+ const request = new Request(url.toString(), {
22
+ method,
23
+ headers,
24
+ body: (body || undefined) as BodyInit | undefined,
25
+ })
26
+ const response = await adapter.handleRequest(request)
27
+
28
+ // SPA fallback for dev mode: if the adapter returned 404 for a GET on a SPA path,
29
+ // fetch the SPA index.html from Vite. In prod, Vercel rewrites handle this.
30
+ if (response.status === 404 && method === 'GET') {
31
+ const pathname = url.pathname
32
+ const vitePort = process.env.__MANTA_VITE_PORT
33
+ if (vitePort && pathname.startsWith('/admin') && !pathname.startsWith('/api/') && !pathname.match(/\.\w+$/)) {
34
+ const viteRes = await fetch(`http://localhost:${vitePort}/admin/`)
35
+ if (viteRes.ok) {
36
+ return new Response(viteRes.body, {
37
+ status: 200,
38
+ headers: { 'content-type': 'text/html; charset=utf-8' },
39
+ })
40
+ }
41
+ }
42
+ }
43
+
44
+ return response
45
+ })