diff options
| author | Bobby <[email protected]> | 2026-04-22 09:47:33 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-04-22 09:47:33 +0530 |
| commit | 8877f532599011ca02f267863189d4ffe6755955 (patch) | |
| tree | 1d764290084dfc3c629f30d10d9814263b2159ae | |
| parent | ae02de7dd6c402d8cc4923668a1e7c17e152ca36 (diff) | |
| download | hollowdark-8877f532599011ca02f267863189d4ffe6755955.tar.xz hollowdark-8877f532599011ca02f267863189d4ffe6755955.zip | |
Wire the begin-state detector through Dexie via world and people repositories
| -rw-r--r-- | loading/session.ts | 25 | ||||
| -rw-r--r-- | persistence/client.ts | 16 | ||||
| -rw-r--r-- | persistence/people.ts | 14 | ||||
| -rw-r--r-- | persistence/worlds.ts | 21 |
4 files changed, 71 insertions, 5 deletions
diff --git a/loading/session.ts b/loading/session.ts index a1a685b..788f0e6 100644 --- a/loading/session.ts +++ b/loading/session.ts @@ -1,3 +1,6 @@ +import { getPerson } from '@hollowdark/persistence/people' +import { getCurrentWorld } from '@hollowdark/persistence/worlds' + /** * The three states the Begin screen can render. * @@ -16,11 +19,23 @@ export type BeginState = | { readonly kind: 'returning-no-active' } /** - * Inspect device-local state and decide which Begin variant to show. The - * real implementation queries IndexedDB for worlds and the currently - * active player character; while persistence is still being wired up this - * returns `first-ever` unconditionally. + * Inspect device-local state and decide which Begin variant to show. Reads + * the single world record (design invariant) and, when a current player + * character is set, reads their name for the continue prompt. */ export async function detectBeginState(): Promise<BeginState> { - return { kind: 'first-ever' } + const world = await getCurrentWorld() + if (world === null) return { kind: 'first-ever' } + + const activeId = world.currentPlayerCharacterId + if (activeId === null) return { kind: 'returning-no-active' } + + const active = await getPerson(activeId) + if (active === null) return { kind: 'returning-no-active' } + + return { kind: 'returning-active', characterName: displayName(active.name) } +} + +function displayName(name: { given: string; preferredName: string | null }): string { + return name.preferredName ?? name.given } diff --git a/persistence/client.ts b/persistence/client.ts new file mode 100644 index 0000000..7e2468b --- /dev/null +++ b/persistence/client.ts @@ -0,0 +1,16 @@ +import { HollowdarkUserData } from '@hollowdark/persistence/db' + +let userData: HollowdarkUserData | null = null + +/** + * The shared `HollowdarkUserData` Dexie client. Lazily constructed on + * first access so pure unit tests that never touch persistence do not + * open an IndexedDB connection. Repositories should import this helper + * rather than instantiating `HollowdarkUserData` themselves. + */ +export function userDataDb(): HollowdarkUserData { + if (userData === null) { + userData = new HollowdarkUserData() + } + return userData +} diff --git a/persistence/people.ts b/persistence/people.ts new file mode 100644 index 0000000..c26819c --- /dev/null +++ b/persistence/people.ts @@ -0,0 +1,14 @@ +import { userDataDb } from '@hollowdark/persistence/client' +import type { PersonId } from '@hollowdark/engine/entities/base' +import type { Person } from '@hollowdark/engine/entities/person' + +/** Fetch a single person by id, or `null` when the row is missing. */ +export async function getPerson(id: PersonId): Promise<Person | null> { + const row = await userDataDb().people.get(id) + return row ?? null +} + +/** Persist a person record. Replaces any existing row with the same id. */ +export async function savePerson(person: Person): Promise<void> { + await userDataDb().people.put(person) +} diff --git a/persistence/worlds.ts b/persistence/worlds.ts new file mode 100644 index 0000000..0938a84 --- /dev/null +++ b/persistence/worlds.ts @@ -0,0 +1,21 @@ +import { userDataDb } from '@hollowdark/persistence/client' +import type { World } from '@hollowdark/engine/entities/world' + +/** + * The single world a player has on this device, or `null` if they have + * never begun one. Design invariant: one continuous world per player. + * Should the table ever hold more than one row, the earliest-created + * row wins — newer rows would only arise from explicit import. + */ +export async function getCurrentWorld(): Promise<World | null> { + const rows = await userDataDb().worlds.toArray() + if (rows.length === 0) return null + return rows.reduce((earliest, candidate) => + candidate.createdAt < earliest.createdAt ? candidate : earliest + ) +} + +/** Persist a world record. Replaces any existing row with the same id. */ +export async function saveWorld(world: World): Promise<void> { + await userDataDb().worlds.put(world) +} |
