@dsh-plus/image-studio 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +558 -113
- package/lib/index.d.ts +171 -9
- package/lib/index.js +530 -55
- package/package.json +1 -1
- package/src/api.ts +83 -3
- package/src/client/api.ts +25 -0
- package/src/client/card.tsx +12 -0
- package/src/client/i18n.ts +17 -0
- package/src/client/panel/controller.ts +4 -2
- package/src/client/panel/gallery.tsx +7 -2
- package/src/client/panel/generator.tsx +89 -26
- package/src/client/panel/panel.tsx +4 -1
- package/src/client/panel/params-form.tsx +50 -6
- package/src/client/panel/picker.tsx +124 -40
- package/src/client/panel/uploads.tsx +124 -0
- package/src/client/styles.ts +50 -0
- package/src/config.ts +6 -0
- package/src/dto.ts +17 -3
- package/src/errors.ts +6 -0
- package/src/gallery/store.ts +16 -15
- package/src/images/id.ts +12 -0
- package/src/images/mime.ts +64 -0
- package/src/index.ts +12 -5
- package/src/limits.ts +12 -0
- package/src/params/catalog.ts +9 -3
- package/src/params/size.ts +98 -0
- package/src/params/spec.ts +17 -2
- package/src/service.ts +157 -28
- package/src/uploads/store.ts +168 -0
package/lib/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ declare const Config: z<Schemastery.ObjectS<{
|
|
|
9
9
|
requestTimeoutMs: z<number, number>;
|
|
10
10
|
proxy: z<string, string>;
|
|
11
11
|
galleryMaxItems: z<number, number>;
|
|
12
|
+
uploadTtlHours: z<number, number>;
|
|
12
13
|
}>, Schemastery.ObjectT<{
|
|
13
14
|
promptPresets: z<unknown[], any[]>;
|
|
14
15
|
paramPresets: z<unknown[], any[]>;
|
|
@@ -17,6 +18,7 @@ declare const Config: z<Schemastery.ObjectS<{
|
|
|
17
18
|
requestTimeoutMs: z<number, number>;
|
|
18
19
|
proxy: z<string, string>;
|
|
19
20
|
galleryMaxItems: z<number, number>;
|
|
21
|
+
uploadTtlHours: z<number, number>;
|
|
20
22
|
}>>;
|
|
21
23
|
type ImageStudioConfig = Schemastery.TypeT<typeof Config>;
|
|
22
24
|
/** 提示词预设(解析后视图)。 */
|
|
@@ -70,8 +72,10 @@ interface GalleryItem {
|
|
|
70
72
|
imageIds: string[];
|
|
71
73
|
/** 每张图的 revised_prompt(与 imageIds 对齐,可为 null)。 */
|
|
72
74
|
revisedPrompts: Array<string | null>;
|
|
73
|
-
/**
|
|
75
|
+
/** 图生图源图中的画廊图片(本画廊 imageId);文生图为空。 */
|
|
74
76
|
sourceIds: string[];
|
|
77
|
+
/** 图生图源图中的本地文件上传(uploads 暂存区 id);上传被回收即失效。 */
|
|
78
|
+
sourceUploads: string[];
|
|
75
79
|
}
|
|
76
80
|
//#endregion
|
|
77
81
|
//#region src/task/runner.d.ts
|
|
@@ -84,7 +88,36 @@ interface GalleryItem {
|
|
|
84
88
|
/** 任务状态。 */
|
|
85
89
|
type TaskState = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled';
|
|
86
90
|
//#endregion
|
|
91
|
+
//#region src/uploads/store.d.ts
|
|
92
|
+
/**
|
|
93
|
+
* 上传暂存区:图生图源图/遮罩的本地文件上传(blobs + JSONL 索引,原子写)。
|
|
94
|
+
* 与画廊分离——上传图片不属于任何画廊条目;生图成功后由条目的
|
|
95
|
+
* sourceUploads 引用(衍生链可见),未被任何条目引用且超过 TTL 的由
|
|
96
|
+
* pruneUploads 回收(见 docs/repo/插件存储规范.md)。
|
|
97
|
+
* 落点 $DSH_HOME/dsh-plus/image-studio/uploads/{index.jsonl, blobs/}
|
|
98
|
+
* @module image-studio/uploads/store
|
|
99
|
+
*/
|
|
100
|
+
/** 上传记录元数据(wire 视图原样投影)。 */
|
|
101
|
+
interface UploadEntry {
|
|
102
|
+
id: string;
|
|
103
|
+
createdAt: string;
|
|
104
|
+
/** 原始文件名(仅作展示,不参与路径拼接)。 */
|
|
105
|
+
name: string;
|
|
106
|
+
mime: string;
|
|
107
|
+
ext: string;
|
|
108
|
+
/** 字节数。 */
|
|
109
|
+
size: number;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
87
112
|
//#region src/dto.d.ts
|
|
113
|
+
/**
|
|
114
|
+
* 源图引用:画廊已落盘图片(gallery)或本地文件上传的暂存图片(upload)。
|
|
115
|
+
* 两个 id 空间互不重叠,故引用必须显式带 kind(同一字符串在两边含义不同)。
|
|
116
|
+
*/
|
|
117
|
+
interface SourceRef {
|
|
118
|
+
kind: 'gallery' | 'upload';
|
|
119
|
+
id: string;
|
|
120
|
+
}
|
|
88
121
|
/** 任务提交请求体。 */
|
|
89
122
|
interface GenerateRequest {
|
|
90
123
|
/** 提供商预设 id 与 inline 二选一(都传时 inline 优先)。 */
|
|
@@ -104,9 +137,13 @@ interface GenerateRequest {
|
|
|
104
137
|
enabled: boolean;
|
|
105
138
|
value?: unknown;
|
|
106
139
|
}>;
|
|
107
|
-
/**
|
|
140
|
+
/** 图生图源图(edit 必填 ≥1,≤16;画廊图片与本地文件上传混用)。 */
|
|
141
|
+
sources?: SourceRef[];
|
|
142
|
+
/** 可选遮罩(官方要求 PNG;与源图同一引用形态)。 */
|
|
143
|
+
mask?: SourceRef;
|
|
144
|
+
/** @deprecated 旧客户端兼容:等价于 kind='gallery' 的 sources。 */
|
|
108
145
|
sourceIds?: string[];
|
|
109
|
-
/**
|
|
146
|
+
/** @deprecated 旧客户端兼容:等价于 kind='gallery' 的 mask。 */
|
|
110
147
|
maskId?: string;
|
|
111
148
|
}
|
|
112
149
|
/** 任务记录 wire 视图。 */
|
|
@@ -165,6 +202,8 @@ declare class ImageStudioService extends Service {
|
|
|
165
202
|
private current;
|
|
166
203
|
private readonly runner;
|
|
167
204
|
private readonly log;
|
|
205
|
+
/** 进行中的孤儿回收(串行化:索引重写不能并发)。 */
|
|
206
|
+
private pruning;
|
|
168
207
|
private settingsRef;
|
|
169
208
|
constructor(ctx: Context, config: ImageStudioConfig);
|
|
170
209
|
/** 配置热更:并发上限即时生效(进行中任务不受影响)。 */
|
|
@@ -200,9 +239,15 @@ declare class ImageStudioService extends Service {
|
|
|
200
239
|
private toTaskWire;
|
|
201
240
|
/**
|
|
202
241
|
* 任务准备(边界校验集中地):提供商预设/inline → target;
|
|
203
|
-
* 参数预设 + 覆盖 → 归一化参数表;
|
|
242
|
+
* 参数预设 + 覆盖 → 归一化参数表;sources/mask 引用 → 输入图字节。
|
|
204
243
|
*/
|
|
205
244
|
private prepareTask;
|
|
245
|
+
/** 源图引用规范化(sources 优先;旧 sourceIds 等价于全部 gallery 引用)。 */
|
|
246
|
+
private sourceRefsOf;
|
|
247
|
+
/** 遮罩引用规范化(mask 优先;旧 maskId 等价于 gallery 引用)。 */
|
|
248
|
+
private maskRefOf;
|
|
249
|
+
/** 引用形态校验(请求体来自浏览器,kind 封闭集合 + id uuid 形态)。 */
|
|
250
|
+
private assertRef;
|
|
206
251
|
/** 提供商预设 / inline → ProviderTarget(凭据即时 resolve)。 */
|
|
207
252
|
private resolveTarget;
|
|
208
253
|
/** 凭据解析(每次操作即时 resolve,不缓存)。 */
|
|
@@ -212,10 +257,18 @@ declare class ImageStudioService extends Service {
|
|
|
212
257
|
/** 模型优先级:inline > 提供商预设(参数表中的 model 仅为展示,不参与)。 */
|
|
213
258
|
private modelOf;
|
|
214
259
|
private providerModelOf;
|
|
215
|
-
/**
|
|
260
|
+
/**
|
|
261
|
+
* 源图字节加载(edit ≥1 张;单图上限 50MB 对齐官方)。
|
|
262
|
+
* 按引用来源分流读取,并把两类 id 分开回传(画廊衍生链 / 上传暂存区)。
|
|
263
|
+
*/
|
|
216
264
|
private loadSourceImages;
|
|
217
|
-
|
|
218
|
-
private
|
|
265
|
+
/** 单个引用 → 输入图字节(两个 id 空间分别查,未知一律 unknown-source)。 */
|
|
266
|
+
private loadRefImage;
|
|
267
|
+
/**
|
|
268
|
+
* 遮罩加载:官方要求带透明通道的 PNG(其它格式上游必然拒绝),
|
|
269
|
+
* 在边界提前给出可读原因,避免白跑一次计费请求。
|
|
270
|
+
*/
|
|
271
|
+
private loadMaskImage;
|
|
219
272
|
/** 任务体:调协议适配器 → 成功入画廊。失败向上抛给 TaskRunner 记录。 */
|
|
220
273
|
private executeTask;
|
|
221
274
|
/** 提交时上下文里的预设 id(executeTask 无原请求,经 target 旁路携带)。 */
|
|
@@ -229,6 +282,23 @@ declare class ImageStudioService extends Service {
|
|
|
229
282
|
data: Uint8Array;
|
|
230
283
|
ext: string;
|
|
231
284
|
} | null>;
|
|
285
|
+
/** 保存上传原图(端点边界已完成 MIME 嗅探与限额)。 */
|
|
286
|
+
saveUpload(input: {
|
|
287
|
+
name: string;
|
|
288
|
+
mime: string;
|
|
289
|
+
data: Uint8Array;
|
|
290
|
+
}): Promise<UploadEntry>;
|
|
291
|
+
/** 上传列表(索引序,最新在后;前端自行倒序展示)。 */
|
|
292
|
+
listUploads(): Promise<UploadEntry[]>;
|
|
293
|
+
/** 读取上传图片字节(缩略图端点;未知 id 返回 null)。 */
|
|
294
|
+
uploadBytes(uploadId: string): Promise<{
|
|
295
|
+
data: Uint8Array;
|
|
296
|
+
ext: string;
|
|
297
|
+
} | null>;
|
|
298
|
+
/** 触发一次孤儿回收(并发调用合并为一次,失败不影响主流程)。 */
|
|
299
|
+
private schedulePrune;
|
|
300
|
+
/** 保留被画廊条目引用的上传;其余超过 TTL 的回收(暂存区不无界增长)。 */
|
|
301
|
+
private pruneOrphans;
|
|
232
302
|
dispose(): void;
|
|
233
303
|
}
|
|
234
304
|
//#endregion
|
|
@@ -250,16 +320,59 @@ declare function credentialRefNameOf(presetId: string): string;
|
|
|
250
320
|
* @module image-studio/errors
|
|
251
321
|
*/
|
|
252
322
|
/** 全部错误码(封闭集合,新增协议/端点行为时按需扩充)。 */
|
|
253
|
-
declare const ERROR_CODES: readonly ["unknown-protocol", "unknown-endpoint", "invalid-request", "unknown-source", "unknown-task", "task-not-runnable", "credential-unavailable", "settings-unavailable", "provider-error"];
|
|
323
|
+
declare const ERROR_CODES: readonly ["unknown-protocol", "unknown-endpoint", "invalid-request", "unknown-source", "unknown-task", "task-not-runnable", "credential-unavailable", "settings-unavailable", "unsupported-media", "upload-too-large", "provider-error"];
|
|
254
324
|
type ErrorCode = (typeof ERROR_CODES)[number];
|
|
255
325
|
declare class ImageStudioError extends Error {
|
|
256
326
|
readonly code: ErrorCode;
|
|
257
327
|
constructor(code: ErrorCode, message?: string);
|
|
258
328
|
}
|
|
329
|
+
/** 按错误码映射 HTTP 状态(端点边界统一使用)。 */
|
|
330
|
+
declare function statusOfCode(code: string): number;
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/images/id.d.ts
|
|
333
|
+
/**
|
|
334
|
+
* 图片标识形态(uuid):画廊 imageId 与上传 uploadId 共用同一约束。
|
|
335
|
+
* 既是路由参数白名单,也是路径拼接的穿越防线(单一事实源)。
|
|
336
|
+
* @module image-studio/images/id
|
|
337
|
+
*/
|
|
338
|
+
/** 是否为合法图片标识(未知类型一律 false)。 */
|
|
339
|
+
declare function isImageId(value: unknown): value is string;
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/images/mime.d.ts
|
|
342
|
+
/**
|
|
343
|
+
* 图片 MIME 单一事实源:扩展名互转 + 魔数嗅探。
|
|
344
|
+
* 上传边界只认官方 images 端点接受的位图格式(png/jpeg/webp/gif),
|
|
345
|
+
* 不信任客户端声明的 content-type(防伪装文件落盘)。
|
|
346
|
+
* 纯函数零依赖,宿主两半均可安全引入。
|
|
347
|
+
* @module image-studio/images/mime
|
|
348
|
+
*/
|
|
349
|
+
/** 落盘扩展名 ← MIME(白名单外一律按 png 处理)。 */
|
|
350
|
+
declare function extOfMime(mime: string): string;
|
|
351
|
+
/** MIME ← 落盘扩展名(读取回程;与 extOfMime 互逆)。 */
|
|
352
|
+
declare function mimeOfExt(ext: string): string;
|
|
353
|
+
/**
|
|
354
|
+
* 魔数嗅探图片类型;非白名单格式返回 null。
|
|
355
|
+
* @param bytes - 文件字节(只需前 16 字节即可判定)。
|
|
356
|
+
*/
|
|
357
|
+
declare function detectImageMime(bytes: Uint8Array): string | null;
|
|
358
|
+
//#endregion
|
|
359
|
+
//#region src/limits.d.ts
|
|
360
|
+
/**
|
|
361
|
+
* 跨半共享的数量/体积上限(单一事实源)。
|
|
362
|
+
* 宿主边界校验与浏览器半控件共用,避免两处各写一个数字而漂移。
|
|
363
|
+
* 纯常量零依赖,浏览器半可安全引入。
|
|
364
|
+
* @module image-studio/limits
|
|
365
|
+
*/
|
|
366
|
+
/** 单次 edits 请求的源图上限(官方 GPT Image 限制)。 */
|
|
367
|
+
declare const MAX_SOURCE_IMAGES = 16;
|
|
368
|
+
/** 单张上传原图体积上限(50MB,对齐官方 images 端点与仓库上传约定)。 */
|
|
369
|
+
declare const UPLOAD_MAX_BYTES: number;
|
|
259
370
|
//#endregion
|
|
260
371
|
//#region src/params/catalog.d.ts
|
|
261
372
|
/** 参数值类型(校验与前端控件形态的依据)。 */
|
|
262
373
|
type ParamKind = 'string' | 'integer' | 'enum' | 'boolean';
|
|
374
|
+
/** 值域规则 id(目录声明、边界校验与前端提示共用同一实现)。 */
|
|
375
|
+
type ParamRuleId = 'image-size';
|
|
263
376
|
/** 单个参数的目录条目。 */
|
|
264
377
|
interface ParamEntry {
|
|
265
378
|
/** 请求体字段名(官方 API 参数名)。 */
|
|
@@ -272,6 +385,8 @@ interface ParamEntry {
|
|
|
272
385
|
min?: number;
|
|
273
386
|
/** integer 时的上界(含)。 */
|
|
274
387
|
max?: number;
|
|
388
|
+
/** 结构化值域规则(如尺寸的倍数/比例/像素约束);无则仅按 kind 校验。 */
|
|
389
|
+
rules?: ParamRuleId;
|
|
275
390
|
/** 适用端点(new-array 是目录实现细节,不外泄)。 */
|
|
276
391
|
applies: readonly ImageEndpoint[];
|
|
277
392
|
/** 适用模型代际:current(GPT Image)| dall-e-3 | dall-e-2 | all。 */
|
|
@@ -288,6 +403,53 @@ declare function paramEntryOf(key: string): ParamEntry | null;
|
|
|
288
403
|
/** 某端点下可用的参数键集合(含 advanced)。 */
|
|
289
404
|
declare function paramKeysFor(endpoint: ImageEndpoint): readonly string[];
|
|
290
405
|
//#endregion
|
|
406
|
+
//#region src/params/size.d.ts
|
|
407
|
+
/**
|
|
408
|
+
* 官方图像尺寸规则与预设尺寸(口径取 gpt-image 系列当前代文档):
|
|
409
|
+
* - 快捷预设:auto + 三档推荐尺寸 + 常见宽屏/竖屏/2K/4K;
|
|
410
|
+
* - 自定义尺寸:宽高均为 16 的倍数、长边 ≤3840、比例 1:3~3:1、
|
|
411
|
+
* 总像素 655,360–8,294,400;
|
|
412
|
+
* - 自由输入始终保留:预设只是快捷入口,非白名单。
|
|
413
|
+
* 同一份规则同时服务宿主边界校验(params/spec)与浏览器半即时提示(参数表单)。
|
|
414
|
+
* 纯函数零依赖,浏览器半可安全引入。
|
|
415
|
+
* @module image-studio/params/size
|
|
416
|
+
*/
|
|
417
|
+
/** 自定义尺寸约束(数值即官方文档口径)。 */
|
|
418
|
+
interface SizeRule {
|
|
419
|
+
/** 宽高须为其整数倍。 */
|
|
420
|
+
multiple: number;
|
|
421
|
+
/** 长边上限(px)。 */
|
|
422
|
+
maxEdge: number;
|
|
423
|
+
/** 总像素下限/上限。 */
|
|
424
|
+
minPixels: number;
|
|
425
|
+
maxPixels: number;
|
|
426
|
+
/** 长边与短边的比例上限(3 即 3:1)。 */
|
|
427
|
+
maxAspect: number;
|
|
428
|
+
}
|
|
429
|
+
/** GPT Image 代自定义尺寸规则。 */
|
|
430
|
+
declare const IMAGE_SIZE_RULE: SizeRule;
|
|
431
|
+
/** 预设尺寸(快捷选择项,非合法值白名单)。 */
|
|
432
|
+
interface SizePreset {
|
|
433
|
+
value: string;
|
|
434
|
+
/** 面向用户的说明(比例/用途)。 */
|
|
435
|
+
label: string;
|
|
436
|
+
}
|
|
437
|
+
/** 预设尺寸表(顺序即展示序:常用在前;全部满足 16 倍数约束)。 */
|
|
438
|
+
declare const SIZE_PRESETS: readonly SizePreset[];
|
|
439
|
+
/** 校验结论:通过或一条面向用户的原因(中文,直接展示)。 */
|
|
440
|
+
type SizeCheck = {
|
|
441
|
+
ok: true;
|
|
442
|
+
} | {
|
|
443
|
+
ok: false;
|
|
444
|
+
message: string;
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* 校验一个尺寸取值(`auto` 或「宽x高」,容忍大小写/全角乘号/空白)。
|
|
448
|
+
* @param value - 用户输入或预设值(提交/保存前校验)。
|
|
449
|
+
* @param rule - 尺寸约束(缺省 GPT Image 代规则)。
|
|
450
|
+
*/
|
|
451
|
+
declare function checkImageSize(value: string, rule?: SizeRule): SizeCheck;
|
|
452
|
+
//#endregion
|
|
291
453
|
//#region src/params/spec.d.ts
|
|
292
454
|
/** 单参数的开关 + 自定义值。 */
|
|
293
455
|
interface ParamSpec {
|
|
@@ -320,4 +482,4 @@ declare module '@deepseek-ai/cordis' {
|
|
|
320
482
|
}
|
|
321
483
|
declare function apply(ctx: Context, config: ImageStudioConfig): void;
|
|
322
484
|
//#endregion
|
|
323
|
-
export { Config, type CredentialStatusWire, type ErrorCode, type GalleryItem, type GalleryListWire, type GenerateRequest, ImageStudioError, ImageStudioService, PARAM_CATALOG, type ParamEntry, type ParamSpec, type ParamSpecMap, ParamValidationError, type PresetsWire, type ProvidersWire, type TaskWire, apply, credentialRefNameOf, inject, isValidPresetId, name, normalizeParamSpecs, paramEntryOf, paramKeysFor, validateParamSpecs };
|
|
485
|
+
export { Config, type CredentialStatusWire, type ErrorCode, type GalleryItem, type GalleryListWire, type GenerateRequest, IMAGE_SIZE_RULE, ImageStudioError, ImageStudioService, MAX_SOURCE_IMAGES, PARAM_CATALOG, type ParamEntry, type ParamSpec, type ParamSpecMap, ParamValidationError, type PresetsWire, type ProvidersWire, SIZE_PRESETS, type SourceRef, type TaskWire, UPLOAD_MAX_BYTES, type UploadEntry, apply, checkImageSize, credentialRefNameOf, detectImageMime, extOfMime, inject, isImageId, isValidPresetId, mimeOfExt, name, normalizeParamSpecs, paramEntryOf, paramKeysFor, statusOfCode, validateParamSpecs };
|