dsh-image-gen 0.10.2 → 0.10.3

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 (55) hide show
  1. package/README.en.md +456 -454
  2. package/README.md +456 -454
  3. package/docs/assets/readme/canvas-edit.webp +0 -0
  4. package/docs/assets/readme/canvas-sketch.webp +0 -0
  5. package/docs/assets/readme/chat-batch.webp +0 -0
  6. package/docs/assets/readme/config.webp +0 -0
  7. package/docs/assets/readme/hero-batch.webp +0 -0
  8. package/docs/assets/readme/hero-canvas.webp +0 -0
  9. package/docs/assets/readme/studio-ref.webp +0 -0
  10. package/docs/assets/readme/studio.webp +0 -0
  11. package/lib/client.js +4871 -3658
  12. package/lib/index.js +2074 -140
  13. package/lib/types/client/browser-image-utils.d.ts +6 -0
  14. package/lib/types/client/datalist-scroll-fix.d.ts +32 -0
  15. package/lib/types/client/gallery-batch-bar.d.ts +8 -0
  16. package/lib/types/client/gallery-card.d.ts +21 -0
  17. package/lib/types/client/gallery-format.d.ts +7 -0
  18. package/lib/types/client/gallery-i18n.d.ts +236 -0
  19. package/lib/types/client/gallery-media.d.ts +46 -0
  20. package/lib/types/client/gallery-merge.d.ts +15 -0
  21. package/lib/types/client/gallery-store.d.ts +21 -2
  22. package/lib/types/client/gallery-thumbs.d.ts +24 -0
  23. package/lib/types/client/gallery-view.d.ts +0 -207
  24. package/lib/types/client/image-result-view.d.ts +24 -0
  25. package/lib/types/client/index.d.ts +1 -20
  26. package/lib/types/client/plugin-i18n.d.ts +375 -0
  27. package/lib/types/client/plugin-style.d.ts +1 -0
  28. package/lib/types/client/studio-helpers.d.ts +63 -0
  29. package/lib/types/client/studio-style.d.ts +1 -1
  30. package/lib/types/client/studio-view.d.ts +0 -7
  31. package/lib/types/client/tl/gallery-image-transfer.d.ts +1 -1
  32. package/lib/types/config.d.ts +12 -0
  33. package/lib/types/import-route.d.ts +11 -0
  34. package/lib/types/multipart.d.ts +29 -0
  35. package/lib/types/openai-compatible.d.ts +8 -0
  36. package/lib/types/request-cache.d.ts +41 -0
  37. package/lib/types/shared.d.ts +23 -0
  38. package/lib/types/storage-stats.d.ts +34 -0
  39. package/lib/types/thumb-route.d.ts +25 -0
  40. package/lib/types/vault-registry.d.ts +36 -0
  41. package/lib/types/vault-route.d.ts +8 -0
  42. package/lib/types/vault-store.d.ts +31 -0
  43. package/lib/types/zip-progress.d.ts +18 -0
  44. package/lib/types/zip-route.d.ts +25 -0
  45. package/lib/types/zip-stream.d.ts +43 -0
  46. package/package.json +139 -139
  47. package/skills/install-dsh-image-gen/SKILL.md +22 -22
  48. package/lib/types/client/tl/tl-trace-bridge.d.ts +0 -55
  49. package/lib/types/client/tl/trace-playback.d.ts +0 -101
  50. package/lib/types/trace-drawing.d.ts +0 -102
  51. package/lib/types/trace-route.d.ts +0 -12
  52. package/lib/types/trace-sketch.d.ts +0 -26
  53. package/lib/types/trace-store.d.ts +0 -23
  54. package/lib/types/vendor/drawai/raster.d.ts +0 -43
  55. package/lib/types/vendor/drawai/trace-image.d.ts +0 -257
