aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-04-22 09:47:33 +0530
committerBobby <[email protected]>2026-04-22 09:47:33 +0530
commit8877f532599011ca02f267863189d4ffe6755955 (patch)
tree1d764290084dfc3c629f30d10d9814263b2159ae
parentae02de7dd6c402d8cc4923668a1e7c17e152ca36 (diff)
downloadhollowdark-8877f532599011ca02f267863189d4ffe6755955.tar.xz
hollowdark-8877f532599011ca02f267863189d4ffe6755955.zip
Wire the begin-state detector through Dexie via world and people repositories
-rw-r--r--loading/session.ts25
-rw-r--r--persistence/client.ts16
-rw-r--r--persistence/people.ts14
-rw-r--r--persistence/worlds.ts21
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)
+}