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>
34 lines
1.2 KiB
TypeScript
34 lines
1.2 KiB
TypeScript
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 };
|
||
},
|
||
},
|
||
),
|
||
);
|