@@ -21,3 +21,9 @@ export interface ZipFileInput {
21
21
  * Zero external dependencies, pure browser ArrayBuffer/Blob, fast and universally compatible with OS extractors.
22
22
  */
23
23
  export declare function createZipBlob(files: ZipFileInput[]): Blob;
24
+ /**
25
+ * Downscale an image for the gallery grid.
26
+ * Returns the source blob when the browser lacks the needed canvas APIs, so
27
+ * callers can always render something without extra capability branches.
28
+ */
29
+ export declare function createImageThumbnail(source: Blob, width: number): Promise<Blob>;
@@ -0,0 +1,32 @@
1
+ /** Close plugin datalist popups on deliberate scrolling without stealing new focus. */
2
+ type Listener = (event?: {
3
+ key?: string;
4
+ target?: unknown;
5
+ }) => void;
6
+ interface EventTargetLike {
7
+ addEventListener(type: string, listener: Listener, capture?: boolean): void;
8
+ removeEventListener(type: string, listener: Listener, capture?: boolean): void;
9
+ }
10
+ export interface FocusableElement {
11
+ tagName: string;
12
+ hasAttribute(name: string): boolean;
13
+ blur(): void;
14
+ }
15
+ export interface DatalistScrollFixEnvironment {
16
+ window: EventTargetLike & Record<string, unknown>;
17
+ document: EventTargetLike & {
18
+ activeElement: FocusableElement | null;
19
+ };
20
+ /** Return a cancellation callback when the scheduler supports cancellation. */
21
+ schedule?: (callback: Listener) => void | (() => void);
22
+ ownsInput?: (element: FocusableElement) => boolean;
23
+ }
24
+ export declare function isDatalistInput(element: FocusableElement | null): boolean;
25
+ export declare function closeDatalistPopup(element: FocusableElement | null): boolean;
26
+ /**
27
+ * Automatic scrolling after Tab/focus or virtual-keyboard resize must not blur
28
+ * the input. Only scrolling preceded by a wheel/touch/scrollbar/key gesture can
29
+ * dismiss the popup, and its original focus must still be current.
30
+ */
31
+ export declare function installDatalistScrollFix(environment?: DatalistScrollFixEnvironment): false | (() => void);
32
+ export {};
@@ -0,0 +1,8 @@
1
+ /** The two gallery tabs that render the selectable grid. */
2
+ export type BatchBarTab = 'gallery' | 'studio' | 'inspiration' | 'favorites';
3
+ /**
4
+ * The batch bar is a fixed overlay at the page root, so it must only render on
5
+ * the grid tabs; leaving them (studio/inspiration) hides it even if manage mode
6
+ * or a selection somehow survives a tab switch.
7
+ */
8
+ export declare function shouldShowBatchBar(activeTab: BatchBarTab, isManageMode: boolean, selectedCount: number): boolean;
@@ -0,0 +1,21 @@
1
+ import { type MouseEvent } from 'react';
2
+ import type { GalleryItem } from './gallery-store.js';
3
+ import type { DictKey } from './gallery-i18n.js';
4
+ /** Stable dispatchers shared by every card, so memoized cards never re-render for selection changes. */
5
+ export interface GalleryCardActions {
6
+ click: (item: GalleryItem, index: number, event: MouseEvent) => void;
7
+ toggleSelect: (item: GalleryItem, index: number, event: MouseEvent) => void;
8
+ requestDelete: (item: GalleryItem) => void;
9
+ preview: (item: GalleryItem, blob?: Blob) => void;
10
+ toast: (message: string) => void;
11
+ }
12
+ export interface GalleryCardProps {
13
+ lang: 'zh' | 'en';
14
+ item: GalleryItem;
15
+ index: number;
16
+ isManageMode: boolean;
17
+ isSelected: boolean;
18
+ t: (key: DictKey, params?: Record<string, string>) => string;
19
+ actions: GalleryCardActions;
20
+ }
21
+ export declare const GalleryCard: import("react").MemoExoticComponent<({ lang, item, index, isManageMode, isSelected, t, actions, }: GalleryCardProps) => import("react").JSX.Element>;
@@ -0,0 +1,7 @@
1
+ import type { GalleryItem } from './gallery-store.js';
2
+ import type { DictKey } from './gallery-i18n.js';
3
+ export declare function formatRelativeTime(timestamp: number, t: (key: DictKey, params?: Record<string, string>) => string): string;
4
+ /** Extract standard aspect ratio for precise filtering */
5
+ export declare function getItemRatio(item: GalleryItem): string;
6
+ /** Format aspect ratio or dimensions for card metadata (e.g., 1024×1024 or 16:9) */
7
+ export declare function formatCardMeta(item: GalleryItem): string;
@@ -0,0 +1,236 @@
1
+ /** Gallery copy for the zh/en dictionaries and their key union. */
2
+ export declare const DICT: {
3
+ readonly zh: {
4
+ readonly tabGallery: "图库";
5
+ readonly tabStudio: "工作台";
6
+ readonly tabInspiration: "灵感";
7
+ readonly tabFavorites: "收藏";
8
+ readonly tabCompare: "对比";
9
+ readonly tabTasks: "任务";
10
+ readonly filterAllProviders: "全部提供商";
11
+ readonly filterGoogle: "Google Gemini";
12
+ readonly filterOpenAI: "OpenAI";
13
+ readonly filterOpenAICompat: "OpenAI 兼容";
14
+ readonly filterSeedream: "字节 Seedream";
15
+ readonly filterDashScope: "阿里 DashScope";
16
+ readonly filterXAI: "xAI Grok";
17
+ readonly filterZhipu: "智谱 GLM";
18
+ readonly filterComfyUI: "本地 ComfyUI";
19
+ readonly filterImport: "导入";
20
+ readonly importImages: "导入图片";
21
+ readonly importAdded: "已导入 {count} 张图片";
22
+ readonly importPartial: "导入 {count} 张,{fail} 张失败";
23
+ readonly importFailed: "导入失败";
24
+ readonly importPickHint: "选择要导入的图片(PNG/JPG/WebP/GIF)";
25
+ readonly filterAllModels: "全部模型";
26
+ readonly filterAllRatios: "全部比例";
27
+ readonly searchPlaceholder: "搜索 Prompt、标签…";
28
+ readonly filterCurrentWorkspace: "仅看此工作区";
29
+ readonly filterCurrentWorkspaceHint: "只展示属于当前工作区的生图记录与物理文件";
30
+ readonly sortNewest: "最新生成";
31
+ readonly sortOldest: "最早生成";
32
+ readonly totalCount: "共 {count} 张生成图片";
33
+ readonly emptyTitle: "暂无生图记录";
34
+ readonly emptyDesc: "在对话中让 Agent 生图后,生成的图片会自动收录到这里。";
35
+ readonly favEmptyTitle: "暂无收藏图片";
36
+ readonly favEmptyDesc: "在图库中点击卡片右下角的 ♡ 按钮,即可将喜爱的图片收录到这里。";
37
+ readonly noMatchTitle: "未找到匹配结果";
38
+ readonly noMatchDesc: "尝试更换搜索关键词或调整筛选条件。";
39
+ readonly copiedPrompt: "已复制 Prompt";
40
+ readonly copiedImage: "已复制图片";
41
+ readonly copyFailed: "复制失败";
42
+ readonly favoriteAdded: "已添加到收藏";
43
+ readonly favoriteRemoved: "已取消收藏";
44
+ readonly preview: "查看大图";
45
+ readonly download: "下载图片";
46
+ readonly copyImg: "复制图片";
47
+ readonly copyPpt: "复制 Prompt";
48
+ readonly regenerate: "重新生成";
49
+ readonly regenerateTitle: "重新生成图片";
50
+ readonly regenerateHint: "可按需修改 Prompt,基于当前模型和比例在画廊生成一张新图片。";
51
+ readonly confirmRegenerate: "开始生成";
52
+ readonly regenerating: "正在重新生成…";
53
+ readonly regenerateSuccess: "已生成新图片并收录到画廊";
54
+ readonly regenerateSaveFailed: "图片已生成,但保存到图库失败,请重试";
55
+ readonly regenerateFailed: "重新生成失败";
56
+ readonly delete: "从画廊删除";
57
+ readonly confirmDelete: "确定要从画廊中删除这张图片吗?若它是导入时被归一化/转码的原图,且没有其他图库或浏览器引用,原图也会永久删除。(不会影响原聊天记录)";
58
+ readonly deleted: "已从画廊删除";
59
+ readonly model: "模型";
60
+ readonly prompt: "Prompt";
61
+ readonly close: "关闭 (Esc)";
62
+ readonly prevImage: "上一张 (←)";
63
+ readonly nextImage: "下一张 (→)";
64
+ readonly manage: "批量管理";
65
+ readonly exitManage: "退出选择";
66
+ readonly selectedCount: "已选 {n} 项";
67
+ readonly selectAll: "全选";
68
+ readonly invertSelect: "反选";
69
+ readonly clearSelect: "清空";
70
+ readonly batchFavorite: "批量收藏";
71
+ readonly batchUnfavorite: "批量取消收藏";
72
+ readonly batchFavoritedToast: "已将 {count} 张图片加入收藏";
73
+ readonly batchUnfavoritedToast: "已取消 {count} 张图片的收藏";
74
+ readonly batchFavoriteFailed: "收藏操作失败,请重试";
75
+ readonly batchDownload: "批量下载";
76
+ readonly batchDownloading: "打包中 ({current}/{total})…";
77
+ readonly batchDownloadSingleToast: "已下载 1 张图片";
78
+ readonly batchDownloadZipToast: "已开始下载 {count} 张图片(ZIP)";
79
+ readonly batchDownloadComplete: "已下载 {count} 张图片(ZIP)";
80
+ readonly batchDownloadFailed: "批量下载失败,请重试";
81
+ readonly batchDownloadLimit: "选择过大:一次最多导出 2000 张,请分批下载";
82
+ readonly batchDelete: "批量删除";
83
+ readonly batchDeleteTitle: "确认批量删除选中的 {count} 张图片?";
84
+ readonly batchDeleteTitleSingle: "确认从画廊中删除这张图片?";
85
+ readonly batchDeleteDesc: "将从画廊历史记录中移除所选图片;其中导入时被归一化/转码的原图,若没有其他引用也会永久删除。";
86
+ readonly deleteWorkspaceFilesOpt: "同时清理工作区磁盘物理文件(不可恢复)";
87
+ readonly cancel: "取消";
88
+ readonly confirmBatchDelete: "确认删除 ({count})";
89
+ readonly confirmDeleteSingle: "确认删除";
90
+ readonly batchDeletedToast: "已删除 {count} 张图片";
91
+ readonly storageTitle: "存储占用";
92
+ readonly storageScanning: "扫描中…";
93
+ readonly storageAttachments: "附件对象";
94
+ readonly storageThumbs: "缩略图缓存(本地回退)";
95
+ readonly storageRequestCache: "请求图缓存";
96
+ readonly storageOrphans: "画廊未引用附件";
97
+ readonly storageItems: "{n} 个文件";
98
+ readonly storageOrphanHint: "只统计本图库记录未引用的对象;其他会话、画布或上传仍可能引用,导出清单不代表可安全删除。";
99
+ readonly storageThumbsHint: "服务端缩略图正常时,本地回退缓存保持为空;320px 缩略图计入请求图缓存。";
100
+ readonly storageExport: "导出孤儿清单";
101
+ readonly storageScanFailed: "存储统计失败";
102
+ readonly storageClose: "关闭";
103
+ readonly batchDeletedWithFilesToast: "已删除 {count} 张图片,并清理了 {files} 个工作区文件";
104
+ readonly deleteFailedFileLocked: "已删除 {count} 张图片,但有 {files} 个文件因被系统占用未能删除";
105
+ readonly deleteFailedDatabase: "删除失败:本地数据库操作异常";
106
+ readonly justNow: "刚刚";
107
+ readonly minutesAgo: "{n} 分钟前";
108
+ readonly hoursAgo: "{n} 小时前";
109
+ readonly daysAgo: "{n} 天前";
110
+ readonly studioTitle: "AI 图像工作台 (Studio)";
111
+ readonly studioDesc: "工作台模块正在紧锣密鼓开发中。在此你将体验大图精修、变体生成 (Variations)、参数重调并一键将生成结果无缝插回 DSH 正在进行的对话。";
112
+ readonly studioTip: "💡 提示:目前你可以在“图库”中点击任意图片,在弹窗中进行查看、复制与下载。";
113
+ readonly compareTitle: "多模型横向对比 (Compare)";
114
+ readonly compareDesc: "支持单个 Prompt 一键同时调度 Gemini、Seedream、DashScope 及本地 ComfyUI 模型并排生成,直观横评画质与细节。";
115
+ readonly tasksTitle: "异步任务队列 (Tasks)";
116
+ readonly tasksDesc: "集中管理后台批量生图、多模型并发生成与本地 ComfyUI 耗时任务。支持状态追踪、失败重试与执行耗时分析。";
117
+ readonly comingSoonBadge: "即将推出";
118
+ };
119
+ readonly en: {
120
+ readonly tabGallery: "Gallery";
121
+ readonly tabStudio: "Studio";
122
+ readonly tabInspiration: "Inspiration";
123
+ readonly tabFavorites: "Favorites";
124
+ readonly tabCompare: "Compare";
125
+ readonly tabTasks: "Tasks";
126
+ readonly filterAllProviders: "All Providers";
127
+ readonly filterGoogle: "Google Gemini";
128
+ readonly filterOpenAI: "OpenAI";
129
+ readonly filterOpenAICompat: "OpenAI-compatible";
130
+ readonly filterSeedream: "ByteDance Seedream";
131
+ readonly filterDashScope: "Aliyun DashScope";
132
+ readonly filterXAI: "xAI Grok";
133
+ readonly filterZhipu: "Zhipu GLM";
134
+ readonly filterComfyUI: "Local ComfyUI";
135
+ readonly filterImport: "Imported";
136
+ readonly importImages: "Import images";
137
+ readonly importAdded: "Imported {count} images";
138
+ readonly importPartial: "Imported {count}, {fail} failed";
139
+ readonly importFailed: "Import failed";
140
+ readonly importPickHint: "Choose images to import (PNG/JPG/WebP/GIF)";
141
+ readonly filterAllModels: "All Models";
142
+ readonly filterAllRatios: "All Ratios";
143
+ readonly searchPlaceholder: "Search prompt, tags…";
144
+ readonly filterCurrentWorkspace: "Current workspace only";
145
+ readonly filterCurrentWorkspaceHint: "Only show images belonging to the active workspace";
146
+ readonly sortNewest: "Newest first";
147
+ readonly sortOldest: "Oldest first";
148
+ readonly totalCount: "{count} images total";
149
+ readonly emptyTitle: "No images generated yet";
150
+ readonly emptyDesc: "Images generated during conversations will automatically appear here.";
151
+ readonly favEmptyTitle: "No favorite images yet";
152
+ readonly favEmptyDesc: "Click the ♡ button on any card in the gallery to collect your favorite images here.";
153
+ readonly noMatchTitle: "No matching images";
154
+ readonly noMatchDesc: "Try a different search keyword or adjust filter criteria.";
155
+ readonly copiedPrompt: "Prompt copied";
156
+ readonly copiedImage: "Image copied";
157
+ readonly copyFailed: "Copy failed";
158
+ readonly favoriteAdded: "Added to favorites";
159
+ readonly favoriteRemoved: "Removed from favorites";
160
+ readonly preview: "Full Preview";
161
+ readonly download: "Download";
162
+ readonly copyImg: "Copy Image";
163
+ readonly copyPpt: "Copy Prompt";
164
+ readonly regenerate: "Regenerate";
165
+ readonly regenerateTitle: "Regenerate Image";
166
+ readonly regenerateHint: "Edit prompt if needed. A new image will be generated and added to the gallery.";
167
+ readonly confirmRegenerate: "Generate";
168
+ readonly regenerating: "Regenerating…";
169
+ readonly regenerateSuccess: "New image generated and added to gallery";
170
+ readonly regenerateSaveFailed: "Image generated, but saving to the gallery failed. Please retry.";
171
+ readonly regenerateFailed: "Regeneration failed";
172
+ readonly delete: "Delete from gallery";
173
+ readonly confirmDelete: "Remove this image from the gallery? If it is a normalized imported original with no other gallery or browser references, the stored original will also be permanently deleted. (Chat history is unaffected.)";
174
+ readonly deleted: "Deleted from gallery";
175
+ readonly model: "Model";
176
+ readonly prompt: "Prompt";
177
+ readonly close: "Close (Esc)";
178
+ readonly prevImage: "Previous (←)";
179
+ readonly nextImage: "Next (→)";
180
+ readonly manage: "Batch Manage";
181
+ readonly exitManage: "Done";
182
+ readonly selectedCount: "{n} selected";
183
+ readonly selectAll: "Select All";
184
+ readonly invertSelect: "Invert";
185
+ readonly clearSelect: "Clear";
186
+ readonly batchFavorite: "Batch Favorite";
187
+ readonly batchUnfavorite: "Batch Unfavorite";
188
+ readonly batchFavoritedToast: "Added {count} images to favorites";
189
+ readonly batchUnfavoritedToast: "Removed {count} images from favorites";
190
+ readonly batchFavoriteFailed: "Favorite operation failed, please retry";
191
+ readonly batchDownload: "Batch Download";
192
+ readonly batchDownloading: "Packaging ({current}/{total})…";
193
+ readonly batchDownloadSingleToast: "Downloaded 1 image";
194
+ readonly batchDownloadZipToast: "Started downloading {count} images (ZIP)";
195
+ readonly batchDownloadComplete: "Downloaded {count} images (ZIP)";
196
+ readonly batchDownloadFailed: "Batch download failed, please retry";
197
+ readonly batchDownloadLimit: "Selection too large: up to 2000 images per export. Please split it.";
198
+ readonly batchDelete: "Batch Delete";
199
+ readonly batchDeleteTitle: "Delete {count} selected images?";
200
+ readonly batchDeleteTitleSingle: "Delete this image from gallery?";
201
+ readonly batchDeleteDesc: "These images will be removed from gallery history; normalized imported originals will also be permanently deleted when no other references remain.";
202
+ readonly deleteWorkspaceFilesOpt: "Also delete files from workspace disk (cannot be undone)";
203
+ readonly cancel: "Cancel";
204
+ readonly confirmBatchDelete: "Delete ({count})";
205
+ readonly confirmDeleteSingle: "Delete";
206
+ readonly batchDeletedToast: "Deleted {count} images";
207
+ readonly storageTitle: "Storage usage";
208
+ readonly storageScanning: "Scanning…";
209
+ readonly storageAttachments: "Attachment objects";
210
+ readonly storageThumbs: "Thumbnail cache (local fallback)";
211
+ readonly storageRequestCache: "Request-image cache";
212
+ readonly storageOrphans: "Gallery-unreferenced attachments";
213
+ readonly storageItems: "{n} files";
214
+ readonly storageOrphanHint: "Counts objects not referenced by this gallery; other sessions, the canvas, or uploads may still use them. The exported list is not a safe-deletion list.";
215
+ readonly storageThumbsHint: "The local fallback stays empty while server thumbnails work; 320px thumbnails count as request-image cache.";
216
+ readonly storageExport: "Export orphan list";
217
+ readonly storageScanFailed: "Storage scan failed";
218
+ readonly storageClose: "Close";
219
+ readonly batchDeletedWithFilesToast: "Deleted {count} images and cleaned {files} workspace files";
220
+ readonly deleteFailedFileLocked: "Deleted {count} images, but {files} files could not be deleted (busy/locked)";
221
+ readonly deleteFailedDatabase: "Failed to delete: local database error";
222
+ readonly justNow: "Just now";
223
+ readonly minutesAgo: "{n}m ago";
224
+ readonly hoursAgo: "{n}h ago";
225
+ readonly daysAgo: "{n}d ago";
226
+ readonly studioTitle: "AI Image Studio";
227
+ readonly studioDesc: "Studio workbench is under active development. Fine-tune prompts, generate variations (2x/4x), and inject images directly into DSH chat.";
228
+ readonly studioTip: "💡 Tip: You can currently click any image in the Gallery to preview, copy, or download it.";
229
+ readonly compareTitle: "Model Comparison (Compare)";
230
+ readonly compareDesc: "Side-by-side multi-model benchmarking coming soon. Test Gemini, Seedream, DashScope, and ComfyUI with a single prompt.";
231
+ readonly tasksTitle: "Task Queue (Tasks)";
232
+ readonly tasksDesc: "Centralized view for batch generation, asynchronous ComfyUI runs, live progress tracking, and retry controls.";
233
+ readonly comingSoonBadge: "Coming Soon";
234
+ };
235
+ };
236
+ export type DictKey = keyof typeof DICT.zh;
@@ -0,0 +1,46 @@
1
+ import type { GalleryItem } from './gallery-store.js';
2
+ /** Hover prefetch stops pulling raw originals above this size; drag-out then uses the attachment. */
3
+ export declare const GALLERY_PREFETCH_ORIGINAL_MAX_BYTES: number;
4
+ /** Stable per-browser-profile identity; the vault registry unions all profiles. */
5
+ export declare function vaultProfileId(): string | undefined;
6
+ /** Sync this profile's references; the server never deletes originals here. */
7
+ export declare function syncVaultRefs(keys: string[]): Promise<void>;
8
+ /** Manual gallery deletion: remove originals only after the server checks every profile. */
9
+ export declare function deleteVaultOriginals(deleteKeys: string[], remainingKeys: string[]): void;
10
+ export declare function vaultKeysOf(items: readonly GalleryItem[]): string[];
11
+ /** Full bytes for copy/download/drag: raw vault first, normalized attachment fallback. */
12
+ export declare function fetchGalleryItemBlob(item: GalleryItem): Promise<Blob>;
13
+ export interface GalleryStorageStats {
14
+ attachments: {
15
+ count: number;
16
+ bytes: number;
17
+ };
18
+ requestImages: {
19
+ count: number;
20
+ bytes: number;
21
+ };
22
+ thumbs: {
23
+ count: number;
24
+ bytes: number;
25
+ };
26
+ orphans: {
27
+ count: number;
28
+ bytes: number;
29
+ ids: string[];
30
+ };
31
+ scannedAt: number;
32
+ }
33
+ export declare function formatStorageBytes(bytes: number): string;
34
+ /** Desktop pickers can omit `File.type` for UNC/temp paths; fall back to the extension. */
35
+ export declare function imageMediaTypeOf(file: File): string | undefined;
36
+ /** Probe once whether this host can stream ZIP exports (older hosts 404 the route). */
37
+ export declare function canUseServerZip(): Promise<boolean>;
38
+ export declare function extensionFor(mediaType: string): string;
39
+ /** Download names must follow the resolved bytes, including vault fallbacks. */
40
+ export declare function galleryDownloadName(item: GalleryItem, blob: Blob): string;
41
+ /**
42
+ * Ask the host to stream the archive through a hidden form post.
43
+ * A real form navigation would replace the SPA, so the response lands in an
44
+ * off-screen iframe and the browser download manager owns the transfer.
45
+ */
46
+ export declare function postZipDownload(items: GalleryItem[], token: string): void;
@@ -0,0 +1,15 @@
1
+ import type { GalleryItem } from './gallery-store.js';
2
+ /** Content addressing makes these five fields the complete attachment identity. */
3
+ export declare function sameAttachment(a: GalleryItem['attachment'], b: GalleryItem['attachment']): boolean;
4
+ /**
5
+ * Field-by-field comparison for one gallery record. Keep this list in sync with
6
+ * GalleryItem: a field added there but missing here would silently keep the old
7
+ * object and show stale data after a reload.
8
+ */
9
+ export declare function sameGalleryItem(a: GalleryItem, b: GalleryItem): boolean;
10
+ /**
11
+ * Reuse the previous object for every unchanged record so memoized cards keep
12
+ * their identity after a full-table reload; only changed records get new
13
+ * objects. The order always follows the incoming list.
14
+ */
15
+ export declare function mergeGalleryItems(prev: readonly GalleryItem[], next: readonly GalleryItem[]): GalleryItem[];
@@ -3,8 +3,9 @@
3
3
  * Stores lightweight metadata indexes; image binaries remain managed by DSH Attachment service.
4
4
  * Supports tombstones to ensure deleted items are never resurrected when revisiting conversations.
5
5
  */
6
- import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
6
+ import type { ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment';
7
7
  import type { ImageProvider, StudioWatermark } from '../shared.js';
8
+ export { GALLERY_THUMB_MAX_AGE_MS, GALLERY_THUMB_MAX_BYTES, GALLERY_THUMB_WIDTH, galleryThumbKey, getGalleryThumb, getGalleryThumbStats, pruneGalleryThumbs, putGalleryThumb, } from './gallery-thumbs.js';
8
9
  export interface GalleryItem {
9
10
  id: string;
10
11
  attachment: ImageAttachmentRef;
@@ -36,6 +37,12 @@ export interface GalleryItem {
36
37
  sessionId?: string | undefined;
37
38
  /** Attachment ids of the source images this image was edited from; used by the canvas to rebuild edit chains. Optional so records written by older versions stay readable. */
38
39
  sourceAttachmentIds?: string[] | undefined;
40
+ /** Raw pre-normalization bytes, present only when the attachment layer changed the import. */
41
+ original?: {
42
+ key: string;
43
+ bytes: number;
44
+ mediaType: ImageMediaType;
45
+ } | undefined;
39
46
  }
40
47
  /** A user-created folder grouping favorite prompts. */
41
48
  export interface FavoriteFolder {
@@ -53,6 +60,13 @@ export interface FavoritePrompt {
53
60
  /** Owning folder id; absent entries are unfiled and appear under "all". */
54
61
  folderId?: string;
55
62
  }
63
+ /** Age at which timestamp metadata can be compacted; deleted IDs never expire. */
64
+ export declare const TOMBSTONE_TTL_MS: number;
65
+ /**
66
+ * Compact old tombstones to permanent IDs. Removing an ID would let an old
67
+ * conversation silently reinsert a deleted image. No IDs are removed.
68
+ */
69
+ export declare function pruneTombstones(maxAgeMs?: number): Promise<number>;
56
70
  type GalleryListener = () => void;
57
71
  /**
58
72
  * Subscribe to gallery mutations (insert/delete/clear).
@@ -72,6 +86,12 @@ export declare function saveGalleryItem(item: Omit<GalleryItem, 'createdAt'> & {
72
86
  * Retrieve all gallery records sorted by createdAt descending.
73
87
  */
74
88
  export declare function getGalleryItems(): Promise<GalleryItem[]>;
89
+ /**
90
+ * Like getGalleryItems, but rejects when IndexedDB is unavailable. Maintenance
91
+ * callers must not treat a read failure as an empty gallery (that would make
92
+ * vault gc delete every original).
93
+ */
94
+ export declare function getGalleryItemsStrict(): Promise<GalleryItem[]>;
75
95
  /**
76
96
  * Toggle favorite status of a gallery item.
77
97
  * Returns the new favorite status (true if favorited, false if unfavorited).
@@ -128,4 +148,3 @@ export declare function deleteFavoriteFolder(id: string): Promise<void>;
128
148
  export declare function moveFavoritePrompt(id: string, folderId: string | undefined): Promise<boolean>;
129
149
  /** Rewrite a favorite prompt's text in place, keeping its id stable. */
130
150
  export declare function updateFavoritePrompt(id: string, text: string): Promise<boolean>;
131
- export {};
@@ -0,0 +1,24 @@
1
+ /** Disposable IndexedDB cache for grid thumbnails. */
2
+ export declare const GALLERY_THUMB_MAX_BYTES: number;
3
+ export declare const GALLERY_THUMB_MAX_AGE_MS: number;
4
+ export declare const GALLERY_THUMB_WIDTH = 320;
5
+ /** Cache key for one attachment thumbnail. */
6
+ export declare function galleryThumbKey(attachmentId: string, width?: number): string;
7
+ /** Read a cached thumbnail; resolves undefined when it was never generated. */
8
+ export declare function getGalleryThumb(key: string): Promise<Blob | undefined>;
9
+ /** Persist a generated thumbnail. Failures are non-fatal: the grid falls back to the original. */
10
+ export declare function putGalleryThumb(key: string, blob: Blob): Promise<void>;
11
+ /** Aggregate size of the disposable thumbnail cache (storage panel). */
12
+ export declare function getGalleryThumbStats(): Promise<{
13
+ count: number;
14
+ bytes: number;
15
+ }>;
16
+ /** Drop cached thumbnails for deleted records. Best-effort: the cache is disposable. */
17
+ export declare function deleteGalleryThumbs(ids: string[]): Promise<void>;
18
+ /**
19
+ * Drop cached thumbnails whose attachment is no longer in the gallery.
20
+ * Returns how many entries were removed.
21
+ */
22
+ export declare function pruneGalleryThumbs(validAttachmentIds: Iterable<string>, maxBytes?: number, maxAgeMs?: number): Promise<number>;
23
+ /** Drop every cached thumbnail (used when the gallery is cleared). */
24
+ export declare function clearGalleryThumbs(): Promise<void>;