@dsh-plus/image-studio 0.1.34 → 0.1.36

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
@@ -306,8 +306,8 @@ declare class ImageStudioService extends Service {
306
306
  //#region src/credentials.d.ts
307
307
  /**
308
308
  * 凭据引用名派生与校验:提供商预设 id → IMAGE_STUDIO_PRESET_<ID>。
309
- * 规则对齐《插件存储规范》:大写下划线、全大写、前缀属主。
310
- * 纯函数,零依赖。
309
+ * 命名与归一走 `@dsh-plus/shared` 的公共助手,本模块只补预设 id 的形态校验。
310
+ * 纯函数,零依赖(浏览器半亦可安全 import)。
311
311
  * @module image-studio/credentials
312
312
  */
313
313
  /** 预设 id 是否合法(kebab-case,用于引用名派生)。 */
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Service } from "@deepseek-ai/cordis";
2
2
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
3
- import { atomicWriteFile, commitTmpFile, pluginDataPath, unwrapVolatile } from "@dsh-plus/shared";
3
+ import { atomicWriteFile, commitTmpFile, credentialRefName, pluginCachePath, pluginDataPath, unwrapVolatile } from "@dsh-plus/shared";
4
4
  import { request } from "node:http";
5
5
  import { request as request$1 } from "node:https";
6
6
  import { HttpsProxyAgent } from "https-proxy-agent";
