From 895b254c2a567b1b497a7af8b28320dcabc14290 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Sat, 19 Sep 2026 16:36:24 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20guard=20against=20malformed=20stored=20s?= =?UTF-8?q?ettings=20(crash=20=E2=86=92=20blank=20window);=20add=20ErrorBo?= =?UTF-8?q?undary=20to=20surface=20render=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/settings.ts | 12 +++++++++--- src/ui.tsx | 29 ++++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 0415310..38d4c13 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "figma-ai-plugin", - "version": "0.1.3", + "version": "0.1.4", "private": true, "dependencies": { "@create-figma-plugin/ui": "^4.0.3", diff --git a/src/settings.ts b/src/settings.ts index 226d53f..deca9ce 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -52,12 +52,18 @@ export function createApinexProvider (): ProviderConfig { } export async function loadSettings (): Promise { + const defaults = defaultSettings() try { const stored = await figma.clientStorage.getAsync(SETTINGS_KEY) - if (stored == null || stored.version !== 1) return defaultSettings() - return stored as Settings + if (stored == null || stored.version !== 1) return defaults + const merged: Settings = { ...defaults, ...(stored as Settings) } + if (!Array.isArray(merged.providers) || merged.providers.length === 0) { + merged.providers = defaults.providers + merged.activeProviderId = defaults.providers[0].id + } + return merged } catch (e) { - return defaultSettings() + return defaults } } diff --git a/src/ui.tsx b/src/ui.tsx index c3208ee..e8e8f7a 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -18,7 +18,7 @@ import { IconComponent24 } from '@create-figma-plugin/ui' import { emit, on } from '@create-figma-plugin/utilities' -import { h, Fragment } from 'preact' +import { h, Fragment, Component } from 'preact' import { useState, useEffect, useRef } from 'preact/hooks' import MenuItem from './MenuItem' import { type Settings, type ProviderConfig, defaultSettings, loadSettings, saveSettings, settingsToJSON, settingsFromJSON, APINEX_BASE_URL } from './settings' @@ -29,7 +29,7 @@ const MIN_WINDOW_SIZE = { width: 320, height: 200 } // very high — actual clamp is done by main via clampWindowSize (bounds*zoom). // Full plugin version shown in the footer status bar. Keep in sync with package.json "version". -const PLUGIN_VERSION = '0.1.3' +const PLUGIN_VERSION = '0.1.4' const fieldStyle = { display: 'flex', @@ -55,6 +55,26 @@ function Separator () { ) } +class ErrorBoundary extends Component<{ children: any }, { error: Error | null }> { + constructor (props: { children: any }) { + super(props) + this.state = { error: null } + } + componentDidCatch (error: Error) { + this.setState({ error: error }) + } + render (props: { children: any }, state: { error: Error | null }) { + if (state.error != null) { + return ( +
+          {String(state.error && state.error.stack ? state.error.stack : state.error)}
+        
+ ) + } + return props.children + } +} + function SettingsPanel (props: { settings: Settings, setSettings: (s: Settings) => void }) { const { settings, setSettings } = props const [showKey, setShowKey] = useState(false) @@ -65,7 +85,8 @@ function SettingsPanel (props: { settings: Settings, setSettings: (s: Settings) settingsRef.current = settings // Static single provider (APInex). Always edit providers[0]. - const provider = settings.providers[0] != null ? settings.providers[0] : null + const providers = Array.isArray(settings.providers) ? settings.providers : [] + const provider = providers.length > 0 ? providers[0] : null useEffect(function () { const dispose = on('MODELS_RESULT', function (payload: { ok: boolean, models: string[], error?: string }) { @@ -488,6 +509,7 @@ function Plugin () { return (
+ {/* Header — navigation bar */}
@@ -523,6 +545,7 @@ function Plugin () { Version {PLUGIN_VERSION} + {/* More-menu modal — old-plugin style: library Modal + Container + Stack of MenuItem */}