libre-webui 0.16.1 → 0.18.0

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 (314) hide show
  1. package/README.md +232 -154
  2. package/backend/dist/db.d.ts.map +1 -1
  3. package/backend/dist/db.js +155 -6
  4. package/backend/dist/db.js.map +1 -1
  5. package/backend/dist/index.d.ts.map +1 -1
  6. package/backend/dist/index.js +17 -10
  7. package/backend/dist/index.js.map +1 -1
  8. package/backend/dist/middleware/auth.d.ts.map +1 -1
  9. package/backend/dist/middleware/auth.js +35 -3
  10. package/backend/dist/middleware/auth.js.map +1 -1
  11. package/backend/dist/models/userModel.d.ts +23 -0
  12. package/backend/dist/models/userModel.d.ts.map +1 -1
  13. package/backend/dist/models/userModel.js +89 -24
  14. package/backend/dist/models/userModel.js.map +1 -1
  15. package/backend/dist/routes/agentCli.d.ts +3 -0
  16. package/backend/dist/routes/agentCli.d.ts.map +1 -0
  17. package/backend/dist/routes/agentCli.js +35 -0
  18. package/backend/dist/routes/agentCli.js.map +1 -0
  19. package/backend/dist/routes/auth.d.ts.map +1 -1
  20. package/backend/dist/routes/auth.js +46 -33
  21. package/backend/dist/routes/auth.js.map +1 -1
  22. package/backend/dist/routes/chat.d.ts.map +1 -1
  23. package/backend/dist/routes/chat.js +30 -1
  24. package/backend/dist/routes/chat.js.map +1 -1
  25. package/backend/dist/routes/documents.d.ts.map +1 -1
  26. package/backend/dist/routes/documents.js +49 -41
  27. package/backend/dist/routes/documents.js.map +1 -1
  28. package/backend/dist/routes/embeddings.js +2 -2
  29. package/backend/dist/routes/embeddings.js.map +1 -1
  30. package/backend/dist/routes/huggingfaceHub.d.ts.map +1 -1
  31. package/backend/dist/routes/huggingfaceHub.js +3 -1
  32. package/backend/dist/routes/huggingfaceHub.js.map +1 -1
  33. package/backend/dist/routes/imageGen.d.ts.map +1 -1
  34. package/backend/dist/routes/imageGen.js +2 -0
  35. package/backend/dist/routes/imageGen.js.map +1 -1
  36. package/backend/dist/routes/media.d.ts +3 -0
  37. package/backend/dist/routes/media.d.ts.map +1 -0
  38. package/backend/dist/routes/media.js +429 -0
  39. package/backend/dist/routes/media.js.map +1 -0
  40. package/backend/dist/routes/ollama.d.ts.map +1 -1
  41. package/backend/dist/routes/ollama.js +15 -83
  42. package/backend/dist/routes/ollama.js.map +1 -1
  43. package/backend/dist/routes/personas.d.ts.map +1 -1
  44. package/backend/dist/routes/personas.js +2 -0
  45. package/backend/dist/routes/personas.js.map +1 -1
  46. package/backend/dist/routes/plugins.d.ts.map +1 -1
  47. package/backend/dist/routes/plugins.js +28 -0
  48. package/backend/dist/routes/plugins.js.map +1 -1
  49. package/backend/dist/routes/systemDiagnostics.d.ts +3 -0
  50. package/backend/dist/routes/systemDiagnostics.d.ts.map +1 -0
  51. package/backend/dist/routes/systemDiagnostics.js +49 -0
  52. package/backend/dist/routes/systemDiagnostics.js.map +1 -0
  53. package/backend/dist/routes/tts.d.ts.map +1 -1
  54. package/backend/dist/routes/tts.js +4 -0
  55. package/backend/dist/routes/tts.js.map +1 -1
  56. package/backend/dist/routes/users.d.ts.map +1 -1
  57. package/backend/dist/routes/users.js +58 -0
  58. package/backend/dist/routes/users.js.map +1 -1
  59. package/backend/dist/routes/work.d.ts.map +1 -1
  60. package/backend/dist/routes/work.js +107 -2
  61. package/backend/dist/routes/work.js.map +1 -1
  62. package/backend/dist/services/agentCliService.d.ts +30 -0
  63. package/backend/dist/services/agentCliService.d.ts.map +1 -0
  64. package/backend/dist/services/agentCliService.js +328 -0
  65. package/backend/dist/services/agentCliService.js.map +1 -0
  66. package/backend/dist/services/authService.d.ts +15 -9
  67. package/backend/dist/services/authService.d.ts.map +1 -1
  68. package/backend/dist/services/authService.js +34 -29
  69. package/backend/dist/services/authService.js.map +1 -1
  70. package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
  71. package/backend/dist/services/chatGenerationService.js +19 -1
  72. package/backend/dist/services/chatGenerationService.js.map +1 -1
  73. package/backend/dist/services/chatRequestService.d.ts +8 -2
  74. package/backend/dist/services/chatRequestService.d.ts.map +1 -1
  75. package/backend/dist/services/chatRequestService.js +30 -3
  76. package/backend/dist/services/chatRequestService.js.map +1 -1
  77. package/backend/dist/services/documentService.d.ts +11 -10
  78. package/backend/dist/services/documentService.d.ts.map +1 -1
  79. package/backend/dist/services/documentService.js +62 -54
  80. package/backend/dist/services/documentService.js.map +1 -1
  81. package/backend/dist/services/encryptionService.d.ts.map +1 -1
  82. package/backend/dist/services/encryptionService.js +18 -8
  83. package/backend/dist/services/encryptionService.js.map +1 -1
  84. package/backend/dist/services/galleryService.d.ts +23 -1
  85. package/backend/dist/services/galleryService.d.ts.map +1 -1
  86. package/backend/dist/services/galleryService.js +125 -8
  87. package/backend/dist/services/galleryService.js.map +1 -1
  88. package/backend/dist/services/mediaGenerationJobService.d.ts +25 -0
  89. package/backend/dist/services/mediaGenerationJobService.d.ts.map +1 -0
  90. package/backend/dist/services/mediaGenerationJobService.js +82 -0
  91. package/backend/dist/services/mediaGenerationJobService.js.map +1 -0
  92. package/backend/dist/services/pluginAudioGenerationService.d.ts +34 -0
  93. package/backend/dist/services/pluginAudioGenerationService.d.ts.map +1 -0
  94. package/backend/dist/services/pluginAudioGenerationService.js +211 -0
  95. package/backend/dist/services/pluginAudioGenerationService.js.map +1 -0
  96. package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
  97. package/backend/dist/services/pluginCapabilityRegistryService.js +6 -0
  98. package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
  99. package/backend/dist/services/pluginEmbeddingService.d.ts +2 -0
  100. package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
  101. package/backend/dist/services/pluginEmbeddingService.js +66 -35
  102. package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
  103. package/backend/dist/services/pluginImageGenerationService.d.ts +2 -0
  104. package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
  105. package/backend/dist/services/pluginImageGenerationService.js +63 -38
  106. package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
  107. package/backend/dist/services/pluginService.d.ts +38 -1
  108. package/backend/dist/services/pluginService.d.ts.map +1 -1
  109. package/backend/dist/services/pluginService.js +390 -69
  110. package/backend/dist/services/pluginService.js.map +1 -1
  111. package/backend/dist/services/pluginTTSService.d.ts +2 -0
  112. package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
  113. package/backend/dist/services/pluginTTSService.js +27 -2
  114. package/backend/dist/services/pluginTTSService.js.map +1 -1
  115. package/backend/dist/services/pluginUsageService.d.ts +82 -0
  116. package/backend/dist/services/pluginUsageService.d.ts.map +1 -0
  117. package/backend/dist/services/pluginUsageService.js +238 -0
  118. package/backend/dist/services/pluginUsageService.js.map +1 -0
  119. package/backend/dist/services/pluginVideoGenerationService.d.ts +45 -0
  120. package/backend/dist/services/pluginVideoGenerationService.d.ts.map +1 -0
  121. package/backend/dist/services/pluginVideoGenerationService.js +198 -0
  122. package/backend/dist/services/pluginVideoGenerationService.js.map +1 -0
  123. package/backend/dist/services/preferencesService.d.ts.map +1 -1
  124. package/backend/dist/services/preferencesService.js +15 -1
  125. package/backend/dist/services/preferencesService.js.map +1 -1
  126. package/backend/dist/services/registrationPolicy.d.ts +5 -0
  127. package/backend/dist/services/registrationPolicy.d.ts.map +1 -0
  128. package/backend/dist/services/registrationPolicy.js +21 -0
  129. package/backend/dist/services/registrationPolicy.js.map +1 -0
  130. package/backend/dist/services/simpleGitHubOAuth.d.ts.map +1 -1
  131. package/backend/dist/services/simpleGitHubOAuth.js +8 -12
  132. package/backend/dist/services/simpleGitHubOAuth.js.map +1 -1
  133. package/backend/dist/services/simpleHuggingFaceOAuth.d.ts.map +1 -1
  134. package/backend/dist/services/simpleHuggingFaceOAuth.js +7 -12
  135. package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -1
  136. package/backend/dist/services/systemDiagnosticsService.d.ts +117 -0
  137. package/backend/dist/services/systemDiagnosticsService.d.ts.map +1 -0
  138. package/backend/dist/services/systemDiagnosticsService.js +326 -0
  139. package/backend/dist/services/systemDiagnosticsService.js.map +1 -0
  140. package/backend/dist/services/turnstileService.d.ts +2 -1
  141. package/backend/dist/services/turnstileService.d.ts.map +1 -1
  142. package/backend/dist/services/turnstileService.js +28 -2
  143. package/backend/dist/services/turnstileService.js.map +1 -1
  144. package/backend/dist/services/workAgentGuidance.js +1 -1
  145. package/backend/dist/services/workAgentGuidance.js.map +1 -1
  146. package/backend/dist/services/workAgentService.d.ts.map +1 -1
  147. package/backend/dist/services/workAgentService.js +37 -0
  148. package/backend/dist/services/workAgentService.js.map +1 -1
  149. package/backend/dist/services/workHostWorkspaceService.d.ts +22 -0
  150. package/backend/dist/services/workHostWorkspaceService.d.ts.map +1 -0
  151. package/backend/dist/services/workHostWorkspaceService.js +136 -0
  152. package/backend/dist/services/workHostWorkspaceService.js.map +1 -0
  153. package/backend/dist/services/workModelProviderService.d.ts +3 -0
  154. package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
  155. package/backend/dist/services/workModelProviderService.js +37 -4
  156. package/backend/dist/services/workModelProviderService.js.map +1 -1
  157. package/backend/dist/services/workPreviewProxyService.d.ts +27 -0
  158. package/backend/dist/services/workPreviewProxyService.d.ts.map +1 -0
  159. package/backend/dist/services/workPreviewProxyService.js +514 -0
  160. package/backend/dist/services/workPreviewProxyService.js.map +1 -0
  161. package/backend/dist/services/workRuntimeService.d.ts +65 -3
  162. package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
  163. package/backend/dist/services/workRuntimeService.js +536 -14
  164. package/backend/dist/services/workRuntimeService.js.map +1 -1
  165. package/backend/dist/services/workTaskService.d.ts +3 -3
  166. package/backend/dist/services/workTaskService.d.ts.map +1 -1
  167. package/backend/dist/services/workTaskService.js +10 -6
  168. package/backend/dist/services/workTaskService.js.map +1 -1
  169. package/backend/dist/services/workTerminalService.d.ts +46 -0
  170. package/backend/dist/services/workTerminalService.d.ts.map +1 -0
  171. package/backend/dist/services/workTerminalService.js +241 -0
  172. package/backend/dist/services/workTerminalService.js.map +1 -0
  173. package/backend/dist/storage.d.ts.map +1 -1
  174. package/backend/dist/storage.js +3 -3
  175. package/backend/dist/storage.js.map +1 -1
  176. package/backend/dist/types/index.d.ts +78 -2
  177. package/backend/dist/types/index.d.ts.map +1 -1
  178. package/backend/dist/types/index.js.map +1 -1
  179. package/backend/dist/types/work.d.ts +53 -0
  180. package/backend/dist/types/work.d.ts.map +1 -1
  181. package/backend/dist/utils/chatDocumentContext.d.ts +1 -1
  182. package/backend/dist/utils/chatDocumentContext.d.ts.map +1 -1
  183. package/backend/dist/utils/chatDocumentContext.js +4 -4
  184. package/backend/dist/utils/chatDocumentContext.js.map +1 -1
  185. package/backend/dist/utils/chatProviderSelection.d.ts.map +1 -1
  186. package/backend/dist/utils/chatProviderSelection.js +7 -5
  187. package/backend/dist/utils/chatProviderSelection.js.map +1 -1
  188. package/backend/dist/utils/pluginDefinitionTrust.js +1 -1
  189. package/backend/dist/utils/pluginValidation.d.ts +3 -2
  190. package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
  191. package/backend/dist/utils/pluginValidation.js +30 -2
  192. package/backend/dist/utils/pluginValidation.js.map +1 -1
  193. package/backend/dist/utils/workGit.d.ts +14 -0
  194. package/backend/dist/utils/workGit.d.ts.map +1 -0
  195. package/backend/dist/utils/workGit.js +207 -0
  196. package/backend/dist/utils/workGit.js.map +1 -0
  197. package/backend/dist/websocketServer.d.ts +1 -0
  198. package/backend/dist/websocketServer.d.ts.map +1 -1
  199. package/backend/dist/websocketServer.js +156 -35
  200. package/backend/dist/websocketServer.js.map +1 -1
  201. package/backend/dist/workTerminalServer.d.ts +17 -0
  202. package/backend/dist/workTerminalServer.d.ts.map +1 -0
  203. package/backend/dist/workTerminalServer.js +226 -0
  204. package/backend/dist/workTerminalServer.js.map +1 -0
  205. package/backend/package.json +1 -1
  206. package/frontend/dist/assets/index-ChhWhug2.css +1 -0
  207. package/frontend/dist/assets/index-CmZntyR1.js +3 -0
  208. package/frontend/dist/assets/xterm-CmMoOwwu.css +1 -0
  209. package/frontend/dist/index.html +28 -6
  210. package/frontend/dist/js/ArtifactContainer-CBAbdoIJ.js +1 -0
  211. package/frontend/dist/js/{ArtifactDemoPage-CWDhGWrz.js → ArtifactDemoPage-BWN0MWCx.js} +1 -1
  212. package/frontend/dist/js/ArtifactSlideOutPanel-D-AvYkfk.js +1 -0
  213. package/frontend/dist/js/{Button-DBk-AREB.js → Button-CRwzOaDZ.js} +1 -1
  214. package/frontend/dist/js/ChatPage-w2FkF_fE.js +16 -0
  215. package/frontend/dist/js/FirstTimeSetup-CzBxl7UH.js +1 -0
  216. package/frontend/dist/js/GalleryPage-Cv8pniRW.js +1 -0
  217. package/frontend/dist/js/HomePage-Vyj4ndU4.js +1 -0
  218. package/frontend/dist/js/LibreClawPage-CYhLgQB-.js +1 -0
  219. package/frontend/dist/js/{ModelManagerModals-DltRprHU.js → ModelManagerModals-C2rwHd01.js} +1 -1
  220. package/frontend/dist/js/ModelSelector-D7kDjZV9.js +1 -0
  221. package/frontend/dist/js/ModelsPage-BnUddkrs.js +2 -0
  222. package/frontend/dist/js/{PersonasPage-C2pqDsWA.js → PersonasPage-BL5XlrEm.js} +2 -2
  223. package/frontend/dist/js/PluginUsagePage-BXqweCCs.js +1 -0
  224. package/frontend/dist/js/RichMessageContent-nAEaPTpH.js +3 -0
  225. package/frontend/dist/js/SettingsModal-DZYCI5-y.js +1 -0
  226. package/frontend/dist/js/SystemPage-jdHYfn9A.js +1 -0
  227. package/frontend/dist/js/UserManagementPage-BpOnt6os.js +1 -0
  228. package/frontend/dist/js/WorkPage-DAp1T1dl.js +5 -0
  229. package/frontend/dist/js/addon-fit-Cj0_dfHF.js +1 -0
  230. package/frontend/dist/js/api-BCqWXjZI.js +19 -0
  231. package/frontend/dist/js/appStore-CDM6V5ny.js +2 -0
  232. package/frontend/dist/js/ar-DS8gs8WK.js +2 -0
  233. package/frontend/dist/js/authStore-Bl5ofD_h.js +4 -0
  234. package/frontend/dist/js/bn-CrMPJwTR.js +2 -0
  235. package/frontend/dist/js/cs-BL116Ezu.js +2 -0
  236. package/frontend/dist/js/da-TDNaKzqy.js +2 -0
  237. package/frontend/dist/js/de-DkIqdAB5.js +2 -0
  238. package/frontend/dist/js/es-CHRXt6Fd.js +2 -0
  239. package/frontend/dist/js/{estree-BRklD62a.js → estree-BFya-bSu.js} +1 -1
  240. package/frontend/dist/js/fr-8715yUKq.js +2 -0
  241. package/frontend/dist/js/hi-C2O08SBU.js +2 -0
  242. package/frontend/dist/js/{html-BgGIAGmn.js → html-DJot0Wwf.js} +1 -1
  243. package/frontend/dist/js/id-Dq7UXUEV.js +2 -0
  244. package/frontend/dist/js/is-B3dbbhSl.js +2 -0
  245. package/frontend/dist/js/it-CLSuu2K7.js +2 -0
  246. package/frontend/dist/js/ja-CthrqyCR.js +2 -0
  247. package/frontend/dist/js/ko-BJvFDJ82.js +2 -0
  248. package/frontend/dist/js/{markdown-CM2nBJJi.js → markdown-CXwWsPYG.js} +1 -1
  249. package/frontend/dist/js/ms-QV0202Mj.js +2 -0
  250. package/frontend/dist/js/nl-Dob1m1pV.js +2 -0
  251. package/frontend/dist/js/pl-urfOKnYI.js +2 -0
  252. package/frontend/dist/js/pt-D52Xkpi0.js +2 -0
  253. package/frontend/dist/js/ru-CwnW9Xe2.js +2 -0
  254. package/frontend/dist/js/{standalone-CUBo-NGt.js → standalone-C0NjJpWr.js} +1 -1
  255. package/frontend/dist/js/sv-BNclj-Fo.js +2 -0
  256. package/frontend/dist/js/th-BlQ4PL57.js +2 -0
  257. package/frontend/dist/js/tr-B80aZ1px.js +2 -0
  258. package/frontend/dist/js/{typescript-Dcy9qxSB.js → typescript-d0TUM2-0.js} +1 -1
  259. package/frontend/dist/js/ui-vendor-ChfdHf5M.js +177 -0
  260. package/frontend/dist/js/uk-DZuuaI56.js +2 -0
  261. package/frontend/dist/js/utils-DmZD5uA3.js +1 -0
  262. package/frontend/dist/js/vi-Bg42fPfF.js +2 -0
  263. package/frontend/dist/js/work-DVgm81bJ.js +1 -0
  264. package/frontend/dist/js/xterm-DKl1QLiw.js +7 -0
  265. package/frontend/dist/js/zh-BSt87zs6.js +2 -0
  266. package/package.json +3 -3
  267. package/plugins/openrouter.json +89 -0
  268. package/backend/dist/services/systemSettingsService.d.ts +0 -12
  269. package/backend/dist/services/systemSettingsService.d.ts.map +0 -1
  270. package/backend/dist/services/systemSettingsService.js +0 -70
  271. package/backend/dist/services/systemSettingsService.js.map +0 -1
  272. package/frontend/dist/assets/index-BVgyQN3z.js +0 -5
  273. package/frontend/dist/assets/index-Dme2Ozol.css +0 -1
  274. package/frontend/dist/js/ArtifactContainer-CbMAYwvr.js +0 -1
  275. package/frontend/dist/js/ArtifactSlideOutPanel-CzUpDM59.js +0 -1
  276. package/frontend/dist/js/ChatPage-D0fdzy7a.js +0 -16
  277. package/frontend/dist/js/FirstTimeSetup-CfnOmy9w.js +0 -1
  278. package/frontend/dist/js/GalleryPage-CMkCur9v.js +0 -1
  279. package/frontend/dist/js/LibreClawPage-CHEfny1k.js +0 -1
  280. package/frontend/dist/js/ModelSelector-COnlNsVM.js +0 -1
  281. package/frontend/dist/js/ModelsPage-nxheiYJp.js +0 -2
  282. package/frontend/dist/js/RichMessageContent-Cz9y-bgl.js +0 -3
  283. package/frontend/dist/js/SettingsModal-B6Se68Hd.js +0 -1
  284. package/frontend/dist/js/UserManagementPage-DQeL-Twp.js +0 -1
  285. package/frontend/dist/js/WorkPage-AcZMp8OB.js +0 -2
  286. package/frontend/dist/js/api-Fi-lJlfu.js +0 -19
  287. package/frontend/dist/js/ar-KceI0PfT.js +0 -2
  288. package/frontend/dist/js/bn-DsKo2dzS.js +0 -2
  289. package/frontend/dist/js/cs-6UKhKj0A.js +0 -2
  290. package/frontend/dist/js/da-CJgZ3YuL.js +0 -2
  291. package/frontend/dist/js/de-BZAmOuCT.js +0 -2
  292. package/frontend/dist/js/es-CD4u7no9.js +0 -2
  293. package/frontend/dist/js/fr-Cou2jOS3.js +0 -2
  294. package/frontend/dist/js/hi-ZxkbNCyB.js +0 -2
  295. package/frontend/dist/js/id-DT9CqaWQ.js +0 -2
  296. package/frontend/dist/js/is-BWSbAIoq.js +0 -2
  297. package/frontend/dist/js/it-CdNoTXm3.js +0 -2
  298. package/frontend/dist/js/ja-CIuQg0xv.js +0 -2
  299. package/frontend/dist/js/ko-BWRUjDOH.js +0 -2
  300. package/frontend/dist/js/ms-gJstIj2a.js +0 -2
  301. package/frontend/dist/js/nl-CydjVNUw.js +0 -2
  302. package/frontend/dist/js/pl-DPN9mAa5.js +0 -2
  303. package/frontend/dist/js/pt-MRXGqIjQ.js +0 -2
  304. package/frontend/dist/js/ru-CvQ9GkJF.js +0 -2
  305. package/frontend/dist/js/sv-BxS2fvhU.js +0 -2
  306. package/frontend/dist/js/th-DMxyn6e4.js +0 -2
  307. package/frontend/dist/js/tr-BTPldUaA.js +0 -2
  308. package/frontend/dist/js/ui-vendor-CAFEDSaO.js +0 -177
  309. package/frontend/dist/js/uk-BGxZOKgp.js +0 -2
  310. package/frontend/dist/js/useBaseQuery-CFTidwqz.js +0 -1
  311. package/frontend/dist/js/useQuery-UsSBfWzs.js +0 -1
  312. package/frontend/dist/js/utils-pTFqSV8c.js +0 -1
  313. package/frontend/dist/js/vi-82JkwFsQ.js +0 -2
  314. package/frontend/dist/js/zh-Bxxfwci3.js +0 -2
