1
0

fix: atomic setup transaction, prune devDependencies from runtime image

This commit is contained in:
2026-08-29 18:46:07 +02:00
parent 56ffda9e88
commit b55a1f8cc1
2 changed files with 20 additions and 12 deletions

View File

@@ -13,6 +13,7 @@ RUN npm ci
COPY tsconfig.json vitest.config.ts ./
COPY server ./server
RUN npm run build:server && npm test
RUN npm prune --omit=dev
# ---- runtime stage ----
FROM node:22-slim

View File

@@ -80,18 +80,25 @@ export async function registerAuthRoutes(app: FastifyInstance): Promise<void> {
const { username, password } = (request.body ?? {}) as { username?: string; password?: string }
const invalid = validateCredentials(username, password)
if (invalid) return reply.code(400).send({ error: 'invalid_input', detail: invalid })
let user
try {
user = createUser(request.server.db, username as string, await hashPassword(password as string), true)
} catch (err: any) {
if (String(err.message).includes('UNIQUE constraint failed')) {
return reply.code(403).send({ error: 'setup_already_done' })
}
throw err
}
request.server.db.prepare('INSERT INTO settings (user_id) VALUES (?)').run(user.id)
const token = createSession(request.server.db, user.id)
return reply.setCookie(COOKIE_NAME, token, cookieOpts()).code(200).send({ user: toPublicUser(user) })
const passwordHash = await hashPassword(password as string)
const insertSetup = request.server.db.transaction((): 'taken' | { user: UserRow } => {
const current = (
request.server.db.prepare('SELECT COUNT(*) AS n FROM users').get() as { n: number }
).n
if (current > 0) return 'taken'
const user = createUser(request.server.db, username as string, passwordHash, true)
request.server.db.prepare('INSERT INTO settings (user_id) VALUES (?)').run(user.id)
return { user }
})
const result = insertSetup.immediate()
if (result === 'taken') return reply.code(403).send({ error: 'setup_already_done' })
const token = createSession(request.server.db, result.user.id)
return reply
.setCookie(COOKIE_NAME, token, cookieOpts())
.code(200)
.send({ user: toPublicUser(result.user) })
})
app.post('/api/login', async (request, reply) => {