@dsh-plus/image-studio 0.1.17 → 0.1.19

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
@@ -3444,7 +3444,7 @@ ${extra}
3444
3444
  * 图像工作室前端样式:侧栏入口 + 工作台(官方 Modal 承载)+ 配置卡片附加件。
3445
3445
  * 设计令牌仅用 dsh-client-ui-theme 实测存在的 --dsw-alias-*(深浅色自适应);
3446
3446
  * 模态骨架(遮罩/Escape/portal 层叠)由官方 Modal 原语承载,本表只覆写尺寸
3447
- * 与内部布局(.ims-modal 等,模式同 web-files/web-terminal 的 wf-/wt-modal)。
3447
+ * 与内部布局(.ims-modal 等,模式同 web-files 的 wf-modal)。
3448
3448
  * 响应式断点 767px 与 @dsh-plus/ui-mobile-fit 对齐(移动端全屏、单列、44px 热区)。
3449
3449
  * @module image-studio/client/styles
3450
3450
  */
package/lib/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Service } from "@deepseek-ai/cordis";
2
2
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
3
- import { pluginDataPath, unwrapVolatile } from "@dsh-plus/shared";
3
+ import { atomicWriteFile, commitTmpFile, 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";
7
7
  import { randomUUID } from "node:crypto";
8
- import { appendFile, mkdir, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
8
+ import { appendFile, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
9
9
  import { join } from "node:path";
10
10
  import z from "@deepseek-ai/schemastery";
11
11
  //#region src/errors.ts
@@ -1068,7 +1068,7 @@ async function saveGalleryItem(input) {
1068
1068
  const target = imagePathOf(imageId, extOfMime(image.mime));
1069
1069
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
1070
1070
  await writeFile(tmp, image.data);
1071
- await rename(tmp, target);
1071
+ await commitTmpFile(tmp, target);
1072
1072
  imageIds.push(imageId);
1073
1073
  }
1074
1074
  const item = {
@@ -1091,9 +1091,7 @@ async function deleteGalleryItem(itemId) {
1091
1091
  for (const name of files) if (name.startsWith(`${imageId}.`)) await rm(join(imagesDir(), name), { force: true });
1092
1092
  }
1093
1093
  const kept = items.filter((item) => item.id !== itemId);
1094
- const tmp = `${indexFile$1()}.tmp-${process.pid}-${Date.now()}`;
1095
- await writeFile(tmp, kept.map((item) => JSON.stringify(item)).join("\n") + (kept.length > 0 ? "\n" : ""), "utf8");
1096
- await rename(tmp, indexFile$1());
1094
+ await atomicWriteFile(indexFile$1(), kept.map((item) => JSON.stringify(item)).join("\n") + (kept.length > 0 ? "\n" : ""));
1097
1095
  return true;
1098
1096
  }
1099
1097
  //#endregion
@@ -1296,7 +1294,7 @@ async function saveUpload(input) {
1296
1294
  const target = blobPathOf(id, ext);
1297
1295
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
1298
1296
  await writeFile(tmp, input.data);
1299
- await rename(tmp, target);
1297
+ await commitTmpFile(tmp, target);
1300
1298
  const entry = {
1301
1299
  id,
1302
1300
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1325,9 +1323,7 @@ async function removeUpload(entry) {
1325
1323
  }
1326
1324
  /** 索引导出为 JSONL(重写式删除的公共收尾)。 */
1327
1325
  async function rewriteIndex(kept) {
1328
- const tmp = `${indexFile()}.tmp-${process.pid}-${Date.now()}`;
1329
- await writeFile(tmp, kept.map((item) => JSON.stringify(item)).join("\n") + (kept.length > 0 ? "\n" : ""), "utf8");
1330
- await rename(tmp, indexFile());
1326
+ await atomicWriteFile(indexFile(), kept.map((item) => JSON.stringify(item)).join("\n") + (kept.length > 0 ? "\n" : ""));
1331
1327
  }
1332
1328
  /**
1333
1329
  * 回收孤儿上传:未被 keepIds 引用且创建时间早于 ttlMs 的条目删除。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/image-studio",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "dsh-plus service+ui plugin: 图像工作室——OpenAI Images 协议文生图/图生图,全参数开关化,双预设体系,并发生图任务与可二次编辑画廊",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -20,23 +20,23 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "https-proxy-agent": "^9.1.0",
23
- "@dsh-plus/shared": "0.1.24"
23
+ "@dsh-plus/shared": "0.1.27"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@deepseek-ai/cordis": "^4.0.4",
27
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.7-rc.1",
28
- "@deepseek-ai/dsh-credentials": "^0.1.7-rc.1",
29
- "@deepseek-ai/dsh-host-webserver": "^0.1.7-rc.1",
30
- "@deepseek-ai/dsh-settings": "^0.1.7-rc.1",
27
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.2.0-rc.1",
28
+ "@deepseek-ai/dsh-credentials": "^0.2.0-rc.1",
29
+ "@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.1",
30
+ "@deepseek-ai/dsh-settings": "^0.2.0-rc.1",
31
31
  "@deepseek-ai/schemastery": "^3.18.4"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@deepseek-ai/cordis": "4.0.4",
35
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.1",
36
- "@deepseek-ai/dsh-credentials": "0.1.7-rc.1",
37
- "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.1",
38
- "@deepseek-ai/dsh-session": "0.1.7-rc.1",
39
- "@deepseek-ai/dsh-settings": "0.1.7-rc.1",
35
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
36
+ "@deepseek-ai/dsh-credentials": "0.2.0-rc.1",
37
+ "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.1",
38
+ "@deepseek-ai/dsh-session": "0.2.0-rc.1",
39
+ "@deepseek-ai/dsh-settings": "0.2.0-rc.1",
40
40
  "@deepseek-ai/schemastery": "3.18.4",
41
41
  "@types/node": "26.4.0",
42
42
  "@types/react": "~18.3.31",
@@ -4,7 +4,7 @@
4
4
  * - shell.overlay:图像工作室面板(文生图/图生图/画廊 + 任务条);
5
5
  * - 配置卡片:injectPluginConfigCard 三槽位(三组预设 + 凭据 + 高级项;
6
6
  * legacy settings.plugin.item 与 0.1.6-alpha.2 插件页 row/bundle config)。
7
- * 模式与 web-files/web-terminal 一致:CJS factory 产物、data-plugin-css 样式
7
+ * 模式与 web-files 一致:CJS factory 产物、data-plugin-css 样式
8
8
  * 约定、slot 失配静默降级;配置读写经 ctx.remote.settings 直连(远程域名可用)。
9
9
  * @module @dsh-plus/image-studio/client
10
10
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 面板开合与跨标签联动控制器:footer 入口 ↔ overlay 面板共享开合态;
3
3
  * 画廊「二次编辑」经 editSeed 单向投递给图生图表单(nonce 保证同参可重复触发)。
4
- * 模式照抄 web-files/web-terminal 的 PanelController。
4
+ * 模式照抄 web-files 的 PanelController。
5
5
  * @module image-studio/client/panel/controller
6
6
  */
7
7
 
@@ -2,7 +2,7 @@
2
2
  * 图像工作室前端样式:侧栏入口 + 工作台(官方 Modal 承载)+ 配置卡片附加件。
3
3
  * 设计令牌仅用 dsh-client-ui-theme 实测存在的 --dsw-alias-*(深浅色自适应);
4
4
  * 模态骨架(遮罩/Escape/portal 层叠)由官方 Modal 原语承载,本表只覆写尺寸
5
- * 与内部布局(.ims-modal 等,模式同 web-files/web-terminal 的 wf-/wt-modal)。
5
+ * 与内部布局(.ims-modal 等,模式同 web-files 的 wf-modal)。
6
6
  * 响应式断点 767px 与 @dsh-plus/ui-mobile-fit 对齐(移动端全屏、单列、44px 热区)。
7
7
  * @module image-studio/client/styles
8
8
  */
@@ -7,10 +7,10 @@
7
7
  */
8
8
 
9
9
  import { randomUUID } from 'node:crypto'
10
- import { appendFile, mkdir, readdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
10
+ import { appendFile, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'
11
11
  import { join } from 'node:path'
12
12
 
13
- import { pluginDataPath } from '@dsh-plus/shared'
13
+ import { atomicWriteFile, commitTmpFile, pluginDataPath } from '@dsh-plus/shared'
14
14
  import { isImageId } from '../images/id.ts'
15
15
  import { extOfMime } from '../images/mime.ts'
16
16
  import type { ImageEndpoint } from '../provider/types.ts'
@@ -121,11 +121,12 @@ export async function saveGalleryItem(input: {
121
121
  for (const image of input.images) {
122
122
  const imageId = randomUUID()
123
123
  const ext = extOfMime(image.mime)
124
- // 原子写:临时文件 + rename,中断不留半截图片。
124
+ // 图片是字节(官方 writeFileAtomic 仅收字符串):tmp 落盘 + commitTmpFile
125
+ // rename 提交,rename 被占用时回退复制,中断不留半截图片。
125
126
  const target = imagePathOf(imageId, ext)
126
127
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`
127
128
  await writeFile(tmp, image.data)
128
- await rename(tmp, target)
129
+ await commitTmpFile(tmp, target)
129
130
  imageIds.push(imageId)
130
131
  }
131
132
  const item: GalleryItem = {
@@ -153,13 +154,10 @@ export async function deleteGalleryItem(itemId: string): Promise<boolean> {
153
154
  }
154
155
  }
155
156
  const kept = items.filter((item) => item.id !== itemId)
156
- const tmp = `${indexFile()}.tmp-${process.pid}-${Date.now()}`
157
- await writeFile(
158
- tmp,
157
+ await atomicWriteFile(
158
+ indexFile(),
159
159
  kept.map((item) => JSON.stringify(item)).join('\n') + (kept.length > 0 ? '\n' : ''),
160
- 'utf8',
161
160
  )
162
- await rename(tmp, indexFile())
163
161
  return true
164
162
  }
165
163
 
@@ -8,10 +8,10 @@
8
8
  */
9
9
 
10
10
  import { randomUUID } from 'node:crypto'
11
- import { appendFile, mkdir, readdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
11
+ import { appendFile, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'
12
12
  import { join } from 'node:path'
13
13
 
14
- import { pluginDataPath } from '@dsh-plus/shared'
14
+ import { atomicWriteFile, commitTmpFile, pluginDataPath } from '@dsh-plus/shared'
15
15
  import { isImageId } from '../images/id.ts'
16
16
  import { extOfMime } from '../images/mime.ts'
17
17
 
@@ -96,9 +96,10 @@ export async function saveUpload(input: {
96
96
  const id = randomUUID()
97
97
  const ext = extOfMime(input.mime)
98
98
  const target = blobPathOf(id, ext)
99
+ // 字节走 tmp + commitTmpFile(官方 writeFileAtomic 仅收字符串)。
99
100
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`
100
101
  await writeFile(tmp, input.data)
101
- await rename(tmp, target)
102
+ await commitTmpFile(tmp, target)
102
103
  const entry: UploadEntry = {
103
104
  id,
104
105
  createdAt: new Date().toISOString(),
@@ -128,13 +129,10 @@ async function removeUpload(entry: UploadEntry): Promise<void> {
128
129
 
129
130
  /** 索引导出为 JSONL(重写式删除的公共收尾)。 */
130
131
  async function rewriteIndex(kept: UploadEntry[]): Promise<void> {
131
- const tmp = `${indexFile()}.tmp-${process.pid}-${Date.now()}`
132
- await writeFile(
133
- tmp,
132
+ await atomicWriteFile(
133
+ indexFile(),
134
134
  kept.map((item) => JSON.stringify(item)).join('\n') + (kept.length > 0 ? '\n' : ''),
135
- 'utf8',
136
135
  )
137
- await rename(tmp, indexFile())
138
136
  }
139
137
 
140
138
  /**