93 lines
5.5 KiB
TypeScript
93 lines
5.5 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, sceneStates, questStates, relationships, memories, storySummaries, auditEntries] = 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([]),
|
|
stageTwoDatabase<Array<Record<string, unknown>>>(
|
|
`scene_states?select=campaign_id,location_id,summary,active_entity_ids,tags,through_round,updated_at&campaign_id=eq.${campaignId}&limit=1`,
|
|
),
|
|
stageTwoDatabase<Array<Record<string, unknown>>>(
|
|
`quest_states?select=campaign_id,quest_entity_id,status,summary,tags,through_round,updated_at&campaign_id=eq.${campaignId}&order=updated_at.desc`,
|
|
),
|
|
stageTwoDatabase<Array<Record<string, unknown>>>(
|
|
`relationships?select=source_entity_id,target_entity_id,score,notes&campaign_id=eq.${campaignId}&order=score.desc&limit=30`,
|
|
),
|
|
stageTwoDatabase<Array<Record<string, unknown>>>(
|
|
`memories?select=id,round_id,summary,importance,tags,entity_ids,created_at&campaign_id=eq.${campaignId}&order=importance.desc,created_at.desc&limit=20`,
|
|
),
|
|
stageTwoDatabase<Array<Record<string, unknown>>>(
|
|
`story_summaries?select=id,through_round,summary,created_at&campaign_id=eq.${campaignId}&order=through_round.desc&limit=1`,
|
|
),
|
|
access.owner ? stageTwoDatabase<Array<Record<string, unknown>>>(
|
|
`audit_entries?select=id,actor_id,action,entity_type,entity_id,before_state,after_state,created_at&campaign_id=eq.${campaignId}&order=created_at.desc&limit=50`,
|
|
) : Promise.resolve([]),
|
|
])
|
|
return {
|
|
campaign,
|
|
world: worlds[0] ?? null,
|
|
members: visibleMembers,
|
|
characters,
|
|
round,
|
|
rounds: visibleRounds,
|
|
intents,
|
|
events: events.slice().reverse(),
|
|
diceRolls,
|
|
sceneState: sceneStates[0] ?? null,
|
|
activeGoals: questStates.filter(quest => quest.status === 'active'),
|
|
relationships,
|
|
memories,
|
|
storySummary: storySummaries[0] ?? null,
|
|
auditEntries,
|
|
}
|
|
} catch (error) {
|
|
stageTwoApiError(error)
|
|
}
|
|
})
|