mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-08 16:43:59 +08:00
Move all renderer source from src/renderer/src/* up one level to
src/renderer/*, removing the redundant nested src directory.
- Update path aliases (@renderer, @types, @logger, @data) and TanStack
Router paths in electron.vite.config.ts; update tsconfig.{json,web,node}
path mappings and include globs.
- Fix Vite root-relative script paths in the 8 renderer HTML entries.
- Update cross-process relative imports in main/preload (language,
apiServer models, preload index) to drop the /src segment.
- Switch renderer test imports of the logger mock to the @test-mocks alias.
- Update hardcoded renderer paths in scripts and their fixtures, lint
configs (eslint/oxlint/biome), CODEOWNERS, docs, and the data-classify tool.
- Convert deep (../../+) relative imports within the renderer to the
@renderer alias (69 files, 108 imports); keep single-level relatives.
- Fix doc links broken by the move and correct one pre-existing broken
link in naming-conventions.md.
8.6 KiB
8.6 KiB
Cache System Overview
Three-tier cache for regenerable data. In-process memory, cross-window shared state, and localStorage-backed persistence.
Scope
Use Cache for data that:
- Can be regenerated or lost without user impact
- Needs no backup or cross-device sync
- Has lifecycle tied to a component, window, or app session
For user settings use Preference; for business data use DataApi.
Tiers
| Tier | Scope | Survives restart | Authority | Use for |
|---|---|---|---|---|
| Memory | Per-process | No | Local to each process | Computed results, API responses |
| Shared | All renderer windows + Main | No | Main (relays + conflict sink) | Cross-window UI state |
| Persist | All renderer windows | Yes (localStorage) | Each renderer (Main relays only) | Recent items, non-critical UI state |
Persist is renderer-only on disk — src/main/data/CacheService.ts:477-479 reserves the interface but does not implement storage; Main only forwards CacheSyncMessage { type: 'persist' } to peers.
Key Types
| Type | Example schema | Call site | Tiers |
|---|---|---|---|
| Fixed | 'app.user.avatar': string |
get('app.user.avatar') |
Memory / Shared / Persist |
| Template | 'scroll.position.${topicId}': number |
get('scroll.position.t42') |
Memory / Shared |
| Casual | (none — type argument only) | getCasual<T>('my.dynamic.key') |
Memory only |
Template keys share one default value across all instances — all web_search.provider.last_used_key.* fall back to ''. Casual keys are blocked at compile time from matching any schema pattern (UseCacheCasualKey in src/shared/data/cache/cacheSchemas.ts:393).
Design Invariants
Non-obvious rules the code enforces; assume them when designing consumers.
- Same-value write is a no-op. Equality via
lodash.isEqual. No broadcast, no subscriber fire, no hook re-render. (src/main/data/CacheService.tsisEqualguards beforebroadcastSync/ notifier) - TTL-only refresh does not fire subscribers. Updating
expireAton the same value is silent. - Subscribers fire only on explicit writes. Lazy TTL cleanup, the 10-min GC sweep, and
onStopdo not fire. - Hooks + TTL is discouraged.
useCache/useSharedCachelog a warn when the key has TTL (src/renderer/data/hooks/useCache.ts:186-192,289-295) — values can expire between renders. - Hooks pin cache entries.
registerHook/unregisterHookrefcount keys;delete/deleteSharedreturnfalsewhile any hook is active. - Persist has no delete. Persist keys are fixed by schema; the API exposes only
getPersist/setPersist/hasPersist. - TTL uses absolute
expireAt(Unix ms). Every process expires the same entry at the same instant, regardless of clock skew in IPC delivery. - Main-wins convergence. All cross-window shared writes are serialized through Main; on window init, Main-priority override applies to conflicts with the renderer's pre-sync copy.
- Re-entrant callbacks are safe. Subscribers may write back into the same key; the
isEqualshort-circuit terminates loops once the value stabilizes. Callback errors are caught and logged without skipping other subscribers. - Template placeholders are runtime-anonymous.
${providerId}and${foo}match identical concrete keys. Dynamic segments match[\w\-]+only — dots, colons, and non-ASCII are rejected (src/shared/data/cache/templateKey.ts:35-46).
Architecture
┌─────────────────────── Renderer Process ──────────────────────┐
│ useCache / useSharedCache / usePersistCache │
│ │ │
│ ▼ │
│ CacheService (Renderer) │
│ - Memory cache (local) │
│ - Shared cache (local copy; init-synced from Main) │
│ - Persist cache (localStorage, authoritative) │
└──────────────────────────┬────────────────────────────────────┘
│ IPC: Cache_Sync / Cache_GetAllShared
┌──────────────────────────▼────────────────────────────────────┐
│ CacheService (Main) │
│ - Internal cache (Main-only) │
│ - Shared cache (authoritative; relays to all windows) │
│ - Persist: IPC relay only (no Main-side store) │
│ - subscribeChange / subscribeSharedChange for Main services │
└───────────────────────────────────────────────────────────────┘
Process Responsibilities
| Concern | Main | Renderer |
|---|---|---|
| Internal memory cache | Yes (services' own scratch space) | Yes (window-local) |
| Shared cache authority | Yes | Local copy; writes broadcast via IPC to Main |
| Persist cache storage | No (relay only) | Yes (localStorage, debounced 200ms, flush on unload) |
| Init sync for new windows | Serves getAllShared() |
Calls getAllShared() on startup |
subscribeChange / subscribeSharedChange |
Main-only API; template-aware | — |
| Hook refcounting | — | registerHook / unregisterHook |
| GC (10-min sweep of expired) | Yes | — |
API Reference
Renderer
| Method | Tier | Key type |
|---|---|---|
useCache / get / set / has / delete / hasTTL |
Memory | Fixed + Template |
getCasual / setCasual / hasCasual / deleteCasual / hasTTLCasual |
Memory | Dynamic only (schema keys blocked) |
useSharedCache / getShared / setShared / hasShared / deleteShared / hasSharedTTL |
Shared | Fixed + Template |
usePersistCache / getPersist / setPersist / hasPersist |
Persist | Fixed only |
isSharedCacheReady / onSharedCacheReady |
Shared | — |
getStats(includeDetails?: boolean) |
All | — |
Main
| Method | Tier | Key type |
|---|---|---|
get / set / has / delete |
Internal | Free-form string |
getShared / setShared / hasShared / deleteShared |
Shared | Fixed + Template |
subscribeChange<T>(key, cb) |
Internal | Exact key |
subscribeSharedChange<K>(key, cb) |
Shared | Fixed + Template (fires for every matching concrete instance) |
See Also
- Cache Usage — React hooks, direct API, patterns
- Cache Schema Guide — Adding fixed and template keys
- Source:
src/main/data/CacheService.ts,src/renderer/data/CacheService.ts,src/renderer/data/hooks/useCache.ts,src/shared/data/cache/