@dsh-plus/image-studio 0.1.8 → 0.1.9

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 CHANGED
@@ -338,28 +338,24 @@ window.__ModuleLoader__.load({
338
338
  }
339
339
  //#endregion
340
340
  //#region ../shared/src/client/fetch.ts
341
- /**
342
- * 同源自定义端点的最小 fetch 封装(各插件 client/api.ts 的公共收编版)。
343
- * 仅同源(credentials: same-origin),错误统一抛 Error(body.error)。
344
- * @module @dsh-plus/shared/client/fetch
345
- */
346
- async function parse(res) {
341
+ async function parse(res, guard) {
347
342
  const body = await res.json();
348
343
  if (!res.ok) throw new Error(body.error ?? `HTTP ${res.status}`);
344
+ if (guard !== void 0 && !guard(body)) throw new Error(`响应结构不符合预期(${res.url})`);
349
345
  return body;
350
346
  }
351
347
  /** GET 同源 JSON 端点。 */
352
- async function getJson(route) {
353
- return parse(await fetch(route, { credentials: "same-origin" }));
348
+ async function getJson(route, guard) {
349
+ return parse(await fetch(route, { credentials: "same-origin" }), guard);
354
350
  }
355
351
  /** POST 同源 JSON 端点(body 可省略)。 */
356
- async function postJson(route, body) {
352
+ async function postJson(route, body, guard) {
357
353
  return parse(await fetch(route, {
358
354
  method: "POST",
359
355
  credentials: "same-origin",
360
356
  headers: { "content-type": "application/json" },
361
- body: body === void 0 ? void 0 : JSON.stringify(body)
362
- }));
357
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
358
+ }), guard);
363
359
  }
364
360
  //#endregion
365
361
  //#region ../shared/src/client/fields.tsx
@@ -929,9 +925,14 @@ ${extra}
929
925
  function cancelTask(taskId) {
930
926
  return postJson(`${BASE}/tasks/${taskId}/cancel`);
931
927
  }
928
+ /** 画廊列表应答形状守卫:items 需为数组(渲染期直接 map)。 */
929
+ function isGalleryList(value) {
930
+ if (typeof value !== "object" || value === null) return false;
931
+ return Array.isArray(value.items);
932
+ }
932
933
  /** 画廊列表。 */
933
934
  function fetchGallery() {
934
- return getJson(`${BASE}/gallery`);
935
+ return getJson(`${BASE}/gallery`, isGalleryList);
935
936
  }
936
937
  /** 删除画廊条目。 */
937
938
  function deleteGalleryItem(itemId) {
package/lib/index.d.ts CHANGED
@@ -1,26 +1,6 @@
1
1
  import z from "@deepseek-ai/schemastery";
2
2
  import { Context, Service } from "@deepseek-ai/cordis";
3
3
  //#region src/config.d.ts
4
- declare const Config: z<Schemastery.ObjectS<{
5
- promptPresets: z<unknown[], any[]>;
6
- paramPresets: z<unknown[], any[]>;
7
- providerPresets: z<unknown[], any[]>;
8
- maxConcurrent: z<number, number>;
9
- requestTimeoutMs: z<number, number>;
10
- proxy: z<string, string>;
11
- galleryMaxItems: z<number, number>;
12
- uploadTtlHours: z<number, number>;
13
- }>, Schemastery.ObjectT<{
14
- promptPresets: z<unknown[], any[]>;
15
- paramPresets: z<unknown[], any[]>;
16
- providerPresets: z<unknown[], any[]>;
17
- maxConcurrent: z<number, number>;
18
- requestTimeoutMs: z<number, number>;
19
- proxy: z<string, string>;
20
- galleryMaxItems: z<number, number>;
21
- uploadTtlHours: z<number, number>;
22
- }>>;
23
- type ImageStudioConfig = Schemastery.TypeT<typeof Config>;
24
4
  /** 提示词预设(解析后视图)。 */
25
5
  interface PromptPresetEntry {
26
6
  id: string;
@@ -44,6 +24,26 @@ interface ProviderPresetEntry {
44
24
  credentialRef: string;
45
25
  extraHeaders: Record<string, string>;
46
26
  }
27
+ declare const Config: z<Schemastery.ObjectS<{
28
+ promptPresets: z<PromptPresetEntry[], PromptPresetEntry[]>;
29
+ paramPresets: z<ParamPresetEntry[], ParamPresetEntry[]>;
30
+ providerPresets: z<ProviderPresetEntry[], ProviderPresetEntry[]>;
31
+ maxConcurrent: z<number, number>;
32
+ requestTimeoutMs: z<number, number>;
33
+ proxy: z<string, string>;
34
+ galleryMaxItems: z<number, number>;
35
+ uploadTtlHours: z<number, number>;
36
+ }>, Schemastery.ObjectT<{
37
+ promptPresets: z<PromptPresetEntry[], PromptPresetEntry[]>;
38
+ paramPresets: z<ParamPresetEntry[], ParamPresetEntry[]>;
39
+ providerPresets: z<ProviderPresetEntry[], ProviderPresetEntry[]>;
40
+ maxConcurrent: z<number, number>;
41
+ requestTimeoutMs: z<number, number>;
42
+ proxy: z<string, string>;
43
+ galleryMaxItems: z<number, number>;
44
+ uploadTtlHours: z<number, number>;
45
+ }>>;
46
+ type ImageStudioConfig = Schemastery.TypeT<typeof Config>;
47
47
  //#endregion
48
48
  //#region src/provider/types.d.ts
49
49
  /**
@@ -320,7 +320,7 @@ declare function credentialRefNameOf(presetId: string): string;
320
320
  * @module image-studio/errors
321
321
  */
322
322
  /** 全部错误码(封闭集合,新增协议/端点行为时按需扩充)。 */
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"];
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'];
324
324
  type ErrorCode = (typeof ERROR_CODES)[number];
325
325
  declare class ImageStudioError extends Error {
326
326
  readonly code: ErrorCode;
@@ -474,7 +474,7 @@ declare function validateParamSpecs(specs: unknown): ParamSpecMap;
474
474
  //#endregion
475
475
  //#region src/index.d.ts
476
476
  declare const name = "dsh-plus-image-studio";
477
- declare const inject: readonly ["credentials"];
477
+ declare const inject: readonly ['credentials'];
478
478
  declare module '@deepseek-ai/cordis' {
479
479
  interface Context {
480
480
  imageStudio: ImageStudioService;
package/lib/index.js CHANGED
@@ -27,7 +27,7 @@ const PromptPreset = z.object({
27
27
  const ParamPreset = z.object({
28
28
  id: z.string().required().description("预设 id"),
29
29
  name: z.string().required().description("预设名称"),
30
- endpoint: z.string().required().description("适用端点:generation | edit"),
30
+ endpoint: z.union([z.const("generation"), z.const("edit")]).required().description("适用端点:generation | edit"),
31
31
  /** 参数表结构由 params/spec 校验,settings 层存原始 JSON。 */
32
32
  paramSpecs: z.any().required().description("参数开关表(ParamSpecMap JSON)")
33
33
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/image-studio",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "dsh-plus service+ui plugin: 图像工作室——OpenAI Images 协议文生图/图生图,全参数开关化,双预设体系,并发生图任务与可二次编辑画廊",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "https-proxy-agent": "^9.1.0",
23
- "@dsh-plus/shared": "0.1.15"
23
+ "@dsh-plus/shared": "0.1.16"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@deepseek-ai/cordis": "^4.0.2",
package/src/client/api.ts CHANGED
@@ -38,9 +38,15 @@ export function cancelTask(taskId: string): Promise<{ ok: boolean }> {
38
38
  return postJson(`${BASE}/tasks/${taskId}/cancel`)
39
39
  }
40
40
 
41
+ /** 画廊列表应答形状守卫:items 需为数组(渲染期直接 map)。 */
42
+ function isGalleryList(value: unknown): value is GalleryListWire {
43
+ if (typeof value !== 'object' || value === null) return false
44
+ return Array.isArray((value as { items?: unknown }).items)
45
+ }
46
+
41
47
  /** 画廊列表。 */
42
48
  export function fetchGallery(): Promise<GalleryListWire> {
43
- return getJson(`${BASE}/gallery`)
49
+ return getJson(`${BASE}/gallery`, isGalleryList)
44
50
  }
45
51
 
46
52
  /** 画廊条目详情(含参数回放)。 */
@@ -77,10 +77,13 @@ interface UploadButtonProps {
77
77
  onUploaded(entries: UploadEntry[]): void
78
78
  /** 允许多选(源图)或单选(遮罩)。 */
79
79
  multiple: boolean
80
- /** 允许的文件类型(缺省四类位图;遮罩场景传 image/png)。 */
81
- accept?: string
82
- disabled?: boolean
83
- className?: string
80
+ /**
81
+ * 允许的文件类型(缺省四类位图;遮罩场景传 image/png)。
82
+ * 并上 undefined:调用方按 `multiple ? undefined : 'image/png'` 直接透传。
83
+ */
84
+ accept?: string | undefined
85
+ disabled?: boolean | undefined
86
+ className?: string | undefined
84
87
  children: ReactNode
85
88
  }
86
89
 
package/src/config.ts CHANGED
@@ -12,26 +12,56 @@ import { SETTINGS_NS as NS_LITERAL } from './ns.ts'
12
12
  /** settings 命名空间(字面量即合法命名空间,编译期校验)。 */
13
13
  export const SETTINGS_NS = NS_LITERAL
14
14
 
15
- // dts 可移植性:嵌套 schema 精确类型经 TypeT 消费,显式断掉推断链
16
- // (同 usage-panel/config 的既有约定)。
17
- /* biome-ignore lint/suspicious/noExplicitAny: 嵌套 schema 的 dts 可移植性 */
18
- const PromptPreset: any = z.object({
15
+ /** 提示词预设(解析后视图)。 */
16
+ export interface PromptPresetEntry {
17
+ id: string
18
+ name: string
19
+ text: string
20
+ }
21
+
22
+ /** 参数预设(解析后视图)。 */
23
+ export interface ParamPresetEntry {
24
+ id: string
25
+ name: string
26
+ endpoint: 'generation' | 'edit'
27
+ paramSpecs: unknown
28
+ }
29
+
30
+ /** 提供商预设(解析后视图)。 */
31
+ export interface ProviderPresetEntry {
32
+ id: string
33
+ name: string
34
+ protocol: string
35
+ baseUrl: string
36
+ model: string
37
+ credentialRef: string
38
+ extraHeaders: Record<string, string>
39
+ }
40
+
41
+ // 显式标注而非 `any`:z.object() 推断类型含 cosmokit 的 `& Dict` 索引签名,
42
+ // 直接导出会触发 TS2883(inferred type cannot be named / not portable)并使
43
+ // tsdown 的 dts 生成失败。标注成具名契约后既保住类型、又让产物可移植——
44
+ // 退回 `any` 会让三个预设数组元素全部退化为 any。
45
+ const PromptPreset: z<PromptPresetEntry, PromptPresetEntry> = z.object({
19
46
  id: z.string().required().description('预设 id(稳定标识,删除级联引用)'),
20
47
  name: z.string().required().description('预设名称'),
21
48
  text: z.string().required().description('提示词模板'),
22
49
  })
23
50
 
24
- /* biome-ignore lint/suspicious/noExplicitAny: 嵌套 schema 的 dts 可移植性 */
25
- const ParamPreset: any = z.object({
51
+ const ParamPreset: z<ParamPresetEntry, ParamPresetEntry> = z.object({
26
52
  id: z.string().required().description('预设 id'),
27
53
  name: z.string().required().description('预设名称'),
28
- endpoint: z.string().required().description('适用端点:generation | edit'),
54
+ // 用字面量联合而非 z.string():endpoint 只有两个合法取值,收窄后与
55
+ // ParamPresetEntry['endpoint'] 对齐,拼错端点会在编译期暴露。
56
+ endpoint: z
57
+ .union([z.const('generation'), z.const('edit')])
58
+ .required()
59
+ .description('适用端点:generation | edit'),
29
60
  /** 参数表结构由 params/spec 校验,settings 层存原始 JSON。 */
30
61
  paramSpecs: z.any().required().description('参数开关表(ParamSpecMap JSON)'),
31
62
  })
32
63
 
33
- /* biome-ignore lint/suspicious/noExplicitAny: 嵌套 schema 的 dts 可移植性 */
34
- const ProviderPreset: any = z.object({
64
+ const ProviderPreset: z<ProviderPresetEntry, ProviderPresetEntry> = z.object({
35
65
  id: z.string().required().description('预设 id'),
36
66
  name: z.string().required().description('预设名称'),
37
67
  protocol: z.string().required().description('协议 id(如 openai-images)'),
@@ -68,29 +98,3 @@ export const Config = z.object({
68
98
  })
69
99
 
70
100
  export type ImageStudioConfig = Schemastery.TypeT<typeof Config>
71
-
72
- /** 提示词预设(解析后视图)。 */
73
- export interface PromptPresetEntry {
74
- id: string
75
- name: string
76
- text: string
77
- }
78
-
79
- /** 参数预设(解析后视图)。 */
80
- export interface ParamPresetEntry {
81
- id: string
82
- name: string
83
- endpoint: 'generation' | 'edit'
84
- paramSpecs: unknown
85
- }
86
-
87
- /** 提供商预设(解析后视图)。 */
88
- export interface ProviderPresetEntry {
89
- id: string
90
- name: string
91
- protocol: string
92
- baseUrl: string
93
- model: string
94
- credentialRef: string
95
- extraHeaders: Record<string, string>
96
- }
package/src/service.ts CHANGED
@@ -126,11 +126,11 @@ export class ImageStudioService extends Service {
126
126
  }
127
127
 
128
128
  private paramPresets(): ParamPresetEntry[] {
129
- return this.current().paramPresets as ParamPresetEntry[]
129
+ return this.current().paramPresets
130
130
  }
131
131
 
132
132
  private providerPresets(): ProviderPresetEntry[] {
133
- return this.current().providerPresets as ProviderPresetEntry[]
133
+ return this.current().providerPresets
134
134
  }
135
135
 
136
136
  /** 预设快照(端点投影)。 */