@lokvis/ui-react 0.2.1 → 0.4.1

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.
Files changed (165) hide show
  1. package/dist/components/AssetPanel.d.ts.map +1 -1
  2. package/dist/components/AssetPanel.js +18 -62
  3. package/dist/components/AssetPanel.js.map +1 -1
  4. package/dist/components/Canvas.d.ts +4 -4
  5. package/dist/components/Canvas.d.ts.map +1 -1
  6. package/dist/components/Canvas.js +9 -9
  7. package/dist/components/Canvas.js.map +1 -1
  8. package/dist/components/CommandPalette.d.ts +7 -7
  9. package/dist/components/CommandPalette.d.ts.map +1 -1
  10. package/dist/components/CommandPalette.js +10 -10
  11. package/dist/components/CommandPalette.js.map +1 -1
  12. package/dist/components/CompareSlider.d.ts +9 -8
  13. package/dist/components/CompareSlider.d.ts.map +1 -1
  14. package/dist/components/CompareSlider.js +10 -9
  15. package/dist/components/CompareSlider.js.map +1 -1
  16. package/dist/components/DownloadPanel.d.ts +3 -3
  17. package/dist/components/DownloadPanel.d.ts.map +1 -1
  18. package/dist/components/DownloadPanel.js +10 -17
  19. package/dist/components/DownloadPanel.js.map +1 -1
  20. package/dist/components/ErrorBanner.d.ts +2 -2
  21. package/dist/components/ErrorBanner.d.ts.map +1 -1
  22. package/dist/components/ErrorBanner.js +3 -3
  23. package/dist/components/ErrorBanner.js.map +1 -1
  24. package/dist/components/ErrorBoundary.d.ts +40 -0
  25. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  26. package/dist/components/ErrorBoundary.js +52 -0
  27. package/dist/components/ErrorBoundary.js.map +1 -0
  28. package/dist/components/ExifPanel.d.ts +1 -1
  29. package/dist/components/ExifPanel.d.ts.map +1 -1
  30. package/dist/components/ExifPanel.js +2 -2
  31. package/dist/components/ExifPanel.js.map +1 -1
  32. package/dist/components/GlobalDropzone.d.ts +5 -5
  33. package/dist/components/GlobalDropzone.d.ts.map +1 -1
  34. package/dist/components/GlobalDropzone.js +15 -8
  35. package/dist/components/GlobalDropzone.js.map +1 -1
  36. package/dist/components/HistoryPanel.d.ts +2 -2
  37. package/dist/components/HistoryPanel.d.ts.map +1 -1
  38. package/dist/components/HistoryPanel.js +23 -23
  39. package/dist/components/HistoryPanel.js.map +1 -1
  40. package/dist/components/Inspector.d.ts.map +1 -1
  41. package/dist/components/Inspector.js +13 -10
  42. package/dist/components/Inspector.js.map +1 -1
  43. package/dist/components/ParamForm.d.ts.map +1 -1
  44. package/dist/components/ParamForm.js +10 -7
  45. package/dist/components/ParamForm.js.map +1 -1
  46. package/dist/components/PipelineBar.d.ts.map +1 -1
  47. package/dist/components/PipelineBar.js +19 -28
  48. package/dist/components/PipelineBar.js.map +1 -1
  49. package/dist/components/ProgressBar.d.ts +4 -4
  50. package/dist/components/ProgressBar.d.ts.map +1 -1
  51. package/dist/components/ProgressBar.js +8 -8
  52. package/dist/components/ProgressBar.js.map +1 -1
  53. package/dist/components/StatusBar.d.ts +3 -3
  54. package/dist/components/StatusBar.d.ts.map +1 -1
  55. package/dist/components/StatusBar.js +12 -21
  56. package/dist/components/StatusBar.js.map +1 -1
  57. package/dist/components/StatusDot.d.ts +12 -0
  58. package/dist/components/StatusDot.d.ts.map +1 -0
  59. package/dist/components/StatusDot.js +15 -0
  60. package/dist/components/StatusDot.js.map +1 -0
  61. package/dist/components/ThemeToggle.d.ts +4 -4
  62. package/dist/components/ThemeToggle.d.ts.map +1 -1
  63. package/dist/components/ThemeToggle.js +7 -7
  64. package/dist/components/ThemeToggle.js.map +1 -1
  65. package/dist/components/ToolRunner.d.ts +53 -0
  66. package/dist/components/ToolRunner.d.ts.map +1 -0
  67. package/dist/components/ToolRunner.js +142 -0
  68. package/dist/components/ToolRunner.js.map +1 -0
  69. package/dist/components/Toolbar.d.ts.map +1 -1
  70. package/dist/components/Toolbar.js +3 -3
  71. package/dist/components/Toolbar.js.map +1 -1
  72. package/dist/components/WorkflowEditor.d.ts +6 -6
  73. package/dist/components/WorkflowEditor.d.ts.map +1 -1
  74. package/dist/components/WorkflowEditor.js +40 -49
  75. package/dist/components/WorkflowEditor.js.map +1 -1
  76. package/dist/components/WorkflowTemplates.d.ts +2 -2
  77. package/dist/components/WorkflowTemplates.d.ts.map +1 -1
  78. package/dist/components/WorkflowTemplates.js +17 -7
  79. package/dist/components/WorkflowTemplates.js.map +1 -1
  80. package/dist/components/Workspace.d.ts +45 -23
  81. package/dist/components/Workspace.d.ts.map +1 -1
  82. package/dist/components/Workspace.js +87 -40
  83. package/dist/components/Workspace.js.map +1 -1
  84. package/dist/hooks/useCustomPresets.d.ts +98 -0
  85. package/dist/hooks/useCustomPresets.d.ts.map +1 -0
  86. package/dist/hooks/useCustomPresets.js +210 -0
  87. package/dist/hooks/useCustomPresets.js.map +1 -0
  88. package/dist/hooks/useLokvis.d.ts +19 -1
  89. package/dist/hooks/useLokvis.d.ts.map +1 -1
  90. package/dist/hooks/useLokvis.js +30 -9
  91. package/dist/hooks/useLokvis.js.map +1 -1
  92. package/dist/index.d.ts +4 -0
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +6 -0
  95. package/dist/index.js.map +1 -1
  96. package/dist/store/assets-slice.d.ts +8 -1
  97. package/dist/store/assets-slice.d.ts.map +1 -1
  98. package/dist/store/assets-slice.js +101 -54
  99. package/dist/store/assets-slice.js.map +1 -1
  100. package/dist/store/capabilities-slice.d.ts +1 -1
  101. package/dist/store/capabilities-slice.d.ts.map +1 -1
  102. package/dist/store/capabilities-slice.js +8 -1
  103. package/dist/store/capabilities-slice.js.map +1 -1
  104. package/dist/store/index.d.ts +1 -1
  105. package/dist/store/index.d.ts.map +1 -1
  106. package/dist/store/index.js +1 -1
  107. package/dist/store/index.js.map +1 -1
  108. package/dist/store/runtime-slice.d.ts.map +1 -1
  109. package/dist/store/runtime-slice.js +22 -16
  110. package/dist/store/runtime-slice.js.map +1 -1
  111. package/dist/store/subscribe-utils.d.ts +45 -0
  112. package/dist/store/subscribe-utils.d.ts.map +1 -0
  113. package/dist/store/subscribe-utils.js +69 -0
  114. package/dist/store/subscribe-utils.js.map +1 -0
  115. package/dist/store/types.d.ts +19 -11
  116. package/dist/store/types.d.ts.map +1 -1
  117. package/dist/store/types.js +0 -10
  118. package/dist/store/types.js.map +1 -1
  119. package/dist/store/workflow-slice.d.ts +1 -1
  120. package/dist/store/workflow-slice.d.ts.map +1 -1
  121. package/dist/store/workflow-slice.js +19 -51
  122. package/dist/store/workflow-slice.js.map +1 -1
  123. package/dist/utils.d.ts +24 -0
  124. package/dist/utils.d.ts.map +1 -0
  125. package/dist/utils.js +31 -0
  126. package/dist/utils.js.map +1 -0
  127. package/package.json +7 -6
  128. package/src/components/AssetPanel.tsx +224 -264
  129. package/src/components/Canvas.tsx +178 -174
  130. package/src/components/CommandPalette.tsx +242 -242
  131. package/src/components/CompareSlider.tsx +168 -165
  132. package/src/components/DownloadPanel.tsx +201 -207
  133. package/src/components/ErrorBanner.tsx +64 -64
  134. package/src/components/ErrorBoundary.tsx +101 -0
  135. package/src/components/ExifPanel.tsx +154 -154
  136. package/src/components/GlobalDropzone.tsx +175 -170
  137. package/src/components/HistoryPanel.tsx +219 -219
  138. package/src/components/Inspector.tsx +145 -137
  139. package/src/components/ParamForm.tsx +140 -137
  140. package/src/components/PipelineBar.tsx +97 -104
  141. package/src/components/ProgressBar.tsx +78 -78
  142. package/src/components/StatusBar.tsx +145 -152
  143. package/src/components/StatusDot.tsx +27 -0
  144. package/src/components/ThemeToggle.tsx +98 -98
  145. package/src/components/ToolRunner.tsx +352 -0
  146. package/src/components/Toolbar.tsx +65 -65
  147. package/src/components/WorkflowEditor.tsx +333 -326
  148. package/src/components/WorkflowTemplates.tsx +101 -78
  149. package/src/components/Workspace.tsx +310 -223
  150. package/src/css-modules.d.ts +3 -0
  151. package/src/hooks/useCustomPresets.ts +284 -0
  152. package/src/hooks/useLokvis.ts +43 -10
  153. package/src/index.ts +7 -0
  154. package/src/store/assets-slice.ts +106 -52
  155. package/src/store/capabilities-slice.ts +10 -2
  156. package/src/store/index.ts +1 -1
  157. package/src/store/runtime-slice.ts +20 -15
  158. package/src/store/subscribe-utils.ts +82 -0
  159. package/src/store/types.ts +19 -12
  160. package/src/store/workflow-slice.ts +19 -53
  161. package/src/utils.ts +41 -0
  162. package/dist/store.d.ts +0 -76
  163. package/dist/store.d.ts.map +0 -1
  164. package/dist/store.js +0 -217
  165. package/dist/store.js.map +0 -1
