import { AbilityScoresSchema } from '@dng/shared' import { z } from 'zod' import { requireCampaignAccess, requireStageTwoSafeText, requireStageTwoUser, stageTwoApiError, stageTwoDatabase, stageTwoUuid } from '~/server/utils/stage-two-supabase' const BodySchema = z.object({ name: z.string().trim().min(1).max(80), concept: z.string().trim().min(3).max(600), controller: z.enum(['human', 'ai']).default('human'), abilities: AbilityScoresSchema, hp: z.number().int().min(0), maxHp: z.number().int().min(1), defense: z.number().int().min(1).max(40), proficiency: z.number().int().min(1).max(10).default(2), inventory: z.array(z.string().trim().min(1).max(120)).max(50).default([]), statuses: z.array(z.string().trim().min(1).max(80)).max(12).default([]), persona: z.record(z.string(), z.unknown()).default({}), }).strict().refine(value => value.hp <= value.maxHp, { message: 'hp must not exceed maxHp', path: ['hp'] }) export default defineEventHandler(async (event) => { try { const user = await requireStageTwoUser(event) const campaignId = stageTwoUuid(getRouterParam(event, 'id'), 'campaign id') const access = await requireCampaignAccess(campaignId, user.id) const body = BodySchema.parse(await readBody(event)) if (body.controller === 'ai' && !access.owner) { throw createError({ statusCode: 403, statusMessage: 'Only the campaign owner can add AI heroes.' }) } requireStageTwoSafeText([body.name, body.concept, ...body.inventory, ...body.statuses, JSON.stringify(body.persona)].join('\n')) const rows = await stageTwoDatabase>>('characters', { method: 'POST', prefer: 'return=representation', body: JSON.stringify({ campaign_id: campaignId, user_id: body.controller === 'human' ? user.id : null, name: body.name, concept: body.concept, controller: body.controller, abilities: body.abilities, hp: body.hp, max_hp: body.maxHp, defense: body.defense, proficiency: body.proficiency, inventory: body.inventory, statuses: body.statuses, persona: body.persona, }), }) setResponseStatus(event, 201) return { character: rows[0] } } catch (error) { stageTwoApiError(error) } })