Files
CherryHQ-cherry-studio/docs/references/data/cache-schema-guide.md
fullex 32e8ef273c feat(window-manager): add declarative rememberBounds persistence
Migrate window-bounds persistence off the electron-window-state library into
a WindowManager built-in `rememberBounds` capability, backed by the main-process
persist cache (`window.bounds` key — its first real consumer).

- New `windowBoundsTracker` free-function module: validates the stored record
  (including displayBounds), restores onto the display the window was last on
  (clamping into its work area, never resetting to primary), and snapshots at
  teardown via getNormalBounds + isMaximized.
- Singleton-only gate (dev warning for non-singleton types). Runtime toggle
  `wm.setRememberBounds` (orthogonal to the registry flag; OFF drops only that
  type's slot) plus `wm.peekWindowBounds`.
- Persist at three teardown exits: native close (singletons), before
  window.destroy() in destroyWindow (programmatic destroys), and a new onStop
  so shutdown writes land before CacheService flushes its persist map.
- Wire Main + QuickAssistant. Main re-applies maximize consumer-side on its own
  show schedule (tray-on-launch defers to first show); remove electron-window-state
  and its orphaned keepers/constants/comments.

Fullscreen is not persisted and old *-state.json is not migrated (one-time
reset, loseable). Adds tracker/integration/persist tests, extends the main
CacheService mock with persist methods, and documents the capability plus a
breaking-change note.
2026-06-26 22:39:52 -07:00

5.2 KiB

Cache Schema Guide

How to add fixed and template keys. Aligned with Preference Schema Guide and Boot Config Schema Guide.

Schemas

Schema Tier File Default map
UseCacheSchema Memory src/shared/data/cache/cacheSchemas.ts DefaultUseCache
SharedCacheSchema Shared src/shared/data/cache/cacheSchemas.ts DefaultSharedCache
RendererPersistCacheSchema Persist (Renderer) src/shared/data/cache/cacheSchemas.ts DefaultRendererPersistCache
MainPersistCacheSchema Persist (Main) src/shared/data/cache/cacheSchemas.ts DefaultMainPersistCache

Complex value types go in src/shared/data/cache/cacheValueTypes.ts and are imported via CacheValueTypes.*.

Naming Convention

Enforced by ESLint rule data-schema-key/valid-key. Pattern: /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.

Valid Invalid Why
app.user.avatar userAvatar No dot separator
chat.multi_select_mode chat.multiSelectMode No camelCase
scroll.position.${topicId} scroll.position:${id} Colon not allowed
entity.cache.${type}_${id} App.user No uppercase

Template placeholders ${xxx} are treated as literal segments for the naming check. At runtime, the placeholder name is ignored — ${providerId} and ${foo} produce identical regex; each placeholder expands to [\w\-]+ (no dots, no colons, no non-ASCII).

Choosing Fixed / Template / Casual

Fixed key Template key Casual (Memory only)
Type inference Automatic Automatic Manual generic
Compile-time validation Yes Yes No
Dynamic segments No Yes Yes
Shared tier Yes Yes Not supported
Persist tier Yes Not supported Not supported
Default value Per key Shared across instances None

Prefer Fixed > Template > Casual. Cross-window dynamic keys must be Template — there is no getSharedCasual.

Adding a Fixed Key

1. Add the entry

// src/shared/data/cache/cacheSchemas.ts
export type UseCacheSchema = {
  // ...existing entries
  'feature.my_feature.data': MyDataType
}

export const DefaultUseCache: UseCacheSchema = {
  // ...existing defaults
  'feature.my_feature.data': { items: [], lastUpdated: 0 }
}

2. Define complex value type (if needed)

// src/shared/data/cache/cacheValueTypes.ts
export interface MyDataType {
  items: string[]
  lastUpdated: number
}

3. Use it

const [data, setData] = useCache('feature.my_feature.data')
// data is MyDataType

Adding a Template Key

// cacheSchemas.ts
export type UseCacheSchema = {
  'scroll.position.${topicId}': number
}

export const DefaultUseCache: UseCacheSchema = {
  'scroll.position.${topicId}': 0  // shared by every concrete instance
}

Use with any string in the dynamic segment:

const [pos, setPos] = useCache(`scroll.position.${topicId}`)
// pos is number; default 0 for every topicId that hasn't been written yet

The placeholder name is documentation-only. ${topicId} and ${id} compile to the same runtime matcher. Pick a name that matches the concept (not convention).

Shared and Persist Variants

  • Shared: add to SharedCacheSchema / DefaultSharedCache. Fixed and template both supported.
  • Persist: add to RendererPersistCacheSchema / DefaultRendererPersistCache. Fixed keys only. Persist values survive restart via localStorage — keep them small and typed.

Validation

Check Command / location
ESLint naming rule pnpm lint (rule: data-schema-key/valid-key)
Template matching unit tests src/shared/data/cache/__tests__/templateKey.test.ts
Schema exhaustiveness TypeScript compiler — default map must satisfy the schema type

See Also