Eingaben werden mit zod validiert, jede aendernde Aktion schreibt ins Audit-Log. Beim ersten Start entsteht ein Administrator samt Startwerten fuer die Produkterkennung; solange ein Erstpasswort gilt, bleiben schreibende Wege bis auf den Passwortwechsel gesperrt. Nicht-API-Pfade fallen auf die SPA zurueck, damit Deep-Links funktionieren.
33 lines
1.0 KiB
TypeScript
33 lines
1.0 KiB
TypeScript
import type { FastifyRequest } from 'fastify';
|
|
import { z } from 'zod';
|
|
import { badRequest, unauthorized } from '../errors.js';
|
|
import type { ActionContext } from '../services/audit.js';
|
|
|
|
// z.output statt z.input: nur so zaehlen .default()-Werte als gesetzt.
|
|
export function parseWith<S extends z.ZodTypeAny>(schema: S, input: unknown): z.output<S> {
|
|
const result = schema.safeParse(input);
|
|
if (!result.success) {
|
|
const message = result.error.issues
|
|
.map((issue) => {
|
|
const path = issue.path.join('.');
|
|
return path ? `${path}: ${issue.message}` : issue.message;
|
|
})
|
|
.join('; ');
|
|
throw badRequest('VALIDATION_FAILED', message);
|
|
}
|
|
return result.data;
|
|
}
|
|
|
|
export function contextOf(request: FastifyRequest): ActionContext {
|
|
if (!request.user) throw unauthorized();
|
|
return {
|
|
actorId: request.user.id,
|
|
actorName: request.user.username,
|
|
ip: request.ip,
|
|
};
|
|
}
|
|
|
|
export const idParam = z.object({ id: z.coerce.number().int().positive() });
|
|
|
|
export const optionalNote = z.string().trim().max(500).optional();
|