@@ -959,12 +959,14 @@ function registerImageStudioApi(ctx, service) {
959
959
  //#region src/credentials.ts
960
960
  /**
961
961
  * 凭据引用名派生与校验:提供商预设 id → IMAGE_STUDIO_PRESET_<ID>。
962
- * 规则对齐《插件存储规范》:大写下划线、全大写、前缀属主。
963
- * 纯函数,零依赖。
962
+ * 命名与归一走 `@dsh-plus/shared` 的公共助手,本模块只补预设 id 的形态校验。
963
+ * 纯函数,零依赖(浏览器半亦可安全 import)。
964
964
  * @module image-studio/credentials
965
965
  */
966
- /** 引用名前缀(属主段)。 */
967
- const REF_PREFIX = "IMAGE_STUDIO_PRESET_";
966
+ /** 属主段(插件 id)。 */
967
+ const REF_OWNER = "image-studio";
968
+ /** 业务段前缀(与属主一起构成 IMAGE_STUDIO_PRESET_<ID>)。 */
969
+ const REF_KIND = "preset";
968
970
  /** 预设 id 是否合法(kebab-case,用于引用名派生)。 */
969
971
  function isValidPresetId(id) {
970
972
  return /^[a-z][a-z0-9-]*$/.test(id) && id.length <= 64;
@@ -972,7 +974,7 @@ function isValidPresetId(id) {
972
974
  /** 预设 id → 凭据引用名(kebab → SNAKE 大写)。 */
973
975
  function credentialRefNameOf(presetId) {
974
976
  if (!isValidPresetId(presetId)) throw new Error(`非法提供商预设 id:${JSON.stringify(presetId)}`);
975
- return `${REF_PREFIX}${presetId.replaceAll("-", "_").toUpperCase()}`;
977
+ return credentialRefName(REF_OWNER, REF_KIND, presetId);
976
978
  }
977
979
  //#endregion
978
980
  //#region src/images/id.ts
@@ -1243,9 +1245,12 @@ function defaultIdCounter() {
1243
1245
  * 落点 $DSH_HOME/dsh-plus/image-studio/uploads/{index.jsonl, blobs/}
1244
1246
  * @module image-studio/uploads/store
1245
1247
  */
1246
- /** 存储层根路径(惰性解析:DSH_HOME 可能在模块加载后才被测试环境设置)。 */
1248
+ /**
1249
+ * 存储层根路径(惰性解析:DSH_HOME 可能在模块加载后才被测试环境设置)。
1250
+ * 上传是带 TTL 的暂存派生物(`uploadTtlHours` 回收),故落缓存目录。
1251
+ */
1247
1252
  function uploadsRoot() {
1248
- return pluginDataPath("image-studio", "uploads");
1253
+ return pluginCachePath("image-studio", "uploads");
1249
1254
  }
1250
1255
  function indexFile() {
1251
1256
  return join(uploadsRoot(), "index.jsonl");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/image-studio",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "dsh-plus service+ui plugin: 图像工作室——OpenAI Images 协议文生图/图生图,全参数开关化,双预设体系,并发生图任务与可二次编辑画廊",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -20,24 +20,24 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "https-proxy-agent": "^9.1.0",
23
- "@dsh-plus/shared": "0.1.42"
23
+ "@dsh-plus/shared": "0.1.44"
24
24
  },
25
25
  "peerDependencies": {
26
- "@deepseek-ai/cordis": "^4.0.5-alpha.2",
27
- "@deepseek-ai/dsh-client-ui-primitives": "^0.2.1-alpha.4",
28
- "@deepseek-ai/dsh-credentials": "^0.2.1-alpha.4",
29
- "@deepseek-ai/dsh-host-webserver": "^0.2.1-alpha.4",
30
- "@deepseek-ai/dsh-settings": "^0.2.1-alpha.4",
31
- "@deepseek-ai/schemastery": "^3.18.5-alpha.2"
26
+ "@deepseek-ai/cordis": "^4.0.5",
27
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.2.1-rc.1",
28
+ "@deepseek-ai/dsh-credentials": "^0.2.1-rc.2",
29
+ "@deepseek-ai/dsh-host-webserver": "^0.2.1-rc.2",
30
+ "@deepseek-ai/dsh-settings": "^0.2.1-rc.2",
31
+ "@deepseek-ai/schemastery": "^3.18.5"
32
32
  },
33
33
  "devDependencies": {
34
- "@deepseek-ai/cordis": "4.0.5-alpha.2",
35
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.4",
36
- "@deepseek-ai/dsh-credentials": "0.2.1-alpha.4",
37
- "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.4",
38
- "@deepseek-ai/dsh-session": "0.2.1-alpha.4",
39
- "@deepseek-ai/dsh-settings": "0.2.1-alpha.4",
40
- "@deepseek-ai/schemastery": "3.18.5-alpha.2",
34
+ "@deepseek-ai/cordis": "4.0.5",
35
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.1",
36
+ "@deepseek-ai/dsh-credentials": "0.2.1-rc.2",
37
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-rc.2",
38
+ "@deepseek-ai/dsh-session": "0.2.1-rc.2",
39
+ "@deepseek-ai/dsh-settings": "0.2.1-rc.2",
40
+ "@deepseek-ai/schemastery": "3.18.5",
41
41
  "@types/node": "26.4.0",
42
42
  "@types/react": "~18.3.31",
43
43
  "react": "^18.2.0"
@@ -10,13 +10,16 @@
10
10
  */
11
11
  import {
12
12
  type CardAction,
13
- CardChrome,
14
13
  CardLoading,
15
14
  type CardStatusState,
15
+ ConfigShell,
16
+ FieldGrid,
16
17
  IDLE_STATUS,
17
18
  type NamespaceSettingsApi,
19
+ NumberField,
18
20
  type PluginConfigViewProps,
19
21
  type Scope,
22
+ Section,
20
23
  TextField,
21
24
  } from '@dsh-plus/shared/client'
22
25
  import { type ReactElement, useEffect, useMemo, useState, useSyncExternalStore } from 'react'
@@ -91,29 +94,24 @@ function AdvancedFields(props: {
91
94
  }): ReactElement {
92
95
  const { t, draft, disabled, onPatch } = props
93
96
  return (
94
- <>
95
- <h4 className="imsc-groupTitle">{t('card.advanced')}</h4>
96
- <div className="imsc-grid2">
97
- <TextField
97
+ <Section prefix="imsc" title={t('card.advanced')} description={t('card.advancedHint')}>
98
+ <FieldGrid prefix="imsc" columns={2}>
99
+ <NumberField
98
100
  prefix="imsc"
99
101
  id="imsc-conc"
100
102
  label={t('card.maxConcurrent')}
101
- numeric
102
103
  value={draft.maxConcurrent}
103
104
  disabled={disabled}
104
105
  onEdit={(v) => onPatch({ maxConcurrent: v })}
105
106
  />
106
- <TextField
107
+ <NumberField
107
108
  prefix="imsc"
108
109
  id="imsc-timeout"
109
110
  label={t('card.requestTimeoutMs')}
110
- numeric
111
111
  value={draft.requestTimeoutMs}
112
112
  disabled={disabled}
113
113
  onEdit={(v) => onPatch({ requestTimeoutMs: v })}
114
114
  />
115
- </div>
116
- <div className="imsc-grid2">
117
115
  <TextField
118
116
  prefix="imsc"
119
117
  id="imsc-proxy"
@@ -122,26 +120,24 @@ function AdvancedFields(props: {
122
120
  disabled={disabled}
123
121
  onEdit={(v) => onPatch({ proxy: v })}
124
122
  />
125
- <TextField
123
+ <NumberField
126
124
  prefix="imsc"
127
125
  id="imsc-gmax"
128
126
  label={t('card.galleryMaxItems')}
129
- numeric
130
127
  value={draft.galleryMaxItems}
131
128
  disabled={disabled}
132
129
  onEdit={(v) => onPatch({ galleryMaxItems: v })}
133
130
  />
134
- </div>
135
- <TextField
136
- prefix="imsc"
137
- id="imsc-upload-ttl"
138
- label={t('card.uploadTtlHours')}
139
- numeric
140
- value={draft.uploadTtlHours}
141
- disabled={disabled}
142
- onEdit={(v) => onPatch({ uploadTtlHours: v })}
143
- />
144
- </>
131
+ <NumberField
132
+ prefix="imsc"
133
+ id="imsc-upload-ttl"
134
+ label={t('card.uploadTtlHours')}
135
+ value={draft.uploadTtlHours}
136
+ disabled={disabled}
137
+ onEdit={(v) => onPatch({ uploadTtlHours: v })}
138
+ />
139
+ </FieldGrid>
140
+ </Section>
145
141
  )
146
142
  }
147
143
 
@@ -226,7 +222,7 @@ export function StudioConfigCard(props: CardProps): ReactElement | string | null
226
222
  }
227
223
 
228
224
  return (
229
- <CardChrome
225
+ <ConfigShell
230
226
  prefix="imsc"
231
227
  title={t('card.title')}
232
228
  description={t('card.description')}
@@ -259,6 +255,6 @@ export function StudioConfigCard(props: CardProps): ReactElement | string | null
259
255
  <PromptPresetSection {...sectionProps} />
260
256
  <ParamPresetSection {...sectionProps} />
261
257
  <AdvancedFields t={t} draft={draft} disabled={disabled} onPatch={patch} />
262
- </CardChrome>
258
+ </ConfigShell>
263
259
  )
264
260
  }
@@ -1,13 +1,17 @@
1
1
  /**
2
2
  * i18n 字典(zh 为键域事实源,en 全量对译);NS 与 settings 命名空间分离,
3
3
  * 仅承载前端文案 key。面板 / 入口 / 配置卡片共用同一命名空间。
4
+ *
5
+ * 公共键(卡片套件的 save/unsaved/code* 等)来自 shared 的 common 字典并在此合并,
6
+ * 本文件只维护业务键。
4
7
  * @module image-studio/client/i18n
5
8
  */
9
+ import { commonEn, commonZh, mergeDict } from '@dsh-plus/shared/client'
6
10
 
7
11
  /** locale 命名空间。 */
8
12
  export const NS = 'dsh-plus-image-studio'
9
13
 
10
- export const zh = {
14
+ const ownZh = {
11
15
  // 入口与面板骨架
12
16
  'entry.label': '图像',
13
17
  'panel.title': '图像工作室',
@@ -98,9 +102,16 @@ export const zh = {
98
102
  'card.description': '文生图/图生图:提供商与 API Key、参数/提示词预设',
99
103
  'card.summary': '文生图/图生图:提供商与 API Key、参数/提示词预设。',
100
104
  'card.providers': '提供商预设',
105
+ 'card.providersHint':
106
+ '按序尝试的提供商预设:条目内 API Key 走官方 credentials(引用名由预设 ID 派生),保存后不回显。',
101
107
  'card.prompts': '提示词预设',
108
+ 'card.promptsHint': '提示词模板列表:生成/编辑面板按名称选用,{prompt} 等占位符由面板注入。',
102
109
  'card.params': '参数预设',
110
+ 'card.paramsHint':
111
+ '参数预设列表:适用端点决定出现在「文生图」还是「图生图」,参数表为 JSON(如 {"size": {"enabled": true, "value": "1024x1024"}})。',
103
112
  'card.advanced': '高级设置',
113
+ 'card.advancedHint':
114
+ '并发、超时、代理与本地画廊保留策略;留空/0 表示沿用内置默认(并发 2、超时 60000ms、画廊 200 张、上传保留 168 小时)。',
104
115
  'card.add': '添加',
105
116
  'card.field.id': 'ID',
106
117
  'card.field.name': '名称',
@@ -134,12 +145,10 @@ export const zh = {
134
145
  'card.badgeOff': '未配置',
135
146
  }
136
147
 
137
- export type DictKey = keyof typeof zh
138
-
139
148
  /** 面板/卡片共用的翻译函数类型(slot 注入的 bind 结果按此消费)。 */
140
149
  export type Translate = (key: DictKey) => string
141
150
 
142
- export const en: Record<DictKey, string> = {
151
+ const ownEn: Record<keyof typeof ownZh, string> = {
143
152
  'entry.label': 'Image',
144
153
  'panel.title': 'Image Studio',
145
154
  'tab.generation': 'Text to Image',
@@ -222,9 +231,17 @@ export const en: Record<DictKey, string> = {
222
231
  'card.description': 'Text/Image-to-image: providers & API keys, param/prompt presets',
223
232
  'card.summary': 'Text/Image-to-image: providers & API keys, param/prompt presets.',
224
233
  'card.providers': 'Provider presets',
234
+ 'card.providersHint':
235
+ 'Providers tried in order; each entry keeps its API key in official credentials (reference derived from the preset id) and never echoes it back.',
225
236
  'card.prompts': 'Prompt presets',
237
+ 'card.promptsHint':
238
+ 'Prompt templates; the generation/edit panels pick them by name and fill placeholders such as {prompt}.',
226
239
  'card.params': 'Parameter presets',
240
+ 'card.paramsHint':
241
+ 'Parameter presets; the endpoint decides whether it shows up in Text to Image or Image to Image, and the spec is JSON such as {"size": {"enabled": true, "value": "1024x1024"}}.',
227
242
  'card.advanced': 'Advanced',
243
+ 'card.advancedHint':
244
+ 'Concurrency, timeout, proxy and local gallery retention; empty/0 keeps the built-in defaults (concurrency 2, timeout 60000ms, gallery 200, uploads 168h).',
228
245
  'card.add': 'Add',
229
246
  'card.field.id': 'ID',
230
247
  'card.field.name': 'Name',
@@ -258,3 +275,9 @@ export const en: Record<DictKey, string> = {
258
275
  'card.badgeOn': '{n} providers',
259
276
  'card.badgeOff': 'Not configured',
260
277
  }
278
+
279
+ /** 卡片公共文案 + 本插件文案(own 覆盖同键):配置卡片经共享套件渲染,公共键只维护一份。 */
280
+ export const zh = mergeDict(commonZh, ownZh)
281
+ export const en: Record<keyof typeof zh, string> = mergeDict(commonEn, ownEn)
282
+
283
+ export type DictKey = keyof typeof zh