Use built-in static server for Mosaic

This commit is contained in:
kbanc85 2026-03-05 15:17:39 -05:00
parent 399bc04688
commit 5f1ba2938c
5 changed files with 125 additions and 681 deletions

698
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
"dev": "next dev",
"prebuild": "tsx scripts/validate-claims.ts && tsx scripts/generate-sitemap.ts && tsx scripts/generate-rss.ts && tsx scripts/generate-llms-txt.ts && tsx scripts/generate-claims-api.ts && tsx scripts/generate-page-markdown.ts",
"build": "next build",
"start": "serve -s out -l 3000",
"start": "node server.js",
"lint": "next lint",
"add-claim-from-json": "tsx scripts/add-claim-to-data.ts",
"check-new-articles": "tsx scripts/check-new-articles.ts",
@ -47,7 +47,6 @@
"next": "^15.5.12",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"serve": "^14.2.5",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"three": "^0.183.1"

View File

@ -1,7 +1,7 @@
{
"totalArticles": 83,
"totalClaims": 415,
"lastUpdated": "2026-03-05T20:14:36.933Z",
"lastUpdated": "2026-03-05T20:17:13.100Z",
"latestArticleDate": "2026-02-14",
"topics": [
"business",

View File

@ -5,7 +5,7 @@
<link>https://kbanc.com</link>
<description>Evidence-based claims about AI implementation, optimized for LLM extraction and research citation.</description>
<language>en-us</language>
<lastBuildDate>Thu, 05 Mar 2026 20:14:36 GMT</lastBuildDate>
<lastBuildDate>Thu, 05 Mar 2026 20:17:12 GMT</lastBuildDate>
<atom:link href="https://kbanc.com/feed.xml" rel="self" type="application/rss+xml"/>
<item>

101
server.js Normal file
View File

@ -0,0 +1,101 @@
const http = require('http')
const fs = require('fs')
const path = require('path')
const port = Number(process.env.PORT || 3000)
const outDir = path.join(__dirname, 'out')
const contentTypes = {
'.css': 'text/css; charset=utf-8',
'.gif': 'image/gif',
'.html': 'text/html; charset=utf-8',
'.ico': 'image/x-icon',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.js': 'application/javascript; charset=utf-8',
'.json': 'application/json; charset=utf-8',
'.md': 'text/markdown; charset=utf-8',
'.png': 'image/png',
'.svg': 'image/svg+xml',
'.txt': 'text/plain; charset=utf-8',
'.webp': 'image/webp',
'.woff2': 'font/woff2',
'.xml': 'application/xml; charset=utf-8',
}
const safeDecode = (value) => {
try {
return decodeURIComponent(value)
} catch {
return value
}
}
const withinOutDir = (filePath) => {
const relativePath = path.relative(outDir, filePath)
return relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath)
}
const findFile = (requestPath) => {
const normalizedPath = safeDecode(requestPath).replace(/\/+$/, '') || '/'
const relativePath = normalizedPath === '/' ? 'index.html' : normalizedPath.replace(/^\/+/, '')
const hasExtension = path.extname(relativePath) !== ''
const candidates = hasExtension
? [path.join(outDir, relativePath)]
: [
path.join(outDir, `${relativePath}.html`),
path.join(outDir, relativePath, 'index.html'),
path.join(outDir, relativePath),
]
for (const candidate of candidates) {
if (!withinOutDir(candidate)) {
continue
}
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
return candidate
}
}
return null
}
const server = http.createServer((req, res) => {
if (!req.url) {
res.writeHead(400)
res.end('Bad Request')
return
}
const requestUrl = new URL(req.url, `http://${req.headers.host || 'localhost'}`)
const filePath = findFile(requestUrl.pathname)
const resolvedPath = filePath || path.join(outDir, '404.html')
const extension = path.extname(resolvedPath).toLowerCase()
const contentType = contentTypes[extension] || 'application/octet-stream'
fs.readFile(resolvedPath, (error, contents) => {
if (error) {
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end('Internal Server Error')
return
}
res.writeHead(filePath ? 200 : 404, {
'Content-Type': contentType,
'Cache-Control': extension === '.html' ? 'no-cache' : 'public, max-age=31536000, immutable',
})
if (req.method === 'HEAD') {
res.end()
return
}
res.end(contents)
})
})
server.listen(port, () => {
console.log(`Static site server running on http://localhost:${port}`)
})