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 tsconfig.json vitest.config.ts ./
COPY server ./server COPY server ./server
RUN npm run build:server && npm test RUN npm run build:server && npm test
RUN npm prune --omit=dev
# ---- runtime stage ---- # ---- runtime stage ----
FROM node:22-slim 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 { username, password } = (request.body ?? {}) as { username?: string; password?: string }
const invalid = validateCredentials(username, password) const invalid = validateCredentials(username, password)
if (invalid) return reply.code(400).send({ error: 'invalid_input', detail: invalid }) if (invalid) return reply.code(400).send({ error: 'invalid_input', detail: invalid })
let user const passwordHash = await hashPassword(password as string)
try {
user = createUser(request.server.db, username as string, await hashPassword(password as string), true) const insertSetup = request.server.db.transaction((): 'taken' | { user: UserRow } => {
} catch (err: any) { const current = (
if (String(err.message).includes('UNIQUE constraint failed')) { request.server.db.prepare('SELECT COUNT(*) AS n FROM users').get() as { n: number }
return reply.code(403).send({ error: 'setup_already_done' }) ).n
} if (current > 0) return 'taken'
throw err const user = createUser(request.server.db, username as string, passwordHash, true)
}
request.server.db.prepare('INSERT INTO settings (user_id) VALUES (?)').run(user.id) request.server.db.prepare('INSERT INTO settings (user_id) VALUES (?)').run(user.id)
const token = createSession(request.server.db, user.id) return { user }
return reply.setCookie(COOKIE_NAME, token, cookieOpts()).code(200).send({ user: toPublicUser(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) => { app.post('/api/login', async (request, reply) => {