diff --git a/features/content-strategy/frontend-dev/vite.config.ts b/features/content-strategy/frontend-dev/vite.config.ts index 022816af9..4b08fed9e 100644 --- a/features/content-strategy/frontend-dev/vite.config.ts +++ b/features/content-strategy/frontend-dev/vite.config.ts @@ -14,6 +14,36 @@ const devPort = process.env.VITE_PORT ? parseInt(process.env.VITE_PORT, 10) : 5160; +const contentRoot = path.resolve(__dirname, '../../../../docs/content'); + +const contentServerPlugin = { + name: 'content-server', + configureServer(server: import('vite').ViteDevServer) { + server.middlewares.use((req, res, next) => { + if (!req.url?.startsWith('/api/content/')) return next(); + + const contentPath = decodeURIComponent(req.url.slice('/api/content/'.length)); + const resolved = path.resolve(contentRoot, contentPath); + + if (!resolved.startsWith(contentRoot)) { + res.writeHead(403, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ error: 'forbidden' })); + return; + } + + if (!fs.existsSync(resolved)) { + res.writeHead(404, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ error: 'not_found', path: contentPath })); + return; + } + + const content = fs.readFileSync(resolved, 'utf-8'); + res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); + res.end(content); + }); + }, +}; + const ignoreStyledDtsPlugin = { name: 'ignore-styled-dts', resolveId(source: string) { @@ -65,6 +95,7 @@ const featureAliasPlugin = { export default defineConfig({ plugins: [ featureAliasPlugin, + contentServerPlugin, react(), platformVite({ allowedHosts: ['.local'] }), versionPlugin({ appName: 'Content Strategy' }),