aboutsummaryrefslogtreecommitdiff
path: root/persistence/db.ts
blob: d8647b0e0e1412454162fa1f4516f48cdaec0c0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import Dexie, { type Table } from 'dexie'

import type { EventLogEntry } from '@hollowdark/engine/entities/event-log-entry'
import type { FlowEntry } from '@hollowdark/engine/entities/flow-entry'
import type { Institution } from '@hollowdark/engine/entities/institution'
import type { Memoir } from '@hollowdark/engine/entities/memoir'
import type { Person } from '@hollowdark/engine/entities/person'
import type { Place } from '@hollowdark/engine/entities/place'
import type { Relationship } from '@hollowdark/engine/entities/relationship'
import type { Routine } from '@hollowdark/engine/entities/routine'
import type { ScheduledEvent } from '@hollowdark/engine/entities/scheduled-event'
import type { World } from '@hollowdark/engine/entities/world'
import type { WorldEvent } from '@hollowdark/engine/entities/world-event'
import type { JsonValue } from '@hollowdark/utils/types/json'

import {
  AUDIO_CACHE_DB_NAME,
  AUDIO_CACHE_SCHEMA_V1,
  CONTENT_CACHE_DB_NAME,
  CONTENT_CACHE_SCHEMA_V1,
  USER_DATA_DB_NAME,
  USER_DATA_SCHEMA_V1
} from '@hollowdark/persistence/schema'

/**
 * A single key/value pair on the Settings table. Keys are short slugs
 * (e.g., 'audio.masterMuted'); values serialise as JSON.
 */
export interface Setting {
  readonly key: string
  readonly value: JsonValue
}

/** Cached content chunk — the in-memory registry is rebuilt from these on
 *  every session start. */
export interface CachedContentChunk {
  readonly chunkId: string
  readonly version: string
  readonly hash: string
  readonly data: JsonValue
  readonly fetchedAt: string
}

/** Last-seen manifest, stored so the diff-download can decide what to
 *  re-fetch without a second round-trip. */
export interface CachedManifest {
  readonly id: 'latest'
  readonly contentVersion: string
  readonly appVersion: string
  readonly generatedAt: string
  readonly payload: JsonValue
}

/** Cached audio track; mirrors CachedContentChunk but binary-friendly. */
export interface CachedAudioTrack {
  readonly trackId: string
  readonly version: string
  readonly hash: string
  readonly data: Blob
  readonly fetchedAt: string
}

/**
 * User save data — the player's world(s). Persists forever on device,
 * untouched by content updates. Changes to this schema require a
 * migration in `persistence/migrations` (added later).
 */
export class HollowdarkUserData extends Dexie {
  worlds!: Table<World, string>
  people!: Table<Person, string>
  relationships!: Table<Relationship, string>
  institutions!: Table<Institution, string>
  places!: Table<Place, string>
  worldEvents!: Table<WorldEvent, string>
  eventLogs!: Table<EventLogEntry, string>
  memoirs!: Table<Memoir, string>
  routines!: Table<Routine, string>
  flowHistory!: Table<FlowEntry, string>
  scheduledEvents!: Table<ScheduledEvent, string>
  settings!: Table<Setting, string>

  constructor() {
    super(USER_DATA_DB_NAME)
    this.version(1).stores(USER_DATA_SCHEMA_V1)
  }
}

/**
 * Content cache — the compiled JSON chunks the client fetched from the
 * CDN. Independently versioned from user data; can be cleared without
 * touching saves.
 */
export class HollowdarkContentCache extends Dexie {
  content!: Table<CachedContentChunk, string>
  manifest!: Table<CachedManifest, string>

  constructor() {
    super(CONTENT_CACHE_DB_NAME)
    this.version(1).stores(CONTENT_CACHE_SCHEMA_V1)
  }
}

/** Audio cache — decoded later in the AudioEngine; stored as Blobs so the
 *  browser can serve them through `URL.createObjectURL` without re-fetch. */
export class HollowdarkAudioCache extends Dexie {
  audio!: Table<CachedAudioTrack, string>
  manifest!: Table<CachedManifest, string>

  constructor() {
    super(AUDIO_CACHE_DB_NAME)
    this.version(1).stores(AUDIO_CACHE_SCHEMA_V1)
  }
}