@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/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
- /** 图生图源图(本画廊内的 imageId);文生图为空。 */
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
- /** 图生图源图(本画廊 imageId;edit 必填 ≥1)。 */
140
+ /** 图生图源图(edit 必填 ≥1,≤16;画廊图片与本地文件上传混用)。 */
141
+ sources?: SourceRef[];
142
+ /** 可选遮罩(官方要求 PNG;与源图同一引用形态)。 */
143
+ mask?: SourceRef;
144
+ /** @deprecated 旧客户端兼容:等价于 kind='gallery' 的 sources。 */
108
145
  sourceIds?: string[];
109
- /** 可选 PNG mask(本画廊 imageId)。 */
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
- * 参数预设 + 覆盖 → 归一化参数表;sourceIds → 输入图字节。
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
- /** 源图字节加载(edit ≥1 张;单图上限 50MB 对齐官方)。 */
260
+ /**
261
+ * 源图字节加载(edit ≥1 张;单图上限 50MB 对齐官方)。
262
+ * 按引用来源分流读取,并把两类 id 分开回传(画廊衍生链 / 上传暂存区)。
263
+ */
216
264
  private loadSourceImages;
217
- private loadMask;
218
- private loadOneImage;
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 };