@goodandready/dsh-image-gen 0.11.0 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +104 -135
- package/lib/fallback-router.js +25 -3
- package/lib/index.js +257 -139
- package/lib/provider-utils.js +0 -2
- package/lib/providers.js +9 -30
- package/lib/settings-route.js +112 -0
- package/lib/tools/anchor.js +1 -2
- package/lib/tools/editing.js +2 -34
- package/lib/tools/frontend.js +2 -35
- package/lib/tools/generation-pack.js +2 -4
- package/lib/tools/generation.js +5 -26
- package/lib/tools/inspect.js +6 -45
- package/lib/tools/pattern.js +10 -0
- package/lib/tools/processing-advanced.js +0 -32
- package/lib/tools/processing-basic.js +2 -25
- package/lib/tools/style-matrix.js +1 -2
- package/lib/tools/theme-pair.js +0 -1
- package/lib/tools/ui-asset.js +1 -1
- package/lib/updater.js +0 -9
- package/lib/vault.js +3 -3
- package/package.json +7 -1
package/lib/client.js
CHANGED
|
@@ -1751,27 +1751,25 @@ window.__ModuleLoader__.load({
|
|
|
1751
1751
|
onLoad: () => setLoaded(true),
|
|
1752
1752
|
}) : null
|
|
1753
1753
|
)
|
|
1754
|
-
}// 105-inpaint-canvas.js — Interactive in-chat canvas drawing overlay for inpainting (#285).
|
|
1754
|
+
}// 105-inpaint-canvas.js — Interactive in-chat canvas drawing overlay for inpainting (#285, #301).
|
|
1755
1755
|
|
|
1756
|
-
function
|
|
1756
|
+
function InpaintCanvas(props) {
|
|
1757
|
+
const { imgUrl, targetRef, onClose, t } = props
|
|
1757
1758
|
const canvasRef = react.useRef(null)
|
|
1758
1759
|
const isDrawingRef = react.useRef(false)
|
|
1760
|
+
const undoStackRef = react.useRef([])
|
|
1759
1761
|
const [brushSize, setBrushSize] = react.useState(24)
|
|
1760
|
-
const [toolMode, setToolMode] = react.useState('brush')
|
|
1761
|
-
const [inpaintPrompt, setInpaintPrompt] = react.useState('')
|
|
1762
|
-
const [copied, setCopied] = react.useState(false)
|
|
1762
|
+
const [toolMode, setToolMode] = react.useState('brush') // 'brush' | 'eraser'
|
|
1763
1763
|
const [hasStrokes, setHasStrokes] = react.useState(false)
|
|
1764
|
-
const
|
|
1765
|
-
|
|
1766
|
-
const imgUrl = (parsed && (parsed.url || (parsed.attachment && attachmentImageUrl(parsed.attachment)))) || ''
|
|
1767
|
-
const targetRef = (parsed && (parsed.attachment?.attachmentId || parsed.path || parsed.url)) || 'current image'
|
|
1764
|
+
const [copied, setCopied] = react.useState(false)
|
|
1765
|
+
const [inpaintPrompt, setInpaintPrompt] = react.useState('')
|
|
1768
1766
|
|
|
1769
1767
|
const initCanvas = react.useCallback(() => {
|
|
1770
1768
|
const canvas = canvasRef.current
|
|
1771
1769
|
if (!canvas) return
|
|
1772
1770
|
const ctx = canvas.getContext('2d')
|
|
1773
1771
|
if (!ctx) return
|
|
1774
|
-
ctx.fillStyle = '
|
|
1772
|
+
ctx.fillStyle = 'black'
|
|
1775
1773
|
ctx.fillRect(0, 0, canvas.width, canvas.height)
|
|
1776
1774
|
undoStackRef.current = [ctx.getImageData(0, 0, canvas.width, canvas.height)]
|
|
1777
1775
|
}, [])
|
|
@@ -1780,9 +1778,7 @@ window.__ModuleLoader__.load({
|
|
|
1780
1778
|
initCanvas()
|
|
1781
1779
|
}, [initCanvas])
|
|
1782
1780
|
|
|
1783
|
-
function getPos(e) {
|
|
1784
|
-
const canvas = canvasRef.current
|
|
1785
|
-
if (!canvas) return { x: 0, y: 0 }
|
|
1781
|
+
function getPos(e, canvas) {
|
|
1786
1782
|
const rect = canvas.getBoundingClientRect()
|
|
1787
1783
|
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
|
1788
1784
|
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
|
@@ -1796,42 +1792,40 @@ window.__ModuleLoader__.load({
|
|
|
1796
1792
|
|
|
1797
1793
|
function startDraw(e) {
|
|
1798
1794
|
if (e.touches && e.touches.length > 1) return
|
|
1799
|
-
e.preventDefault()
|
|
1800
1795
|
const canvas = canvasRef.current
|
|
1801
1796
|
if (!canvas) return
|
|
1802
1797
|
const ctx = canvas.getContext('2d')
|
|
1803
1798
|
if (!ctx) return
|
|
1804
|
-
|
|
1805
1799
|
isDrawingRef.current = true
|
|
1806
|
-
const pos = getPos(e)
|
|
1800
|
+
const pos = getPos(e, canvas)
|
|
1801
|
+
ctx.beginPath()
|
|
1802
|
+
ctx.moveTo(pos.x, pos.y)
|
|
1807
1803
|
ctx.lineWidth = brushSize
|
|
1808
1804
|
ctx.lineCap = 'round'
|
|
1809
1805
|
ctx.lineJoin = 'round'
|
|
1810
|
-
const color = toolMode === 'eraser' ? '
|
|
1806
|
+
const color = toolMode === 'eraser' ? 'black' : 'white'
|
|
1811
1807
|
ctx.strokeStyle = color
|
|
1812
1808
|
ctx.fillStyle = color
|
|
1813
1809
|
|
|
1814
|
-
ctx.beginPath()
|
|
1815
1810
|
ctx.arc(pos.x, pos.y, brushSize / 2, 0, Math.PI * 2)
|
|
1816
1811
|
ctx.fill()
|
|
1817
1812
|
ctx.beginPath()
|
|
1818
1813
|
ctx.moveTo(pos.x, pos.y)
|
|
1814
|
+
setHasStrokes(true)
|
|
1819
1815
|
}
|
|
1820
1816
|
|
|
1821
1817
|
function draw(e) {
|
|
1822
1818
|
if (!isDrawingRef.current) return
|
|
1823
1819
|
if (e.touches && e.touches.length > 1) return
|
|
1824
|
-
e.preventDefault()
|
|
1825
1820
|
const canvas = canvasRef.current
|
|
1826
1821
|
if (!canvas) return
|
|
1827
1822
|
const ctx = canvas.getContext('2d')
|
|
1828
1823
|
if (!ctx) return
|
|
1829
|
-
|
|
1830
|
-
const pos = getPos(e)
|
|
1824
|
+
const pos = getPos(e, canvas)
|
|
1831
1825
|
ctx.lineWidth = brushSize
|
|
1832
1826
|
ctx.lineCap = 'round'
|
|
1833
1827
|
ctx.lineJoin = 'round'
|
|
1834
|
-
const color = toolMode === 'eraser' ? '
|
|
1828
|
+
const color = toolMode === 'eraser' ? 'black' : 'white'
|
|
1835
1829
|
ctx.strokeStyle = color
|
|
1836
1830
|
ctx.lineTo(pos.x, pos.y)
|
|
1837
1831
|
ctx.stroke()
|
|
@@ -2005,7 +1999,7 @@ window.__ModuleLoader__.load({
|
|
|
2005
1999
|
borderRadius: '8px',
|
|
2006
2000
|
overflow: 'hidden',
|
|
2007
2001
|
border: '1px solid var(--dsw-alias-border-l2)',
|
|
2008
|
-
background: '
|
|
2002
|
+
background: 'black',
|
|
2009
2003
|
margin: '4px 0',
|
|
2010
2004
|
userSelect: 'none',
|
|
2011
2005
|
touchAction: 'none',
|
|
@@ -2071,9 +2065,11 @@ window.__ModuleLoader__.load({
|
|
|
2071
2065
|
)
|
|
2072
2066
|
)
|
|
2073
2067
|
}
|
|
2074
|
-
|
|
2068
|
+
var InpaintCanvasOverlay = InpaintCanvas
|
|
2069
|
+
// 106-style-matrix-view.js — 2×2 Style Matrix toolview with Blind A/B Compare (#286, #297, #301).
|
|
2075
2070
|
|
|
2076
2071
|
function StyleMatrixCard(props) {
|
|
2072
|
+
const t = props.t || ((k) => k)
|
|
2077
2073
|
const block = props.block || {}
|
|
2078
2074
|
const parsed = react.useMemo(() => {
|
|
2079
2075
|
const raw = block.output || block.text || ''
|
|
@@ -2166,7 +2162,7 @@ window.__ModuleLoader__.load({
|
|
|
2166
2162
|
left: 0,
|
|
2167
2163
|
right: 0,
|
|
2168
2164
|
bottom: 0,
|
|
2169
|
-
background: '
|
|
2165
|
+
background: 'var(--dsw-alias-bg-overlay, rgb(0 0 0 / 85%))',
|
|
2170
2166
|
display: 'flex',
|
|
2171
2167
|
alignItems: 'center',
|
|
2172
2168
|
justifyContent: 'center',
|
|
@@ -2183,8 +2179,8 @@ window.__ModuleLoader__.load({
|
|
|
2183
2179
|
) : null
|
|
2184
2180
|
)
|
|
2185
2181
|
}
|
|
2186
|
-
// -------------------------------------------------------------- Theme Pair Toolview (#189)
|
|
2187
|
-
function
|
|
2182
|
+
// -------------------------------------------------------------- Theme Pair Toolview (#189, #296)
|
|
2183
|
+
function ThemePairView(props) {
|
|
2188
2184
|
const block = props.block
|
|
2189
2185
|
const t = props.t || ((k) => k)
|
|
2190
2186
|
const [copiedHtml, setCopiedHtml] = react.useState(false)
|
|
@@ -2285,11 +2281,14 @@ window.__ModuleLoader__.load({
|
|
|
2285
2281
|
) : null
|
|
2286
2282
|
) : null
|
|
2287
2283
|
)
|
|
2288
|
-
}
|
|
2284
|
+
}
|
|
2285
|
+
var ThemePairToolView = ThemePairView
|
|
2286
|
+
const en = {
|
|
2289
2287
|
'settings.navLabel': 'Image Studio',
|
|
2290
2288
|
'settings.title': 'Image Studio',
|
|
2291
2289
|
'settings.description': 'AI Image generation, inpainting, variations, upscale & vectorization.',
|
|
2292
|
-
'settings.unavailable': 'Plugin settings are
|
|
2290
|
+
'settings.unavailable': 'Plugin settings are unavailable: the host settings namespace is not ready.',
|
|
2291
|
+
'settings.loading': 'Loading plugin settings…',
|
|
2293
2292
|
'settings.unsaved': 'Unsaved changes',
|
|
2294
2293
|
'settings.saving': 'Saving…',
|
|
2295
2294
|
'settings.save': 'Save settings',
|
|
@@ -2602,6 +2601,7 @@ window.__ModuleLoader__.load({
|
|
|
2602
2601
|
'settings.reset': '重置',
|
|
2603
2602
|
'settings.invalidNumber': '请输入有效数值',
|
|
2604
2603
|
'settings.unavailable': '设置命名空间当前不可用。',
|
|
2604
|
+
'settings.loading': '正在加载插件设置…',
|
|
2605
2605
|
|
|
2606
2606
|
'f.enabled': '启用图像生成',
|
|
2607
2607
|
'f.enabledHint': '关闭后将禁用所有图像生成及处理工具。',
|
|
@@ -2766,46 +2766,19 @@ window.__ModuleLoader__.load({
|
|
|
2766
2766
|
}
|
|
2767
2767
|
|
|
2768
2768
|
// -------------------------------------------------------------- Registration & Apply
|
|
2769
|
-
// Dual compatibility with DSH 0.1.5-rc.3 (settingsScope) and 0.1.6+ (configForms) (#291)
|
|
2769
|
+
// Dual compatibility with DSH 0.1.5-rc.3 (settingsScope) and 0.1.6+ (configForms) (#291, #295)
|
|
2770
2770
|
const inject = ['slots', 'locale', 'sessions']
|
|
2771
2771
|
|
|
2772
2772
|
function resolveActiveScope(ctx) {
|
|
2773
2773
|
if (!ctx) return null
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
try {
|
|
2783
|
-
const cf = ctx.get('configForms')
|
|
2784
|
-
if (cf && typeof cf.get === 'function') {
|
|
2785
|
-
const s = cf.get(SETTINGS_NS)
|
|
2786
|
-
if (s) return s
|
|
2787
|
-
}
|
|
2788
|
-
} catch (_) { /* scope unavailable */ }
|
|
2789
|
-
try {
|
|
2790
|
-
const ss = ctx.get('settingsScope')
|
|
2791
|
-
if (ss && typeof ss.bind === 'function') {
|
|
2792
|
-
const s = ss.bind({ namespace: SETTINGS_NS })
|
|
2793
|
-
if (s) return s
|
|
2794
|
-
}
|
|
2795
|
-
} catch (_) { /* scope unavailable */ }
|
|
2796
|
-
}
|
|
2797
|
-
if (ctx.configForms && typeof ctx.configForms.get === 'function') {
|
|
2798
|
-
try {
|
|
2799
|
-
const s = ctx.configForms.get(SETTINGS_NS)
|
|
2800
|
-
if (s) return s
|
|
2801
|
-
} catch (_) { /* scope unavailable */ }
|
|
2802
|
-
}
|
|
2803
|
-
if (ctx.settingsScope && typeof ctx.settingsScope.bind === 'function') {
|
|
2804
|
-
try {
|
|
2805
|
-
const s = ctx.settingsScope.bind({ namespace: SETTINGS_NS })
|
|
2806
|
-
if (s) return s
|
|
2807
|
-
} catch (_) { /* scope unavailable */ }
|
|
2808
|
-
}
|
|
2774
|
+
try {
|
|
2775
|
+
const lan = (ctx.get && ctx.get('lanSettings')) || ctx.lanSettings
|
|
2776
|
+
if (lan?.get) return lan.get(SETTINGS_NS)
|
|
2777
|
+
const cf = (ctx.get && ctx.get('configForms')) || ctx.configForms
|
|
2778
|
+
if (cf?.get) return cf.get(SETTINGS_NS)
|
|
2779
|
+
const ss = (ctx.get && ctx.get('settingsScope')) || ctx.settingsScope
|
|
2780
|
+
if (ss?.bind) return ss.bind({ namespace: SETTINGS_NS })
|
|
2781
|
+
} catch (_) { /* scope unavailable */ }
|
|
2809
2782
|
return null
|
|
2810
2783
|
}
|
|
2811
2784
|
|
|
@@ -2813,70 +2786,93 @@ window.__ModuleLoader__.load({
|
|
|
2813
2786
|
const listeners = new Set()
|
|
2814
2787
|
let activeTarget = resolveActiveScope(ctx)
|
|
2815
2788
|
let activeUnsub = null
|
|
2789
|
+
let httpSnapshot = { status: 'loading', writable: true, value: {} }
|
|
2790
|
+
|
|
2791
|
+
const notify = () => { for (const fn of listeners) fn() }
|
|
2792
|
+
|
|
2793
|
+
const syncHttpConfig = () => {
|
|
2794
|
+
if (typeof fetch !== 'function') return
|
|
2795
|
+
fetch('/dsh-image-gen/config', { cache: 'no-store' })
|
|
2796
|
+
.then((r) => r.json())
|
|
2797
|
+
.then((data) => {
|
|
2798
|
+
if (data && data.ok && data.config) {
|
|
2799
|
+
httpSnapshot = { status: 'ready', writable: true, value: data.config }
|
|
2800
|
+
notify()
|
|
2801
|
+
}
|
|
2802
|
+
})
|
|
2803
|
+
.catch(() => {})
|
|
2804
|
+
}
|
|
2805
|
+
syncHttpConfig()
|
|
2816
2806
|
|
|
2817
2807
|
const bindTarget = (target) => {
|
|
2818
2808
|
if (!target || target === activeTarget) return
|
|
2819
2809
|
if (typeof activeUnsub === 'function') {
|
|
2820
|
-
try { activeUnsub() } catch
|
|
2810
|
+
try { activeUnsub() } catch { /* ignore */ }
|
|
2821
2811
|
activeUnsub = null
|
|
2822
2812
|
}
|
|
2823
2813
|
activeTarget = target
|
|
2824
2814
|
if (typeof activeTarget.subscribe === 'function') {
|
|
2825
2815
|
try {
|
|
2826
|
-
activeUnsub = activeTarget.subscribe(
|
|
2827
|
-
|
|
2828
|
-
})
|
|
2829
|
-
} catch (_) { /* scope unavailable */ }
|
|
2816
|
+
activeUnsub = activeTarget.subscribe(notify)
|
|
2817
|
+
} catch { /* ignore */ }
|
|
2830
2818
|
}
|
|
2831
|
-
|
|
2819
|
+
notify()
|
|
2832
2820
|
}
|
|
2833
2821
|
|
|
2834
|
-
if (activeTarget
|
|
2835
|
-
try {
|
|
2836
|
-
activeUnsub = activeTarget.subscribe(() => {
|
|
2837
|
-
for (const fn of listeners) fn()
|
|
2838
|
-
})
|
|
2839
|
-
} catch (_) { /* scope unavailable */ }
|
|
2822
|
+
if (activeTarget?.subscribe) {
|
|
2823
|
+
try { activeUnsub = activeTarget.subscribe(notify) } catch { /* ignore */ }
|
|
2840
2824
|
}
|
|
2841
2825
|
|
|
2842
2826
|
if (typeof ctx?.inject === 'function') {
|
|
2843
2827
|
try {
|
|
2844
2828
|
ctx.inject(['configForms'], (sctx) => {
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
if (s) bindTarget(s)
|
|
2848
|
-
} catch (_) { /* scope unavailable */ }
|
|
2829
|
+
const s = sctx?.configForms?.get?.(SETTINGS_NS)
|
|
2830
|
+
if (s) bindTarget(s)
|
|
2849
2831
|
})
|
|
2850
|
-
} catch (_) { /* scope unavailable */ }
|
|
2851
|
-
try {
|
|
2852
2832
|
ctx.inject(['settingsScope'], (sctx) => {
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
if (s) bindTarget(s)
|
|
2856
|
-
} catch (_) { /* scope unavailable */ }
|
|
2833
|
+
const s = sctx?.settingsScope?.bind?.({ namespace: SETTINGS_NS })
|
|
2834
|
+
if (s) bindTarget(s)
|
|
2857
2835
|
})
|
|
2858
|
-
} catch
|
|
2836
|
+
} catch { /* ignore */ }
|
|
2859
2837
|
}
|
|
2860
2838
|
|
|
2861
2839
|
return {
|
|
2862
2840
|
getSnapshot() {
|
|
2863
2841
|
const target = activeTarget || resolveActiveScope(ctx)
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
return
|
|
2842
|
+
const snap = target?.getSnapshot ? target.getSnapshot() : null
|
|
2843
|
+
if (snap?.status === 'ready' && snap.writable) return snap
|
|
2844
|
+
if (httpSnapshot.status === 'ready') return httpSnapshot
|
|
2845
|
+
return snap || httpSnapshot
|
|
2868
2846
|
},
|
|
2869
2847
|
async set(key, val) {
|
|
2870
2848
|
const target = activeTarget || resolveActiveScope(ctx)
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
}
|
|
2849
|
+
const snap = target?.getSnapshot ? target.getSnapshot() : null
|
|
2850
|
+
if (snap?.status === 'ready' && snap.writable && target.set) return target.set(key, val)
|
|
2851
|
+
httpSnapshot = { ...httpSnapshot, value: { ...httpSnapshot.value, [key]: val } }
|
|
2852
|
+
notify()
|
|
2853
|
+
try {
|
|
2854
|
+
await fetch('/dsh-image-gen/config', {
|
|
2855
|
+
method: 'PUT',
|
|
2856
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2857
|
+
body: JSON.stringify({ [key]: val }),
|
|
2858
|
+
})
|
|
2859
|
+
} catch { /* ignore */ }
|
|
2874
2860
|
},
|
|
2875
2861
|
async delete(key) {
|
|
2876
2862
|
const target = activeTarget || resolveActiveScope(ctx)
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
}
|
|
2863
|
+
const snap = target?.getSnapshot ? target.getSnapshot() : null
|
|
2864
|
+
if (snap?.status === 'ready' && snap.writable && target.delete) return target.delete(key)
|
|
2865
|
+
const nextVal = { ...httpSnapshot.value }
|
|
2866
|
+
delete nextVal[key]
|
|
2867
|
+
httpSnapshot = { ...httpSnapshot, value: nextVal }
|
|
2868
|
+
notify()
|
|
2869
|
+
try {
|
|
2870
|
+
await fetch('/dsh-image-gen/config', {
|
|
2871
|
+
method: 'PUT',
|
|
2872
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2873
|
+
body: JSON.stringify({ [key]: undefined }),
|
|
2874
|
+
})
|
|
2875
|
+
} catch { /* ignore */ }
|
|
2880
2876
|
},
|
|
2881
2877
|
subscribe(fn) {
|
|
2882
2878
|
listeners.add(fn)
|
|
@@ -2905,27 +2901,17 @@ window.__ModuleLoader__.load({
|
|
|
2905
2901
|
if (typeof ctx.slots.inject === 'function') {
|
|
2906
2902
|
try {
|
|
2907
2903
|
ctx.slots.inject(slotName, () => {
|
|
2908
|
-
try {
|
|
2909
|
-
return registerFn()
|
|
2910
|
-
} catch (err) {
|
|
2911
|
-
console.warn('[dsh-image-gen] Error registering slot ' + slotName + ':', err)
|
|
2912
|
-
}
|
|
2904
|
+
try { return registerFn() } catch (err) { console.warn('[dsh-image-gen] Slot err ' + slotName + ':', err) }
|
|
2913
2905
|
})
|
|
2914
2906
|
return
|
|
2915
|
-
} catch (err) {
|
|
2916
|
-
console.warn('[dsh-image-gen] Failed to inject slot ' + slotName + ':', err)
|
|
2917
|
-
}
|
|
2907
|
+
} catch (err) { console.warn('[dsh-image-gen] Failed inject ' + slotName + ':', err) }
|
|
2918
2908
|
}
|
|
2919
2909
|
if (typeof ctx.slots.register === 'function') {
|
|
2920
|
-
try {
|
|
2921
|
-
registerFn()
|
|
2922
|
-
} catch (err) {
|
|
2923
|
-
console.warn('[dsh-image-gen] Failed direct registration for ' + slotName + ':', err)
|
|
2924
|
-
}
|
|
2910
|
+
try { registerFn() } catch (err) { console.warn('[dsh-image-gen] Direct reg err ' + slotName + ':', err) }
|
|
2925
2911
|
}
|
|
2926
2912
|
}
|
|
2927
2913
|
|
|
2928
|
-
// Register toolviews for all
|
|
2914
|
+
// Register toolviews for all visual tools
|
|
2929
2915
|
const toolviewTools = [
|
|
2930
2916
|
'generate_image',
|
|
2931
2917
|
'edit_image',
|
|
@@ -2981,7 +2967,6 @@ window.__ModuleLoader__.load({
|
|
|
2981
2967
|
)
|
|
2982
2968
|
)
|
|
2983
2969
|
|
|
2984
|
-
|
|
2985
2970
|
// Native Sidebar Right Pane Tab & BetterSidebar
|
|
2986
2971
|
if (typeof ctx.inject === 'function') {
|
|
2987
2972
|
try {
|
|
@@ -3035,7 +3020,7 @@ window.__ModuleLoader__.load({
|
|
|
3035
3020
|
console.warn('[dsh-image-gen] native sidebar registration failed', e)
|
|
3036
3021
|
}
|
|
3037
3022
|
})
|
|
3038
|
-
} catch (
|
|
3023
|
+
} catch (_) { /* native sidebar unavailable */ }
|
|
3039
3024
|
|
|
3040
3025
|
try {
|
|
3041
3026
|
ctx.inject(['betterSidebar'], (sctx) => {
|
|
@@ -3053,7 +3038,7 @@ window.__ModuleLoader__.load({
|
|
|
3053
3038
|
console.warn('[dsh-image-gen] betterSidebar registerTab failed', e)
|
|
3054
3039
|
}
|
|
3055
3040
|
})
|
|
3056
|
-
} catch (
|
|
3041
|
+
} catch (_) { /* betterSidebar unavailable */ }
|
|
3057
3042
|
}
|
|
3058
3043
|
|
|
3059
3044
|
// Conversation header utilities chip (quick-access gallery button in chat header)
|
|
@@ -3070,22 +3055,7 @@ window.__ModuleLoader__.load({
|
|
|
3070
3055
|
)
|
|
3071
3056
|
)
|
|
3072
3057
|
|
|
3073
|
-
//
|
|
3074
|
-
registerSlotWhenReady('plugins.item', () =>
|
|
3075
|
-
ctx.slots.register(
|
|
3076
|
-
{
|
|
3077
|
-
name: 'plugins.item',
|
|
3078
|
-
id: 'dsh-image-gen',
|
|
3079
|
-
order: 60,
|
|
3080
|
-
label: () => 'Image Studio',
|
|
3081
|
-
locale: NS,
|
|
3082
|
-
inject: () => cardOnce().inject(),
|
|
3083
|
-
},
|
|
3084
|
-
(props) => react.createElement(ErrorBoundary, null, react.createElement(FalSettingsCard, props))
|
|
3085
|
-
)
|
|
3086
|
-
)
|
|
3087
|
-
|
|
3088
|
-
// Settings card item (legacy seat, kept as a fallback)
|
|
3058
|
+
// Settings card item — sole slot registration for settings card (#208, #300)
|
|
3089
3059
|
registerSlotWhenReady('settings.plugin.item', () =>
|
|
3090
3060
|
ctx.slots.register(
|
|
3091
3061
|
{
|
|
@@ -3098,7 +3068,6 @@ window.__ModuleLoader__.load({
|
|
|
3098
3068
|
)
|
|
3099
3069
|
)
|
|
3100
3070
|
}
|
|
3101
|
-
|
|
3102
3071
|
// -------------------------------------------------------------- Asset Vault View (#159)
|
|
3103
3072
|
function AssetVaultView(props) {
|
|
3104
3073
|
const { ctx, onSelectAsset } = props
|
|
@@ -3146,7 +3115,7 @@ window.__ModuleLoader__.load({
|
|
|
3146
3115
|
}, [q, provider, aspect, sort])
|
|
3147
3116
|
|
|
3148
3117
|
const handleDelete = (id) => {
|
|
3149
|
-
if (!confirm('Are you sure you want to delete this asset?')) return
|
|
3118
|
+
if (!window.confirm('Are you sure you want to delete this asset?')) return
|
|
3150
3119
|
fetch('/dsh-image-gen/vault?id=' + encodeURIComponent(id), { method: 'DELETE' })
|
|
3151
3120
|
.then((r) => r.json())
|
|
3152
3121
|
.then((res) => {
|
|
@@ -3342,7 +3311,7 @@ window.__ModuleLoader__.load({
|
|
|
3342
3311
|
const [isFullscreen, setIsFullscreen] = react.useState(false)
|
|
3343
3312
|
const [layoutGrid, setLayoutGrid] = react.useState('1x1') // '1x1' | '2x2' | '1x4'
|
|
3344
3313
|
const [prompt, setPrompt] = react.useState(() => {
|
|
3345
|
-
try { return localStorage.getItem('dsh_studio_prompt') || '' } catch (_) { return '' }
|
|
3314
|
+
try { return window.localStorage.getItem('dsh_studio_prompt') || '' } catch (_) { return '' }
|
|
3346
3315
|
})
|
|
3347
3316
|
const [stylePreset, setStylePreset] = react.useState('none')
|
|
3348
3317
|
const [aspectRatio, setAspectRatio] = react.useState('1:1')
|
|
@@ -3381,7 +3350,7 @@ window.__ModuleLoader__.load({
|
|
|
3381
3350
|
|
|
3382
3351
|
const updatePrompt = (val) => {
|
|
3383
3352
|
setPrompt(val)
|
|
3384
|
-
try { localStorage.setItem('dsh_studio_prompt', val) } catch (_) { /* storage unavailable */ }
|
|
3353
|
+
try { window.localStorage.setItem('dsh_studio_prompt', val) } catch (_) { /* storage unavailable */ }
|
|
3385
3354
|
}
|
|
3386
3355
|
|
|
3387
3356
|
const handleSelectFromVault = (asset) => {
|
package/lib/fallback-router.js
CHANGED
|
@@ -35,6 +35,25 @@ export function isFatalPromptError(error) {
|
|
|
35
35
|
export function isRetryableProviderError(error) {
|
|
36
36
|
if (isFatalPromptError(error)) return false
|
|
37
37
|
const msg = (error?.message || String(error || '')).toLowerCase()
|
|
38
|
+
|
|
39
|
+
// Non-retryable: authentication, authorization, or invalid request / client configuration errors
|
|
40
|
+
if (
|
|
41
|
+
msg.includes('401') ||
|
|
42
|
+
msg.includes('403') ||
|
|
43
|
+
msg.includes('unauthorized') ||
|
|
44
|
+
msg.includes('forbidden') ||
|
|
45
|
+
msg.includes('invalid api key') ||
|
|
46
|
+
msg.includes('invalid key') ||
|
|
47
|
+
msg.includes('api key missing') ||
|
|
48
|
+
msg.includes('api_key_invalid') ||
|
|
49
|
+
msg.includes('bad request') ||
|
|
50
|
+
msg.includes('invalid argument') ||
|
|
51
|
+
msg.includes('invalid parameter') ||
|
|
52
|
+
msg.includes('400')
|
|
53
|
+
) {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
38
57
|
return (
|
|
39
58
|
msg.includes('429') ||
|
|
40
59
|
msg.includes('rate limit') ||
|
|
@@ -57,10 +76,9 @@ export function isRetryableProviderError(error) {
|
|
|
57
76
|
msg.includes('balance is insufficient') ||
|
|
58
77
|
msg.includes('quota') ||
|
|
59
78
|
msg.includes('credit') ||
|
|
60
|
-
msg.includes('unauthorized') ||
|
|
61
|
-
msg.includes('401') ||
|
|
62
|
-
msg.includes('invalid api key') ||
|
|
63
79
|
msg.includes('econnrefused') ||
|
|
80
|
+
msg.includes('econnreset') ||
|
|
81
|
+
msg.includes('etimedout') ||
|
|
64
82
|
msg.includes('enotfound') ||
|
|
65
83
|
msg.includes('fetch failed') ||
|
|
66
84
|
msg.includes('network')
|
|
@@ -150,6 +168,10 @@ export async function executeWithFallback(generators, chain, seed, prompt, optio
|
|
|
150
168
|
throw new Error(`Content or policy error on ${providerKey} (not cascading): ${formatted}`)
|
|
151
169
|
}
|
|
152
170
|
|
|
171
|
+
if (!isRetryableProviderError(err)) {
|
|
172
|
+
throw new Error(`Non-retryable provider error on ${providerKey} (not cascading): ${formatted}`)
|
|
173
|
+
}
|
|
174
|
+
|
|
153
175
|
if (logger && typeof logger.warn === 'function') {
|
|
154
176
|
logger.warn(`[dsh-image-gen] Provider ${providerKey} failed: ${formatted}. Trying next candidate...`)
|
|
155
177
|
}
|