@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.
- package/dist/build.d.ts +30 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +128 -0
- package/dist/build.js.map +1 -0
- package/dist/dev.d.ts +34 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +215 -0
- package/dist/dev.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/start.d.ts +21 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +36 -0
- package/dist/start.js.map +1 -0
- package/package.json +25 -0
- package/templates/server/manta-bootstrap.ts +73 -0
- package/templates/server/middleware/spa-fallback.ts +32 -0
- package/templates/server/routes/[...].ts +45 -0
package/dist/build.d.ts
ADDED
|
@@ -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":"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"}
|
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
|
package/dist/dev.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/start.d.ts
ADDED
|
@@ -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
|
+
})
|