@@ -0,0 +1,429 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ */
7
+ import express from 'express';
8
+ import rateLimit from 'express-rate-limit';
9
+ import { authenticate } from '../middleware/auth.js';
10
+ import galleryService from '../services/galleryService.js';
11
+ import mediaGenerationJobService from '../services/mediaGenerationJobService.js';
12
+ import pluginService from '../services/pluginService.js';
13
+ import { createLogger } from '../utils/logger.js';
14
+ const logger = createLogger('routes:media');
15
+ const router = express.Router();
16
+ const generationRateLimiter = rateLimit({
17
+ windowMs: 60000,
18
+ max: 10,
19
+ standardHeaders: true,
20
+ legacyHeaders: false,
21
+ });
22
+ const pollingRateLimiter = rateLimit({
23
+ windowMs: 60000,
24
+ max: 60,
25
+ standardHeaders: true,
26
+ legacyHeaders: false,
27
+ });
28
+ const galleryRateLimiter = rateLimit({
29
+ windowMs: 60000,
30
+ max: 120,
31
+ standardHeaders: true,
32
+ legacyHeaders: false,
33
+ });
34
+ // Umbrella limit ahead of authentication; per-route limiters below stay tighter.
35
+ const routerRateLimiter = rateLimit({
36
+ windowMs: 60000,
37
+ max: 240,
38
+ standardHeaders: true,
39
+ legacyHeaders: false,
40
+ });
41
+ router.use(routerRateLimiter);
42
+ router.use(authenticate);
43
+ function userId(req) {
44
+ if (!req.user)
45
+ throw new Error('Authenticated user context is required');
46
+ return req.user.userId;
47
+ }
48
+ router.get('/models', async (req, res) => {
49
+ try {
50
+ const id = userId(req);
51
+ await Promise.all([
52
+ pluginService.refreshStaleCapabilityModels('video', id),
53
+ pluginService.refreshStaleCapabilityModels('tts', id),
54
+ pluginService.refreshStaleCapabilityModels('audio', id),
55
+ ]);
56
+ res.json({
57
+ success: true,
58
+ data: {
59
+ video: pluginService.getAvailableVideoGenModels(id),
60
+ audio: [
61
+ ...pluginService
62
+ .getAvailableAudioGenModels(id)
63
+ .map(model => ({ ...model, mode: 'sound' })),
64
+ ...pluginService
65
+ .getAvailableTTSModels(id)
66
+ .map(model => ({ ...model, mode: 'speech' })),
67
+ ],
68
+ },
69
+ });
70
+ }
71
+ catch (error) {
72
+ logger.error('Failed to load media generation models:', error);
73
+ res.status(500).json({
74
+ success: false,
75
+ message: 'Failed to load media generation models',
76
+ });
77
+ }
78
+ });
79
+ router.post('/audio/generate', generationRateLimiter, async (req, res) => {
80
+ try {
81
+ const { model, pluginId, input, voice, response_format, speed } = req.body;
82
+ if (typeof model !== 'string' ||
83
+ typeof pluginId !== 'string' ||
84
+ typeof input !== 'string' ||
85
+ input.trim().length === 0) {
86
+ res.status(400).json({
87
+ success: false,
88
+ message: 'model, pluginId, and input are required',
89
+ });
90
+ return;
91
+ }
92
+ const id = userId(req);
93
+ const format = isAudioFormat(response_format) ? response_format : 'mp3';
94
+ const audio = await pluginService.executeTTSRequest(model, input.trim(), {
95
+ pluginId,
96
+ userId: id,
97
+ ...(typeof voice === 'string' && voice ? { voice } : {}),
98
+ ...(typeof speed === 'number' ? { speed } : {}),
99
+ response_format: format,
100
+ });
101
+ const mimeType = audioMimeType(format);
102
+ const mediaData = `data:${mimeType};base64,${audio.toString('base64')}`;
103
+ const saved = galleryService.saveMedia(id, {
104
+ kind: 'audio',
105
+ prompt: input.trim(),
106
+ model,
107
+ pluginId,
108
+ mediaData,
109
+ mimeType,
110
+ metadata: { voice: voice || null, format },
111
+ });
112
+ if (!saved)
113
+ throw new Error('Failed to save generated audio');
114
+ res.json({ success: true, data: publicMedia(saved) });
115
+ }
116
+ catch (error) {
117
+ logger.error('Audio generation failed:', error);
118
+ res.status(500).json({
119
+ success: false,
120
+ message: error instanceof Error ? error.message : 'Audio generation failed',
121
+ });
122
+ }
123
+ });
124
+ router.post('/sound/generate', generationRateLimiter, async (req, res) => {
125
+ try {
126
+ const { model, pluginId, prompt, voice, format } = req.body;
127
+ if (typeof model !== 'string' ||
128
+ typeof pluginId !== 'string' ||
129
+ typeof prompt !== 'string' ||
130
+ prompt.trim().length === 0) {
131
+ res.status(400).json({
132
+ success: false,
133
+ message: 'model, pluginId, and prompt are required',
134
+ });
135
+ return;
136
+ }
137
+ const id = userId(req);
138
+ const generated = await pluginService.executeAudioGenRequest(model, prompt.trim(), {
139
+ pluginId,
140
+ userId: id,
141
+ ...(typeof voice === 'string' && voice ? { voice } : {}),
142
+ ...(isGeneratedAudioFormat(format) ? { format } : {}),
143
+ });
144
+ const mediaData = `data:${generated.mimeType};base64,${generated.audio.toString('base64')}`;
145
+ const saved = galleryService.saveMedia(id, {
146
+ kind: 'audio',
147
+ prompt: prompt.trim(),
148
+ model,
149
+ pluginId,
150
+ mediaData,
151
+ mimeType: generated.mimeType,
152
+ metadata: {
153
+ mode: 'sound',
154
+ voice: voice || null,
155
+ format: format || null,
156
+ transcript: generated.transcript || null,
157
+ },
158
+ });
159
+ if (!saved)
160
+ throw new Error('Failed to save generated audio');
161
+ res.json({ success: true, data: publicMedia(saved) });
162
+ }
163
+ catch (error) {
164
+ logger.error('Audio generation failed:', error);
165
+ res.status(500).json({
166
+ success: false,
167
+ message: error instanceof Error ? error.message : 'Audio generation failed',
168
+ });
169
+ }
170
+ });
171
+ router.post('/video/generate', generationRateLimiter, async (req, res) => {
172
+ try {
173
+ const { model, pluginId, prompt, duration, resolution, aspect_ratio, generate_audio, } = req.body;
174
+ if (typeof model !== 'string' ||
175
+ typeof pluginId !== 'string' ||
176
+ typeof prompt !== 'string' ||
177
+ prompt.trim().length === 0) {
178
+ res.status(400).json({
179
+ success: false,
180
+ message: 'model, pluginId, and prompt are required',
181
+ });
182
+ return;
183
+ }
184
+ const id = userId(req);
185
+ const options = {
186
+ ...(Number.isInteger(duration) && duration > 0 ? { duration } : {}),
187
+ ...(typeof resolution === 'string' && resolution ? { resolution } : {}),
188
+ ...(typeof aspect_ratio === 'string' && aspect_ratio
189
+ ? { aspectRatio: aspect_ratio }
190
+ : {}),
191
+ ...(typeof generate_audio === 'boolean'
192
+ ? { generateAudio: generate_audio }
193
+ : {}),
194
+ };
195
+ const submitted = await pluginService.submitVideoGenRequest(model, prompt.trim(), { pluginId, userId: id, ...options });
196
+ const job = mediaGenerationJobService.create(id, {
197
+ providerJobId: submitted.providerJobId,
198
+ pluginId,
199
+ model,
200
+ prompt: prompt.trim(),
201
+ options,
202
+ });
203
+ res.status(202).json({ success: true, data: publicJob(job) });
204
+ }
205
+ catch (error) {
206
+ logger.error('Video generation submission failed:', error);
207
+ res.status(500).json({
208
+ success: false,
209
+ message: error instanceof Error ? error.message : 'Video generation failed',
210
+ });
211
+ }
212
+ });
213
+ router.get('/video/jobs/:jobId', pollingRateLimiter, async (req, res) => {
214
+ try {
215
+ const id = userId(req);
216
+ const jobId = Array.isArray(req.params.jobId)
217
+ ? req.params.jobId[0]
218
+ : req.params.jobId;
219
+ const job = mediaGenerationJobService.get(jobId, id);
220
+ if (!job) {
221
+ res
222
+ .status(404)
223
+ .json({ success: false, message: 'Video job not found' });
224
+ return;
225
+ }
226
+ if (job.status === 'completed') {
227
+ res.json({
228
+ success: true,
229
+ data: {
230
+ ...publicJob(job),
231
+ media: publicMedia(galleryService.getMediaItem(job.galleryId, id)),
232
+ },
233
+ });
234
+ return;
235
+ }
236
+ if (job.status === 'failed') {
237
+ res.json({ success: true, data: publicJob(job) });
238
+ return;
239
+ }
240
+ const status = await pluginService.pollVideoGenRequest(job.model, job.providerJobId, job.pluginId, id);
241
+ if (status.status === 'failed') {
242
+ mediaGenerationJobService.update(job.id, id, 'failed', {
243
+ error: status.error || 'Video provider reported failure',
244
+ });
245
+ res.json({
246
+ success: true,
247
+ data: { ...publicJob(job), status: 'failed', error: status.error },
248
+ });
249
+ return;
250
+ }
251
+ if (status.status !== 'completed') {
252
+ mediaGenerationJobService.update(job.id, id, status.status);
253
+ res.json({
254
+ success: true,
255
+ data: { ...publicJob(job), status: status.status },
256
+ });
257
+ return;
258
+ }
259
+ const downloaded = await pluginService.downloadVideoGenResult(job.model, job.providerJobId, job.pluginId, id);
260
+ const media = galleryService.saveMedia(id, {
261
+ kind: 'video',
262
+ prompt: job.prompt,
263
+ model: job.model,
264
+ pluginId: job.pluginId,
265
+ mediaData: `data:${downloaded.mimeType};base64,${downloaded.video.toString('base64')}`,
266
+ mimeType: downloaded.mimeType,
267
+ metadata: { ...job.options, usage: status.usage || null },
268
+ });
269
+ if (!media)
270
+ throw new Error('Failed to save generated video');
271
+ mediaGenerationJobService.update(job.id, id, 'completed', {
272
+ galleryId: media.id,
273
+ });
274
+ res.json({
275
+ success: true,
276
+ data: {
277
+ ...publicJob(job),
278
+ status: 'completed',
279
+ media: publicMedia(media),
280
+ },
281
+ });
282
+ }
283
+ catch (error) {
284
+ logger.error('Video generation polling failed:', error);
285
+ res.status(500).json({
286
+ success: false,
287
+ message: error instanceof Error ? error.message : 'Video polling failed',
288
+ });
289
+ }
290
+ });
291
+ router.get('/gallery', galleryRateLimiter, (req, res) => {
292
+ const kind = req.query.kind;
293
+ if (kind && !['image', 'video', 'audio'].includes(String(kind))) {
294
+ res.status(400).json({ success: false, message: 'Invalid media kind' });
295
+ return;
296
+ }
297
+ const result = galleryService.getMedia(userId(req), {
298
+ limit: Number(req.query.limit) || 20,
299
+ offset: Number(req.query.offset) || 0,
300
+ ...(kind ? { kind: kind } : {}),
301
+ });
302
+ res.json({
303
+ success: true,
304
+ data: { ...result, media: result.media.map(publicMedia) },
305
+ });
306
+ });
307
+ router.get('/gallery/:mediaId/content', galleryRateLimiter, (req, res) => {
308
+ const mediaId = Array.isArray(req.params.mediaId)
309
+ ? req.params.mediaId[0]
310
+ : req.params.mediaId;
311
+ const item = galleryService.getMediaItem(mediaId, userId(req));
312
+ if (!item) {
313
+ res.status(404).json({ success: false, message: 'Media not found' });
314
+ return;
315
+ }
316
+ const match = /^data:([a-z0-9.+-]+\/[a-z0-9.+-]+);base64,([a-z0-9+/]+={0,2})$/i.exec(item.mediaData);
317
+ if (match) {
318
+ const encodedMimeType = match[1].toLowerCase();
319
+ if (encodedMimeType !== item.mimeType.toLowerCase() ||
320
+ !isSafeMediaMimeType(item.kind, encodedMimeType)) {
321
+ res
322
+ .status(422)
323
+ .json({ success: false, message: 'Stored media type is invalid' });
324
+ return;
325
+ }
326
+ const data = Buffer.from(match[2], 'base64');
327
+ if (data.length > 200 * 1024 * 1024) {
328
+ res.status(413).json({ success: false, message: 'Media is too large' });
329
+ return;
330
+ }
331
+ res.set({
332
+ 'Content-Type': encodedMimeType,
333
+ 'Content-Length': String(data.length),
334
+ 'Cache-Control': 'private, max-age=300',
335
+ 'Content-Security-Policy': "default-src 'none'; sandbox",
336
+ 'X-Content-Type-Options': 'nosniff',
337
+ });
338
+ res.send(data);
339
+ return;
340
+ }
341
+ try {
342
+ const url = new URL(item.mediaData);
343
+ if (item.kind !== 'image' ||
344
+ (url.protocol !== 'http:' && url.protocol !== 'https:')) {
345
+ throw new Error();
346
+ }
347
+ res.redirect(302, url.toString());
348
+ }
349
+ catch {
350
+ res
351
+ .status(422)
352
+ .json({ success: false, message: 'Stored media is invalid' });
353
+ }
354
+ });
355
+ router.delete('/gallery/:mediaId', galleryRateLimiter, (req, res) => {
356
+ const mediaId = Array.isArray(req.params.mediaId)
357
+ ? req.params.mediaId[0]
358
+ : req.params.mediaId;
359
+ const deleted = galleryService.deleteMedia(mediaId, userId(req));
360
+ if (!deleted) {
361
+ res.status(404).json({ success: false, message: 'Media not found' });
362
+ return;
363
+ }
364
+ res.json({ success: true });
365
+ });
366
+ function isSafeMediaMimeType(kind, mimeType) {
367
+ const allowed = {
368
+ image: new Set([
369
+ 'image/avif',
370
+ 'image/gif',
371
+ 'image/jpeg',
372
+ 'image/png',
373
+ 'image/webp',
374
+ ]),
375
+ video: new Set(['video/mp4', 'video/quicktime', 'video/webm']),
376
+ audio: new Set([
377
+ 'audio/aac',
378
+ 'audio/flac',
379
+ 'audio/l16',
380
+ 'audio/mpeg',
381
+ 'audio/mp4',
382
+ 'audio/ogg',
383
+ 'audio/opus',
384
+ 'audio/wav',
385
+ 'audio/webm',
386
+ ]),
387
+ };
388
+ return allowed[kind].has(mimeType.toLowerCase());
389
+ }
390
+ function audioMimeType(format) {
391
+ return ({
392
+ mp3: 'audio/mpeg',
393
+ pcm: 'audio/L16',
394
+ wav: 'audio/wav',
395
+ opus: 'audio/opus',
396
+ aac: 'audio/aac',
397
+ flac: 'audio/flac',
398
+ }[format] || 'audio/mpeg');
399
+ }
400
+ function isAudioFormat(value) {
401
+ return (typeof value === 'string' &&
402
+ ['mp3', 'opus', 'aac', 'flac', 'wav', 'pcm'].includes(value));
403
+ }
404
+ function isGeneratedAudioFormat(value) {
405
+ return (typeof value === 'string' &&
406
+ ['wav', 'mp3', 'flac', 'opus', 'pcm16'].includes(value));
407
+ }
408
+ function publicJob(job) {
409
+ return {
410
+ id: job.id,
411
+ status: job.status,
412
+ model: job.model,
413
+ pluginId: job.pluginId,
414
+ galleryId: job.galleryId,
415
+ error: job.error,
416
+ createdAt: job.createdAt,
417
+ updatedAt: job.updatedAt,
418
+ };
419
+ }
420
+ function publicMedia(media) {
421
+ return media
422
+ ? {
423
+ ...media,
424
+ mediaData: `/api/media/gallery/${encodeURIComponent(media.id)}/content`,
425
+ }
426
+ : null;
427
+ }
428
+ export default router;
429
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/routes/media.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../src/routes/ollama.ts"],"names":[],"mappings":"AA6BA,QAAA,MAAM,MAAM,4CAAmB,CAAC;AAwpBhC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../src/routes/ollama.ts"],"names":[],"mappings":"AA+BA,QAAA,MAAM,MAAM,4CAAmB,CAAC;AA0kBhC,eAAe,MAAM,CAAC"}
@@ -18,64 +18,10 @@ import express from 'express';
18
18
  import embeddingService from '../services/embeddingService.js';
