@dickpy/dsh-imagegen 1.5.6 → 1.5.7

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/src/protocol.ts CHANGED
@@ -1,580 +1,580 @@
1
- /**
2
- * Wire contract shared by the host and client halves of dsh-imagegen: the
3
- * settings namespace, the route paths, and the generate payload/result shapes.
4
- * Pure types + constants 鈥?safe for the client bundle to inline.
5
- */
6
-
7
- /** Settings namespace this plugin owns (host settings seam + bridge). */
8
- export const IMAGEGEN_SETTINGS_NAMESPACE = 'dsh-imagegen'
9
-
10
- /** Published package version shared by the host updater and the client UI. */
11
- export const PLUGIN_VERSION = '1.5.6'
12
-
13
- /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
14
- export const SETTINGS_API = {
15
- describe: '/api/dsh-imagegen/settings/describe',
16
- mutate: '/api/dsh-imagegen/settings/mutate',
17
- } as const
18
-
19
- /** The image-generation proxy route. */
20
- export const GENERATE_API = '/api/dsh-imagegen/generate'
21
-
22
- /** Host-mediated OpenAI-compatible prompt enhancement endpoints. */
23
- export const PROMPT_ENHANCE_API = {
24
- models: '/api/dsh-imagegen/prompt-enhance/models',
25
- enhance: '/api/dsh-imagegen/prompt-enhance',
26
- } as const
27
-
28
- /** Host-mediated candidate discovery for the configured image API. */
29
- export const IMAGE_MODEL_API = {
30
- models: '/api/dsh-imagegen/image-models',
31
- } as const
32
-
33
- /** Host-served built-in provider catalog (channels the user can instantiate). */
34
- export const PRESETS_API = '/api/dsh-imagegen/presets' as const
35
-
36
- /** Loopback-only image reader for Agent tool-result previews. */
37
- export const AGENT_IMAGE_API = '/api/dsh-imagegen/agent-image' as const
38
-
39
- /** Store the current composer image for the direct edit_image command. */
40
- export const CONVERSATION_IMAGE_API = '/api/dsh-imagegen/conversation-image' as const
41
-
42
- /**
43
- * Host-computed per-channel usage counters (generation-count badges in the
44
- * settings card): entries are tallied from the persisted history and gallery
45
- * by channel + model alias.
46
- */
47
- export const USAGE_API = '/api/dsh-imagegen/usage' as const
48
-
49
- /** Host-resident generation queue endpoints. */
50
- export const TASK_API = {
51
- submit: '/api/dsh-imagegen/tasks/submit',
52
- list: '/api/dsh-imagegen/tasks/list',
53
- cancel: '/api/dsh-imagegen/tasks/cancel',
54
- retry: '/api/dsh-imagegen/tasks/retry',
55
- } as const
56
-
57
- /** Reveal the host data directory (saved images) in the OS file manager. */
58
- export const DATA_FOLDER_API = '/api/dsh-imagegen/data-folder/open' as const
59
-
60
- /** Probe the configured S3-compatible object storage. */
61
- export const STORAGE_API = {
62
- test: '/api/dsh-imagegen/storage/test',
63
- } as const
64
-
65
- /** Host-mediated GitHub Release update routes. */
66
- export const UPDATE_API = {
67
- check: '/api/dsh-imagegen/update/check',
68
- apply: '/api/dsh-imagegen/update/apply',
69
- } as const
70
-
71
- /**
72
- * Same-origin route family for the host-persisted generation history. Images
73
- * live as files under ~/.dsh/dsh-imagegen/images/ and are served back through
74
- * the `image` prefix route, so list responses carry metadata only (never
75
- * base64) and the browser loads thumbnails/previews lazily.
76
- */
77
- export const HISTORY_API = {
78
- list: '/api/dsh-imagegen/history/list',
79
- append: '/api/dsh-imagegen/history/append',
80
- remove: '/api/dsh-imagegen/history/remove',
81
- clear: '/api/dsh-imagegen/history/clear',
82
- image: '/api/dsh-imagegen/history/image',
83
- } as const
84
-
85
- /**
86
- * Same-origin route family for the user-curated gallery (favorites). Entries
87
- * reuse the history wire shape and persist under ~/.dsh/dsh-imagegen/gallery/;
88
- * unlike history there is no size cap 鈥?the user adds images on purpose.
89
- */
90
- export const GALLERY_API = {
91
- list: '/api/dsh-imagegen/gallery/list',
92
- append: '/api/dsh-imagegen/gallery/append',
93
- remove: '/api/dsh-imagegen/gallery/remove',
94
- clear: '/api/dsh-imagegen/gallery/clear',
95
- tags: '/api/dsh-imagegen/gallery/tags',
96
- image: '/api/dsh-imagegen/gallery/image',
97
- } as const
98
-
99
- /** Host-persisted infinite canvas projects and their content-addressed assets. */
100
- export const CANVAS_API = {
101
- list: '/api/dsh-imagegen/canvas/list',
102
- create: '/api/dsh-imagegen/canvas/create',
103
- read: '/api/dsh-imagegen/canvas/read',
104
- save: '/api/dsh-imagegen/canvas/save',
105
- remove: '/api/dsh-imagegen/canvas/remove',
106
- assetUpload: '/api/dsh-imagegen/canvas/asset/upload',
107
- assetImport: '/api/dsh-imagegen/canvas/asset/import',
108
- asset: '/api/dsh-imagegen/canvas/asset',
109
- } as const
110
-
111
- /** Maximum number of history entries retained host-side (oldest evicted). */
112
- export const HISTORY_MAX = 50
113
-
114
- /**
115
- * Same-origin route family for the prompt-template libraries. The library is
116
- * multi-source: every request names a source id from {@link TEMPLATE_SOURCES},
117
- * each source keeps an independent snapshot/image cache host-side, and
118
- * reference images are proxied through the source-scoped `image` prefix route
119
- * (`…/image/<sourceId>/<file>`) and cached on disk so repeated views never hit
120
- * the network again.
121
- */
122
- export const TEMPLATES_API = {
123
- list: '/api/dsh-imagegen/templates/list',
124
- refresh: '/api/dsh-imagegen/templates/refresh',
125
- sample: '/api/dsh-imagegen/templates/sample',
126
- image: '/api/dsh-imagegen/templates/image',
127
- } as const
128
-
129
- /** Same-origin route family for the user's saved (favorited) templates. */
130
- export const TEMPLATE_FAVORITES_API = {
131
- list: '/api/dsh-imagegen/templates/favorites/list',
132
- add: '/api/dsh-imagegen/templates/favorites/add',
133
- remove: '/api/dsh-imagegen/templates/favorites/remove',
134
- } as const
135
-
136
- /** One prompt-template library source (a tab in the library overlay). */
137
- export interface TemplateSourceMeta {
138
- /** Stable source id: snapshot dir name, image-cache dir, and request key. */
139
- id: string
140
- /** Tab label shown in the library overlay. */
141
- label: string
142
- /** Source homepage linked in the overlay footer. */
143
- homepage: string
144
- /** One-line description of the source (tab tooltip). */
145
- description: string
146
- }
147
-
148
- /**
149
- * The template-library source registry. Each entry is fully independent (own
150
- * upstream JSON, own image pool, own refresh state) and renders as its own
151
- * tab; adding a source later means appending an entry here plus a host-side
152
- * fetch definition in templates-store.ts and an optional bundled snapshot.
153
- */
154
- export const TEMPLATE_SOURCES: TemplateSourceMeta[] = [
155
- {
156
- id: 'vibeui',
157
- label: '精选案例库',
158
- homepage: 'https://vibeui.top/',
159
- description: 'awesome-gpt-image-2 精选提示词案例(vibeui.top 镜像)',
160
- },
161
- {
162
- id: 'canghe',
163
- label: '沧河案例库',
164
- homepage: 'https://gpt-image2.canghe.ai/',
165
- description: 'GPT-Image2 Prompt Gallery(gpt-image2.canghe.ai,定期更新)',
166
- },
167
- ]
168
-
169
- /** Default source id when a request does not name one (legacy clients). */
170
- export const DEFAULT_TEMPLATE_SOURCE_ID = TEMPLATE_SOURCES[0]!.id
171
-
172
- /** True when the id names a registered template source. */
173
- export function isTemplateSourceId(id: string): boolean {
174
- return TEMPLATE_SOURCES.some(source => source.id === id)
175
- }
176
-
177
- /** One prompt-library case as the browser consumes it. */
178
- export interface TemplateCase {
179
- /** Upstream case number (stable across refreshes). */
180
- id: number
181
- /** Short case title. */
182
- title: string
183
- /** Full reusable prompt text. */
184
- prompt: string
185
- /** English category name (grouping key). */
186
- category: string
187
- /** Chinese category display name. */
188
- categoryZh: string
189
- /** Style tags. */
190
- styles: string[]
191
- /** Scene tags. */
192
- scenes: string[]
193
- /** Original author handle, e.g. @vista8. */
194
- sourceLabel: string
195
- /** Original author link. */
196
- sourceUrl: string
197
- /** awesome-gpt-image-2 repo anchor link. */
198
- githubUrl: string
199
- /** Reference-image file name served through the image route ('' when none). */
200
- image: string
201
- /** Whether the source gallery featured the case. */
202
- featured: boolean
203
- }
204
-
205
- /** Template-library list payload (one source). */
206
- export interface TemplateListResult {
207
- /** The source this list belongs to. */
208
- sourceId: string
209
- cases: TemplateCase[]
210
- total: number
211
- /** Where the served list came from. */
212
- origin: 'bundled' | 'refreshed'
213
- /** Upstream repository the library mirrors. */
214
- repository: string
215
- /** ISO time of the last successful refresh / bundle snapshot. */
216
- fetchedAt: string
217
- }
218
-
219
- /** Template-library refresh outcome (one source). */
220
- export interface TemplateRefreshResult {
221
- sourceId: string
222
- total: number
223
- fetchedAt: string
224
- }
225
-
226
- /** One random inspiration pick served to the studio's empty state. */
227
- export interface TemplateSample {
228
- /** Source the case came from (drives the image proxy URL). */
229
- sourceId: string
230
- /** The sampled case (full prompt is handed to the form on use). */
231
- case: TemplateCase
232
- }
233
-
234
- /** One favorited template as persisted host-side and served to the browser. */
235
- export interface TemplateFavorite {
236
- /** Stable key: `${sourceId}:${caseId}`. */
237
- key: string
238
- /** Source the case came from. */
239
- sourceId: string
240
- /** ISO time the favorite was saved. */
241
- savedAt: string
242
- /** Full case snapshot, so favorites survive upstream list churn. */
243
- case: TemplateCase
244
- }
245
-
246
- /** Generation modes. */
247
- export type GenerateMode = 'text' | 'edit'
248
-
249
- /** Origin information carried by a generation started from the canvas. */
250
- export interface CanvasTaskMeta {
251
- canvasId: string
252
- sourceNodeId?: string
253
- /** Legacy v1 annotation workflow; kept so old history entries still parse. */
254
- annotationNodeId?: string
255
- parentNodeId?: string
256
- placement?: 'right' | 'below'
257
- }
258
-
259
- /** One image asset referenced by a canvas node. */
260
- export interface CanvasAssetRef {
261
- assetId: string
262
- url: string
263
- mime: string
264
- bytes: number
265
- width: number
266
- height: number
267
- origin: 'upload' | 'history' | 'gallery' | 'generated'
268
- originId?: string
269
- entryId?: string
270
- imageIndex?: number
271
- }
272
-
273
- export type CanvasNodeType = 'image' | 'text' | 'config'
274
-
275
- export interface CanvasViewport {
276
- x: number
277
- y: number
278
- /** Zoom factor. */
279
- k: number
280
- }
281
-
282
- /** Free-form per-node state, mirroring the node-graph canvas model. */
283
- export interface CanvasNodeMetadata {
284
- /** Image nodes: the rendered asset. */
285
- asset?: CanvasAssetRef
286
- status?: 'idle' | 'generating' | 'success' | 'error'
287
- error?: string
288
- /** Config/image nodes: generation settings. */
289
- prompt?: string
290
- model?: string
291
- size?: string
292
- quality?: string
293
- /** Config nodes: how many images to generate (1-4). */
294
- count?: number
295
- /** Config nodes: generation mode (image) or plain writing (text). */
296
- mode?: 'image' | 'text'
297
- taskId?: string
298
- sourceNodeId?: string
299
- /** Text nodes. */
300
- text?: string
301
- fontSize?: number
302
- }
303
-
304
- export interface CanvasNode {
305
- id: string
306
- type: CanvasNodeType
307
- title: string
308
- x: number
309
- y: number
310
- width: number
311
- height: number
312
- metadata?: CanvasNodeMetadata
313
- }
314
-
315
- export interface CanvasConnection {
316
- id: string
317
- fromNodeId: string
318
- toNodeId: string
319
- }
320
-
321
- export interface CanvasDocument {
322
- version: 2
323
- id: string
324
- title: string
325
- revision: number
326
- viewport: CanvasViewport
327
- background: 'dots' | 'lines' | 'diagonal' | 'checker' | 'blank' | 'image'
328
- /** Custom background image URL (a canvas asset) when background is 'image'. */
329
- backgroundImage?: string
330
- nodes: CanvasNode[]
331
- connections: CanvasConnection[]
332
- createdAt: number
333
- updatedAt: number
334
- }
335
-
336
- export interface CanvasSummary {
337
- id: string
338
- title: string
339
- revision: number
340
- nodeCount: number
341
- createdAt: number
342
- updatedAt: number
343
- }
344
-
345
- /** Metadata shared by the ecommerce product-set workflow. */
346
- export interface EcommerceTaskMeta {
347
- workflow?: 'ecommerce'
348
- projectId?: string
349
- projectName?: string
350
- slotKey?: string
351
- slotLabel?: string
352
- }
353
-
354
- /** Role an uploaded product asset plays in the ecommerce workflow. 'none' is
355
- * only used as a slot selection meaning "generate without a reference". */
356
- export type EcommerceRefRole = 'none' | 'product' | 'packaging' | 'detail' | 'style'
357
-
358
- /** One planned image slot in a product set. */
359
- export interface ProductSetSlot {
360
- key: string
361
- label: string
362
- description: string
363
- count: number
364
- enabled: boolean
365
- /** Which uploaded asset role this slot uses as its edit reference. */
366
- refRole?: EcommerceRefRole
367
- }
368
-
369
- /** A browser-local ecommerce product-set draft. */
370
- export interface ProductSetDraft {
371
- projectId: string
372
- projectName: string
373
- category: string
374
- platform: string
375
- language: string
376
- /** Custom copy language when language is 'custom'. */
377
- customLanguage?: string
378
- size: string
379
- productName: string
380
- sellingPoints: string
381
- protectedFeatures: string
382
- styleHint: string
383
- slots: ProductSetSlot[]
384
- }
385
-
386
- /** A client → host generate request (what the panel collects). */
387
- export interface GenerateRequest extends EcommerceTaskMeta {
388
- /** text-to-image (images/generations) or image-to-image (images/edits). */
389
- mode: GenerateMode
390
- /**
391
- * User-facing model name (an alias from the channel's model catalog). The
392
- * host maps it onto the configured channel and fills `upstream` with the
393
- * real id before the engine sees it.
394
- */
395
- model: string
396
- /** The prompt. Upstream providers may impose their own length limits. */
397
- prompt: string
398
- /** Canvas size as an aspect ratio: 'auto' or e.g. '1:1' / '16:9' / '21:9'.
399
- * The host maps it onto each model's own vocabulary (aspect_ratio for Grok
400
- * and Nano Banana, resolution-tier size for Seedream, the closest pixel size for
401
- * OpenAI-compatible endpoints). */
402
- size: string
403
- /** Clarity tier: 'auto' | '1k' | '2k' | '4k'. The host maps it onto the
404
- * model's own vocabulary (resolution for Grok, image_size for Nano Banana,
405
- * and size for Seedream,
406
- * Nano Banana, quality for OpenAI). */
407
- quality: string
408
- /** Number of images, 1-4. */
409
- n: number
410
- /**
411
- * Passthrough detail parameter: '' (omit), 'standard', or 'high'. Some
412
- * gpt-image-2 gateways expose it; official OpenAI endpoints reject unknown
413
- * parameters, so the UI defaults to '' (omit).
414
- */
415
- detail: string
416
- /** Reference image as a data URL (edit mode only). */
417
- image?: string
418
- /** Additional reference images as data URLs (edit mode only). The first
419
- * image stays in `image`; providers that accept several references get them
420
- * all, single-reference providers see `image` alone. */
421
- images?: string[]
422
- /** Original reference-image name, retained in the history entry. */
423
- refName?: string
424
- /** Channel this request targets (the host falls back to the default when
425
- * absent, and re-routes by model alias when the alias lives elsewhere). */
426
- channelId?: string
427
- /** Channel display name snapshot, kept on the history entry (host-filled). */
428
- channel?: string
429
- /** Upstream model id actually sent to the gateway (host-filled from the
430
- * alias mapping; defaults to `model` when absent). */
431
- upstream?: string
432
- /** Stable client-created id shared by the tasks in one comparison run. */
433
- comparisonId?: string
434
- /** All model aliases selected for one comparison run. */
435
- comparisonModels?: string[]
436
- /** Optional canvas lineage metadata. */
437
- canvas?: CanvasTaskMeta
438
- }
439
-
440
- /** One generated image, normalized host-side to base64 so the browser never
441
- * has to fetch the upstream (no CORS, no key exposure). */
442
- export interface GeneratedImage {
443
- /** Raw base64 payload (no data: prefix). */
444
- b64: string
445
- /** MIME type of the payload, e.g. image/png. */
446
- mime: string
447
- /** Upstream revised prompt, when provided. */
448
- revisedPrompt?: string
449
- }
450
-
451
- /** Successful generate outcome. */
452
- export interface GenerateResult {
453
- images: GeneratedImage[]
454
- /** Updated host-persisted history, when returned by the generate route. */
455
- history?: HistoryEntry[]
456
- /** Persistence failure after images were successfully generated. */
457
- historyError?: string
458
- }
459
-
460
- /**
461
- * One model mapping in a channel's catalog: the display alias the user, the
462
- * panel, and the Agent see, and the upstream model id actually sent to the
463
- * gateway. The alias defaults to the upstream id but can be renamed freely.
464
- */
465
- export interface ModelMapping {
466
- /** User-facing model name (defaults to the upstream id). */
467
- alias: string
468
- /** Upstream model id sent to the gateway. */
469
- id: string
470
- }
471
-
472
- /**
473
- * One configured image channel (provider). Secrets never live here — the API
474
- * key is stored at `channelSecrets.<channelId>` in the settings document so
475
- * whole-array writes can never clobber keys the user did not re-enter.
476
- */
477
- export interface ChannelConfig {
478
- /** Stable channel id (the channelSecrets dict is keyed by it). */
479
- id: string
480
- /** Preset provider id this channel was created from ('' = custom). */
481
- preset: string
482
- /** Display name shown in the list, the panel, and Agent guidance. */
483
- name: string
484
- /** OpenAI-compatible base URL. */
485
- apiUrl: string
486
- /** The channel's model catalog (alias → upstream id). */
487
- models: ModelMapping[]
488
- }
489
-
490
- /** One built-in provider as the settings card consumes it. */
491
- export interface PresetProviderView {
492
- id: string
493
- name: string
494
- apiUrl: string
495
- hint: string
496
- models: ModelMapping[]
497
- }
498
-
499
- export type GenerationTaskStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled'
500
-
501
- export interface GenerationTask extends EcommerceTaskMeta {
502
- id: string
503
- request: GenerateRequest
504
- status: GenerationTaskStatus
505
- createdAt: number
506
- startedAt?: number
507
- finishedAt?: number
508
- result?: GenerateResult
509
- error?: string
510
- }
511
-
512
- /** GitHub Release update information shown by the client. */
513
- export interface UpdateInfo {
514
- currentVersion: string
515
- latestVersion: string
516
- updateAvailable: boolean
517
- releaseUrl: string
518
- publishedAt?: string
519
- }
520
-
521
- /** One history image reference as the browser consumes it (a served URL). */
522
- export interface HistoryImageRef {
523
- /** Same-origin URL: `${HISTORY_API.image}/<file>`. */
524
- url: string
525
- /** MIME type, e.g. image/png. */
526
- mime: string
527
- /** Upstream revised prompt, when provided. */
528
- revisedPrompt?: string
529
- }
530
-
531
- /** A saved generation as the browser consumes it (metadata + served images). */
532
- export interface HistoryEntry extends EcommerceTaskMeta {
533
- id: string
534
- createdAt: number
535
- mode: GenerateMode
536
- model: string
537
- prompt: string
538
- size: string
539
- quality: string
540
- detail: string
541
- n: number
542
- images: HistoryImageRef[]
543
- /** Reference-image filename (edit mode), kept for display only. */
544
- refName?: string
545
- /** User-managed gallery labels (unused by history entries). */
546
- tags?: string[]
547
- /** Channel id snapshot (usage counters key by it for new entries). */
548
- channelId?: string
549
- /** Channel display name snapshot (survives channel deletion). */
550
- channel?: string
551
- /** Stable id shared by the history entries in one comparison run. */
552
- comparisonId?: string
553
- /** Model aliases included in the comparison run. */
554
- comparisonModels?: string[]
555
- canvas?: CanvasTaskMeta
556
- }
557
-
558
- /** A history entry the client submits for persistence (images still carry base64). */
559
- export interface HistoryEntryInput extends EcommerceTaskMeta {
560
- id: string
561
- createdAt: number
562
- mode: GenerateMode
563
- model: string
564
- prompt: string
565
- size: string
566
- quality: string
567
- detail: string
568
- n: number
569
- images: GeneratedImage[]
570
- refName?: string
571
- /** Channel id snapshot, tallied by the usage endpoint. */
572
- channelId?: string
573
- /** Channel display name snapshot (survives channel deletion). */
574
- channel?: string
575
- /** Stable id shared by the history entries in one comparison run. */
576
- comparisonId?: string
577
- /** Model aliases included in the comparison run. */
578
- comparisonModels?: string[]
579
- canvas?: CanvasTaskMeta
580
- }
1
+ /**
2
+ * Wire contract shared by the host and client halves of dsh-imagegen: the
3
+ * settings namespace, the route paths, and the generate payload/result shapes.
4
+ * Pure types + constants 鈥?safe for the client bundle to inline.
5
+ */
6
+
7
+ /** Settings namespace this plugin owns (host settings seam + bridge). */
8
+ export const IMAGEGEN_SETTINGS_NAMESPACE = 'dsh-imagegen'
9
+
10
+ /** Published package version shared by the host updater and the client UI. */
11
+ export const PLUGIN_VERSION = '1.5.7'
12
+
13
+ /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
14
+ export const SETTINGS_API = {
15
+ describe: '/api/dsh-imagegen/settings/describe',
16
+ mutate: '/api/dsh-imagegen/settings/mutate',
17
+ } as const
18
+
19
+ /** The image-generation proxy route. */
20
+ export const GENERATE_API = '/api/dsh-imagegen/generate'
21
+
22
+ /** Host-mediated OpenAI-compatible prompt enhancement endpoints. */
23
+ export const PROMPT_ENHANCE_API = {
24
+ models: '/api/dsh-imagegen/prompt-enhance/models',
25
+ enhance: '/api/dsh-imagegen/prompt-enhance',
26
+ } as const
27
+
28
+ /** Host-mediated candidate discovery for the configured image API. */
29
+ export const IMAGE_MODEL_API = {
30
+ models: '/api/dsh-imagegen/image-models',
31
+ } as const
32
+
33
+ /** Host-served built-in provider catalog (channels the user can instantiate). */
34
+ export const PRESETS_API = '/api/dsh-imagegen/presets' as const
35
+
36
+ /** Loopback-only image reader for Agent tool-result previews. */
37
+ export const AGENT_IMAGE_API = '/api/dsh-imagegen/agent-image' as const
38
+
39
+ /** Store the current composer image for the direct edit_image command. */
40
+ export const CONVERSATION_IMAGE_API = '/api/dsh-imagegen/conversation-image' as const
41
+
42
+ /**
43
+ * Host-computed per-channel usage counters (generation-count badges in the
44
+ * settings card): entries are tallied from the persisted history and gallery
45
+ * by channel + model alias.
46
+ */
47
+ export const USAGE_API = '/api/dsh-imagegen/usage' as const
48
+
49
+ /** Host-resident generation queue endpoints. */
50
+ export const TASK_API = {
51
+ submit: '/api/dsh-imagegen/tasks/submit',
52
+ list: '/api/dsh-imagegen/tasks/list',
53
+ cancel: '/api/dsh-imagegen/tasks/cancel',
54
+ retry: '/api/dsh-imagegen/tasks/retry',
55
+ } as const
56
+
57
+ /** Reveal the host data directory (saved images) in the OS file manager. */
58
+ export const DATA_FOLDER_API = '/api/dsh-imagegen/data-folder/open' as const
59
+
60
+ /** Probe the configured S3-compatible object storage. */
61
+ export const STORAGE_API = {
62
+ test: '/api/dsh-imagegen/storage/test',
63
+ } as const
64
+
65
+ /** Host-mediated GitHub Release update routes. */
66
+ export const UPDATE_API = {
67
+ check: '/api/dsh-imagegen/update/check',
68
+ apply: '/api/dsh-imagegen/update/apply',
69
+ } as const
70
+
71
+ /**
72
+ * Same-origin route family for the host-persisted generation history. Images
73
+ * live as files under ~/.dsh/dsh-imagegen/images/ and are served back through
74
+ * the `image` prefix route, so list responses carry metadata only (never
75
+ * base64) and the browser loads thumbnails/previews lazily.
76
+ */
77
+ export const HISTORY_API = {
78
+ list: '/api/dsh-imagegen/history/list',
79
+ append: '/api/dsh-imagegen/history/append',
80
+ remove: '/api/dsh-imagegen/history/remove',
81
+ clear: '/api/dsh-imagegen/history/clear',
82
+ image: '/api/dsh-imagegen/history/image',
83
+ } as const
84
+
85
+ /**
86
+ * Same-origin route family for the user-curated gallery (favorites). Entries
87
+ * reuse the history wire shape and persist under ~/.dsh/dsh-imagegen/gallery/;
88
+ * unlike history there is no size cap 鈥?the user adds images on purpose.
89
+ */
90
+ export const GALLERY_API = {
91
+ list: '/api/dsh-imagegen/gallery/list',
92
+ append: '/api/dsh-imagegen/gallery/append',
93
+ remove: '/api/dsh-imagegen/gallery/remove',
94
+ clear: '/api/dsh-imagegen/gallery/clear',
95
+ tags: '/api/dsh-imagegen/gallery/tags',
96
+ image: '/api/dsh-imagegen/gallery/image',
97
+ } as const
98
+
99
+ /** Host-persisted infinite canvas projects and their content-addressed assets. */
100
+ export const CANVAS_API = {
101
+ list: '/api/dsh-imagegen/canvas/list',
102
+ create: '/api/dsh-imagegen/canvas/create',
103
+ read: '/api/dsh-imagegen/canvas/read',
104
+ save: '/api/dsh-imagegen/canvas/save',
105
+ remove: '/api/dsh-imagegen/canvas/remove',
106
+ assetUpload: '/api/dsh-imagegen/canvas/asset/upload',
107
+ assetImport: '/api/dsh-imagegen/canvas/asset/import',
108
+ asset: '/api/dsh-imagegen/canvas/asset',
109
+ } as const
110
+
111
+ /** Maximum number of history entries retained host-side (oldest evicted). */
112
+ export const HISTORY_MAX = 50
113
+
114
+ /**
115
+ * Same-origin route family for the prompt-template libraries. The library is
116
+ * multi-source: every request names a source id from {@link TEMPLATE_SOURCES},
117
+ * each source keeps an independent snapshot/image cache host-side, and
118
+ * reference images are proxied through the source-scoped `image` prefix route
119
+ * (`…/image/<sourceId>/<file>`) and cached on disk so repeated views never hit
120
+ * the network again.
121
+ */
122
+ export const TEMPLATES_API = {
123
+ list: '/api/dsh-imagegen/templates/list',
124
+ refresh: '/api/dsh-imagegen/templates/refresh',
125
+ sample: '/api/dsh-imagegen/templates/sample',
126
+ image: '/api/dsh-imagegen/templates/image',
127
+ } as const
128
+
129
+ /** Same-origin route family for the user's saved (favorited) templates. */
130
+ export const TEMPLATE_FAVORITES_API = {
131
+ list: '/api/dsh-imagegen/templates/favorites/list',
132
+ add: '/api/dsh-imagegen/templates/favorites/add',
133
+ remove: '/api/dsh-imagegen/templates/favorites/remove',
134
+ } as const
135
+
136
+ /** One prompt-template library source (a tab in the library overlay). */
137
+ export interface TemplateSourceMeta {
138
+ /** Stable source id: snapshot dir name, image-cache dir, and request key. */
139
+ id: string
140
+ /** Tab label shown in the library overlay. */
141
+ label: string
142
+ /** Source homepage linked in the overlay footer. */
143
+ homepage: string
144
+ /** One-line description of the source (tab tooltip). */
145
+ description: string
146
+ }
147
+
148
+ /**
149
+ * The template-library source registry. Each entry is fully independent (own
150
+ * upstream JSON, own image pool, own refresh state) and renders as its own
151
+ * tab; adding a source later means appending an entry here plus a host-side
152
+ * fetch definition in templates-store.ts and an optional bundled snapshot.
153
+ */
154
+ export const TEMPLATE_SOURCES: TemplateSourceMeta[] = [
155
+ {
156
+ id: 'vibeui',
157
+ label: '精选案例库',
158
+ homepage: 'https://vibeui.top/',
159
+ description: 'awesome-gpt-image-2 精选提示词案例(vibeui.top 镜像)',
160
+ },
161
+ {
162
+ id: 'canghe',
163
+ label: '沧河案例库',
164
+ homepage: 'https://gpt-image2.canghe.ai/',
165
+ description: 'GPT-Image2 Prompt Gallery(gpt-image2.canghe.ai,定期更新)',
166
+ },
167
+ ]
168
+
169
+ /** Default source id when a request does not name one (legacy clients). */
170
+ export const DEFAULT_TEMPLATE_SOURCE_ID = TEMPLATE_SOURCES[0]!.id
171
+
172
+ /** True when the id names a registered template source. */
173
+ export function isTemplateSourceId(id: string): boolean {
174
+ return TEMPLATE_SOURCES.some(source => source.id === id)
175
+ }
176
+
177
+ /** One prompt-library case as the browser consumes it. */
178
+ export interface TemplateCase {
179
+ /** Upstream case number (stable across refreshes). */
180
+ id: number
181
+ /** Short case title. */
182
+ title: string
183
+ /** Full reusable prompt text. */
184
+ prompt: string
185
+ /** English category name (grouping key). */
186
+ category: string
187
+ /** Chinese category display name. */
188
+ categoryZh: string
189
+ /** Style tags. */
190
+ styles: string[]
191
+ /** Scene tags. */
192
+ scenes: string[]
193
+ /** Original author handle, e.g. @vista8. */
194
+ sourceLabel: string
195
+ /** Original author link. */
196
+ sourceUrl: string
197
+ /** awesome-gpt-image-2 repo anchor link. */
198
+ githubUrl: string
199
+ /** Reference-image file name served through the image route ('' when none). */
200
+ image: string
201
+ /** Whether the source gallery featured the case. */
202
+ featured: boolean
203
+ }
204
+
205
+ /** Template-library list payload (one source). */
206
+ export interface TemplateListResult {
207
+ /** The source this list belongs to. */
208
+ sourceId: string
209
+ cases: TemplateCase[]
210
+ total: number
211
+ /** Where the served list came from. */
212
+ origin: 'bundled' | 'refreshed'
213
+ /** Upstream repository the library mirrors. */
214
+ repository: string
215
+ /** ISO time of the last successful refresh / bundle snapshot. */
216
+ fetchedAt: string
217
+ }
218
+
219
+ /** Template-library refresh outcome (one source). */
220
+ export interface TemplateRefreshResult {
221
+ sourceId: string
222
+ total: number
223
+ fetchedAt: string
224
+ }
225
+
226
+ /** One random inspiration pick served to the studio's empty state. */
227
+ export interface TemplateSample {
228
+ /** Source the case came from (drives the image proxy URL). */
229
+ sourceId: string
230
+ /** The sampled case (full prompt is handed to the form on use). */
231
+ case: TemplateCase
232
+ }
233
+
234
+ /** One favorited template as persisted host-side and served to the browser. */
235
+ export interface TemplateFavorite {
236
+ /** Stable key: `${sourceId}:${caseId}`. */
237
+ key: string
238
+ /** Source the case came from. */
239
+ sourceId: string
240
+ /** ISO time the favorite was saved. */
241
+ savedAt: string
242
+ /** Full case snapshot, so favorites survive upstream list churn. */
243
+ case: TemplateCase
244
+ }
245
+
246
+ /** Generation modes. */
247
+ export type GenerateMode = 'text' | 'edit'
248
+
249
+ /** Origin information carried by a generation started from the canvas. */
250
+ export interface CanvasTaskMeta {
251
+ canvasId: string
252
+ sourceNodeId?: string
253
+ /** Legacy v1 annotation workflow; kept so old history entries still parse. */
254
+ annotationNodeId?: string
255
+ parentNodeId?: string
256
+ placement?: 'right' | 'below'
257
+ }
258
+
259
+ /** One image asset referenced by a canvas node. */
260
+ export interface CanvasAssetRef {
261
+ assetId: string
262
+ url: string
263
+ mime: string
264
+ bytes: number
265
+ width: number
266
+ height: number
267
+ origin: 'upload' | 'history' | 'gallery' | 'generated'
268
+ originId?: string
269
+ entryId?: string
270
+ imageIndex?: number
271
+ }
272
+
273
+ export type CanvasNodeType = 'image' | 'text' | 'config'
274
+
275
+ export interface CanvasViewport {
276
+ x: number
277
+ y: number
278
+ /** Zoom factor. */
279
+ k: number
280
+ }
281
+
282
+ /** Free-form per-node state, mirroring the node-graph canvas model. */
283
+ export interface CanvasNodeMetadata {
284
+ /** Image nodes: the rendered asset. */
285
+ asset?: CanvasAssetRef
286
+ status?: 'idle' | 'generating' | 'success' | 'error'
287
+ error?: string
288
+ /** Config/image nodes: generation settings. */
289
+ prompt?: string
290
+ model?: string
291
+ size?: string
292
+ quality?: string
293
+ /** Config nodes: how many images to generate (1-4). */
294
+ count?: number
295
+ /** Config nodes: generation mode (image) or plain writing (text). */
296
+ mode?: 'image' | 'text'
297
+ taskId?: string
298
+ sourceNodeId?: string
299
+ /** Text nodes. */
300
+ text?: string
301
+ fontSize?: number
302
+ }
303
+
304
+ export interface CanvasNode {
305
+ id: string
306
+ type: CanvasNodeType
307
+ title: string
308
+ x: number
309
+ y: number
310
+ width: number
311
+ height: number
312
+ metadata?: CanvasNodeMetadata
313
+ }
314
+
315
+ export interface CanvasConnection {
316
+ id: string
317
+ fromNodeId: string
318
+ toNodeId: string
319
+ }
320
+
321
+ export interface CanvasDocument {
322
+ version: 2
323
+ id: string
324
+ title: string
325
+ revision: number
326
+ viewport: CanvasViewport
327
+ background: 'dots' | 'lines' | 'diagonal' | 'checker' | 'blank' | 'image'
328
+ /** Custom background image URL (a canvas asset) when background is 'image'. */
329
+ backgroundImage?: string
330
+ nodes: CanvasNode[]
331
+ connections: CanvasConnection[]
332
+ createdAt: number
333
+ updatedAt: number
334
+ }
335
+
336
+ export interface CanvasSummary {
337
+ id: string
338
+ title: string
339
+ revision: number
340
+ nodeCount: number
341
+ createdAt: number
342
+ updatedAt: number
343
+ }
344
+
345
+ /** Metadata shared by the ecommerce product-set workflow. */
346
+ export interface EcommerceTaskMeta {
347
+ workflow?: 'ecommerce'
348
+ projectId?: string
349
+ projectName?: string
350
+ slotKey?: string
351
+ slotLabel?: string
352
+ }
353
+
354
+ /** Role an uploaded product asset plays in the ecommerce workflow. 'none' is
355
+ * only used as a slot selection meaning "generate without a reference". */
356
+ export type EcommerceRefRole = 'none' | 'product' | 'packaging' | 'detail' | 'style'
357
+
358
+ /** One planned image slot in a product set. */
359
+ export interface ProductSetSlot {
360
+ key: string
361
+ label: string
362
+ description: string
363
+ count: number
364
+ enabled: boolean
365
+ /** Which uploaded asset role this slot uses as its edit reference. */
366
+ refRole?: EcommerceRefRole
367
+ }
368
+
369
+ /** A browser-local ecommerce product-set draft. */
370
+ export interface ProductSetDraft {
371
+ projectId: string
372
+ projectName: string
373
+ category: string
374
+ platform: string
375
+ language: string
376
+ /** Custom copy language when language is 'custom'. */
377
+ customLanguage?: string
378
+ size: string
379
+ productName: string
380
+ sellingPoints: string
381
+ protectedFeatures: string
382
+ styleHint: string
383
+ slots: ProductSetSlot[]
384
+ }
385
+
386
+ /** A client → host generate request (what the panel collects). */
387
+ export interface GenerateRequest extends EcommerceTaskMeta {
388
+ /** text-to-image (images/generations) or image-to-image (images/edits). */
389
+ mode: GenerateMode
390
+ /**
391
+ * User-facing model name (an alias from the channel's model catalog). The
392
+ * host maps it onto the configured channel and fills `upstream` with the
393
+ * real id before the engine sees it.
394
+ */
395
+ model: string
396
+ /** The prompt. Upstream providers may impose their own length limits. */
397
+ prompt: string
398
+ /** Canvas size as an aspect ratio: 'auto' or e.g. '1:1' / '16:9' / '21:9'.
399
+ * The host maps it onto each model's own vocabulary (aspect_ratio for Grok
400
+ * and Nano Banana, resolution-tier size for Seedream, the closest pixel size for
401
+ * OpenAI-compatible endpoints). */
402
+ size: string
403
+ /** Clarity tier: 'auto' | '1k' | '2k' | '4k'. The host maps it onto the
404
+ * model's own vocabulary (resolution for Grok, image_size for Nano Banana,
405
+ * and size for Seedream,
406
+ * Nano Banana, quality for OpenAI). */
407
+ quality: string
408
+ /** Number of images, 1-4. */
409
+ n: number
410
+ /**
411
+ * Passthrough detail parameter: '' (omit), 'standard', or 'high'. Some
412
+ * gpt-image-2 gateways expose it; official OpenAI endpoints reject unknown
413
+ * parameters, so the UI defaults to '' (omit).
414
+ */
415
+ detail: string
416
+ /** Reference image as a data URL (edit mode only). */
417
+ image?: string
418
+ /** Additional reference images as data URLs (edit mode only). The first
419
+ * image stays in `image`; providers that accept several references get them
420
+ * all, single-reference providers see `image` alone. */
421
+ images?: string[]
422
+ /** Original reference-image name, retained in the history entry. */
423
+ refName?: string
424
+ /** Channel this request targets (the host falls back to the default when
425
+ * absent, and re-routes by model alias when the alias lives elsewhere). */
426
+ channelId?: string
427
+ /** Channel display name snapshot, kept on the history entry (host-filled). */
428
+ channel?: string
429
+ /** Upstream model id actually sent to the gateway (host-filled from the
430
+ * alias mapping; defaults to `model` when absent). */
431
+ upstream?: string
432
+ /** Stable client-created id shared by the tasks in one comparison run. */
433
+ comparisonId?: string
434
+ /** All model aliases selected for one comparison run. */
435
+ comparisonModels?: string[]
436
+ /** Optional canvas lineage metadata. */
437
+ canvas?: CanvasTaskMeta
438
+ }
439
+
440
+ /** One generated image, normalized host-side to base64 so the browser never
441
+ * has to fetch the upstream (no CORS, no key exposure). */
442
+ export interface GeneratedImage {
443
+ /** Raw base64 payload (no data: prefix). */
444
+ b64: string
445
+ /** MIME type of the payload, e.g. image/png. */
446
+ mime: string
447
+ /** Upstream revised prompt, when provided. */
448
+ revisedPrompt?: string
449
+ }
450
+
451
+ /** Successful generate outcome. */
452
+ export interface GenerateResult {
453
+ images: GeneratedImage[]
454
+ /** Updated host-persisted history, when returned by the generate route. */
455
+ history?: HistoryEntry[]
456
+ /** Persistence failure after images were successfully generated. */
457
+ historyError?: string
458
+ }
459
+
460
+ /**
461
+ * One model mapping in a channel's catalog: the display alias the user, the
462
+ * panel, and the Agent see, and the upstream model id actually sent to the
463
+ * gateway. The alias defaults to the upstream id but can be renamed freely.
464
+ */
465
+ export interface ModelMapping {
466
+ /** User-facing model name (defaults to the upstream id). */
467
+ alias: string
468
+ /** Upstream model id sent to the gateway. */
469
+ id: string
470
+ }
471
+
472
+ /**
473
+ * One configured image channel (provider). Secrets never live here — the API
474
+ * key is stored at `channelSecrets.<channelId>` in the settings document so
475
+ * whole-array writes can never clobber keys the user did not re-enter.
476
+ */
477
+ export interface ChannelConfig {
478
+ /** Stable channel id (the channelSecrets dict is keyed by it). */
479
+ id: string
480
+ /** Preset provider id this channel was created from ('' = custom). */
481
+ preset: string
482
+ /** Display name shown in the list, the panel, and Agent guidance. */
483
+ name: string
484
+ /** OpenAI-compatible base URL. */
485
+ apiUrl: string
486
+ /** The channel's model catalog (alias → upstream id). */
487
+ models: ModelMapping[]
488
+ }
489
+
490
+ /** One built-in provider as the settings card consumes it. */
491
+ export interface PresetProviderView {
492
+ id: string
493
+ name: string
494
+ apiUrl: string
495
+ hint: string
496
+ models: ModelMapping[]
497
+ }
498
+
499
+ export type GenerationTaskStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled'
500
+
501
+ export interface GenerationTask extends EcommerceTaskMeta {
502
+ id: string
503
+ request: GenerateRequest
504
+ status: GenerationTaskStatus
505
+ createdAt: number
506
+ startedAt?: number
507
+ finishedAt?: number
508
+ result?: GenerateResult
509
+ error?: string
510
+ }
511
+
512
+ /** GitHub Release update information shown by the client. */
513
+ export interface UpdateInfo {
514
+ currentVersion: string
515
+ latestVersion: string
516
+ updateAvailable: boolean
517
+ releaseUrl: string
518
+ publishedAt?: string
519
+ }
520
+
521
+ /** One history image reference as the browser consumes it (a served URL). */
522
+ export interface HistoryImageRef {
523
+ /** Same-origin URL: `${HISTORY_API.image}/<file>`. */
524
+ url: string
525
+ /** MIME type, e.g. image/png. */
526
+ mime: string
527
+ /** Upstream revised prompt, when provided. */
528
+ revisedPrompt?: string
529
+ }
530
+
531
+ /** A saved generation as the browser consumes it (metadata + served images). */
532
+ export interface HistoryEntry extends EcommerceTaskMeta {
533
+ id: string
534
+ createdAt: number
535
+ mode: GenerateMode
536
+ model: string
537
+ prompt: string
538
+ size: string
539
+ quality: string
540
+ detail: string
541
+ n: number
542
+ images: HistoryImageRef[]
543
+ /** Reference-image filename (edit mode), kept for display only. */
544
+ refName?: string
545
+ /** User-managed gallery labels (unused by history entries). */
546
+ tags?: string[]
547
+ /** Channel id snapshot (usage counters key by it for new entries). */
548
+ channelId?: string
549
+ /** Channel display name snapshot (survives channel deletion). */
550
+ channel?: string
551
+ /** Stable id shared by the history entries in one comparison run. */
552
+ comparisonId?: string
553
+ /** Model aliases included in the comparison run. */
554
+ comparisonModels?: string[]
555
+ canvas?: CanvasTaskMeta
556
+ }
557
+
558
+ /** A history entry the client submits for persistence (images still carry base64). */
559
+ export interface HistoryEntryInput extends EcommerceTaskMeta {
560
+ id: string
561
+ createdAt: number
562
+ mode: GenerateMode
563
+ model: string
564
+ prompt: string
565
+ size: string
566
+ quality: string
567
+ detail: string
568
+ n: number
569
+ images: GeneratedImage[]
570
+ refName?: string
571
+ /** Channel id snapshot, tallied by the usage endpoint. */
572
+ channelId?: string
573
+ /** Channel display name snapshot (survives channel deletion). */
574
+ channel?: string
575
+ /** Stable id shared by the history entries in one comparison run. */
576
+ comparisonId?: string
577
+ /** Model aliases included in the comparison run. */
578
+ comparisonModels?: string[]
579
+ canvas?: CanvasTaskMeta
580
+ }