Files
Dungeons-Ground/apps/web/server/api/v1/campaigns/[id].get.ts
pavel444-byte 6c39188027
Some checks failed
CI / validate (push) Failing after 3m36s
CI / validate (pull_request) Failing after 11s
feat(gameplay): add versioned SRD rules migration
Co-authored-by: multica-agent <github@multica.ai>
2026-08-26 08:45:50 +05:00

59 lines
3.9 KiB
TypeScript

import { requireCampaignAccess, requireStageTwoUser, stageTwoApiError, stageTwoDatabase, stageTwoUuid } from '~/server/utils/stage-two-supabase'
import { visibleProfile, type ProfileRecord } from '~/server/utils/profile'
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 campaign = access.campaign
const worldId = String(campaign.world_id)
const [worlds, members, characters, openRounds, rounds] = await Promise.all([
stageTwoDatabase<Array<Record<string, unknown>>>(
`worlds?select=id,title,genre,tone,premise,content_boundaries,hook,opening_scene&id=eq.${worldId}&limit=1`,
),
stageTwoDatabase<Array<Record<string, unknown>>>(
`campaign_members?select=id,user_id,role,active,ai_takeover_allowed,joined_at&campaign_id=eq.${campaignId}&order=joined_at.asc`,
),
stageTwoDatabase<Array<Record<string, unknown>>>(
`characters?select=id,campaign_id,user_id,name,concept,controller,abilities,hp,max_hp,defense,proficiency,inventory,statuses,persona,rules_state,created_at&campaign_id=eq.${campaignId}&order=created_at.asc`,
),
stageTwoDatabase<Array<Record<string, unknown>>>(
`rounds?select=id,campaign_id,number,status,forced_by,narration,next_prompt,queued_at,resolved_at,error,created_at&campaign_id=eq.${campaignId}&status=eq.open&order=number.desc&limit=1`,
),
stageTwoDatabase<Array<Record<string, unknown>>>(
`rounds?select=id,campaign_id,number,status,forced_by,narration,next_prompt,queued_at,resolved_at,error,created_at&campaign_id=eq.${campaignId}&order=number.desc&limit=30`,
),
])
const fallbackRounds = openRounds.length ? [] : await stageTwoDatabase<Array<Record<string, unknown>>>(
`rounds?select=id,campaign_id,number,status,forced_by,narration,next_prompt,queued_at,resolved_at,error,created_at&campaign_id=eq.${campaignId}&order=number.desc&limit=1`,
)
const round = openRounds[0] ?? fallbackRounds[0] ?? null
const userIds = [...new Set(members.map(member => String(member.user_id)))]
const profiles = userIds.length
? await stageTwoDatabase<ProfileRecord[]>(
`profiles?select=id,display_name,description,avatar_path,created_at,updated_at&id=in.(${userIds.join(',')})`,
)
: []
const supabaseUrl = useRuntimeConfig().supabaseUrl
const profileById = new Map(profiles.map(profile => [profile.id, visibleProfile(profile, supabaseUrl)]))
const visibleMembers = members.map(member => ({ ...member, profile: profileById.get(String(member.user_id)) ?? null }))
const visibleRounds = rounds.slice().reverse()
const visibleRoundIds = visibleRounds.map(item => String(item.id))
const [intents, events, diceRolls] = await Promise.all([
round ? stageTwoDatabase<Array<Record<string, unknown>>>(
`player_intents?select=id,round_id,member_id,character_id,action,ready,created_at,updated_at&round_id=eq.${String(round.id)}&order=created_at.asc`,
) : Promise.resolve([]),
stageTwoDatabase<Array<Record<string, unknown>>>(
`game_events?select=id,campaign_id,round_id,event_type,payload,created_at&campaign_id=eq.${campaignId}&order=created_at.desc&limit=50`,
),
visibleRoundIds.length ? stageTwoDatabase<Array<Record<string, unknown>>>(
`dice_rolls?select=id,round_id,actor_id,target_id,check_kind,formula,rolls,kept,modifier,total,difficulty,success,created_at&round_id=in.(${visibleRoundIds.join(',')})&order=created_at.asc`,
) : Promise.resolve([]),
])
return { campaign, world: worlds[0] ?? null, members: visibleMembers, characters, round, rounds: visibleRounds, intents, events: events.slice().reverse(), diceRolls }
} catch (error) {
stageTwoApiError(error)
}
})