19
19
  import ollamaService from '../services/ollamaService.js';
20
20
  import { getErrorMessage } from '../types/index.js';
21
- import { optionalAuth } from '../middleware/auth.js';
22
- import { authService } from '../services/authService.js';
23
- import { systemSettingsService } from '../services/systemSettingsService.js';
21
+ import { authenticate, requireAdmin, } from '../middleware/auth.js';
24
22
  import { getOllamaLibraryModels, } from '../utils/ollamaLibrary.js';
25
23
  const router = express.Router();
26
- const getRequestToken = (req) => {
27
- const authHeader = req.headers.authorization;
28
- if (authHeader && authHeader.startsWith('Bearer ')) {
29
- return authHeader.substring(7);
30
- }
31
- const queryToken = req.query.token;
32
- if (typeof queryToken === 'string' && queryToken.trim()) {
33
- return queryToken;
34
- }
35
- return null;
36
- };
37
- const checkModelPullPermission = (req) => {
38
- // When enabled, preserve current behavior.
39
- if (systemSettingsService.getAllowUserModelPull()) {
40
- return { allowed: true };
41
- }
42
- const token = getRequestToken(req);
43
- if (!token) {
44
- return {
45
- allowed: false,
46
- status: 401,
47
- error: 'Authentication required to install models',
48
- };
49
- }
50
- const payload = authService.verifyToken(token);
51
- if (!payload) {
52
- return {
53
- allowed: false,
54
- status: 401,
55
- error: 'Invalid or expired token',
56
- };
57
- }
58
- req.user = payload;
59
- if (payload.role !== 'admin') {
60
- return {
61
- allowed: false,
62
- status: 403,
63
- error: 'Only admins can install new models on this instance',
64
- };
65
- }
66
- return { allowed: true };
67
- };
68
- const enforceModelPullPermission = (req, res, next) => {
69
- const permission = checkModelPullPermission(req);
70
- if (!permission.allowed) {
71
- res.status(permission.status).json({
72
- success: false,
73
- error: permission.error,
74
- });
75
- return;
76
- }
77
- next();
78
- };
24
+ router.use(authenticate);
79
25
  // Health check
