Files
CherryHQ-cherry-studio/docs/references/data/cache-schema-guide.md
fullex f60ef2bfd6 docs(cache): rewrite to match current API and add design invariants
Align cache-overview.md and cache-usage.md with the template-key and
subscribe* APIs (sharedCasual was dropped in 3fbc52e05). Extract the
"adding keys" content into a new cache-schema-guide.md aligned with
preference and boot-config schema guides. Lift non-obvious invariants
(isEqual short-circuit, TTL-with-hooks warning, Persist has no delete,
Main-wins convergence, template placeholder rules) into a first-class
Design Invariants section in the overview.

Fix two code-contradicted claims:
- useCache does not accept a TTL options argument (hook signature is
  (key, initValue?)).
- Persist is renderer-authoritative; Main only relays IPC and does
  not store (CacheService.ts:477-479 is "Reserved, not implemented").

Update peripheral references in the same pass so cross-references stay
coherent: v2-renderer skill, CLAUDE.md, architecture-overview.md,
api-design-guidelines.md (Cache vs DataApi matcher contrast), and the
package READMEs.

Net change: +249 / -579.
2026-04-22 22:56:34 -07:00

5.0 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 packages/shared/data/cache/cacheSchemas.ts DefaultUseCache
SharedCacheSchema Shared packages/shared/data/cache/cacheSchemas.ts DefaultSharedCache
RendererPersistCacheSchema Persist packages/shared/data/cache/cacheSchemas.ts DefaultRendererPersistCache

Complex value types go in packages/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

// packages/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)

// packages/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 packages/shared/data/cache/__tests__/templateKey.test.ts
Schema exhaustiveness TypeScript compiler — default map must satisfy the schema type

See Also