Skip to content

Commit 9339583

Browse files
committed
fix(mothership): catch draft restore errors instead of crashing /home
Wrap the mount-time draft restore in try/catch with clearDraft on throw, and coerce text to a string in the useState initializer. A corrupt entry in mothership-drafts:v1 localStorage previously took down the entire workspace via the error boundary.
1 parent 57dc745 commit 9339583

1 file changed

Lines changed: 29 additions & 24 deletions

File tree

  • apps/sim/app/workspace/[workspaceId]/home/components/user-input

apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
148148
const [value, setValue] = useState(() => {
149149
if (defaultValue) return defaultValue
150150
if (!draftScopeKey) return ''
151-
return useMothershipDraftsStore.getState().drafts[draftScopeKey]?.text ?? ''
151+
const text = useMothershipDraftsStore.getState().drafts[draftScopeKey]?.text
152+
return typeof text === 'string' ? text : ''
152153
})
153154
const overlayRef = useRef<HTMLDivElement>(null)
154155
const plusMenuRef = useRef<PlusMenuHandle>(null)
@@ -189,30 +190,34 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
189190
useEffect(() => {
190191
if (hasRestoredDraftRef.current || !draftScopeKey) return
191192
hasRestoredDraftRef.current = true
192-
const draft = useMothershipDraftsStore.getState().drafts[draftScopeKey]
193-
if (!draft) return
194-
if (draft.contexts?.length) {
195-
contextManagement.setSelectedContexts(draft.contexts)
196-
}
197-
if (draft.fileAttachments?.length) {
198-
files.restoreAttachedFiles(
199-
draft.fileAttachments.map((a) => ({
200-
id: a.id,
201-
name: a.filename,
202-
size: a.size,
203-
type: a.media_type,
204-
path: a.path ?? '',
205-
key: a.key,
206-
uploading: false,
207-
}))
208-
)
209-
}
210-
if (draft.text) {
211-
const textarea = textareaRef.current
212-
if (textarea) {
213-
textarea.focus()
214-
textarea.setSelectionRange(draft.text.length, draft.text.length)
193+
try {
194+
const draft = useMothershipDraftsStore.getState().drafts[draftScopeKey]
195+
if (!draft) return
196+
if (draft.contexts?.length) {
197+
contextManagement.setSelectedContexts(draft.contexts)
198+
}
199+
if (draft.fileAttachments?.length) {
200+
files.restoreAttachedFiles(
201+
draft.fileAttachments.map((a) => ({
202+
id: a.id,
203+
name: a.filename,
204+
size: a.size,
205+
type: a.media_type,
206+
path: a.path ?? '',
207+
key: a.key,
208+
uploading: false,
209+
}))
210+
)
211+
}
212+
if (typeof draft.text === 'string' && draft.text.length > 0) {
213+
const textarea = textareaRef.current
214+
if (textarea) {
215+
textarea.focus()
216+
textarea.setSelectionRange(draft.text.length, draft.text.length)
217+
}
215218
}
219+
} catch {
220+
useMothershipDraftsStore.getState().clearDraft(draftScopeKey)
216221
}
217222
}, []) // eslint-disable-line react-hooks/exhaustive-deps -- intentional mount-only restore
218223

0 commit comments

Comments
 (0)