80
26
  router.get('/health', async (req, res) => {
81
27
  try {
@@ -118,7 +64,7 @@ router.get('/models', async (req, res) => {
118
64
  }
119
65
  });
120
66
  // Pull all models
121
- router.post('/models/pull-all', async (req, res) => {
67
+ router.post('/models/pull-all', requireAdmin, async (req, res) => {
122
68
  try {
123
69
  const result = await ollamaService.pullAllModels();
124
70
  res.json({
@@ -137,12 +83,11 @@ router.post('/models/pull-all', async (req, res) => {
137
83
  }
138
84
  });
139
85
  // Pull all models with streaming progress (GET for Server-Sent Events)
140
- router.get('/models/pull-all/stream', async (req, res) => {
86
+ router.get('/models/pull-all/stream', requireAdmin, async (req, res) => {
141
87
  try {
142
88
  res.setHeader('Content-Type', 'text/event-stream');
143
89
  res.setHeader('Cache-Control', 'no-cache');
144
90
  res.setHeader('Connection', 'keep-alive');
145
- res.setHeader('Access-Control-Allow-Origin', '*');
146
91
  await ollamaService.pullAllModelsStream(progress => {
147
92
  res.write(`data: ${JSON.stringify({ type: 'progress', ...progress })}\n\n`);
148
93
  }, () => {
@@ -159,7 +104,7 @@ router.get('/models/pull-all/stream', async (req, res) => {
159
104
  }
160
105
  });
161
106
  // Pull a new model (uses request body to support model names with slashes like hf.co/author/model:tag)
162
- router.post('/models/pull', enforceModelPullPermission, async (req, res) => {
107
+ router.post('/models/pull', requireAdmin, async (req, res) => {
163
108
  try {
164
109
  const modelName = req.body.name;
165
110
  if (!modelName) {
@@ -184,19 +129,8 @@ router.post('/models/pull', enforceModelPullPermission, async (req, res) => {
184
129
  });
185
130
  // Pull a model with streaming progress
186
131
  // Uses query param ?model= to support model names with slashes (e.g., hf.co/author/model)
187
- // Optional ?token= can be provided for role checks when EventSource cannot set auth headers
188
- router.get('/pull/stream', async (req, res) => {
132
+ router.get('/pull/stream', requireAdmin, async (req, res) => {
189
133
  try {
190
- const permission = checkModelPullPermission(req);
191
- if (!permission.allowed) {
192
- res.setHeader('Content-Type', 'text/event-stream');
193
- res.setHeader('Cache-Control', 'no-cache');
194
- res.setHeader('Connection', 'keep-alive');
195
- res.setHeader('Access-Control-Allow-Origin', '*');
196
- res.write(`data: ${JSON.stringify({ type: 'error', error: permission.error })}\n\n`);
197
- res.end();
198
- return;
199
- }
200
134
  const modelName = req.query.model;
201
135
  if (!modelName) {
202
136
  res
@@ -207,7 +141,6 @@ router.get('/pull/stream', async (req, res) => {
207
141
  res.setHeader('Content-Type', 'text/event-stream');
208
142
  res.setHeader('Cache-Control', 'no-cache');
209
143
  res.setHeader('Connection', 'keep-alive');
210
- res.setHeader('Access-Control-Allow-Origin', '*');
211
144
  await ollamaService.pullModelStream(modelName, progress => {
212
145
  res.write(`data: ${JSON.stringify({ type: 'progress', ...progress })}\n\n`);
213
146
  }, error => {
@@ -224,7 +157,7 @@ router.get('/pull/stream', async (req, res) => {
224
157
  }
225
158
  });
226
159
  // Delete a model (uses query param ?name= to support model names with slashes like hf.co/author/model:tag)
227
- router.delete('/models', async (req, res) => {
160
+ router.delete('/models', requireAdmin, async (req, res) => {
228
161
  try {
229
162
  const modelName = req.query.name;
230
163
  if (!modelName) {
@@ -270,7 +203,7 @@ router.get('/models/show', async (req, res) => {
270
203
  }
271
204
  });
272
205
  // Create a model
273
- router.post('/models', async (req, res) => {
206
+ router.post('/models', requireAdmin, async (req, res) => {
274
207
  try {
275
208
  await ollamaService.createModel(req.body);
276
209
  res.json({ success: true, message: 'Model created successfully' });
@@ -283,7 +216,7 @@ router.post('/models', async (req, res) => {
283
216
  }
284
217
  });
285
218
  // Copy a model
286
- router.post('/models/copy', async (req, res) => {
219
+ router.post('/models/copy', requireAdmin, async (req, res) => {
287
220
  try {
288
221
  const { source, destination } = req.body;
289
222
  await ollamaService.copyModel(source, destination);
@@ -297,7 +230,7 @@ router.post('/models/copy', async (req, res) => {
297
230
  }
298
231
  });
299
232
  // Push a model (uses request body to support model names with slashes like hf.co/author/model:tag)
300
- router.post('/models/push', async (req, res) => {
233
+ router.post('/models/push', requireAdmin, async (req, res) => {
301
234
  try {
302
235
  const modelName = req.body.name;
303
236
  if (!modelName) {
@@ -321,7 +254,7 @@ router.post('/models/push', async (req, res) => {
321
254
  }
322
255
  });
323
256
  // Generate embeddings
324
- router.post('/embed', optionalAuth, async (req, res) => {
257
+ router.post('/embed', async (req, res) => {
325
258
  try {
326
259
  const data = await embeddingService.generateEmbeddings(req.body, req.user?.userId);
327
260
  res.json({ success: true, data });
@@ -347,7 +280,7 @@ router.get('/running', async (req, res) => {
347
280
  }
348
281
  });
349
282
  // Unload a model from memory (free VRAM)
350
- router.post('/models/unload', async (req, res) => {
283
+ router.post('/models/unload', requireAdmin, async (req, res) => {
351
284
  try {
352
285
  const modelName = req.body.name;
353
286
  if (!modelName) {
@@ -371,7 +304,7 @@ router.post('/models/unload', async (req, res) => {
371
304
  }
372
305
  });
373
306
  // Unload all running models from memory
374
- router.post('/models/unload-all', async (req, res) => {
307
+ router.post('/models/unload-all', requireAdmin, async (req, res) => {
375
308
  try {
376
309
  await ollamaService.unloadAllModels();
377
310
  res.json({
@@ -418,7 +351,6 @@ router.post('/chat/stream', async (req, res) => {
418
351
  res.setHeader('Content-Type', 'text/event-stream');
419
352
  res.setHeader('Cache-Control', 'no-cache');
420
353
  res.setHeader('Connection', 'keep-alive');
421
- res.setHeader('Access-Control-Allow-Origin', '*');
422
354
  await ollamaService.generateChatStreamResponse(req.body, chunk => {
423
355
  res.write(`data: ${JSON.stringify(chunk)}\n\n`);
424
356
  }, error => {
@@ -458,7 +390,7 @@ router.head('/blobs/:digest', async (req, res) => {
458
390
  }
459
391
  });
460
392
  // Push a blob
461
- router.post('/blobs/:digest', async (req, res) => {
393
+ router.post('/blobs/:digest', requireAdmin, async (req, res) => {
462
394
  try {
463
395
  const digest = req.params.digest;
464
396
  // Only allow lowercase hex strings of length 64 (SHA256)
@@ -495,7 +427,7 @@ router.post('/blobs/:digest', async (req, res) => {
495
427
  }
496
428
  });
497
429
  // Legacy embeddings endpoint (deprecated)
498
- router.post('/embeddings', optionalAuth, async (req, res) => {
430
+ router.post('/embeddings', async (req, res) => {
499
431
  try {
500
432
  const data = await embeddingService.generateEmbeddings({
501
433
  model: req.body.model,