libre-webui 0.2.4

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 (233) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +204 -0
  3. package/backend/dist/db.d.ts +19 -0
  4. package/backend/dist/db.d.ts.map +1 -0
  5. package/backend/dist/db.js +355 -0
  6. package/backend/dist/db.js.map +1 -0
  7. package/backend/dist/env.d.ts +2 -0
  8. package/backend/dist/env.d.ts.map +1 -0
  9. package/backend/dist/env.js +22 -0
  10. package/backend/dist/env.js.map +1 -0
  11. package/backend/dist/index.d.ts +4 -0
  12. package/backend/dist/index.d.ts.map +1 -0
  13. package/backend/dist/index.js +751 -0
  14. package/backend/dist/index.js.map +1 -0
  15. package/backend/dist/middleware/auth.d.ts +18 -0
  16. package/backend/dist/middleware/auth.d.ts.map +1 -0
  17. package/backend/dist/middleware/auth.js +98 -0
  18. package/backend/dist/middleware/auth.js.map +1 -0
  19. package/backend/dist/middleware/index.d.ts +5 -0
  20. package/backend/dist/middleware/index.d.ts.map +1 -0
  21. package/backend/dist/middleware/index.js +62 -0
  22. package/backend/dist/middleware/index.js.map +1 -0
  23. package/backend/dist/models/personaModel.d.ts +37 -0
  24. package/backend/dist/models/personaModel.d.ts.map +1 -0
  25. package/backend/dist/models/personaModel.js +269 -0
  26. package/backend/dist/models/personaModel.js.map +1 -0
  27. package/backend/dist/models/userModel.d.ts +86 -0
  28. package/backend/dist/models/userModel.d.ts.map +1 -0
  29. package/backend/dist/models/userModel.js +212 -0
  30. package/backend/dist/models/userModel.js.map +1 -0
  31. package/backend/dist/routes/auth.d.ts +3 -0
  32. package/backend/dist/routes/auth.d.ts.map +1 -0
  33. package/backend/dist/routes/auth.js +389 -0
  34. package/backend/dist/routes/auth.js.map +1 -0
  35. package/backend/dist/routes/chat.d.ts +3 -0
  36. package/backend/dist/routes/chat.d.ts.map +1 -0
  37. package/backend/dist/routes/chat.js +767 -0
  38. package/backend/dist/routes/chat.js.map +1 -0
  39. package/backend/dist/routes/documents.d.ts +3 -0
  40. package/backend/dist/routes/documents.d.ts.map +1 -0
  41. package/backend/dist/routes/documents.js +244 -0
  42. package/backend/dist/routes/documents.js.map +1 -0
  43. package/backend/dist/routes/ollama.d.ts +3 -0
  44. package/backend/dist/routes/ollama.d.ts.map +1 -0
  45. package/backend/dist/routes/ollama.js +549 -0
  46. package/backend/dist/routes/ollama.js.map +1 -0
  47. package/backend/dist/routes/personas.d.ts +3 -0
  48. package/backend/dist/routes/personas.d.ts.map +1 -0
  49. package/backend/dist/routes/personas.js +505 -0
  50. package/backend/dist/routes/personas.js.map +1 -0
  51. package/backend/dist/routes/plugins.d.ts +3 -0
  52. package/backend/dist/routes/plugins.d.ts.map +1 -0
  53. package/backend/dist/routes/plugins.js +417 -0
  54. package/backend/dist/routes/plugins.js.map +1 -0
  55. package/backend/dist/routes/preferences.d.ts +3 -0
  56. package/backend/dist/routes/preferences.d.ts.map +1 -0
  57. package/backend/dist/routes/preferences.js +303 -0
  58. package/backend/dist/routes/preferences.js.map +1 -0
  59. package/backend/dist/routes/tts.d.ts +3 -0
  60. package/backend/dist/routes/tts.d.ts.map +1 -0
  61. package/backend/dist/routes/tts.js +304 -0
  62. package/backend/dist/routes/tts.js.map +1 -0
  63. package/backend/dist/routes/users.d.ts +3 -0
  64. package/backend/dist/routes/users.d.ts.map +1 -0
  65. package/backend/dist/routes/users.js +246 -0
  66. package/backend/dist/routes/users.js.map +1 -0
  67. package/backend/dist/services/authService.d.ts +51 -0
  68. package/backend/dist/services/authService.d.ts.map +1 -0
  69. package/backend/dist/services/authService.js +153 -0
  70. package/backend/dist/services/authService.js.map +1 -0
  71. package/backend/dist/services/chatService.d.ts +52 -0
  72. package/backend/dist/services/chatService.d.ts.map +1 -0
  73. package/backend/dist/services/chatService.js +645 -0
  74. package/backend/dist/services/chatService.js.map +1 -0
  75. package/backend/dist/services/documentService.d.ts +34 -0
  76. package/backend/dist/services/documentService.d.ts.map +1 -0
  77. package/backend/dist/services/documentService.js +428 -0
  78. package/backend/dist/services/documentService.js.map +1 -0
  79. package/backend/dist/services/encryptionService.d.ts +62 -0
  80. package/backend/dist/services/encryptionService.d.ts.map +1 -0
  81. package/backend/dist/services/encryptionService.js +284 -0
  82. package/backend/dist/services/encryptionService.js.map +1 -0
  83. package/backend/dist/services/memoryService.d.ts +140 -0
  84. package/backend/dist/services/memoryService.d.ts.map +1 -0
  85. package/backend/dist/services/memoryService.js +867 -0
  86. package/backend/dist/services/memoryService.js.map +1 -0
  87. package/backend/dist/services/mutationEngineService.d.ts +49 -0
  88. package/backend/dist/services/mutationEngineService.d.ts.map +1 -0
  89. package/backend/dist/services/mutationEngineService.js +432 -0
  90. package/backend/dist/services/mutationEngineService.js.map +1 -0
  91. package/backend/dist/services/ollamaService.d.ts +55 -0
  92. package/backend/dist/services/ollamaService.d.ts.map +1 -0
  93. package/backend/dist/services/ollamaService.js +450 -0
  94. package/backend/dist/services/ollamaService.js.map +1 -0
  95. package/backend/dist/services/personaService.d.ts +67 -0
  96. package/backend/dist/services/personaService.d.ts.map +1 -0
  97. package/backend/dist/services/personaService.js +373 -0
  98. package/backend/dist/services/personaService.js.map +1 -0
  99. package/backend/dist/services/pluginService.d.ts +42 -0
  100. package/backend/dist/services/pluginService.d.ts.map +1 -0
  101. package/backend/dist/services/pluginService.js +961 -0
  102. package/backend/dist/services/pluginService.js.map +1 -0
  103. package/backend/dist/services/preferencesService.d.ts +35 -0
  104. package/backend/dist/services/preferencesService.d.ts.map +1 -0
  105. package/backend/dist/services/preferencesService.js +255 -0
  106. package/backend/dist/services/preferencesService.js.map +1 -0
  107. package/backend/dist/services/simpleGitHubOAuth.d.ts +48 -0
  108. package/backend/dist/services/simpleGitHubOAuth.d.ts.map +1 -0
  109. package/backend/dist/services/simpleGitHubOAuth.js +203 -0
  110. package/backend/dist/services/simpleGitHubOAuth.js.map +1 -0
  111. package/backend/dist/services/simpleHuggingFaceOAuth.d.ts +43 -0
  112. package/backend/dist/services/simpleHuggingFaceOAuth.d.ts.map +1 -0
  113. package/backend/dist/services/simpleHuggingFaceOAuth.js +159 -0
  114. package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -0
  115. package/backend/dist/services/userService.d.ts +1 -0
  116. package/backend/dist/services/userService.d.ts.map +1 -0
  117. package/backend/dist/services/userService.js +18 -0
  118. package/backend/dist/services/userService.js.map +1 -0
  119. package/backend/dist/storage.d.ts +55 -0
  120. package/backend/dist/storage.d.ts.map +1 -0
  121. package/backend/dist/storage.js +741 -0
  122. package/backend/dist/storage.js.map +1 -0
  123. package/backend/dist/test-encryption.d.ts +2 -0
  124. package/backend/dist/test-encryption.d.ts.map +1 -0
  125. package/backend/dist/test-encryption.js +64 -0
  126. package/backend/dist/test-encryption.js.map +1 -0
  127. package/backend/dist/types/index.d.ts +523 -0
  128. package/backend/dist/types/index.d.ts.map +1 -0
  129. package/backend/dist/types/index.js +31 -0
  130. package/backend/dist/types/index.js.map +1 -0
  131. package/backend/dist/utils/generationUtils.d.ts +10 -0
  132. package/backend/dist/utils/generationUtils.d.ts.map +1 -0
  133. package/backend/dist/utils/generationUtils.js +49 -0
  134. package/backend/dist/utils/generationUtils.js.map +1 -0
  135. package/backend/dist/utils/hash.d.ts +29 -0
  136. package/backend/dist/utils/hash.d.ts.map +1 -0
  137. package/backend/dist/utils/hash.js +73 -0
  138. package/backend/dist/utils/hash.js.map +1 -0
  139. package/backend/dist/utils/jwt.d.ts +37 -0
  140. package/backend/dist/utils/jwt.d.ts.map +1 -0
  141. package/backend/dist/utils/jwt.js +86 -0
  142. package/backend/dist/utils/jwt.js.map +1 -0
  143. package/bin/cli.js +150 -0
  144. package/electron/main.js +322 -0
  145. package/frontend/dist/_redirects +1 -0
  146. package/frontend/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  147. package/frontend/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  148. package/frontend/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  149. package/frontend/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  150. package/frontend/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  151. package/frontend/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  152. package/frontend/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  153. package/frontend/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  154. package/frontend/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  155. package/frontend/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  156. package/frontend/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  157. package/frontend/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  158. package/frontend/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  159. package/frontend/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  160. package/frontend/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  161. package/frontend/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  162. package/frontend/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  163. package/frontend/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  164. package/frontend/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  165. package/frontend/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  166. package/frontend/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  167. package/frontend/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  168. package/frontend/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  169. package/frontend/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  170. package/frontend/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  171. package/frontend/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  172. package/frontend/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  173. package/frontend/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  174. package/frontend/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  175. package/frontend/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  176. package/frontend/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  177. package/frontend/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  178. package/frontend/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  179. package/frontend/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  180. package/frontend/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  181. package/frontend/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  182. package/frontend/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  183. package/frontend/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  184. package/frontend/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  185. package/frontend/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  186. package/frontend/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  187. package/frontend/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  188. package/frontend/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  189. package/frontend/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  190. package/frontend/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  191. package/frontend/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  192. package/frontend/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  193. package/frontend/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  194. package/frontend/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  195. package/frontend/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  196. package/frontend/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  197. package/frontend/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  198. package/frontend/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  199. package/frontend/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  200. package/frontend/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  201. package/frontend/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  202. package/frontend/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  203. package/frontend/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  204. package/frontend/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  205. package/frontend/dist/assets/index-CRQkB7Wz.js +3 -0
  206. package/frontend/dist/css/index-B1OjddR-.css +1 -0
  207. package/frontend/dist/favicon-dark.png +0 -0
  208. package/frontend/dist/favicon-light.png +0 -0
  209. package/frontend/dist/index.html +23 -0
  210. package/frontend/dist/js/ArtifactContainer-c_oi7XMs.js +23 -0
  211. package/frontend/dist/js/ArtifactDemoPage-CdfwJVXu.js +98 -0
  212. package/frontend/dist/js/ChatPage-CyotkmS0.js +281 -0
  213. package/frontend/dist/js/ModelsPage-DNaziPHc.js +2 -0
  214. package/frontend/dist/js/PersonasPage-DcnbJf8Q.js +13 -0
  215. package/frontend/dist/js/UserManagementPage-DtTf92dS.js +1 -0
  216. package/frontend/dist/js/markdown-vendor-D-79K2xZ.js +22 -0
  217. package/frontend/dist/js/react-vendor-N--QU9DW.js +8 -0
  218. package/frontend/dist/js/router-vendor-B-t91v39.js +3 -0
  219. package/frontend/dist/js/ui-vendor-VxSCY_bv.js +177 -0
  220. package/frontend/dist/js/utils-vendor-DNzxLBGx.js +6 -0
  221. package/frontend/dist/logo-dark.png +0 -0
  222. package/frontend/dist/logo-light.png +0 -0
  223. package/frontend/dist/logo.svg +14 -0
  224. package/package.json +128 -0
  225. package/plugins/anthropic.json +25 -0
  226. package/plugins/elevenlabs.json +58 -0
  227. package/plugins/gemini.json +57 -0
  228. package/plugins/github.json +23 -0
  229. package/plugins/groq.json +25 -0
  230. package/plugins/mistral.json +73 -0
  231. package/plugins/openai-tts.json +38 -0
  232. package/plugins/openai.json +132 -0
  233. package/plugins/openrouter.json +353 -0
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at:
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ // Helper function to extract error message from unknown error
18
+ export const getErrorMessage = (error, fallback) => {
19
+ if (error && typeof error === 'object' && 'response' in error) {
20
+ const response = error;
21
+ if (response.response?.data?.error) {
22
+ return response.response.data.error;
23
+ }
24
+ }
25
+ if (error instanceof Error) {
26
+ return error.message;
27
+ }
28
+ return fallback;
29
+ };
30
+ // Note: Legacy interfaces have been merged into the main Persona interface with optional advanced features
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAkdH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAc,EAAE,QAAgB,EAAU,EAAE;IAC1E,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;QAC9D,MAAM,QAAQ,GAAG,KAAqD,CAAC;QACvE,IAAI,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YACnC,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QACtC,CAAC;IACH,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AA8JF,2GAA2G"}
@@ -0,0 +1,10 @@
1
+ import { GenerationOptions, GenerationStatistics, OllamaChatResponse } from '../types/index.js';
2
+ /**
3
+ * Merges user preferences with request options, giving precedence to request options
4
+ */
5
+ export declare const mergeGenerationOptions: (userOptions: Partial<GenerationOptions>, requestOptions?: Partial<GenerationOptions>) => GenerationOptions;
6
+ /**
7
+ * Extracts generation statistics from Ollama response
8
+ */
9
+ export declare const extractStatistics: (response: OllamaChatResponse) => GenerationStatistics;
10
+ //# sourceMappingURL=generationUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generationUtils.d.ts","sourceRoot":"","sources":["../../src/utils/generationUtils.ts"],"names":[],"mappings":"AAiBA,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,aAAa,OAAO,CAAC,iBAAiB,CAAC,EACvC,iBAAiB,OAAO,CAAC,iBAAiB,CAAC,KAC1C,iBAKF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAU,kBAAkB,KAC3B,oBAqBF,CAAC"}
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at:
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Merges user preferences with request options, giving precedence to request options
19
+ */
20
+ export const mergeGenerationOptions = (userOptions, requestOptions) => {
21
+ return {
22
+ ...userOptions,
23
+ ...requestOptions,
24
+ };
25
+ };
26
+ /**
27
+ * Extracts generation statistics from Ollama response
28
+ */
29
+ export const extractStatistics = (response) => {
30
+ const stats = {
31
+ total_duration: response.total_duration,
32
+ load_duration: response.load_duration,
33
+ prompt_eval_count: response.prompt_eval_count,
34
+ prompt_eval_duration: response.prompt_eval_duration,
35
+ eval_count: response.eval_count,
36
+ eval_duration: response.eval_duration,
37
+ created_at: response.created_at,
38
+ model: response.model,
39
+ };
40
+ // Calculate tokens per second if we have the necessary data
41
+ if (response.eval_count && response.eval_duration) {
42
+ // Convert nanoseconds to seconds and calculate tokens/second
43
+ stats.tokens_per_second =
44
+ Math.round((response.eval_count / (response.eval_duration / 1e9)) * 100) /
45
+ 100;
46
+ }
47
+ return stats;
48
+ };
49
+ //# sourceMappingURL=generationUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generationUtils.js","sourceRoot":"","sources":["../../src/utils/generationUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,WAAuC,EACvC,cAA2C,EACxB,EAAE;IACrB,OAAO;QACL,GAAG,WAAW;QACd,GAAG,cAAc;KAClB,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,QAA4B,EACN,EAAE;IACxB,MAAM,KAAK,GAAyB;QAClC,cAAc,EAAE,QAAQ,CAAC,cAAc;QACvC,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;QAC7C,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB;QACnD,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAC;IAEF,4DAA4D;IAC5D,IAAI,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;QAClD,6DAA6D;QAC7D,KAAK,CAAC,iBAAiB;YACrB,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,UAAU,GAAG,CAAC,QAAQ,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;gBACxE,GAAG,CAAC;IACR,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Hash a password using bcrypt
3
+ * @param password - The plain text password to hash
4
+ * @returns Promise<string> - The hashed password
5
+ */
6
+ export declare function hashPassword(password: string): Promise<string>;
7
+ /**
8
+ * Compare a plain text password with a hashed password
9
+ * @param password - The plain text password
10
+ * @param hash - The hashed password to compare against
11
+ * @returns Promise<boolean> - True if passwords match, false otherwise
12
+ */
13
+ export declare function comparePassword(password: string, hash: string): Promise<boolean>;
14
+ /**
15
+ * Generate a random password
16
+ * @param length - Length of the password (default: 12)
17
+ * @returns string - Random password
18
+ */
19
+ export declare function generateRandomPassword(length?: number): string;
20
+ /**
21
+ * Validate password strength
22
+ * @param password - The password to validate
23
+ * @returns object - Validation result with isValid and errors
24
+ */
25
+ export declare function validatePasswordStrength(password: string): {
26
+ isValid: boolean;
27
+ errors: string[];
28
+ };
29
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAmBA;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGpE;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAElB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM,CAUlE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAuBA"}
@@ -0,0 +1,73 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at:
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import bcrypt from 'bcrypt';
18
+ /**
19
+ * Hash a password using bcrypt
20
+ * @param password - The plain text password to hash
21
+ * @returns Promise<string> - The hashed password
22
+ */
23
+ export async function hashPassword(password) {
24
+ const saltRounds = 12; // Higher salt rounds for better security
25
+ return await bcrypt.hash(password, saltRounds);
26
+ }
27
+ /**
28
+ * Compare a plain text password with a hashed password
29
+ * @param password - The plain text password
30
+ * @param hash - The hashed password to compare against
31
+ * @returns Promise<boolean> - True if passwords match, false otherwise
32
+ */
33
+ export async function comparePassword(password, hash) {
34
+ return await bcrypt.compare(password, hash);
35
+ }
36
+ /**
37
+ * Generate a random password
38
+ * @param length - Length of the password (default: 12)
39
+ * @returns string - Random password
40
+ */
41
+ export function generateRandomPassword(length = 12) {
42
+ const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
43
+ let password = '';
44
+ for (let i = 0; i < length; i++) {
45
+ password += charset.charAt(Math.floor(Math.random() * charset.length));
46
+ }
47
+ return password;
48
+ }
49
+ /**
50
+ * Validate password strength
51
+ * @param password - The password to validate
52
+ * @returns object - Validation result with isValid and errors
53
+ */
54
+ export function validatePasswordStrength(password) {
55
+ const errors = [];
56
+ if (password.length < 6) {
57
+ errors.push('Password must be at least 6 characters long');
58
+ }
59
+ if (!/[A-Z]/.test(password)) {
60
+ errors.push('Password must contain at least one uppercase letter');
61
+ }
62
+ if (!/[a-z]/.test(password)) {
63
+ errors.push('Password must contain at least one lowercase letter');
64
+ }
65
+ if (!/[0-9]/.test(password)) {
66
+ errors.push('Password must contain at least one number');
67
+ }
68
+ return {
69
+ isValid: errors.length === 0,
70
+ errors,
71
+ };
72
+ }
73
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,yCAAyC;IAChE,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,IAAY;IAEZ,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE;IACxD,MAAM,OAAO,GACX,wEAAwE,CAAC;IAC3E,IAAI,QAAQ,GAAG,EAAE,CAAC;IAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,QAAgB;IAIvD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC5B,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { User } from '../types/index.js';
2
+ /**
3
+ * JWT payload interface
4
+ */
5
+ export interface JWTPayload {
6
+ userId: string;
7
+ username: string;
8
+ email?: string;
9
+ role: string;
10
+ iat?: number;
11
+ exp?: number;
12
+ }
13
+ /**
14
+ * Generate a JWT token for a user
15
+ * @param user - User object
16
+ * @returns string - JWT token
17
+ */
18
+ export declare function generateToken(user: User): string;
19
+ /**
20
+ * Verify and decode a JWT token
21
+ * @param token - JWT token string
22
+ * @returns JWTPayload - Decoded payload
23
+ */
24
+ export declare function verifyToken(token: string): JWTPayload;
25
+ /**
26
+ * Generate a refresh token (longer expiry)
27
+ * @param user - User object
28
+ * @returns string - Refresh token
29
+ */
30
+ export declare function generateRefreshToken(user: User): string;
31
+ /**
32
+ * Extract token from Authorization header
33
+ * @param authHeader - Authorization header value
34
+ * @returns string | null - Token or null if not found
35
+ */
36
+ export declare function extractTokenFromHeader(authHeader: string | undefined): string | null;
37
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/utils/jwt.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAWhD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAarD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAUvD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,MAAM,GAAG,IAAI,CAWf"}
@@ -0,0 +1,86 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at:
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import jwt from 'jsonwebtoken';
18
+ import { JWT_SECRET } from '../services/authService.js';
19
+ /**
20
+ * Generate a JWT token for a user
21
+ * @param user - User object
22
+ * @returns string - JWT token
23
+ */
24
+ export function generateToken(user) {
25
+ const payload = {
26
+ userId: user.id,
27
+ username: user.username,
28
+ email: user.email,
29
+ role: user.role,
30
+ };
31
+ const expiresIn = process.env.JWT_EXPIRES_IN || '7d';
32
+ return jwt.sign(payload, JWT_SECRET, { expiresIn });
33
+ }
34
+ /**
35
+ * Verify and decode a JWT token
36
+ * @param token - JWT token string
37
+ * @returns JWTPayload - Decoded payload
38
+ */
39
+ export function verifyToken(token) {
40
+ try {
41
+ const decoded = jwt.verify(token, JWT_SECRET);
42
+ return decoded;
43
+ }
44
+ catch (error) {
45
+ if (error instanceof jwt.TokenExpiredError) {
46
+ throw new Error('Token has expired');
47
+ }
48
+ else if (error instanceof jwt.JsonWebTokenError) {
49
+ throw new Error('Invalid token');
50
+ }
51
+ else {
52
+ throw new Error('Token verification failed');
53
+ }
54
+ }
55
+ }
56
+ /**
57
+ * Generate a refresh token (longer expiry)
58
+ * @param user - User object
59
+ * @returns string - Refresh token
60
+ */
61
+ export function generateRefreshToken(user) {
62
+ const payload = {
63
+ userId: user.id,
64
+ username: user.username,
65
+ email: user.email,
66
+ role: user.role,
67
+ };
68
+ // Refresh tokens have longer expiry (30 days)
69
+ return jwt.sign(payload, JWT_SECRET, { expiresIn: '30d' });
70
+ }
71
+ /**
72
+ * Extract token from Authorization header
73
+ * @param authHeader - Authorization header value
74
+ * @returns string | null - Token or null if not found
75
+ */
76
+ export function extractTokenFromHeader(authHeader) {
77
+ if (!authHeader) {
78
+ return null;
79
+ }
80
+ const parts = authHeader.split(' ');
81
+ if (parts.length !== 2 || parts[0] !== 'Bearer') {
82
+ return null;
83
+ }
84
+ return parts[1];
85
+ }
86
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/utils/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,GAAG,MAAM,cAAc,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAcxD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,MAAM,OAAO,GAAe;QAC1B,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC;IAEF,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC;IAErD,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,SAAS,EAAqB,CAAC,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAe,CAAC;QAC5D,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,GAAG,CAAC,iBAAiB,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,KAAK,YAAY,GAAG,CAAC,iBAAiB,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAU;IAC7C,MAAM,OAAO,GAAe;QAC1B,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC;IAEF,8CAA8C;IAC9C,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,KAAK,EAAqB,CAAC,CAAC;AAChF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAA8B;IAE9B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
package/bin/cli.js ADDED
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+
3
+ /*
4
+ * Libre WebUI
5
+ * Copyright (C) 2025 Kroonen AI, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at:
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ const { spawn } = require('child_process');
21
+ const path = require('path');
22
+ const fs = require('fs');
23
+
24
+ // Parse command line arguments
25
+ const args = process.argv.slice(2);
26
+ const helpFlags = ['-h', '--help'];
27
+ const versionFlags = ['-v', '--version'];
28
+
29
+ if (args.some(arg => helpFlags.includes(arg))) {
30
+ console.log(`
31
+ Libre WebUI - Privacy-First AI Chat Interface
32
+
33
+ Usage: npx libre-webui [options]
34
+
35
+ Options:
36
+ -h, --help Show this help message
37
+ -v, --version Show version number
38
+ -p, --port Set the port (default: 8080)
39
+
40
+ Environment Variables:
41
+ PORT Server port (default: 8080)
42
+ OLLAMA_BASE_URL Ollama API URL (default: http://localhost:11434)
43
+ OPENAI_API_KEY OpenAI API key (optional)
44
+ ANTHROPIC_API_KEY Anthropic API key (optional)
45
+
46
+ Examples:
47
+ npx libre-webui
48
+ npx libre-webui --port 3000
49
+ PORT=3000 npx libre-webui
50
+
51
+ Documentation: https://docs.librewebui.org
52
+ `);
53
+ process.exit(0);
54
+ }
55
+
56
+ if (args.some(arg => versionFlags.includes(arg))) {
57
+ const packageJson = require('../package.json');
58
+ console.log(`libre-webui v${packageJson.version}`);
59
+ process.exit(0);
60
+ }
61
+
62
+ // Handle --port argument
63
+ const portArgIndex = args.findIndex(arg => arg === '-p' || arg === '--port');
64
+ if (portArgIndex !== -1 && args[portArgIndex + 1]) {
65
+ process.env.PORT = args[portArgIndex + 1];
66
+ }
67
+
68
+ // Find the backend entry point
69
+ const possibleBackendPaths = [
70
+ path.join(__dirname, '../backend/dist/index.js'),
71
+ path.join(__dirname, '../dist/backend/index.js'),
72
+ ];
73
+
74
+ let backendPath = '';
75
+ for (const p of possibleBackendPaths) {
76
+ if (fs.existsSync(p)) {
77
+ backendPath = p;
78
+ break;
79
+ }
80
+ }
81
+
82
+ if (!backendPath) {
83
+ console.error('Error: Backend not found. The package may be corrupted.');
84
+ console.error('Please try reinstalling: npm install -g libre-webui');
85
+ process.exit(1);
86
+ }
87
+
88
+ // Check if frontend exists
89
+ const possibleFrontendPaths = [
90
+ path.join(__dirname, '../frontend/dist/index.html'),
91
+ path.join(__dirname, '../dist/frontend/index.html'),
92
+ ];
93
+
94
+ let frontendExists = false;
95
+ for (const p of possibleFrontendPaths) {
96
+ if (fs.existsSync(p)) {
97
+ frontendExists = true;
98
+ break;
99
+ }
100
+ }
101
+
102
+ if (!frontendExists) {
103
+ console.error('Error: Frontend not found. The package may be corrupted.');
104
+ console.error('Please try reinstalling: npm install -g libre-webui');
105
+ process.exit(1);
106
+ }
107
+
108
+ // Set production environment
109
+ const env = {
110
+ ...process.env,
111
+ NODE_ENV: 'production',
112
+ SERVE_FRONTEND: 'true',
113
+ };
114
+
115
+ const port = env.PORT || '8080';
116
+
117
+ console.log(`
118
+ ╭─────────────────────────────────────────────────╮
119
+ │ │
120
+ │ Libre WebUI │
121
+ │ Privacy-First AI Chat Interface │
122
+ │ │
123
+ ╰─────────────────────────────────────────────────╯
124
+
125
+ Starting server...
126
+ `);
127
+
128
+ // Start the backend server
129
+ const server = spawn('node', [backendPath], {
130
+ stdio: 'inherit',
131
+ env,
132
+ });
133
+
134
+ server.on('error', err => {
135
+ console.error('Failed to start server:', err.message);
136
+ process.exit(1);
137
+ });
138
+
139
+ server.on('close', code => {
140
+ process.exit(code || 0);
141
+ });
142
+
143
+ // Handle graceful shutdown
144
+ process.on('SIGINT', () => {
145
+ server.kill('SIGINT');
146
+ });
147
+
148
+ process.on('SIGTERM', () => {
149
+ server.kill('SIGTERM');
150
+ });