@@ -0,0 +1,210 @@
1
+ /**
2
+ * useCustomPresets - 自定义尺寸预设持久化 hook(W17.5)
3
+ *
4
+ * 提供用户自定义图像尺寸预设的本地保存能力(免费 3 / Pro 无限)。
5
+ * 数据存储在 localStorage 的 `lokvis.customPresets` key,JSON 数组形式。
6
+ *
7
+ * 与 useWorkflows 的区别:
8
+ * - 自定义预设是尺寸配置(name/width/height/fit/format),轻量
9
+ * - 工作流槽位是完整 Workflow 定义(含 nodes/edges/inputs/outputs)
10
+ *
11
+ * 与 PLATFORM_PRESETS 的区别:
12
+ * - PLATFORM_PRESETS 是内置的固定预设(YouTube/TikTok 等平台标准尺寸)
13
+ * - 自定义预设是用户自建的任意尺寸配置,自由命名
14
+ *
15
+ * id 命名空间约定:自定义预设 id 以 `custom.` 前缀,与内置预设区分
16
+ * (如 `custom.my-instagram-square`),避免 PlatformPresetSelector 冲突。
17
+ *
18
+ * 多 tab / 多实例同步:
19
+ * - 原生 storage 事件:跨 tab 同步
20
+ * - 自定义 SYNC_EVENT:同 tab 多实例同步
21
+ *
22
+ * @module useCustomPresets
23
+ */
24
+ import { useCallback, useEffect, useState } from 'react';
25
+ const STORAGE_KEY = 'lokvis.customPresets';
26
+ /** 同 tab 多实例同步用的自定义事件名 */
27
+ const SYNC_EVENT = 'lokvis:custom-presets-change';
28
+ /** 免费用户自定义预设上限 */
29
+ export const FREE_PRESET_LIMIT = 3;
30
+ /** Pro 用户无上限 */
31
+ export const PRO_PRESET_LIMIT = Infinity;
32
+ /** 类型守卫:判断 unknown 是否为 Record<string, unknown> */
33
+ function isRecord(x) {
34
+ return typeof x === 'object' && x !== null;
35
+ }
36
+ const VALID_FIT_STRATEGIES = ['cover', 'contain', 'fill', 'inside', 'outside'];
37
+ const VALID_FORMATS = ['png', 'jpeg', 'webp'];
38
+ /** 从 localStorage 读取自定义预设。
39
+ * 容错:JSON 解析失败 / 非数组 / 字段缺失时返回空数组。
40
+ *
41
+ * 导出供测试直接调用(避免渲染 React 组件)。 */
42
+ export function readCustomPresetsFromStorage() {
43
+ if (typeof window === 'undefined')
44
+ return [];
45
+ try {
46
+ const raw = window.localStorage.getItem(STORAGE_KEY);
47
+ if (!raw)
48
+ return [];
49
+ const parsed = JSON.parse(raw);
50
+ if (!Array.isArray(parsed))
51
+ return [];
52
+ // 字段白名单过滤(防御损坏数据)
53
+ const result = parsed.filter((it) => {
54
+ if (!isRecord(it))
55
+ return false;
56
+ if (typeof it.id !== 'string' ||
57
+ typeof it.name !== 'string' ||
58
+ typeof it.width !== 'number' ||
59
+ typeof it.height !== 'number' ||
60
+ typeof it.fit !== 'string' ||
61
+ typeof it.createdAt !== 'number' ||
62
+ typeof it.updatedAt !== 'number') {
63
+ return false;
64
+ }
65
+ // id 必须以 custom. 前缀开头,与内置 PLATFORM_PRESETS 隔离
66
+ if (!it.id.startsWith('custom.'))
67
+ return false;
68
+ // fit 必须是合法值
69
+ if (!VALID_FIT_STRATEGIES.includes(it.fit)) {
70
+ return false;
71
+ }
72
+ // format 可选,若有则必须是合法值
73
+ if (it.format !== undefined && !VALID_FORMATS.includes(it.format)) {
74
+ return false;
75
+ }
76
+ // width / height 必须为正整数
77
+ if (it.width <= 0 || it.height <= 0)
78
+ return false;
79
+ return true;
80
+ });
81
+ // 按 updatedAt 降序(最新在前),与接口契约一致
82
+ result.sort((a, b) => b.updatedAt - a.updatedAt);
83
+ return result;
84
+ }
85
+ catch {
86
+ console.warn('[lokvis] Failed to read custom presets from storage');
87
+ return [];
88
+ }
89
+ }
90
+ /**
91
+ * 写入 localStorage。
92
+ * @returns true 成功;false 失败(隐私模式 / 配额超限 / 序列化异常)
93
+ *
94
+ * 导出供测试直接调用。
95
+ */
96
+ export function writeCustomPresetsToStorage(presets) {
97
+ if (typeof window === 'undefined')
98
+ return false;
99
+ try {
100
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(presets));
101
+ window.dispatchEvent(new CustomEvent(SYNC_EVENT));
102
+ return true;
103
+ }
104
+ catch (err) {
105
+ console.warn('[lokvis] Failed to persist custom presets to localStorage:', err);
106
+ return false;
107
+ }
108
+ }
109
+ /** 生成唯一 ID(custom. 前缀,与内置预设命名空间隔离) */
110
+ export function genCustomPresetId() {
111
+ const rand = Math.random().toString(36).slice(2, 8);
112
+ return `custom.${Date.now()}-${rand}`;
113
+ }
114
+ /**
115
+ * @param isPro 是否为 Pro 模式。父组件从 runtime.isPro 传入。
116
+ * 影响 limit:免费 3 / Pro 无上限。
117
+ */
118
+ export function useCustomPresets(isPro = false) {
119
+ const limit = isPro ? PRO_PRESET_LIMIT : FREE_PRESET_LIMIT;
120
+ const [presets, setPresets] = useState(() => readCustomPresetsFromStorage());
121
+ // 监听跨 tab storage + 同 tab SYNC_EVENT
122
+ useEffect(() => {
123
+ const handler = () => setPresets(readCustomPresetsFromStorage());
124
+ window.addEventListener('storage', handler);
125
+ window.addEventListener(SYNC_EVENT, handler);
126
+ return () => {
127
+ window.removeEventListener('storage', handler);
128
+ window.removeEventListener(SYNC_EVENT, handler);
129
+ };
130
+ }, []);
131
+ const save = useCallback((input) => {
132
+ // 输入校验
133
+ if (input.width <= 0 || input.height <= 0) {
134
+ throw new Error('预设尺寸必须为正数');
135
+ }
136
+ if (!input.name.trim()) {
137
+ throw new Error('预设名称不能为空');
138
+ }
139
+ const current = readCustomPresetsFromStorage();
140
+ const now = Date.now();
141
+ // 更新已有
142
+ if (input.id) {
143
+ const existing = current.find((p) => p.id === input.id);
144
+ if (existing) {
145
+ const updated = {
146
+ ...existing,
147
+ name: input.name,
148
+ width: input.width,
149
+ height: input.height,
150
+ fit: input.fit ?? existing.fit,
151
+ format: input.format ?? existing.format,
152
+ updatedAt: now,
153
+ };
154
+ const next = current.map((p) => (p.id === input.id ? updated : p));
155
+ const ok = writeCustomPresetsToStorage(next);
156
+ if (!ok) {
157
+ console.warn('[lokvis] 自定义预设未持久化到 localStorage,仅当前会话有效');
158
+ }
159
+ setPresets(next);
160
+ return updated;
161
+ }
162
+ }
163
+ // 新增
164
+ if (current.length >= limit) {
165
+ throw new Error(`自定义预设已达上限(${limit} 个)${isPro ? '' : ',升级 Pro 可无限制保存'}`);
166
+ }
167
+ const preset = {
168
+ id: genCustomPresetId(),
169
+ name: input.name,
170
+ width: input.width,
171
+ height: input.height,
172
+ fit: input.fit ?? 'cover',
173
+ format: input.format,
174
+ createdAt: now,
175
+ updatedAt: now,
176
+ };
177
+ const next = [...current, preset];
178
+ const ok = writeCustomPresetsToStorage(next);
179
+ if (!ok) {
180
+ console.warn('[lokvis] 自定义预设未持久化到 localStorage,仅当前会话有效');
181
+ }
182
+ setPresets(next);
183
+ return preset;
184
+ }, [limit, isPro]);
185
+ const remove = useCallback((id) => {
186
+ const current = readCustomPresetsFromStorage();
187
+ const next = current.filter((p) => p.id !== id);
188
+ const ok = writeCustomPresetsToStorage(next);
189
+ if (!ok) {
190
+ console.warn('[lokvis] Failed to persist custom presets removal');
191
+ }
192
+ setPresets(next);
193
+ }, []);
194
+ const get = useCallback((id) => {
195
+ const current = readCustomPresetsFromStorage();
196
+ return current.find((p) => p.id === id) ?? null;
197
+ }, []);
198
+ const canSaveMore = presets.length < limit;
199
+ const remaining = Math.max(0, limit - presets.length);
200
+ return {
201
+ presets,
202
+ save,
203
+ remove,
204
+ get,
205
+ limit,
206
+ canSaveMore,
207
+ remaining,
208
+ };
209
+ }
210
+ //# sourceMappingURL=useCustomPresets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCustomPresets.js","sourceRoot":"","sources":["../../src/hooks/useCustomPresets.ts"],"names":[],"mappings":"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"}
@@ -14,14 +14,32 @@
14
14
  * return <Workspace />;
