Files
ttstd-infinite-canvas/web/src/stores/use-theme-store.ts
爱笑的毛毛虫 6671c331e3 fix(canvas): 主题存储 - 修复非法 theme 值导致 /create 崩溃 (#155)
useThemeStore persist 无 merge 校验,坏 session/后端同步失败时可能将
非法 theme 值写入 localStorage,导致 canvasThemes[非法值] 为 undefined,
渲染时访问 theme.node 抛出 "Cannot read properties of undefined
(reading 'node')",/create 页面崩溃。

4 层防线(只加校验,不回退代码):
- useThemeStore persist merge 白名单校验,非法值回退 dark
- useThemeStore setTheme 写入前校验,防止同步路径绕过 merge
- normalizeConfigSnapshot 入口兜底 undefined/partial 快照
- ModelPicker 与 CanvasResourceMentionTextarea 消费端加 fallback

Closes #154

Co-authored-by: sikongyue <3155157671@qq.com>
2026-08-06 08:32:27 +08:00

34 lines
1.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { create } from "zustand";
import { persist } from "zustand/middleware";
export type ThemeName = "light" | "dark";
type ThemeStore = {
theme: ThemeName;
setTheme: (theme: ThemeName) => void;
};
const VALID_THEMES: ThemeName[] = ["light", "dark"];
export const useThemeStore = create<ThemeStore>()(
persist(
(set) => ({
theme: "dark",
// 写入前校验:非法 theme 直接忽略,防止 syncRemoteUserData 等路径绕过 merge 写入坏值
setTheme: (next) => set((state) => (VALID_THEMES.includes(next) ? { theme: next } : state)),
}),
{
name: "infinite-canvas:theme_store",
// 持久化恢复校验:旧版本/坏 session 写入的非法值回退到 dark,
// 避免 canvasThemes[非法值] = undefined 触发 "reading 'node'" 崩溃
merge: (persisted, current) => {
const stored = (persisted || {}) as Partial<ThemeStore>;
const theme = VALID_THEMES.includes(stored.theme as ThemeName)
? (stored.theme as ThemeName)
: "dark";
return { ...current, theme };
},
},
),
);