From 7e692f9862d31cf455ea6a9ba545df2f52cf74f1 Mon Sep 17 00:00:00 2001 From: Aryan Keluskar Date: Thu, 6 Nov 2025 22:20:57 -0800 Subject: Migrate Chat Persistence from localStorage to IndexedDB to Fix QuotaExceededError (#560) --- apps/web/package.json | 1 + apps/web/stores/chat.ts | 4 +++- apps/web/stores/indexeddb-storage.ts | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 apps/web/stores/indexeddb-storage.ts (limited to 'apps') diff --git a/apps/web/package.json b/apps/web/package.json index e2247046..46bfa8fb 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -59,6 +59,7 @@ "embla-carousel-autoplay": "^8.6.0", "embla-carousel-react": "^8.6.0", "framer-motion": "^12.23.12", + "idb-keyval": "^6.2.2", "is-hotkey": "^0.2.0", "lucide-react": "^0.525.0", "masonic": "^4.1.0", diff --git a/apps/web/stores/chat.ts b/apps/web/stores/chat.ts index ac204442..f1701139 100644 --- a/apps/web/stores/chat.ts +++ b/apps/web/stores/chat.ts @@ -1,7 +1,8 @@ import type { UIMessage } from "@ai-sdk/react" import { create } from "zustand" -import { persist } from "zustand/middleware" +import { persist, createJSONStorage } from "zustand/middleware" import { useCallback } from "react" +import { indexedDBStorage } from "./indexeddb-storage" /** * Deep equality check for UIMessage arrays to prevent unnecessary state updates @@ -175,6 +176,7 @@ export const usePersistentChatStore = create()( }), { name: "supermemory-chats", + storage: createJSONStorage(() => indexedDBStorage), }, ), ) diff --git a/apps/web/stores/indexeddb-storage.ts b/apps/web/stores/indexeddb-storage.ts new file mode 100644 index 00000000..c2a1db91 --- /dev/null +++ b/apps/web/stores/indexeddb-storage.ts @@ -0,0 +1,24 @@ +import { get, set, del } from 'idb-keyval'; + +export const indexedDBStorage = { + getItem: async (name: string) => { + let value = await get(name); + if (value !== undefined) { + return value; + } + // Migrate from localStorage if exists + value = localStorage.getItem(name); + if (value !== null) { + await set(name, value); + localStorage.removeItem(name); + return value; + } + return null; + }, + setItem: async (name: string, value: string) => { + await set(name, value); + }, + removeItem: async (name: string) => { + await del(name); + }, +}; -- cgit v1.2.3