15
15
  * }
16
16
  * ```
17
+ *
18
+ * @example 接 cloud session(W17.6)
19
+ * ```tsx
20
+ * const { runtime } = useLokvis({
21
+ * plugins: [imageToolsPlugin()],
22
+ * auth: { session: cloudJwt }, // → isPro: true,批量/槽位无上限
23
+ * });
24
+ * ```
17
25
  */
18
26
  import type { LokvisRuntime, RuntimeConfig } from '@lokvis/runtime';
19
- import type { PluginLoadEntry } from '@lokvis/sdk';
27
+ import type { LokvisAuthSession, PluginLoadEntry } from '@lokvis/sdk';
20
28
  export interface UseLokvisOptions extends RuntimeConfig {
21
29
  /** 预加载的插件列表 */
22
30
  plugins?: PluginLoadEntry[];
23
31
  /** 是否在挂载时自动初始化(默认 true) */
24
32
  autoInit?: boolean;
33
+ /**
34
+ * Cloud 注入的认证信息(W17.3 / W17.6)。
35
+ *
36
+ * 透传到 `createLokvis({ auth })`,SDK 据 presence 推导 `isPro`:
37
+ * - 传入非空 `session` 或 `token` 且未显式 `isPro: false` → Pro 模式
38
+ * - 不传 `auth`:保持 free 模式
39
+ *
40
+ * 详见 `@lokvis/sdk` 的 `LokvisAuthSession` 与 `resolveIsPro()` 文档。
41
+ */
42
+ auth?: LokvisAuthSession;
25
43
  }
26
44
  export interface UseLokvisResult {
27
45
  runtime: LokvisRuntime | null;
@@ -1 +1 @@
1
- {"version":3,"file":"useLokvis.d.ts","sourceRoot":"","sources":["../../src/hooks/useLokvis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,eAAe;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC;IACpD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAwCzE"}
1
+ {"version":3,"file":"useLokvis.d.ts","sourceRoot":"","sources":["../../src/hooks/useLokvis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGtE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,eAAe;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC;IACpD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAuDzE"}
@@ -14,33 +14,55 @@
14
14
  * return <Workspace />;
15
15
  * }
16
16
  * ```
