summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-19 14:41:24 -0600
committerAdam <[email protected]>2026-01-20 05:21:32 -0600
commit5f0372183a1f7447de111e170b915783823f4b11 (patch)
tree8c7c7cdbd7d216bd6c9e11cc7d5518a56e75550d /packages
parent616329ae97c975f21687f6c8c9c6d4d8018e6fd9 (diff)
downloadopencode-5f0372183a1f7447de111e170b915783823f4b11.tar.gz
opencode-5f0372183a1f7447de111e170b915783823f4b11.zip
fix(app): persist quota
Diffstat (limited to 'packages')
-rw-r--r--packages/app/src/utils/persist.ts51
1 files changed, 45 insertions, 6 deletions
diff --git a/packages/app/src/utils/persist.ts b/packages/app/src/utils/persist.ts
index 0c20ee31c..06e80142a 100644
--- a/packages/app/src/utils/persist.ts
+++ b/packages/app/src/utils/persist.ts
@@ -17,6 +17,36 @@ type PersistTarget = {
const LEGACY_STORAGE = "default.dat"
const GLOBAL_STORAGE = "opencode.global.dat"
+function quota(error: unknown) {
+ if (error instanceof DOMException) {
+ if (error.name === "QuotaExceededError") return true
+ if (error.name === "NS_ERROR_DOM_QUOTA_REACHED") return true
+ if (error.code === 22 || error.code === 1014) return true
+ return false
+ }
+
+ if (!error || typeof error !== "object") return false
+ const name = (error as { name?: string }).name
+ if (name === "QuotaExceededError" || name === "NS_ERROR_DOM_QUOTA_REACHED") return true
+ return false
+}
+
+function write(storage: Storage, key: string, value: string) {
+ try {
+ storage.setItem(key, value)
+ return
+ } catch (error) {
+ if (!quota(error)) throw error
+ }
+
+ try {
+ storage.removeItem(key)
+ storage.setItem(key, value)
+ } catch (error) {
+ if (!quota(error)) throw error
+ }
+}
+
function snapshot(value: unknown) {
return JSON.parse(JSON.stringify(value)) as unknown
}
@@ -67,10 +97,19 @@ function workspaceStorage(dir: string) {
function localStorageWithPrefix(prefix: string): SyncStorage {
const base = `${prefix}:`
+ const item = (key: string) => base + key
+ return {
+ getItem: (key) => localStorage.getItem(item(key)),
+ setItem: (key, value) => write(localStorage, item(key), value),
+ removeItem: (key) => localStorage.removeItem(item(key)),
+ }
+}
+
+function localStorageDirect(): SyncStorage {
return {
- getItem: (key) => localStorage.getItem(base + key),
- setItem: (key, value) => localStorage.setItem(base + key, value),
- removeItem: (key) => localStorage.removeItem(base + key),
+ getItem: (key) => localStorage.getItem(key),
+ setItem: (key, value) => write(localStorage, key, value),
+ removeItem: (key) => localStorage.removeItem(key),
}
}
@@ -99,7 +138,7 @@ export function removePersisted(target: { storage?: string; key: string }) {
}
if (!target.storage) {
- localStorage.removeItem(target.key)
+ localStorageDirect().removeItem(target.key)
return
}
@@ -120,12 +159,12 @@ export function persisted<T>(
const currentStorage = (() => {
if (isDesktop) return platform.storage?.(config.storage)
- if (!config.storage) return localStorage
+ if (!config.storage) return localStorageDirect()
return localStorageWithPrefix(config.storage)
})()
const legacyStorage = (() => {
- if (!isDesktop) return localStorage
+ if (!isDesktop) return localStorageDirect()
if (!config.storage) return platform.storage?.()
return platform.storage?.(LEGACY_STORAGE)
})()