Splash case picker + playable-mystery list
GET /api/mysteries returns only mysteries with an entrypoint (empties are filtered out), and the splash now lists them as case files with a per-case BEGIN / RESUME action instead of a single hardcoded New Game. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,7 @@ export interface NarrativeRepository {
|
||||
awardAchievement(playthroughId: string, flagKey: string, nodeId?: string | null): Promise<{ ok: boolean; earned: boolean; error?: string }>
|
||||
gotoNode(userId: string, playthroughId: string, nodeId: string): Promise<{ ok: boolean; state?: PlaythroughState; error?: string }>
|
||||
listMysteries(): Promise<MysterySummary[]>
|
||||
listPlayableMysteries(): Promise<{ slug: string; title: string }[]>
|
||||
deleteMystery(id: string): Promise<boolean>
|
||||
uploadAsset(file: UploadedFile): Promise<AssetDto>
|
||||
listAssets(): Promise<AssetDto[]>
|
||||
@@ -304,6 +305,14 @@ export function createNarrativeRepository(pool: Pool, objectStorage: ObjectStora
|
||||
return { ok: true, state: state ?? undefined }
|
||||
},
|
||||
|
||||
// Play mode: only mysteries with an entrypoint are launchable (this filters out
|
||||
// half-authored, empty ones). Returns the minimum the case picker needs.
|
||||
async listPlayableMysteries() {
|
||||
const result = await pool.query<{ slug: string; title: string }>(
|
||||
'SELECT slug,title FROM osint.mysteries WHERE entry_node_id IS NOT NULL ORDER BY title')
|
||||
return result.rows.map(row => ({ slug: row.slug, title: row.title }))
|
||||
},
|
||||
|
||||
async listMysteries() {
|
||||
const result = await pool.query<{ id: string; slug: string; title: string; nodes: string }>(
|
||||
`SELECT m.id,m.slug,m.title,COUNT(n.id)::text AS nodes
|
||||
|
||||
Reference in New Issue
Block a user