koishi-plugin-media-luna 0.0.1

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.
Files changed (437) hide show
  1. package/client/README.md +558 -0
  2. package/client/api.ts +256 -0
  3. package/client/components/ChannelConfigDialog.vue +1113 -0
  4. package/client/components/ChannelsView.vue +698 -0
  5. package/client/components/ConfigRenderer.vue +164 -0
  6. package/client/components/EmptyState.vue +87 -0
  7. package/client/components/GenerateView.vue +778 -0
  8. package/client/components/HistoryGallery.vue +590 -0
  9. package/client/components/ImageLightbox.vue +510 -0
  10. package/client/components/ImageUpload.vue +298 -0
  11. package/client/components/JsonEditor.vue +68 -0
  12. package/client/components/LoadingState.vue +73 -0
  13. package/client/components/PresetsView.vue +800 -0
  14. package/client/components/ScrollContainer.vue +45 -0
  15. package/client/components/SettingsView.vue +231 -0
  16. package/client/components/StatusBadge.vue +55 -0
  17. package/client/components/TagFilter.vue +139 -0
  18. package/client/components/TagInput.vue +63 -0
  19. package/client/components/TasksView.vue +1074 -0
  20. package/client/components/ViewModeSwitch.vue +78 -0
  21. package/client/components/settings/CachePanel.vue +142 -0
  22. package/client/components/settings/MiddlewaresPanel.vue +480 -0
  23. package/client/components/settings/PluginsPanel.vue +493 -0
  24. package/client/index.ts +13 -0
  25. package/client/pages/index.vue +177 -0
  26. package/client/styles/shared.css +258 -0
  27. package/client/types.ts +158 -0
  28. package/client/utils/format.ts +72 -0
  29. package/dist/index.js +1 -0
  30. package/dist/style.css +1 -0
  31. package/lib/api/README.md +643 -0
  32. package/lib/api/cache-api.d.ts +6 -0
  33. package/lib/api/cache-api.d.ts.map +1 -0
  34. package/lib/api/cache-api.js +147 -0
  35. package/lib/api/cache-api.js.map +1 -0
  36. package/lib/api/channel-api.d.ts +6 -0
  37. package/lib/api/channel-api.d.ts.map +1 -0
  38. package/lib/api/channel-api.js +148 -0
  39. package/lib/api/channel-api.js.map +1 -0
  40. package/lib/api/connector-api.d.ts +6 -0
  41. package/lib/api/connector-api.d.ts.map +1 -0
  42. package/lib/api/connector-api.js +63 -0
  43. package/lib/api/connector-api.js.map +1 -0
  44. package/lib/api/generate-api.d.ts +6 -0
  45. package/lib/api/generate-api.d.ts.map +1 -0
  46. package/lib/api/generate-api.js +123 -0
  47. package/lib/api/generate-api.js.map +1 -0
  48. package/lib/api/index.d.ts +15 -0
  49. package/lib/api/index.d.ts.map +1 -0
  50. package/lib/api/index.js +34 -0
  51. package/lib/api/index.js.map +1 -0
  52. package/lib/api/middleware-api.d.ts +6 -0
  53. package/lib/api/middleware-api.d.ts.map +1 -0
  54. package/lib/api/middleware-api.js +212 -0
  55. package/lib/api/middleware-api.js.map +1 -0
  56. package/lib/api/plugin-api.d.ts +6 -0
  57. package/lib/api/plugin-api.d.ts.map +1 -0
  58. package/lib/api/plugin-api.js +78 -0
  59. package/lib/api/plugin-api.js.map +1 -0
  60. package/lib/api/preset-api.d.ts +6 -0
  61. package/lib/api/preset-api.d.ts.map +1 -0
  62. package/lib/api/preset-api.js +256 -0
  63. package/lib/api/preset-api.js.map +1 -0
  64. package/lib/api/settings-api.d.ts +6 -0
  65. package/lib/api/settings-api.d.ts.map +1 -0
  66. package/lib/api/settings-api.js +118 -0
  67. package/lib/api/settings-api.js.map +1 -0
  68. package/lib/api/task-api.d.ts +6 -0
  69. package/lib/api/task-api.d.ts.map +1 -0
  70. package/lib/api/task-api.js +148 -0
  71. package/lib/api/task-api.js.map +1 -0
  72. package/lib/config.d.ts +6 -0
  73. package/lib/config.d.ts.map +1 -0
  74. package/lib/config.js +8 -0
  75. package/lib/config.js.map +1 -0
  76. package/lib/connectors/builtin/chat-api.d.ts +9 -0
  77. package/lib/connectors/builtin/chat-api.d.ts.map +1 -0
  78. package/lib/connectors/builtin/chat-api.js +351 -0
  79. package/lib/connectors/builtin/chat-api.js.map +1 -0
  80. package/lib/connectors/builtin/dalle.d.ts +6 -0
  81. package/lib/connectors/builtin/dalle.d.ts.map +1 -0
  82. package/lib/connectors/builtin/dalle.js +109 -0
  83. package/lib/connectors/builtin/dalle.js.map +1 -0
  84. package/lib/connectors/builtin/flux.d.ts +7 -0
  85. package/lib/connectors/builtin/flux.d.ts.map +1 -0
  86. package/lib/connectors/builtin/flux.js +199 -0
  87. package/lib/connectors/builtin/flux.js.map +1 -0
  88. package/lib/connectors/builtin/index.d.ts +5 -0
  89. package/lib/connectors/builtin/index.d.ts.map +1 -0
  90. package/lib/connectors/builtin/index.js +6 -0
  91. package/lib/connectors/builtin/index.js.map +1 -0
  92. package/lib/connectors/builtin/sd-webui.d.ts +7 -0
  93. package/lib/connectors/builtin/sd-webui.d.ts.map +1 -0
  94. package/lib/connectors/builtin/sd-webui.js +157 -0
  95. package/lib/connectors/builtin/sd-webui.js.map +1 -0
  96. package/lib/connectors/connector-registry.d.ts +36 -0
  97. package/lib/connectors/connector-registry.d.ts.map +1 -0
  98. package/lib/connectors/connector-registry.js +66 -0
  99. package/lib/connectors/connector-registry.js.map +1 -0
  100. package/lib/connectors/index.d.ts +3 -0
  101. package/lib/connectors/index.d.ts.map +1 -0
  102. package/lib/connectors/index.js +4 -0
  103. package/lib/connectors/index.js.map +1 -0
  104. package/lib/core/api/api-utils.d.ts +46 -0
  105. package/lib/core/api/api-utils.d.ts.map +1 -0
  106. package/lib/core/api/api-utils.js +78 -0
  107. package/lib/core/api/api-utils.js.map +1 -0
  108. package/lib/core/api/cache-api.d.ts +6 -0
  109. package/lib/core/api/cache-api.d.ts.map +1 -0
  110. package/lib/core/api/cache-api.js +147 -0
  111. package/lib/core/api/cache-api.js.map +1 -0
  112. package/lib/core/api/channel-api.d.ts +6 -0
  113. package/lib/core/api/channel-api.d.ts.map +1 -0
  114. package/lib/core/api/channel-api.js +146 -0
  115. package/lib/core/api/channel-api.js.map +1 -0
  116. package/lib/core/api/connector-api.d.ts +6 -0
  117. package/lib/core/api/connector-api.d.ts.map +1 -0
  118. package/lib/core/api/connector-api.js +63 -0
  119. package/lib/core/api/connector-api.js.map +1 -0
  120. package/lib/core/api/generate-api.d.ts +6 -0
  121. package/lib/core/api/generate-api.d.ts.map +1 -0
  122. package/lib/core/api/generate-api.js +124 -0
  123. package/lib/core/api/generate-api.js.map +1 -0
  124. package/lib/core/api/index.d.ts +16 -0
  125. package/lib/core/api/index.d.ts.map +1 -0
  126. package/lib/core/api/index.js +38 -0
  127. package/lib/core/api/index.js.map +1 -0
  128. package/lib/core/api/middleware-api.d.ts +6 -0
  129. package/lib/core/api/middleware-api.d.ts.map +1 -0
  130. package/lib/core/api/middleware-api.js +196 -0
  131. package/lib/core/api/middleware-api.js.map +1 -0
  132. package/lib/core/api/plugin-api.d.ts +6 -0
  133. package/lib/core/api/plugin-api.d.ts.map +1 -0
  134. package/lib/core/api/plugin-api.js +78 -0
  135. package/lib/core/api/plugin-api.js.map +1 -0
  136. package/lib/core/api/preset-api.d.ts +6 -0
  137. package/lib/core/api/preset-api.d.ts.map +1 -0
  138. package/lib/core/api/preset-api.js +272 -0
  139. package/lib/core/api/preset-api.js.map +1 -0
  140. package/lib/core/api/settings-api.d.ts +6 -0
  141. package/lib/core/api/settings-api.d.ts.map +1 -0
  142. package/lib/core/api/settings-api.js +118 -0
  143. package/lib/core/api/settings-api.js.map +1 -0
  144. package/lib/core/api/task-api.d.ts +6 -0
  145. package/lib/core/api/task-api.d.ts.map +1 -0
  146. package/lib/core/api/task-api.js +281 -0
  147. package/lib/core/api/task-api.js.map +1 -0
  148. package/lib/core/channel.service.d.ts +44 -0
  149. package/lib/core/channel.service.d.ts.map +1 -0
  150. package/lib/core/channel.service.js +146 -0
  151. package/lib/core/channel.service.js.map +1 -0
  152. package/lib/core/config/config.service.d.ts +89 -0
  153. package/lib/core/config/config.service.d.ts.map +1 -0
  154. package/lib/core/config/config.service.js +216 -0
  155. package/lib/core/config/config.service.js.map +1 -0
  156. package/lib/core/config/index.d.ts +3 -0
  157. package/lib/core/config/index.d.ts.map +1 -0
  158. package/lib/core/config/index.js +3 -0
  159. package/lib/core/config/index.js.map +1 -0
  160. package/lib/core/error.d.ts +73 -0
  161. package/lib/core/error.d.ts.map +1 -0
  162. package/lib/core/error.js +137 -0
  163. package/lib/core/error.js.map +1 -0
  164. package/lib/core/index.d.ts +12 -0
  165. package/lib/core/index.d.ts.map +1 -0
  166. package/lib/core/index.js +23 -0
  167. package/lib/core/index.js.map +1 -0
  168. package/lib/core/logger.d.ts +18 -0
  169. package/lib/core/logger.d.ts.map +1 -0
  170. package/lib/core/logger.js +39 -0
  171. package/lib/core/logger.js.map +1 -0
  172. package/lib/core/medialuna.service.d.ts +168 -0
  173. package/lib/core/medialuna.service.d.ts.map +1 -0
  174. package/lib/core/medialuna.service.js +423 -0
  175. package/lib/core/medialuna.service.js.map +1 -0
  176. package/lib/core/pipeline/dependency-graph.d.ts +43 -0
  177. package/lib/core/pipeline/dependency-graph.d.ts.map +1 -0
  178. package/lib/core/pipeline/dependency-graph.js +223 -0
  179. package/lib/core/pipeline/dependency-graph.js.map +1 -0
  180. package/lib/core/pipeline/generation-pipeline.d.ts +40 -0
  181. package/lib/core/pipeline/generation-pipeline.d.ts.map +1 -0
  182. package/lib/core/pipeline/generation-pipeline.js +216 -0
  183. package/lib/core/pipeline/generation-pipeline.js.map +1 -0
  184. package/lib/core/pipeline/index.d.ts +4 -0
  185. package/lib/core/pipeline/index.d.ts.map +1 -0
  186. package/lib/core/pipeline/index.js +5 -0
  187. package/lib/core/pipeline/index.js.map +1 -0
  188. package/lib/core/pipeline/middleware-registry.d.ts +33 -0
  189. package/lib/core/pipeline/middleware-registry.d.ts.map +1 -0
  190. package/lib/core/pipeline/middleware-registry.js +78 -0
  191. package/lib/core/pipeline/middleware-registry.js.map +1 -0
  192. package/lib/core/plugin-loader.d.ts +77 -0
  193. package/lib/core/plugin-loader.d.ts.map +1 -0
  194. package/lib/core/plugin-loader.js +300 -0
  195. package/lib/core/plugin-loader.js.map +1 -0
  196. package/lib/core/registry/connector.registry.d.ts +36 -0
  197. package/lib/core/registry/connector.registry.d.ts.map +1 -0
  198. package/lib/core/registry/connector.registry.js +65 -0
  199. package/lib/core/registry/connector.registry.js.map +1 -0
  200. package/lib/core/registry/index.d.ts +3 -0
  201. package/lib/core/registry/index.d.ts.map +1 -0
  202. package/lib/core/registry/index.js +4 -0
  203. package/lib/core/registry/index.js.map +1 -0
  204. package/lib/core/registry/service.registry.d.ts +27 -0
  205. package/lib/core/registry/service.registry.d.ts.map +1 -0
  206. package/lib/core/registry/service.registry.js +54 -0
  207. package/lib/core/registry/service.registry.js.map +1 -0
  208. package/lib/core/request.service.d.ts +83 -0
  209. package/lib/core/request.service.d.ts.map +1 -0
  210. package/lib/core/request.service.js +237 -0
  211. package/lib/core/request.service.js.map +1 -0
  212. package/lib/core/types.d.ts +270 -0
  213. package/lib/core/types.d.ts.map +1 -0
  214. package/lib/core/types.js +17 -0
  215. package/lib/core/types.js.map +1 -0
  216. package/lib/database.d.ts +6 -0
  217. package/lib/database.d.ts.map +1 -0
  218. package/lib/database.js +89 -0
  219. package/lib/database.js.map +1 -0
  220. package/lib/index.d.ts +13 -0
  221. package/lib/index.d.ts.map +1 -0
  222. package/lib/index.js +54 -0
  223. package/lib/index.js.map +1 -0
  224. package/lib/middlewares/builtin/billing.d.ts +45 -0
  225. package/lib/middlewares/builtin/billing.d.ts.map +1 -0
  226. package/lib/middlewares/builtin/billing.js +362 -0
  227. package/lib/middlewares/builtin/billing.js.map +1 -0
  228. package/lib/middlewares/builtin/index.d.ts +6 -0
  229. package/lib/middlewares/builtin/index.d.ts.map +1 -0
  230. package/lib/middlewares/builtin/index.js +7 -0
  231. package/lib/middlewares/builtin/index.js.map +1 -0
  232. package/lib/middlewares/builtin/preset.d.ts +14 -0
  233. package/lib/middlewares/builtin/preset.d.ts.map +1 -0
  234. package/lib/middlewares/builtin/preset.js +156 -0
  235. package/lib/middlewares/builtin/preset.js.map +1 -0
  236. package/lib/middlewares/builtin/remote-preset-sync.d.ts +8 -0
  237. package/lib/middlewares/builtin/remote-preset-sync.d.ts.map +1 -0
  238. package/lib/middlewares/builtin/remote-preset-sync.js +32 -0
  239. package/lib/middlewares/builtin/remote-preset-sync.js.map +1 -0
  240. package/lib/middlewares/builtin/request.d.ts +10 -0
  241. package/lib/middlewares/builtin/request.d.ts.map +1 -0
  242. package/lib/middlewares/builtin/request.js +50 -0
  243. package/lib/middlewares/builtin/request.js.map +1 -0
  244. package/lib/middlewares/builtin/storage.d.ts +64 -0
  245. package/lib/middlewares/builtin/storage.d.ts.map +1 -0
  246. package/lib/middlewares/builtin/storage.js +715 -0
  247. package/lib/middlewares/builtin/storage.js.map +1 -0
  248. package/lib/middlewares/builtin/task-recorder.d.ts +20 -0
  249. package/lib/middlewares/builtin/task-recorder.d.ts.map +1 -0
  250. package/lib/middlewares/builtin/task-recorder.js +138 -0
  251. package/lib/middlewares/builtin/task-recorder.js.map +1 -0
  252. package/lib/middlewares/index.d.ts +2 -0
  253. package/lib/middlewares/index.d.ts.map +1 -0
  254. package/lib/middlewares/index.js +3 -0
  255. package/lib/middlewares/index.js.map +1 -0
  256. package/lib/pipeline/dependency-graph.d.ts +43 -0
  257. package/lib/pipeline/dependency-graph.d.ts.map +1 -0
  258. package/lib/pipeline/dependency-graph.js +240 -0
  259. package/lib/pipeline/dependency-graph.js.map +1 -0
  260. package/lib/pipeline/generation-pipeline.d.ts +38 -0
  261. package/lib/pipeline/generation-pipeline.d.ts.map +1 -0
  262. package/lib/pipeline/generation-pipeline.js +211 -0
  263. package/lib/pipeline/generation-pipeline.js.map +1 -0
  264. package/lib/pipeline/index.d.ts +4 -0
  265. package/lib/pipeline/index.d.ts.map +1 -0
  266. package/lib/pipeline/index.js +5 -0
  267. package/lib/pipeline/index.js.map +1 -0
  268. package/lib/pipeline/middleware-registry.d.ts +36 -0
  269. package/lib/pipeline/middleware-registry.d.ts.map +1 -0
  270. package/lib/pipeline/middleware-registry.js +83 -0
  271. package/lib/pipeline/middleware-registry.js.map +1 -0
  272. package/lib/plugins/billing/config.d.ts +19 -0
  273. package/lib/plugins/billing/config.d.ts.map +1 -0
  274. package/lib/plugins/billing/config.js +98 -0
  275. package/lib/plugins/billing/config.js.map +1 -0
  276. package/lib/plugins/billing/index.d.ts +4 -0
  277. package/lib/plugins/billing/index.d.ts.map +1 -0
  278. package/lib/plugins/billing/index.js +20 -0
  279. package/lib/plugins/billing/index.js.map +1 -0
  280. package/lib/plugins/billing/middleware.d.ts +12 -0
  281. package/lib/plugins/billing/middleware.d.ts.map +1 -0
  282. package/lib/plugins/billing/middleware.js +233 -0
  283. package/lib/plugins/billing/middleware.js.map +1 -0
  284. package/lib/plugins/cache/config.d.ts +44 -0
  285. package/lib/plugins/cache/config.d.ts.map +1 -0
  286. package/lib/plugins/cache/config.js +187 -0
  287. package/lib/plugins/cache/config.js.map +1 -0
  288. package/lib/plugins/cache/index.d.ts +6 -0
  289. package/lib/plugins/cache/index.d.ts.map +1 -0
  290. package/lib/plugins/cache/index.js +87 -0
  291. package/lib/plugins/cache/index.js.map +1 -0
  292. package/lib/plugins/cache/middleware.d.ts +12 -0
  293. package/lib/plugins/cache/middleware.d.ts.map +1 -0
  294. package/lib/plugins/cache/middleware.js +194 -0
  295. package/lib/plugins/cache/middleware.js.map +1 -0
  296. package/lib/plugins/cache/service.d.ts +106 -0
  297. package/lib/plugins/cache/service.d.ts.map +1 -0
  298. package/lib/plugins/cache/service.js +467 -0
  299. package/lib/plugins/cache/service.js.map +1 -0
  300. package/lib/plugins/cache/utils/index.d.ts +4 -0
  301. package/lib/plugins/cache/utils/index.d.ts.map +1 -0
  302. package/lib/plugins/cache/utils/index.js +5 -0
  303. package/lib/plugins/cache/utils/index.js.map +1 -0
  304. package/lib/plugins/cache/utils/mime.d.ts +9 -0
  305. package/lib/plugins/cache/utils/mime.d.ts.map +1 -0
  306. package/lib/plugins/cache/utils/mime.js +65 -0
  307. package/lib/plugins/cache/utils/mime.js.map +1 -0
  308. package/lib/plugins/cache/utils/s3.d.ts +19 -0
  309. package/lib/plugins/cache/utils/s3.d.ts.map +1 -0
  310. package/lib/plugins/cache/utils/s3.js +147 -0
  311. package/lib/plugins/cache/utils/s3.js.map +1 -0
  312. package/lib/plugins/cache/utils/webdav.d.ts +16 -0
  313. package/lib/plugins/cache/utils/webdav.d.ts.map +1 -0
  314. package/lib/plugins/cache/utils/webdav.js +69 -0
  315. package/lib/plugins/cache/utils/webdav.js.map +1 -0
  316. package/lib/plugins/connector-chat-api/index.d.ts +7 -0
  317. package/lib/plugins/connector-chat-api/index.d.ts.map +1 -0
  318. package/lib/plugins/connector-chat-api/index.js +400 -0
  319. package/lib/plugins/connector-chat-api/index.js.map +1 -0
  320. package/lib/plugins/connector-dalle/index.d.ts +7 -0
  321. package/lib/plugins/connector-dalle/index.d.ts.map +1 -0
  322. package/lib/plugins/connector-dalle/index.js +140 -0
  323. package/lib/plugins/connector-dalle/index.js.map +1 -0
  324. package/lib/plugins/connector-flux/index.d.ts +7 -0
  325. package/lib/plugins/connector-flux/index.d.ts.map +1 -0
  326. package/lib/plugins/connector-flux/index.js +232 -0
  327. package/lib/plugins/connector-flux/index.js.map +1 -0
  328. package/lib/plugins/connector-sd-webui/index.d.ts +7 -0
  329. package/lib/plugins/connector-sd-webui/index.d.ts.map +1 -0
  330. package/lib/plugins/connector-sd-webui/index.js +171 -0
  331. package/lib/plugins/connector-sd-webui/index.js.map +1 -0
  332. package/lib/plugins/index.d.ts +22 -0
  333. package/lib/plugins/index.d.ts.map +1 -0
  334. package/lib/plugins/index.js +21 -0
  335. package/lib/plugins/index.js.map +1 -0
  336. package/lib/plugins/preset/config.d.ts +37 -0
  337. package/lib/plugins/preset/config.d.ts.map +1 -0
  338. package/lib/plugins/preset/config.js +74 -0
  339. package/lib/plugins/preset/config.js.map +1 -0
  340. package/lib/plugins/preset/index.d.ts +6 -0
  341. package/lib/plugins/preset/index.d.ts.map +1 -0
  342. package/lib/plugins/preset/index.js +58 -0
  343. package/lib/plugins/preset/index.js.map +1 -0
  344. package/lib/plugins/preset/middleware.d.ts +6 -0
  345. package/lib/plugins/preset/middleware.d.ts.map +1 -0
  346. package/lib/plugins/preset/middleware.js +126 -0
  347. package/lib/plugins/preset/middleware.js.map +1 -0
  348. package/lib/plugins/preset/remote-sync.service.d.ts +84 -0
  349. package/lib/plugins/preset/remote-sync.service.d.ts.map +1 -0
  350. package/lib/plugins/preset/remote-sync.service.js +342 -0
  351. package/lib/plugins/preset/remote-sync.service.js.map +1 -0
  352. package/lib/plugins/preset/service.d.ts +64 -0
  353. package/lib/plugins/preset/service.d.ts.map +1 -0
  354. package/lib/plugins/preset/service.js +196 -0
  355. package/lib/plugins/preset/service.js.map +1 -0
  356. package/lib/plugins/prompt-encoding/config.d.ts +25 -0
  357. package/lib/plugins/prompt-encoding/config.d.ts.map +1 -0
  358. package/lib/plugins/prompt-encoding/config.js +62 -0
  359. package/lib/plugins/prompt-encoding/config.js.map +1 -0
  360. package/lib/plugins/prompt-encoding/index.d.ts +5 -0
  361. package/lib/plugins/prompt-encoding/index.d.ts.map +1 -0
  362. package/lib/plugins/prompt-encoding/index.js +21 -0
  363. package/lib/plugins/prompt-encoding/index.js.map +1 -0
  364. package/lib/plugins/prompt-encoding/middleware.d.ts +6 -0
  365. package/lib/plugins/prompt-encoding/middleware.d.ts.map +1 -0
  366. package/lib/plugins/prompt-encoding/middleware.js +151 -0
  367. package/lib/plugins/prompt-encoding/middleware.js.map +1 -0
  368. package/lib/plugins/task/config.d.ts +15 -0
  369. package/lib/plugins/task/config.d.ts.map +1 -0
  370. package/lib/plugins/task/config.js +33 -0
  371. package/lib/plugins/task/config.js.map +1 -0
  372. package/lib/plugins/task/index.d.ts +5 -0
  373. package/lib/plugins/task/index.d.ts.map +1 -0
  374. package/lib/plugins/task/index.js +58 -0
  375. package/lib/plugins/task/index.js.map +1 -0
  376. package/lib/plugins/task/middleware.d.ts +14 -0
  377. package/lib/plugins/task/middleware.d.ts.map +1 -0
  378. package/lib/plugins/task/middleware.js +123 -0
  379. package/lib/plugins/task/middleware.js.map +1 -0
  380. package/lib/plugins/task/service.d.ts +94 -0
  381. package/lib/plugins/task/service.d.ts.map +1 -0
  382. package/lib/plugins/task/service.js +226 -0
  383. package/lib/plugins/task/service.js.map +1 -0
  384. package/lib/plugins/webui-auth/config.d.ts +12 -0
  385. package/lib/plugins/webui-auth/config.d.ts.map +1 -0
  386. package/lib/plugins/webui-auth/config.js +30 -0
  387. package/lib/plugins/webui-auth/config.js.map +1 -0
  388. package/lib/plugins/webui-auth/index.d.ts +5 -0
  389. package/lib/plugins/webui-auth/index.d.ts.map +1 -0
  390. package/lib/plugins/webui-auth/index.js +99 -0
  391. package/lib/plugins/webui-auth/index.js.map +1 -0
  392. package/lib/plugins/webui-auth/service.d.ts +42 -0
  393. package/lib/plugins/webui-auth/service.d.ts.map +1 -0
  394. package/lib/plugins/webui-auth/service.js +106 -0
  395. package/lib/plugins/webui-auth/service.js.map +1 -0
  396. package/lib/services/asset-cache.service.d.ts +133 -0
  397. package/lib/services/asset-cache.service.d.ts.map +1 -0
  398. package/lib/services/asset-cache.service.js +882 -0
  399. package/lib/services/asset-cache.service.js.map +1 -0
  400. package/lib/services/cache.service.d.ts +110 -0
  401. package/lib/services/cache.service.d.ts.map +1 -0
  402. package/lib/services/cache.service.js +333 -0
  403. package/lib/services/cache.service.js.map +1 -0
  404. package/lib/services/channel.service.d.ts +44 -0
  405. package/lib/services/channel.service.d.ts.map +1 -0
  406. package/lib/services/channel.service.js +154 -0
  407. package/lib/services/channel.service.js.map +1 -0
  408. package/lib/services/config.service.d.ts +73 -0
  409. package/lib/services/config.service.d.ts.map +1 -0
  410. package/lib/services/config.service.js +171 -0
  411. package/lib/services/config.service.js.map +1 -0
  412. package/lib/services/index.d.ts +8 -0
  413. package/lib/services/index.d.ts.map +1 -0
  414. package/lib/services/index.js +9 -0
  415. package/lib/services/index.js.map +1 -0
  416. package/lib/services/medialuna.service.d.ts +173 -0
  417. package/lib/services/medialuna.service.d.ts.map +1 -0
  418. package/lib/services/medialuna.service.js +455 -0
  419. package/lib/services/medialuna.service.js.map +1 -0
  420. package/lib/services/preset.service.d.ts +69 -0
  421. package/lib/services/preset.service.d.ts.map +1 -0
  422. package/lib/services/preset.service.js +202 -0
  423. package/lib/services/preset.service.js.map +1 -0
  424. package/lib/services/remote-preset.service.d.ts +97 -0
  425. package/lib/services/remote-preset.service.d.ts.map +1 -0
  426. package/lib/services/remote-preset.service.js +212 -0
  427. package/lib/services/remote-preset.service.js.map +1 -0
  428. package/lib/services/task.service.d.ts +57 -0
  429. package/lib/services/task.service.d.ts.map +1 -0
  430. package/lib/services/task.service.js +138 -0
  431. package/lib/services/task.service.js.map +1 -0
  432. package/lib/types/index.d.ts +357 -0
  433. package/lib/types/index.d.ts.map +1 -0
  434. package/lib/types/index.js +21 -0
  435. package/lib/types/index.js.map +1 -0
  436. package/package.json +66 -0
  437. package/readme.md +326 -0
