mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart theming: custom named themes + Theme Builder
This commit is contained in:
@@ -91,6 +91,19 @@ export function openDB(): Promise<IDBDatabase> {
|
||||
}
|
||||
```
|
||||
|
||||
**Verify the layout, don't trust the version.** An interrupted upgrade can stamp
|
||||
the new version without creating the new stores (observed in dev: a hot reload
|
||||
opened a bumped `DB_VERSION` before the store-creation code for it existed) —
|
||||
after which `onupgradeneeded` never fires again for that version and every
|
||||
transaction on the missing store throws `NotFoundError`, permanently. The real
|
||||
`openDB` therefore checks `db.objectStoreNames` against the expected store list
|
||||
after every successful open and, if anything is missing, closes and reopens at
|
||||
`db.version + 1` to force another (idempotent) upgrade pass. Two consequences:
|
||||
the database **self-heals** instead of being stuck until manually deleted, and
|
||||
the on-disk version may run **ahead of** `DB_VERSION` — so the open also
|
||||
catches `VersionError` and retries without an explicit version. Covered by
|
||||
`db.test.ts` (fake-indexeddb).
|
||||
|
||||
### 2.2 Promise-wrapped CRUD helpers
|
||||
|
||||
Wrap a single IDB request and a whole transaction so callers write linear `async/await` code.
|
||||
@@ -478,5 +491,9 @@ spec §08 "no partial import is committed" contract holds and the user gets an a
|
||||
3. Add the object store in `openDB`'s `onupgradeneeded`, guarded by `contains(...)`; bump `DB_VERSION` only if you changed store _layout_.
|
||||
4. Add a `migrate<Entity>()` function and call it on every read.
|
||||
5. Expose typed `load*/save*/ensure*` functions from one infrastructure module — and from _only_ there.
|
||||
6. If the tier has a budget, hook it into the storage monitor and propagate `QuotaExceededError`.
|
||||
7. Test the adapter against `fake-indexeddb` / a localStorage stub; test the migration with fixtures from each historical version.
|
||||
6. Add the app layer: a Zustand store whose low-level `add`/`update`/`remove` are the single mutation point for the collection, and a diffing **write-through subscriber** in `orchestration/` (the `dataset-persistence.ts` shape: compare the array against the previous snapshot, upsert changed records, delete missing ones, toast on failure).
|
||||
7. Hydrate in `orchestration/startup.ts` and wire the subscriber **after** hydrate — wiring first would re-save every loaded record on each startup.
|
||||
8. If the tier has a budget, hook it into the storage monitor and propagate `QuotaExceededError`.
|
||||
9. Test the adapter against `fake-indexeddb` / a localStorage stub; test the migration with fixtures from each historical version.
|
||||
|
||||
The stack for one entity is four files with fixed roles: `infrastructure/<entity>-store.ts` (typed IDB adapter) + `infrastructure/<entity>-migrations.ts` (read-time upgrade) + `stores/<Entity>Store.ts` (in-memory collection + feature state) + `orchestration/<entity>-persistence.ts` (write-through), joined in `startup.ts`. Snippets, datasets, and custom themes each follow it.
|
||||
|
||||
Reference in New Issue
Block a user