From bf3f88bf62378a1a72df420255b772fabc339ec3 Mon Sep 17 00:00:00 2001 From: tulsi Date: Wed, 29 Apr 2026 16:16:59 -0700 Subject: [PATCH] fix(goose2): harden home widget storage Signed-off-by: tulsi --- .../features/home/stores/homeWidgetStore.ts | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/ui/goose2/src/features/home/stores/homeWidgetStore.ts b/ui/goose2/src/features/home/stores/homeWidgetStore.ts index c5c1f56a8f..af588ce320 100644 --- a/ui/goose2/src/features/home/stores/homeWidgetStore.ts +++ b/ui/goose2/src/features/home/stores/homeWidgetStore.ts @@ -1,5 +1,5 @@ import { create } from "zustand"; -import { persist } from "zustand/middleware"; +import { createJSONStorage, persist } from "zustand/middleware"; import { HOME_WIDGET_CATALOG_BY_ID } from "../widgets/catalog"; import type { CanvasBounds, WidgetInstance } from "../widgets/types"; @@ -7,6 +7,42 @@ export const HOME_WIDGET_STORAGE_KEY = "goose2:home-widgets"; const BASELINE_CANVAS: CanvasBounds = { width: 1080, height: 760 }; +function createMemoryStorage(): Storage { + const store = new Map(); + return { + get length() { + return store.size; + }, + clear: () => store.clear(), + getItem: (key) => store.get(key) ?? null, + key: (index) => Array.from(store.keys())[index] ?? null, + removeItem: (key) => { + store.delete(key); + }, + setItem: (key, value) => { + store.set(key, value); + }, + }; +} + +function getPersistStorage(): Storage { + if (typeof window === "undefined") { + return createMemoryStorage(); + } + + const storage = window.localStorage; + if ( + storage && + typeof storage.getItem === "function" && + typeof storage.setItem === "function" && + typeof storage.removeItem === "function" + ) { + return storage; + } + + return createMemoryStorage(); +} + function maxZ(instances: WidgetInstance[]): number { return instances.reduce((max, instance) => Math.max(max, instance.z), 0); } @@ -158,6 +194,7 @@ export const useHomeWidgetStore = create()( }), { name: HOME_WIDGET_STORAGE_KEY, + storage: createJSONStorage(getPersistStorage), version: 1, partialize: (state) => ({ instances: state.instances }), },