Add Fastify backend — static serving and save API

This commit is contained in:
otivm
2026-04-25 15:06:51 +00:00
parent b15f288305
commit 6689721a06

71
server/index.js Normal file
View File

@@ -0,0 +1,71 @@
import Fastify from 'fastify'
import fastifyStatic from '@fastify/static'
import { readFile, writeFile, mkdir } from 'fs/promises'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
import { existsSync } from 'fs'
const __dirname = dirname(fileURLToPath(import.meta.url))
const ROOT = join(__dirname, '..')
const DIST = join(ROOT, 'dist')
const SAVES_DIR = join(ROOT, 'data', 'saves')
// Ensure saves directory exists
await mkdir(SAVES_DIR, { recursive: true })
const fastify = Fastify({ logger: false })
// Serve built frontend
await fastify.register(fastifyStatic, {
root: DIST,
prefix: '/',
})
// Load save state
fastify.get('/api/save/:token', async (req, reply) => {
const { token } = req.params
if (!/^[0-9a-f]{8}$/.test(token)) {
return reply.code(400).send({ error: 'Invalid token' })
}
const path = join(SAVES_DIR, `${token}.json`)
if (!existsSync(path)) {
return reply.code(404).send({ error: 'Save not found' })
}
try {
const raw = await readFile(path, 'utf8')
return reply.send(JSON.parse(raw))
} catch {
return reply.code(500).send({ error: 'Failed to read save' })
}
})
// Write save state
fastify.post('/api/save/:token', async (req, reply) => {
const { token } = req.params
if (!/^[0-9a-f]{8}$/.test(token)) {
return reply.code(400).send({ error: 'Invalid token' })
}
if (!req.body || typeof req.body !== 'object') {
return reply.code(400).send({ error: 'Invalid body' })
}
const path = join(SAVES_DIR, `${token}.json`)
try {
await writeFile(path, JSON.stringify(req.body, null, 2), 'utf8')
return reply.send({ ok: true })
} catch {
return reply.code(500).send({ error: 'Failed to write save' })
}
})
// Fallback — serve index.html for client-side routing
fastify.setNotFoundHandler((req, reply) => {
reply.sendFile('index.html')
})
try {
await fastify.listen({ port: 3000, host: '0.0.0.0' })
console.log('OTIVM server running on port 3000')
} catch (err) {
console.error(err)
process.exit(1)
}