Skip to content

Commit 347cd8a

Browse files
committed
chore: cleanup
1 parent b711ca5 commit 347cd8a

2 files changed

Lines changed: 96 additions & 10 deletions

File tree

packages/app/src/utils/persist.ts

Lines changed: 92 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ type PersistTarget = {
1616

1717
const LEGACY_STORAGE = "default.dat"
1818
const GLOBAL_STORAGE = "opencode.global.dat"
19+
const LOCAL_PREFIX = "opencode."
20+
const fallback = { disabled: false }
21+
const cache = new Map<string, string>()
1922

2023
function quota(error: unknown) {
2124
if (error instanceof DOMException) {
@@ -40,20 +43,55 @@ function quota(error: unknown) {
4043
return false
4144
}
4245

46+
type Evict = { key: string; size: number }
47+
48+
function evict(storage: Storage, keep: string, value: string) {
49+
const total = storage.length
50+
const indexes = Array.from({ length: total }, (_, index) => index)
51+
const items: Evict[] = []
52+
53+
for (const index of indexes) {
54+
const name = storage.key(index)
55+
if (!name) continue
56+
if (!name.startsWith(LOCAL_PREFIX)) continue
57+
if (name === keep) continue
58+
const stored = storage.getItem(name)
59+
items.push({ key: name, size: stored?.length ?? 0 })
60+
}
61+
62+
items.sort((a, b) => b.size - a.size)
63+
64+
for (const item of items) {
65+
storage.removeItem(item.key)
66+
67+
try {
68+
storage.setItem(keep, value)
69+
return true
70+
} catch (error) {
71+
if (!quota(error)) throw error
72+
}
73+
}
74+
75+
return false
76+
}
77+
4378
function write(storage: Storage, key: string, value: string) {
4479
try {
4580
storage.setItem(key, value)
46-
return
81+
return true
4782
} catch (error) {
4883
if (!quota(error)) throw error
4984
}
5085

5186
try {
5287
storage.removeItem(key)
5388
storage.setItem(key, value)
89+
return true
5490
} catch (error) {
5591
if (!quota(error)) throw error
5692
}
93+
94+
return evict(storage, key, value)
5795
}
5896

5997
function snapshot(value: unknown) {
@@ -108,17 +146,64 @@ function localStorageWithPrefix(prefix: string): SyncStorage {
108146
const base = `${prefix}:`
109147
const item = (key: string) => base + key
110148
return {
111-
getItem: (key) => localStorage.getItem(item(key)),
112-
setItem: (key, value) => write(localStorage, item(key), value),
113-
removeItem: (key) => localStorage.removeItem(item(key)),
149+
getItem: (key) => {
150+
const name = item(key)
151+
const cached = cache.get(name)
152+
if (fallback.disabled && cached !== undefined) return cached
153+
154+
const stored = localStorage.getItem(name)
155+
if (stored === null) return cached ?? null
156+
cache.set(name, stored)
157+
return stored
158+
},
159+
setItem: (key, value) => {
160+
const name = item(key)
161+
cache.set(name, value)
162+
if (fallback.disabled) return
163+
try {
164+
if (write(localStorage, name, value)) return
165+
} catch {
166+
fallback.disabled = true
167+
return
168+
}
169+
fallback.disabled = true
170+
},
171+
removeItem: (key) => {
172+
const name = item(key)
173+
cache.delete(name)
174+
if (fallback.disabled) return
175+
localStorage.removeItem(name)
176+
},
114177
}
115178
}
116179

117180
function localStorageDirect(): SyncStorage {
118181
return {
119-
getItem: (key) => localStorage.getItem(key),
120-
setItem: (key, value) => write(localStorage, key, value),
121-
removeItem: (key) => localStorage.removeItem(key),
182+
getItem: (key) => {
183+
const cached = cache.get(key)
184+
if (fallback.disabled && cached !== undefined) return cached
185+
186+
const stored = localStorage.getItem(key)
187+
if (stored === null) return cached ?? null
188+
cache.set(key, stored)
189+
return stored
190+
},
191+
setItem: (key, value) => {
192+
cache.set(key, value)
193+
if (fallback.disabled) return
194+
try {
195+
if (write(localStorage, key, value)) return
196+
} catch {
197+
fallback.disabled = true
198+
return
199+
}
200+
fallback.disabled = true
201+
},
202+
removeItem: (key) => {
203+
cache.delete(key)
204+
if (fallback.disabled) return
205+
localStorage.removeItem(key)
206+
},
122207
}
123208
}
124209

packages/ui/src/components/message-part.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,15 +363,16 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
363363
}
364364

365365
return (
366-
<div data-component="user-message" data-expanded={expanded()} data-can-expand={canExpand()}>
366+
<div data-component="user-message" data-expanded={expanded()} data-can-expand={canExpand()} onClick={toggleExpanded}>
367367
<Show when={attachments().length > 0}>
368368
<div data-slot="user-message-attachments">
369369
<For each={attachments()}>
370370
{(file) => (
371371
<div
372372
data-slot="user-message-attachment"
373373
data-type={file.mime.startsWith("image/") ? "image" : "file"}
374-
onClick={() => {
374+
onClick={(event) => {
375+
event.stopPropagation()
375376
if (file.mime.startsWith("image/") && file.url) {
376377
openImagePreview(file.url, file.filename)
377378
}
@@ -393,7 +394,7 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
393394
</div>
394395
</Show>
395396
<Show when={text()}>
396-
<div data-slot="user-message-text" ref={(el) => (textRef = el)} onClick={toggleExpanded}>
397+
<div data-slot="user-message-text" ref={(el) => (textRef = el)}>
397398
<HighlightedText text={text()} references={inlineFiles()} agents={agents()} />
398399
<button
399400
data-slot="user-message-expand"

0 commit comments

Comments
 (0)