mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-04 13:11:56 +08:00
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.
115 lines
5.2 KiB
Markdown
115 lines
5.2 KiB
Markdown
# Cache Schema Guide
|
|
|
|
How to add fixed and template keys. Aligned with [Preference Schema Guide](./preference-schema-guide.md) and [Boot Config Schema Guide](./boot-config-schema-guide.md).
|
|
|
|
## 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
|
|
|
|
```typescript
|
|
// 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)
|
|
|
|
```typescript
|
|
// src/shared/data/cache/cacheValueTypes.ts
|
|
export interface MyDataType {
|
|
items: string[]
|
|
lastUpdated: number
|
|
}
|
|
```
|
|
|
|
### 3. Use it
|
|
|
|
```typescript
|
|
const [data, setData] = useCache('feature.my_feature.data')
|
|
// data is MyDataType
|
|
```
|
|
|
|
## Adding a Template Key
|
|
|
|
```typescript
|
|
// 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:
|
|
|
|
```typescript
|
|
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
|
|
|
|
- [Cache Overview](./cache-overview.md) — design invariants, tier semantics
|
|
- [Cache Usage](./cache-usage.md) — hooks, direct API, patterns
|