@@ -0,0 +1,715 @@
1
+ // 存储中间件 - 将输入文件和生成结果缓存到外部存储
2
+ import { createHash } from 'crypto';
3
+ import { promises as fs } from 'fs';
4
+ import { join, dirname } from 'path';
5
+ /**
6
+ * 存储配置字段
7
+ */
8
+ export const storageConfigFields = [
9
+ {
10
+ key: 'backend',
11
+ label: '存储后端',
12
+ type: 'select',
13
+ default: 'none',
14
+ options: [
15
+ { label: '不使用(保留原始 URL)', value: 'none' },
16
+ { label: 'Koishi 资源服务(推荐)', value: 'koishi' },
17
+ { label: '本地缓存(自定义)', value: 'local' },
18
+ { label: 'S3 兼容存储', value: 's3' },
19
+ { label: 'WebDAV', value: 'webdav' }
20
+ ],
21
+ description: '选择存储后端用于缓存生成结果。推荐使用 Koishi 资源服务,需安装 assets-local 等 assets 插件。'
22
+ },
23
+ // 本地缓存配置(仅当选择 local 时显示)
24
+ {
25
+ key: 'localCacheDir',
26
+ label: '缓存目录',
27
+ type: 'text',
28
+ default: 'data/media-luna/assets',
29
+ placeholder: 'data/media-luna/assets',
30
+ description: '本地缓存文件存储目录(相对于 Koishi 根目录)',
31
+ showWhen: { field: 'backend', value: 'local' }
32
+ },
33
+ {
34
+ key: 'localMaxSizeMB',
35
+ label: '最大容量 (MB)',
36
+ type: 'number',
37
+ default: 1024,
38
+ placeholder: '1024',
39
+ description: '本地缓存最大容量(超出时自动清理旧文件)',
40
+ showWhen: { field: 'backend', value: 'local' }
41
+ },
42
+ {
43
+ key: 'localPublicPath',
44
+ label: '公开访问路径',
45
+ type: 'text',
46
+ default: '/media-luna/assets',
47
+ placeholder: '/media-luna/assets',
48
+ description: '通过 Koishi 内置 HTTP 服务访问缓存文件的 URL 路径',
49
+ showWhen: { field: 'backend', value: 'local' }
50
+ },
51
+ {
52
+ key: 'localPublicBaseUrl',
53
+ label: '公开访问地址',
54
+ type: 'text',
55
+ placeholder: 'http://your-domain.com:5140',
56
+ description: '对外访问的 URL 前缀(默认自动检测,如需暴露到公网请手动配置)',
57
+ showWhen: { field: 'backend', value: 'local' }
58
+ },
59
+ // S3 配置
60
+ {
61
+ key: 's3Endpoint',
62
+ label: 'S3 端点',
63
+ type: 'text',
64
+ placeholder: 'https://s3.amazonaws.com',
65
+ description: 'S3 兼容服务端点地址',
66
+ showWhen: { field: 'backend', value: 's3' }
67
+ },
68
+ {
69
+ key: 's3Region',
70
+ label: 'S3 区域',
71
+ type: 'text',
72
+ default: 'us-east-1',
73
+ placeholder: 'us-east-1',
74
+ showWhen: { field: 'backend', value: 's3' }
75
+ },
76
+ {
77
+ key: 's3AccessKeyId',
78
+ label: 'Access Key ID',
79
+ type: 'text',
80
+ showWhen: { field: 'backend', value: 's3' }
81
+ },
82
+ {
83
+ key: 's3SecretAccessKey',
84
+ label: 'Secret Access Key',
85
+ type: 'password',
86
+ showWhen: { field: 'backend', value: 's3' }
87
+ },
88
+ {
89
+ key: 's3Bucket',
90
+ label: 'Bucket 名称',
91
+ type: 'text',
92
+ placeholder: 'my-bucket',
93
+ showWhen: { field: 'backend', value: 's3' }
94
+ },
95
+ {
96
+ key: 's3PublicBaseUrl',
97
+ label: '公开访问 URL',
98
+ type: 'text',
99
+ placeholder: 'https://cdn.example.com',
100
+ description: 'CDN 或直接访问的 URL 前缀(可选)',
101
+ showWhen: { field: 'backend', value: 's3' }
102
+ },
103
+ {
104
+ key: 's3ForcePathStyle',
105
+ label: '强制路径风格',
106
+ type: 'boolean',
107
+ default: false,
108
+ description: '使用路径风格而非虚拟主机风格(适用于 MinIO 等)',
109
+ showWhen: { field: 'backend', value: 's3' }
110
+ },
111
+ {
112
+ key: 's3Acl',
113
+ label: 'ACL 权限',
114
+ type: 'select',
115
+ default: 'public-read',
116
+ options: [
117
+ { label: '公开读取', value: 'public-read' },
118
+ { label: '私有', value: 'private' }
119
+ ],
120
+ showWhen: { field: 'backend', value: 's3' }
121
+ },
122
+ // WebDAV 配置
123
+ {
124
+ key: 'webdavEndpoint',
125
+ label: 'WebDAV 端点',
126
+ type: 'text',
127
+ placeholder: 'https://dav.example.com/files',
128
+ description: 'WebDAV 服务根地址',
129
+ showWhen: { field: 'backend', value: 'webdav' }
130
+ },
131
+ {
132
+ key: 'webdavUsername',
133
+ label: '用户名',
134
+ type: 'text',
135
+ showWhen: { field: 'backend', value: 'webdav' }
136
+ },
137
+ {
138
+ key: 'webdavPassword',
139
+ label: '密码',
140
+ type: 'password',
141
+ showWhen: { field: 'backend', value: 'webdav' }
142
+ },
143
+ {
144
+ key: 'webdavBasePath',
145
+ label: '基础路径',
146
+ type: 'text',
147
+ placeholder: 'media-luna',
148
+ description: '上传文件的目录路径(可选)',
149
+ showWhen: { field: 'backend', value: 'webdav' }
150
+ },
151
+ {
152
+ key: 'webdavPublicBaseUrl',
153
+ label: '公开访问 URL',
154
+ type: 'text',
155
+ placeholder: 'https://files.example.com',
156
+ description: '对外访问的 URL 前缀(若与端点不同)',
157
+ showWhen: { field: 'backend', value: 'webdav' }
158
+ }
159
+ ];
160
+ // ============ S3 上传实现 ============
161
+ import { createHmac } from 'crypto';
162
+ function toAmzDate(d) {
163
+ const pad = (n, w = 2) => n.toString().padStart(w, '0');
164
+ return (d.getUTCFullYear().toString() +
165
+ pad(d.getUTCMonth() + 1) +
166
+ pad(d.getUTCDate()) +
167
+ 'T' +
168
+ pad(d.getUTCHours()) +
169
+ pad(d.getUTCMinutes()) +
170
+ pad(d.getUTCSeconds()) +
171
+ 'Z');
172
+ }
173
+ function sha256Hex(data) {
174
+ return createHash('sha256').update(data).digest('hex');
175
+ }
176
+ function hmac(key, data) {
177
+ return createHmac('sha256', key).update(data, 'utf8').digest();
178
+ }
179
+ function hmacHex(key, data) {
180
+ return createHmac('sha256', key).update(data, 'utf8').digest('hex');
181
+ }
182
+ function getSignatureKey(secretKey, dateStamp, regionName, serviceName) {
183
+ const kDate = hmac('AWS4' + secretKey, dateStamp);
184
+ const kRegion = hmac(kDate, regionName);
185
+ const kService = hmac(kRegion, serviceName);
186
+ return hmac(kService, 'aws4_request');
187
+ }
188
+ function trimSpaces(str) {
189
+ return str.replace(/\s+/g, ' ').trim();
190
+ }
191
+ function encodeKey(key) {
192
+ return key.split('/').map(encodeURIComponent).join('/');
193
+ }
194
+ function joinUrl(base, key) {
195
+ const b = base.replace(/\/$/, '');
196
+ return `${b}/${encodeKey(key)}`;
197
+ }
198
+ async function uploadToS3(buffer, filename, mime, config) {
199
+ const bucket = config.s3Bucket;
200
+ const region = config.s3Region || 'us-east-1';
201
+ const accessKeyId = config.s3AccessKeyId;
202
+ const secretAccessKey = config.s3SecretAccessKey;
203
+ if (!bucket)
204
+ throw new Error('S3 缺少 bucket 配置');
205
+ if (!accessKeyId || !secretAccessKey)
206
+ throw new Error('S3 需提供访问凭证');
207
+ const now = new Date();
208
+ const amzDate = toAmzDate(now);
209
+ const dateStamp = amzDate.slice(0, 8);
210
+ const key = filename;
211
+ const hostInfo = buildS3HostAndPath(config, key);
212
+ const { host, url, canonicalUri } = hostInfo;
213
+ const payloadHash = sha256Hex(buffer);
214
+ const headers = {
215
+ 'host': host,
216
+ 'x-amz-content-sha256': payloadHash,
217
+ 'x-amz-date': amzDate,
218
+ };
219
+ if (mime)
220
+ headers['content-type'] = mime;
221
+ if (config.s3Acl)
222
+ headers['x-amz-acl'] = config.s3Acl;
223
+ const signedHeaders = Object.keys(headers)
224
+ .map(k => k.toLowerCase())
225
+ .sort()
226
+ .join(';');
227
+ const canonicalHeaders = Object.keys(headers)
228
+ .map(k => k.toLowerCase())
229
+ .sort()
230
+ .map(k => `${k}:${trimSpaces(String(headers[k]))}\n`)
231
+ .join('');
232
+ const canonicalRequest = [
233
+ 'PUT',
234
+ canonicalUri,
235
+ '',
236
+ canonicalHeaders,
237
+ signedHeaders,
238
+ payloadHash,
239
+ ].join('\n');
240
+ const algorithm = 'AWS4-HMAC-SHA256';
241
+ const credentialScope = `${dateStamp}/${region}/s3/aws4_request`;
242
+ const stringToSign = [
243
+ algorithm,
244
+ amzDate,
245
+ credentialScope,
246
+ sha256Hex(Buffer.from(canonicalRequest, 'utf8')),
247
+ ].join('\n');
248
+ const signingKey = getSignatureKey(secretAccessKey, dateStamp, region, 's3');
249
+ const signature = hmacHex(signingKey, stringToSign);
250
+ const authorization = `${algorithm} Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
251
+ const reqHeaders = { ...headers, Authorization: authorization };
252
+ const resp = await fetch(url, { method: 'PUT', headers: reqHeaders, body: new Uint8Array(buffer) });
253
+ if (!resp.ok)
254
+ throw new Error(`S3 上传失败: ${resp.status}`);
255
+ const publicUrl = config.s3PublicBaseUrl
256
+ ? joinUrl(config.s3PublicBaseUrl, key)
257
+ : url;
258
+ return { url: publicUrl, key };
259
+ }
260
+ function buildS3HostAndPath(config, key) {
261
+ let base;
262
+ if (config.s3Endpoint) {
263
+ base = new URL(config.s3Endpoint);
264
+ }
265
+ else {
266
+ base = new URL(`https://s3.${config.s3Region || 'us-east-1'}.amazonaws.com`);
267
+ }
268
+ const bucket = config.s3Bucket;
269
+ const isIp = /^\d{1,3}(?:\.\d{1,3}){3}$/.test(base.hostname);
270
+ const hasPort = !!base.port;
271
+ const isLocal = base.hostname === 'localhost';
272
+ const preferPath = isIp || hasPort || isLocal;
273
+ const usePath = !!config.s3ForcePathStyle || preferPath;
274
+ const hostname = base.hostname;
275
+ const port = base.port ? `:${base.port}` : '';
276
+ let host = hostname + port;
277
+ let path = '';
278
+ if (usePath) {
279
+ path = `/${bucket}/${encodeKey(key)}`;
280
+ }
281
+ else {
282
+ host = `${bucket}.${hostname}${port}`;
283
+ path = `/${encodeKey(key)}`;
284
+ }
285
+ const url = `${base.protocol}//${host}${path}`;
286
+ const canonicalUri = path;
287
+ return { host, url, canonicalUri };
288
+ }
289
+ function b64(str) {
290
+ return Buffer.from(str, 'utf8').toString('base64');
291
+ }
292
+ function trimSlash(s) {
293
+ return s.replace(/\/+$/, '');
294
+ }
295
+ function encodePath(path) {
296
+ return path.split('/').map(encodeURIComponent).join('/');
297
+ }
298
+ async function ensureWebDavBasePath(config) {
299
+ const base = (config.webdavBasePath || '').replace(/^\/+|\/+$/g, '');
300
+ if (!base)
301
+ return;
302
+ const segments = base.split('/').filter(Boolean);
303
+ let current = '';
304
+ for (const seg of segments) {
305
+ current = current ? `${current}/${seg}` : seg;
306
+ const url = `${trimSlash(config.webdavEndpoint)}/${encodePath(current)}`;
307
+ try {
308
+ await fetch(url, {
309
+ method: 'MKCOL',
310
+ headers: { 'Authorization': `Basic ${b64(`${config.webdavUsername}:${config.webdavPassword}`)}` }
311
+ });
312
+ }
313
+ catch {
314
+ // Ignore errors
315
+ }
316
+ }
317
+ }
318
+ async function uploadToWebDav(buffer, filename, mime, config) {
319
+ if (!config.webdavEndpoint || !config.webdavUsername || !config.webdavPassword) {
320
+ throw new Error('WebDAV 缺少必要配置');
321
+ }
322
+ await ensureWebDavBasePath(config);
323
+ const remotePath = config.webdavBasePath
324
+ ? `${config.webdavBasePath.replace(/\/+$/, '')}/${filename}`
325
+ : filename;
326
+ const url = `${trimSlash(config.webdavEndpoint)}/${encodePath(remotePath)}`;
327
+ const headers = {
328
+ 'Authorization': `Basic ${b64(`${config.webdavUsername}:${config.webdavPassword}`)}`,
329
+ };
330
+ if (mime)
331
+ headers['Content-Type'] = mime;
332
+ const res = await fetch(url, { method: 'PUT', headers: headers, body: new Uint8Array(buffer) });
333
+ if (!res.ok)
334
+ throw new Error(`WebDAV 上传失败: ${res.status}`);
335
+ const publicUrl = config.webdavPublicBaseUrl
336
+ ? `${trimSlash(config.webdavPublicBaseUrl)}/${encodePath(remotePath)}`
337
+ : url;
338
+ return { url: publicUrl, key: remotePath };
339
+ }
340
+ // 本地缓存上下文(用于存储 ctx 和 baseUrl)
341
+ let localStorageCtx = null;
342
+ let localStorageBaseUrl = null;
343
+ /**
344
+ * 初始化本地存储 baseUrl 检测
345
+ * 注意:HTTP 路由由 asset-cache.service 统一注册 (/media-luna/assets/*)
346
+ */
347
+ export function initLocalStorage(ctx, logger) {
348
+ localStorageCtx = ctx;
349
+ // 监听 server 事件获取 baseUrl
350
+ ctx.on('server/ready', () => {
351
+ const server = ctx.get('server');
352
+ if (server) {
353
+ // 获取服务器配置的端口
354
+ const port = server.config?.port || 5140;
355
+ const host = server.config?.host || 'localhost';
356
+ localStorageBaseUrl = `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;
357
+ logger.info(`Local storage base URL: ${localStorageBaseUrl}`);
358
+ }
359
+ });
360
+ }
361
+ /**
362
+ * 获取本地存储的公开 URL
363
+ */
364
+ function getLocalPublicUrl(config, relativePath) {
365
+ const publicPath = config.localPublicPath || '/media-luna/assets';
366
+ // 优先使用用户配置的 baseUrl,否则使用自动检测的
367
+ const baseUrl = config.localPublicBaseUrl || localStorageBaseUrl || '';
368
+ return `${baseUrl}${publicPath}/${relativePath}`;
369
+ }
370
+ /**
371
+ * 获取缓存统计信息
372
+ */
373
+ export async function getLocalCacheStats(config) {
374
+ const cacheDir = config.localCacheDir || 'data/media-luna/assets';
375
+ const maxSizeMB = config.localMaxSizeMB || 1024;
376
+ const fullCacheDir = join(process.cwd(), cacheDir);
377
+ let totalFiles = 0;
378
+ let totalSize = 0;
379
+ try {
380
+ await countFilesRecursive(fullCacheDir, (size) => {
381
+ totalFiles++;
382
+ totalSize += size;
383
+ });
384
+ }
385
+ catch {
386
+ // 目录不存在
387
+ }
388
+ return {
389
+ totalFiles,
390
+ totalSizeMB: totalSize / (1024 * 1024),
391
+ maxSizeMB
392
+ };
393
+ }
394
+ async function countFilesRecursive(dir, callback) {
395
+ const entries = await fs.readdir(dir, { withFileTypes: true });
396
+ for (const entry of entries) {
397
+ const fullPath = join(dir, entry.name);
398
+ if (entry.isDirectory()) {
399
+ await countFilesRecursive(fullPath, callback);
400
+ }
401
+ else {
402
+ const stat = await fs.stat(fullPath);
403
+ callback(stat.size);
404
+ }
405
+ }
406
+ }
407
+ /**
408
+ * 清理本地缓存
409
+ */
410
+ export async function clearLocalCache(config) {
411
+ const cacheDir = config.localCacheDir || 'data/media-luna/assets';
412
+ const fullCacheDir = join(process.cwd(), cacheDir);
413
+ try {
414
+ await fs.rm(fullCacheDir, { recursive: true, force: true });
415
+ await fs.mkdir(fullCacheDir, { recursive: true });
416
+ }
417
+ catch {
418
+ // 忽略错误
419
+ }
420
+ }
421
+ /**
422
+ * 自动清理超出容量的旧文件
423
+ */
424
+ async function autoCleanup(config, logger) {
425
+ const cacheDir = config.localCacheDir || 'data/media-luna/assets';
426
+ const maxSizeMB = config.localMaxSizeMB || 1024;
427
+ const maxSizeBytes = maxSizeMB * 1024 * 1024;
428
+ const fullCacheDir = join(process.cwd(), cacheDir);
429
+ const files = [];
430
+ try {
431
+ await collectFilesRecursive(fullCacheDir, files);
432
+ }
433
+ catch {
434
+ return;
435
+ }
436
+ // 按修改时间排序(旧的在前)
437
+ files.sort((a, b) => a.mtime - b.mtime);
438
+ let totalSize = files.reduce((sum, f) => sum + f.size, 0);
439
+ // 删除旧文件直到总大小低于限制
440
+ while (totalSize > maxSizeBytes && files.length > 0) {
441
+ const oldest = files.shift();
442
+ try {
443
+ await fs.unlink(oldest.path);
444
+ totalSize -= oldest.size;
445
+ logger.debug(`Auto-cleaned old cache file: ${oldest.path}`);
446
+ }
447
+ catch {
448
+ // 忽略删除错误
449
+ }
450
+ }
451
+ }
452
+ async function collectFilesRecursive(dir, files) {
453
+ const entries = await fs.readdir(dir, { withFileTypes: true });
454
+ for (const entry of entries) {
455
+ const fullPath = join(dir, entry.name);
456
+ if (entry.isDirectory()) {
457
+ await collectFilesRecursive(fullPath, files);
458
+ }
459
+ else {
460
+ const stat = await fs.stat(fullPath);
461
+ files.push({ path: fullPath, mtime: stat.mtimeMs, size: stat.size });
462
+ }
463
+ }
464
+ }
465
+ async function uploadToLocal(buffer, filename, mime, config, logger) {
466
+ const cacheDir = config.localCacheDir || 'data/media-luna/assets';
467
+ const fullCacheDir = join(process.cwd(), cacheDir);
468
+ const filePath = join(fullCacheDir, filename);
469
+ // 确保目录存在
470
+ await fs.mkdir(dirname(filePath), { recursive: true });
471
+ // 写入文件
472
+ await fs.writeFile(filePath, buffer);
473
+ // 自动清理
474
+ await autoCleanup(config, logger);
475
+ const publicUrl = getLocalPublicUrl(config, filename);
476
+ return {
477
+ url: publicUrl,
478
+ key: filename,
479
+ filePath
480
+ };
481
+ }
482
+ // ============ 存储中间件 ============
483
+ /**
484
+ * 根据 URL 获取文件扩展名
485
+ */
486
+ function getExtension(url, mime) {
487
+ // 优先使用 MIME 类型
488
+ if (mime) {
489
+ const mimeMap = {
490
+ 'image/png': '.png',
491
+ 'image/jpeg': '.jpg',
492
+ 'image/gif': '.gif',
493
+ 'image/webp': '.webp',
494
+ 'video/mp4': '.mp4',
495
+ 'video/webm': '.webm',
496
+ 'audio/mp3': '.mp3',
497
+ 'audio/mpeg': '.mp3',
498
+ 'audio/wav': '.wav',
499
+ };
500
+ if (mimeMap[mime])
501
+ return mimeMap[mime];
502
+ }
503
+ // 从 URL 提取
504
+ try {
505
+ const pathname = new URL(url).pathname;
506
+ const ext = pathname.match(/\.[a-zA-Z0-9]+$/)?.[0];
507
+ if (ext)
508
+ return ext;
509
+ }
510
+ catch { }
511
+ return '.bin';
512
+ }
513
+ /**
514
+ * 生成唯一文件名
515
+ */
516
+ function generateFilename(asset, index) {
517
+ const content = asset.url || asset.content || '';
518
+ const hash = createHash('md5').update(content).digest('hex').slice(0, 8);
519
+ const ext = asset.url ? getExtension(asset.url, asset.mime) : '.txt';
520
+ const timestamp = Date.now();
521
+ return `media-luna/output/${asset.kind}/${timestamp}-${index}-${hash}${ext}`;
522
+ }
523
+ /**
524
+ * 生成输入文件名
525
+ */
526
+ function generateInputFilename(file, index) {
527
+ const hash = createHash('md5').update(Buffer.from(file.data)).digest('hex').slice(0, 8);
528
+ const ext = getExtensionFromMime(file.mime);
529
+ const timestamp = Date.now();
530
+ return `media-luna/input/${timestamp}-${index}-${hash}${ext}`;
531
+ }
532
+ /**
533
+ * 从 MIME 类型获取扩展名
534
+ */
535
+ function getExtensionFromMime(mime) {
536
+ const mimeMap = {
537
+ 'image/png': '.png',
538
+ 'image/jpeg': '.jpg',
539
+ 'image/gif': '.gif',
540
+ 'image/webp': '.webp',
541
+ 'video/mp4': '.mp4',
542
+ 'video/webm': '.webm',
543
+ 'audio/mp3': '.mp3',
544
+ 'audio/mpeg': '.mp3',
545
+ 'audio/wav': '.wav',
546
+ 'audio/ogg': '.ogg',
547
+ 'application/pdf': '.pdf',
548
+ };
549
+ return mimeMap[mime] || '.bin';
550
+ }
551
+ /**
552
+ * 下载文件
553
+ */
554
+ async function downloadAsset(url) {
555
+ const resp = await fetch(url);
556
+ if (!resp.ok)
557
+ throw new Error(`下载失败: ${resp.status}`);
558
+ const arrayBuffer = await resp.arrayBuffer();
559
+ const mime = resp.headers.get('content-type') || 'application/octet-stream';
560
+ return { buffer: Buffer.from(arrayBuffer), mime };
561
+ }
562
+ /**
563
+ * 创建存储中间件
564
+ *
565
+ * 在 lifecycle-post-request 阶段将生成结果上传到外部存储
566
+ * 使用 AssetCacheService 统一处理缓存,享受数据库追踪和内容去重
567
+ */
568
+ export function createStorageMiddleware(ctx, logger) {
569
+ return {
570
+ name: 'storage',
571
+ displayName: '存储缓存',
572
+ description: '将生成结果保存到本地或外部存储(本地缓存/S3/WebDAV)',
573
+ category: 'cache',
574
+ phase: 'lifecycle-post-request',
575
+ // 依赖通过 phase 自动处理,在 request 之后执行
576
+ configFields: storageConfigFields,
577
+ configGroup: 'storage',
578
+ async execute(mctx, next) {
579
+ const config = await mctx.getMiddlewareConfig('storage');
580
+ // 如果没有输出或未配置存储后端,跳过
581
+ if (!mctx.output || mctx.output.length === 0 || !config || config.backend === 'none') {
582
+ return next();
583
+ }
584
+ // 确保 AssetCacheService 使用最新配置
585
+ ctx.mediaLuna.assetCache.setConfig(config);
586
+ const uploadedAssets = [];
587
+ const uploadLogs = [];
588
+ for (let i = 0; i < mctx.output.length; i++) {
589
+ const asset = mctx.output[i];
590
+ // 文本类型资产使用 content,不需要上传
591
+ if (asset.kind === 'text' || !asset.url) {
592
+ uploadedAssets.push(asset);
593
+ continue;
594
+ }
595
+ try {
596
+ const isBase64 = asset.url.startsWith('data:');
597
+ // 使用 AssetCacheService 统一缓存(享受数据库追踪和内容去重)
598
+ const cacheResult = await ctx.mediaLuna.assetCache.cacheAsset(asset.url);
599
+ // 替换 URL
600
+ uploadedAssets.push({
601
+ ...asset,
602
+ url: cacheResult.cachedUrl,
603
+ meta: {
604
+ ...asset.meta,
605
+ ...(isBase64 ? {} : { originalUrl: asset.url }),
606
+ storageKey: cacheResult.contentHash,
607
+ storageBackend: cacheResult.backend,
608
+ fromCache: cacheResult.fromCache
609
+ }
610
+ });
611
+ uploadLogs.push({
612
+ index: i,
613
+ originalUrl: isBase64 ? '[base64 data]' : asset.url,
614
+ newUrl: cacheResult.cachedUrl
615
+ });
616
+ logger.debug(`Cached asset ${i} to ${cacheResult.backend}: ${cacheResult.cachedUrl}${cacheResult.fromCache ? ' (from cache)' : ''}`);
617
+ }
618
+ catch (error) {
619
+ // 上传失败,保留原始资产
620
+ uploadedAssets.push(asset);
621
+ const isBase64 = asset.url.startsWith('data:');
622
+ uploadLogs.push({
623
+ index: i,
624
+ originalUrl: isBase64 ? '[base64 data]' : asset.url,
625
+ error: error instanceof Error ? error.message : String(error)
626
+ });
627
+ logger.warn(`Failed to cache asset ${i}:`, error);
628
+ }
629
+ }
630
+ // 更新输出
631
+ mctx.output = uploadedAssets;
632
+ mctx.setMiddlewareLog('storage', {
633
+ backend: config.backend,
634
+ total: mctx.output.length,
635
+ uploaded: uploadLogs.filter(l => l.newUrl).length,
636
+ failed: uploadLogs.filter(l => l.error).length,
637
+ logs: uploadLogs
638
+ });
639
+ return next();
640
+ }
641
+ };
642
+ }
643
+ /**
644
+ * 创建输入存储中间件
645
+ *
646
+ * 在 lifecycle-prepare 阶段将输入文件上传到外部存储
647
+ * 将 files 中的二进制数据替换为 URL,便于后续存储到任务记录
648
+ * 使用 AssetCacheService 统一处理缓存,享受数据库追踪和内容去重
649
+ */
650
+ export function createStorageInputMiddleware(ctx, logger) {
651
+ return {
652
+ name: 'storage-input',
653
+ displayName: '输入文件存储',
654
+ description: '将输入文件保存到本地或外部存储(本地缓存/S3/WebDAV)',
655
+ category: 'cache',
656
+ phase: 'lifecycle-prepare',
657
+ configFields: storageConfigFields,
658
+ configGroup: 'storage',
659
+ async execute(mctx, next) {
660
+ const config = await mctx.getMiddlewareConfig('storage');
661
+ // 如果没有输入文件或未配置存储后端,跳过
662
+ if (!mctx.files || mctx.files.length === 0 || !config || config.backend === 'none') {
663
+ return next();
664
+ }
665
+ // 确保 AssetCacheService 使用最新配置
666
+ ctx.mediaLuna.assetCache.setConfig(config);
667
+ const uploadLogs = [];
668
+ const uploadedUrls = [];
669
+ for (let i = 0; i < mctx.files.length; i++) {
670
+ const file = mctx.files[i];
671
+ // 跳过空数据的文件
672
+ if (!file.data || file.data.byteLength === 0) {
673
+ continue;
674
+ }
675
+ try {
676
+ // 将二进制数据转换为 data URL
677
+ const buffer = Buffer.from(file.data);
678
+ const base64 = buffer.toString('base64');
679
+ const dataUrl = `data:${file.mime};base64,${base64}`;
680
+ // 使用 AssetCacheService 统一缓存
681
+ const cacheResult = await ctx.mediaLuna.assetCache.cacheAsset(dataUrl);
682
+ uploadedUrls.push(cacheResult.cachedUrl);
683
+ uploadLogs.push({
684
+ index: i,
685
+ filename: file.filename,
686
+ url: cacheResult.cachedUrl
687
+ });
688
+ logger.debug(`Cached input file ${i} to ${cacheResult.backend}: ${cacheResult.cachedUrl}${cacheResult.fromCache ? ' (from cache)' : ''}`);
689
+ }
690
+ catch (error) {
691
+ uploadLogs.push({
692
+ index: i,
693
+ filename: file.filename,
694
+ error: error instanceof Error ? error.message : String(error)
695
+ });
696
+ logger.warn(`Failed to cache input file ${i}:`, error);
697
+ }
698
+ }
699
+ // 将上传的 URL 存储到 store 中,供 task-recorder 使用
700
+ if (uploadedUrls.length > 0) {
701
+ mctx.store.set('inputFileUrls', uploadedUrls);
702
+ }
703
+ mctx.setMiddlewareLog('storage-input', {
704
+ backend: config.backend,
705
+ total: mctx.files.length,
706
+ uploaded: uploadLogs.filter(l => l.url).length,
707
+ failed: uploadLogs.filter(l => l.error).length,
708
+ urls: uploadedUrls,
709
+ logs: uploadLogs
710
+ });
711
+ return next();
712
+ }
713
+ };
714
+ }
715
+ //# sourceMappingURL=storage.js.map