17
+ *
18
+ * @example 接 cloud session(W17.6)
19
+ * ```tsx
20
+ * const { runtime } = useLokvis({
21
+ * plugins: [imageToolsPlugin()],
22
+ * auth: { session: cloudJwt }, // → isPro: true,批量/槽位无上限
23
+ * });
24
+ * ```
17
25
  */
18
26
  import { useEffect, useRef, useState } from 'react';
19
27
  import { createLokvis } from '@lokvis/sdk';
20
28
  import { useWorkspaceStore } from '../store/index.js';
21
29
  export function useLokvis(options = {}) {
22
- const { plugins = [], autoInit = true, ...runtimeConfig } = options;
30
+ const { plugins = [], autoInit = true, auth, ...runtimeConfig } = options;
23
31
  const [runtime, setRuntime] = useState(null);
24
32
  const [status, setStatus] = useState('idle');
25
33
  const [error, setError] = useState(null);
26
- const initRef = useRef(false);
27
34
  const storeInit = useWorkspaceStore((s) => s.init);
35
+ // 用 useRef 持有 plugins / runtimeConfig / auth / storeInit 的最新值,
36
+ // 避免 effect 依赖这些对象引用导致每次 render 都重新初始化 runtime。
37
+ // effect 仅在 authKey / autoInit 变化时触发,内部从 ref 读取当前值。
38
+ const pluginsRef = useRef(plugins);
39
+ const runtimeConfigRef = useRef(runtimeConfig);
40
+ const authRef = useRef(auth);
41
+ const storeInitRef = useRef(storeInit);
42
+ pluginsRef.current = plugins;
43
+ runtimeConfigRef.current = runtimeConfig;
44
+ authRef.current = auth;
45
+ storeInitRef.current = storeInit;
46
+ // 用 JSON.stringify(auth) 作为 effect 依赖,使 auth 变化时重新初始化。
47
+ // (auth 是对象,直接放依赖数组会因引用变化每次 render 都触发;
48
+ // JSON.stringify 提供稳定的 primitive 依赖,只在 auth 内容变化时重 init)
49
+ const authKey = JSON.stringify(auth ?? null);
28
50
  useEffect(() => {
29
- if (!autoInit || initRef.current)
51
+ if (!autoInit)
30
52
  return;
31
- initRef.current = true;
32
53
  let cancelled = false;
33
54
  (async () => {
34
55
  try {
35
56
  setStatus('initializing');
36
57
  const rt = await createLokvis({
37
- ...runtimeConfig,
38
- plugins,
58
+ ...runtimeConfigRef.current,
59
+ plugins: pluginsRef.current,
60
+ auth: authRef.current,
39
61
  });
40
62
  if (cancelled)
41
63
  return;
42
64
  setRuntime(rt);
43
- await storeInit(rt);
65
+ await storeInitRef.current(rt);
44
66
  if (cancelled)
45
67
  return;
46
68
  setStatus('ready');
@@ -55,8 +77,7 @@ export function useLokvis(options = {}) {
55
77
  return () => {
56
78
  cancelled = true;
57
79
  };
58
- // oxlint-disable-next-line react-hooks/exhaustive-deps
59
- }, []);
80
+ }, [authKey, autoInit]);
60
81
  return { runtime, status, error };
61
82
  }
62
83
  //# sourceMappingURL=useLokvis.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLokvis.js","sourceRoot":"","sources":["../../src/hooks/useLokvis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAetD,MAAM,UAAU,SAAS,CAAC,UAA4B,EAAE;IACtD,MAAM,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IACpE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAuB,IAAI,CAAC,CAAC;IACnE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA4B,MAAM,CAAC,CAAC;IACxE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9B,MAAM,SAAS,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEnD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,OAAO;YAAE,OAAO;QACzC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QAEvB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC;gBACH,SAAS,CAAC,cAAc,CAAC,CAAC;gBAC1B,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC;oBAC5B,GAAG,aAAa;oBAChB,OAAO;iBACR,CAAC,CAAC;gBACH,IAAI,SAAS;oBAAE,OAAO;gBACtB,UAAU,CAAC,EAAE,CAAC,CAAC;gBACf,MAAM,SAAS,CAAC,EAAE,CAAC,CAAC;gBACpB,IAAI,SAAS;oBAAE,OAAO;gBACtB,SAAS,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,SAAS;oBAAE,OAAO;gBACtB,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3D,SAAS,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;QACF,uDAAuD;IACzD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"useLokvis.js","sourceRoot":"","sources":["../../src/hooks/useLokvis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAyBtD,MAAM,UAAU,SAAS,CAAC,UAA4B,EAAE;IACtD,MAAM,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,IAAI,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IAC1E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAuB,IAAI,CAAC,CAAC;IACnE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA4B,MAAM,CAAC,CAAC;IACxE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,MAAM,SAAS,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEnD,+DAA+D;IAC/D,gDAAgD;IAChD,oDAAoD;IACpD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IACvC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAC7B,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC;IACzC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC;IAEjC,uDAAuD;IACvD,wCAAwC;IACxC,0DAA0D;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAE7C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ;YAAE,OAAO;QAEtB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC;gBACH,SAAS,CAAC,cAAc,CAAC,CAAC;gBAC1B,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC;oBAC5B,GAAG,gBAAgB,CAAC,OAAO;oBAC3B,OAAO,EAAE,UAAU,CAAC,OAAO;oBAC3B,IAAI,EAAE,OAAO,CAAC,OAAO;iBACtB,CAAC,CAAC;gBACH,IAAI,SAAS;oBAAE,OAAO;gBACtB,UAAU,CAAC,EAAE,CAAC,CAAC;gBACf,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC/B,IAAI,SAAS;oBAAE,OAAO;gBACtB,SAAS,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,SAAS;oBAAE,OAAO;gBACtB,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3D,SAAS,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAExB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACpC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -22,14 +22,17 @@
22
22
  * - `useMediaQuery()` / `useBreakpoints()` - Responsive hooks (W9.8)
23
23
  * - `useCommandPalette()` - ⌘K shortcut registration hook (W9.2)
24
24
  */
25
+ import '@lokvis/ui-core/styles.css';
25
26
  export { useLokvis, type UseLokvisOptions, type UseLokvisResult } from './hooks/useLokvis.js';
26
27
  export { useTheme, type UseThemeResult, type ThemeMode } from './hooks/useTheme.js';
27
28
  export { useMediaQuery, useBreakpoints, type Breakpoints } from './hooks/useMediaQuery.js';
28
29
  export { useWorkflows, FREE_WORKFLOW_LIMIT, PRO_WORKFLOW_LIMIT, type UseWorkflowsResult, type WorkflowSlot, type SaveWorkflowInput } from './hooks/useWorkflows.js';
30
+ export { useCustomPresets, FREE_PRESET_LIMIT, PRO_PRESET_LIMIT, readCustomPresetsFromStorage, writeCustomPresetsToStorage, genCustomPresetId, type UseCustomPresetsResult, type CustomSizePreset, type SavePresetInput } from './hooks/useCustomPresets.js';
29
31
  export { useDebouncedRun, type UseDebouncedRunOptions, type UseDebouncedRunResult } from './hooks/useDebouncedRun.js';
30
32
  export { useShareLink, type UseShareLinkResult, encodeWorkflowForShare, decodeWorkflowFromShare } from './hooks/useShareLink.js';
31
33
  export { useWorkspaceStore, type WorkspaceState, type WorkspaceActions } from './store/index.js';
32
34
  export { Workspace, type WorkspaceProps } from './components/Workspace.js';
35
+ export { ErrorBoundary, type ErrorBoundaryProps } from './components/ErrorBoundary.js';
33
36
  export { AssetPanel } from './components/AssetPanel.js';
34
37
  export { Canvas } from './components/Canvas.js';
35
38
  export { Inspector } from './components/Inspector.js';
@@ -48,6 +51,7 @@ export { GlobalDropzone, type GlobalDropzoneProps } from './components/GlobalDro
48
51
  export { CompareSlider, type CompareSliderProps } from './components/CompareSlider.js';
49
52
  export { DownloadPanel, type DownloadPanelProps } from './components/DownloadPanel.js';
50
53
  export { ThemeToggle, type ThemeToggleProps } from './components/ThemeToggle.js';
54
+ export { ToolRunner, type ToolRunnerProps } from './components/ToolRunner.js';
51
55
  export { WORKFLOW_TEMPLATES, type WorkflowTemplate, type WorkflowTemplateNode, findTemplate, } from './data/workflow-templates.js';
52
56
  export type { WorkspaceEvent, NodeStatus, } from './types.js';
53
57
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACpK,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACtH,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACjI,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEjG,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,KAAK,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC5I,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEjF,OAAO,EACL,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,YAAY,GACb,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EACV,cAAc,EACd,UAAU,GACX,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -22,14 +22,19 @@
22
22
  * - `useMediaQuery()` / `useBreakpoints()` - Responsive hooks (W9.8)
23
23
  * - `useCommandPalette()` - ⌘K shortcut registration hook (W9.2)
24
24
  */
25
+ // 引入设计 token(--lokvis-* CSS 变量),消费方无需手动 import styles.css。
26
+ // sideEffects: ["**/*.css"] 保证 bundler 不 tree-shake 此 import。
27
+ import '@lokvis/ui-core/styles.css';
25
28
  export { useLokvis } from './hooks/useLokvis.js';
26
29
  export { useTheme } from './hooks/useTheme.js';
27
30
  export { useMediaQuery, useBreakpoints } from './hooks/useMediaQuery.js';
28
31
  export { useWorkflows, FREE_WORKFLOW_LIMIT, PRO_WORKFLOW_LIMIT } from './hooks/useWorkflows.js';
32
+ export { useCustomPresets, FREE_PRESET_LIMIT, PRO_PRESET_LIMIT, readCustomPresetsFromStorage, writeCustomPresetsToStorage, genCustomPresetId } from './hooks/useCustomPresets.js';
29
33
  export { useDebouncedRun } from './hooks/useDebouncedRun.js';
30
34
  export { useShareLink, encodeWorkflowForShare, decodeWorkflowFromShare } from './hooks/useShareLink.js';
31
35
  export { useWorkspaceStore } from './store/index.js';
32
36
  export { Workspace } from './components/Workspace.js';
37
+ export { ErrorBoundary } from './components/ErrorBoundary.js';
33
38
  export { AssetPanel } from './components/AssetPanel.js';
34
39
  export { Canvas } from './components/Canvas.js';
35
40
  export { Inspector } from './components/Inspector.js';
@@ -48,5 +53,6 @@ export { GlobalDropzone } from './components/GlobalDropzone.js';
48
53
  export { CompareSlider } from './components/CompareSlider.js';
49
54
  export { DownloadPanel } from './components/DownloadPanel.js';
50
55
  export { ThemeToggle } from './components/ThemeToggle.js';
56
+ export { ToolRunner } from './components/ToolRunner.js';
51
57
  export { WORKFLOW_TEMPLATES, findTemplate, } from './data/workflow-templates.js';
52
58
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,SAAS,EAA+C,MAAM,sBAAsB,CAAC;AAC9F,OAAO,EAAE,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAoB,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAsE,MAAM,yBAAyB,CAAC;AACpK,OAAO,EAAE,eAAe,EAA2D,MAAM,4BAA4B,CAAC;AACtH,OAAO,EAAE,YAAY,EAA2B,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACjI,OAAO,EAAE,iBAAiB,EAA8C,MAAM,kBAAkB,CAAC;AAEjG,OAAO,EAAE,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAA4B,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAA+B,MAAM,mCAAmC,CAAC;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAA0B,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAA2D,MAAM,gCAAgC,CAAC;AAC5I,OAAO,EAAE,cAAc,EAA4B,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AAEjF,OAAO,EACL,kBAAkB,EAGlB,YAAY,GACb,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,2DAA2D;AAC3D,8DAA8D;AAC9D,OAAO,4BAA4B,CAAC;AAEpC,OAAO,EAAE,SAAS,EAA+C,MAAM,sBAAsB,CAAC;AAC9F,OAAO,EAAE,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAoB,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAsE,MAAM,yBAAyB,CAAC;AACpK,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,iBAAiB,EAA4E,MAAM,6BAA6B,CAAC;AAC5P,OAAO,EAAE,eAAe,EAA2D,MAAM,4BAA4B,CAAC;AACtH,OAAO,EAAE,YAAY,EAA2B,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACjI,OAAO,EAAE,iBAAiB,EAA8C,MAAM,kBAAkB,CAAC;AAEjG,OAAO,EAAE,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAA4B,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAA+B,MAAM,mCAAmC,CAAC;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAA0B,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAA2D,MAAM,gCAAgC,CAAC;AAC5I,OAAO,EAAE,cAAc,EAA4B,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,UAAU,EAAwB,MAAM,4BAA4B,CAAC;AAE9E,OAAO,EACL,kBAAkB,EAGlB,YAAY,GACb,MAAM,8BAA8B,CAAC"}
@@ -1,9 +1,16 @@
1
1
  /**
2
2
  * Assets slice —— 资产导入 / 选择 / 删除 / 缩略图
3
+ *
4
+ * TD-5.1 长期方案:缩略图 ObjectURL 的创建 / 替换 / 释放统一在 store 内管理,
5
+ * 消除原先"创建在 AssetPanel effect、释放在 removeAsset action"的跨边界脆弱性。
6
+ * - ensureThumbnails:iterate assets → exportAsset → createObjectURL → setThumbnail
7
+ * - setThumbnail:替换时自动 revoke 旧 ObjectURL
8
+ * - removeAsset:删除时 revoke ObjectURL + 清理 entry
9
+ * inflight 去重通过闭包捕获的 Set(非响应式,不触发额外 re-render)。
3
10
  */
4
11
  import type { StateCreator } from 'zustand';
5
12
  import type { WorkspaceStore, WorkspaceState, WorkspaceActions } from './types.js';
6
- export interface AssetsSlice extends Pick<WorkspaceState, 'assets' | 'selectedAssetId' | 'thumbnails'>, Pick<WorkspaceActions, 'refreshAssets' | 'importFiles' | 'selectAsset' | 'setThumbnail' | 'removeAsset'> {
13
+ export interface AssetsSlice extends Pick<WorkspaceState, 'assets' | 'selectedAssetId' | 'thumbnails'>, Pick<WorkspaceActions, 'refreshAssets' | 'importFiles' | 'selectAsset' | 'setThumbnail' | 'ensureThumbnails' | 'removeAsset'> {
7
14
  }
8
15
  export declare const createAssetsSlice: StateCreator<WorkspaceStore, [
9
16
  ], [
@@ -1 +1 @@
1
- {"version":3,"file":"assets-slice.d.ts","sourceRoot":"","sources":["../../src/store/assets-slice.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,iBAAiB,GAAG,YAAY,CAAC,EACvE,IAAI,CACF,gBAAgB,EAChB,eAAe,GAAG,aAAa,GAAG,aAAa,GAAG,cAAc,GAAG,aAAa,CACjF;CAAG;AAER,eAAO,MAAM,iBAAiB,EAAE,YAAY,CAC1C,cAAc,EACd;CAAE,EACF;CAAE,EACF,WAAW,CA0DX,CAAC"}
1
+ {"version":3,"file":"assets-slice.d.ts","sourceRoot":"","sources":["../../src/store/assets-slice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,iBAAiB,GAAG,YAAY,CAAC,EACvE,IAAI,CACF,gBAAgB,EACd,eAAe,GACf,aAAa,GACb,aAAa,GACb,cAAc,GACd,kBAAkB,GAClB,aAAa,CAChB;CAAG;AAER,eAAO,MAAM,iBAAiB,EAAE,YAAY,CAC1C,cAAc,EACd;CAAE,EACF;CAAE,EACF,WAAW,CAoGZ,CAAC"}
@@ -1,58 +1,105 @@
1
- export const createAssetsSlice = (set, get) => ({
2
- assets: [],
3
- selectedAssetId: null,
4
- thumbnails: {},
5
- async refreshAssets() {
6
- const { runtime } = get();
7
- if (!runtime)
8
- return;
9
- const assets = await runtime.listAssets();
10
- set({ assets });
11
- },
12
- async importFiles(files) {
13
- const { runtime } = get();
14
- if (!runtime)
15
- return;
16
- set({ statusMessage: `Importing ${files.length} file(s)...` });
17
- for (const file of files) {
18
- await runtime.importAsset({ kind: 'file', file });
19
- }
20
- await get().refreshAssets();
21
- await get().refreshStorageUsage();
22
- set({ statusMessage: `Imported ${files.length} file(s)` });
23
- },
24
- selectAsset(id) {
25
- set({ selectedAssetId: id });
26
- },
27
- setThumbnail(id, url) {
28
- set((state) => ({ thumbnails: { ...state.thumbnails, [id]: url } }));
29
- },
30
- async removeAsset(id) {
31
- const { runtime } = get();
32
- if (!runtime)
33
- return;
34
- await runtime.removeAsset(id);
35
- await get().refreshAssets();
36
- await get().refreshStorageUsage();
37
- if (get().selectedAssetId === id)
38
- set({ selectedAssetId: null });
39
- // 修复 review 报告:原实现删除 asset 后未 revoke 缩略图 ObjectURL,导致
40
- // 浏览器 Blob 引用泄漏(每删一张图就漏一个 blob 内存)。
41
- // 同时从 thumbnails map 中删除该 entry,避免 stale ref
42
- const oldUrl = get().thumbnails[id];
43
- if (oldUrl) {
44
- try {
45
- URL.revokeObjectURL(oldUrl);
46
- }
47
- catch {
48
- /* URL 已失效或非 ObjectURL,忽略 */
1
+ export const createAssetsSlice = (set, get) => {
2
+ // TD-5.1:per-store inflight 缩略图去重(闭包捕获,非响应式,不触发 re-render)
3
+ const inflightThumbnails = new Set();
4
+ return {
5
+ assets: [],
6
+ selectedAssetId: null,
7
+ thumbnails: {},
8
+ async refreshAssets() {
9
+ const { runtime } = get();
10
+ if (!runtime)
11
+ return;
12
+ const assets = await runtime.listAssets();
13
+ set({ assets });
14
+ },
15
+ async importFiles(files) {
16
+ const { runtime } = get();
17
+ if (!runtime)
18
+ return;
19
+ set({ statusMessage: `Importing ${files.length} file(s)...` });
20
+ for (const file of files) {
21
+ await runtime.importAsset({ kind: 'file', file });
49
22
  }
23
+ await get().refreshAssets();
24
+ await get().refreshStorageUsage();
25
+ set({ statusMessage: `Imported ${files.length} file(s)` });
26
+ },
27
+ selectAsset(id) {
28
+ set({ selectedAssetId: id });
29
+ },
30
+ setThumbnail(id, url) {
31
+ // TD-5.1:替换时 revoke 旧 ObjectURL,集中管理释放,避免孤儿 URL
50
32
  set((state) => {
51
- const next = { ...state.thumbnails };
52
- delete next[id];
53
- return { thumbnails: next };
33
+ const old = state.thumbnails[id];
34
+ if (old) {
35
+ try {
36
+ URL.revokeObjectURL(old);
37
+ }
38
+ catch {
39
+ /* URL 已失效或非 ObjectURL,忽略 */
40
+ }
41
+ }
42
+ return { thumbnails: { ...state.thumbnails, [id]: url } };
54
43
  });
55
- }
56
- },
57
- });
44
+ },
45
+ ensureThumbnails() {
46
+ const { runtime, assets, thumbnails } = get();
47
+ if (!runtime)
48
+ return;
49
+ for (const asset of assets) {
50
+ if (thumbnails[asset.id])
51
+ continue;
52
+ if (asset.type !== 'image')
53
+ continue;
54
+ if (inflightThumbnails.has(asset.id))
55
+ continue;
56
+ inflightThumbnails.add(asset.id);
57
+ void (async () => {
58
+ try {
59
+ const blob = await runtime.exportAsset(asset.id);
60
+ const url = URL.createObjectURL(blob);
61
+ // 资产可能在 await 期间被删除:若已不在 assets 中,revoke URL 不入 store
62
+ if (!get().assets.some((a) => a.id === asset.id)) {
63
+ URL.revokeObjectURL(url);
64
+ return;
65
+ }
66
+ get().setThumbnail(asset.id, url);
67
+ }
68
+ catch {
69
+ // export 失败,不留缩略图(下次 ensureThumbnails 会重试)
70
+ }
71
+ finally {
72
+ inflightThumbnails.delete(asset.id);
73
+ }
74
+ })();
75
+ }
76
+ },
77
+ async removeAsset(id) {
78
+ const { runtime } = get();
79
+ if (!runtime)
80
+ return;
81
+ await runtime.removeAsset(id);
82
+ await get().refreshAssets();
83
+ await get().refreshStorageUsage();
84
+ if (get().selectedAssetId === id)
85
+ set({ selectedAssetId: null });
86
+ // TD-5.1:删除资产时 revoke 缩略图 ObjectURL + 清理 entry(与 setThumbnail
87
+ // 的 replace-revoke 一起,构成"创建/替换/释放"全在 store 内的闭环)
88
+ const oldUrl = get().thumbnails[id];
89
+ if (oldUrl) {
90
+ try {
91
+ URL.revokeObjectURL(oldUrl);
92
+ }
93
+ catch {
94
+ /* URL 已失效或非 ObjectURL,忽略 */
95
+ }
96
+ set((state) => {
97
+ const next = { ...state.thumbnails };
98
+ delete next[id];
99
+ return { thumbnails: next };
100
+ });
101
+ }
102
+ },
103
+ };
104
+ };
58
105
  //# sourceMappingURL=assets-slice.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"assets-slice.js","sourceRoot":"","sources":["../../src/store/assets-slice.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,MAAM,iBAAiB,GAK1B,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACjB,MAAM,EAAE,EAAE;IACV,eAAe,EAAE,IAAI;IACrB,UAAU,EAAE,EAAE;IAEd,KAAK,CAAC,aAAa;QACjB,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC1C,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAK;QACrB,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,GAAG,CAAC,EAAE,aAAa,EAAE,aAAa,KAAK,CAAC,MAAM,aAAa,EAAE,CAAC,CAAC;QAC/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;QAC5B,MAAM,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC;QAClC,GAAG,CAAC,EAAE,aAAa,EAAE,YAAY,KAAK,CAAC,MAAM,UAAU,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,WAAW,CAAC,EAAE;QACZ,GAAG,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,YAAY,CAAC,EAAE,EAAE,GAAG;QAClB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,EAAE;QAClB,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;QAC5B,MAAM,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC;QAClC,IAAI,GAAG,EAAE,CAAC,eAAe,KAAK,EAAE;YAAE,GAAG,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjE,sDAAsD;QACtD,oCAAoC;QACpC,6CAA6C;QAC7C,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;gBACP,4BAA4B;YAC9B,CAAC;YACD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBACZ,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;gBACrC,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;gBAChB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;YAC9B,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"assets-slice.js","sourceRoot":"","sources":["../../src/store/assets-slice.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import type { StateCreator } from 'zustand';
5
5
  import type { WorkspaceStore, WorkspaceState, WorkspaceActions } from './types.js';
6
- export interface CapabilitiesSlice extends Pick<WorkspaceState, 'capabilities' | 'capabilityMap'>, Pick<WorkspaceActions, 'refreshCapabilities'> {
6
+ export interface CapabilitiesSlice extends Pick<WorkspaceState, 'capabilities' | 'capabilityMap' | 'stubCapabilities'>, Pick<WorkspaceActions, 'refreshCapabilities'> {
7
7
  }
8
8
  export declare const createCapabilitiesSlice: StateCreator<WorkspaceStore, [
9
9
  ], [