@sync-in/server 1.7.0 → 1.8.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 (269) hide show
  1. package/CHANGELOG.md +164 -58
  2. package/environment/environment.dist.yaml +6 -3
  3. package/migrations/0003_giant_luckman.sql +6 -0
  4. package/migrations/meta/0003_snapshot.json +2463 -0
  5. package/migrations/meta/_journal.json +7 -0
  6. package/package.json +16 -15
  7. package/server/app.bootstrap.js +1 -0
  8. package/server/app.bootstrap.js.map +1 -1
  9. package/server/app.constants.js +0 -4
  10. package/server/app.constants.js.map +1 -1
  11. package/server/app.service.js +7 -6
  12. package/server/app.service.js.map +1 -1
  13. package/server/applications/files/constants/only-office.js +12 -0
  14. package/server/applications/files/constants/only-office.js.map +1 -1
  15. package/server/applications/files/files.config.js +5 -0
  16. package/server/applications/files/files.config.js.map +1 -1
  17. package/server/applications/files/services/files-content-manager.service.js +6 -6
  18. package/server/applications/files/services/files-content-manager.service.js.map +1 -1
  19. package/server/applications/files/services/files-manager.service.js +4 -4
  20. package/server/applications/files/services/files-manager.service.js.map +1 -1
  21. package/server/applications/files/services/files-methods.service.js +5 -3
  22. package/server/applications/files/services/files-methods.service.js.map +1 -1
  23. package/server/applications/files/services/files-only-office-manager.service.js +2 -2
  24. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  25. package/server/applications/files/services/files-parser.service.js +6 -3
  26. package/server/applications/files/services/files-parser.service.js.map +1 -1
  27. package/server/applications/files/services/files-scheduler.service.js +51 -3
  28. package/server/applications/files/services/files-scheduler.service.js.map +1 -1
  29. package/server/applications/files/services/files-search-manager.service.js +4 -0
  30. package/server/applications/files/services/files-search-manager.service.js.map +1 -1
  31. package/server/applications/files/utils/doc-textify/adapters/pdf.js +10 -1
  32. package/server/applications/files/utils/doc-textify/adapters/pdf.js.map +1 -1
  33. package/server/applications/notifications/i18n/de.js +56 -0
  34. package/server/applications/notifications/i18n/de.js.map +1 -0
  35. package/server/applications/notifications/i18n/es.js +52 -0
  36. package/server/applications/notifications/i18n/es.js.map +1 -0
  37. package/server/applications/notifications/i18n/hi.js +52 -0
  38. package/server/applications/notifications/i18n/hi.js.map +1 -0
  39. package/server/applications/notifications/i18n/index.js +73 -8
  40. package/server/applications/notifications/i18n/index.js.map +1 -1
  41. package/server/applications/notifications/i18n/it.js +52 -0
  42. package/server/applications/notifications/i18n/it.js.map +1 -0
  43. package/server/applications/notifications/i18n/ja.js +52 -0
  44. package/server/applications/notifications/i18n/ja.js.map +1 -0
  45. package/server/applications/notifications/i18n/ko.js +52 -0
  46. package/server/applications/notifications/i18n/ko.js.map +1 -0
  47. package/server/applications/notifications/i18n/pl.js +52 -0
  48. package/server/applications/notifications/i18n/pl.js.map +1 -0
  49. package/server/applications/notifications/i18n/pt.js +52 -0
  50. package/server/applications/notifications/i18n/pt.js.map +1 -0
  51. package/server/applications/notifications/i18n/pt_br.js +52 -0
  52. package/server/applications/notifications/i18n/pt_br.js.map +1 -0
  53. package/server/applications/notifications/i18n/ru.js +52 -0
  54. package/server/applications/notifications/i18n/ru.js.map +1 -0
  55. package/server/applications/notifications/i18n/tr.js +52 -0
  56. package/server/applications/notifications/i18n/tr.js.map +1 -0
  57. package/server/applications/notifications/i18n/zh.js +52 -0
  58. package/server/applications/notifications/i18n/zh.js.map +1 -0
  59. package/server/applications/notifications/mails/models.js +6 -7
  60. package/server/applications/notifications/mails/models.js.map +1 -1
  61. package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
  62. package/server/applications/shares/dto/create-or-update-share.dto.js +11 -0
  63. package/server/applications/shares/dto/create-or-update-share.dto.js.map +1 -1
  64. package/server/applications/shares/interfaces/share-props.interface.js.map +1 -1
  65. package/server/applications/shares/schemas/share.interface.js.map +1 -1
  66. package/server/applications/shares/schemas/shares.schema.js +9 -0
  67. package/server/applications/shares/schemas/shares.schema.js.map +1 -1
  68. package/server/applications/shares/services/shares-manager.service.js +46 -17
  69. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  70. package/server/applications/shares/services/shares-queries.service.js +24 -5
  71. package/server/applications/shares/services/shares-queries.service.js.map +1 -1
  72. package/server/applications/spaces/constants/cache.js +4 -0
  73. package/server/applications/spaces/constants/cache.js.map +1 -1
  74. package/server/applications/spaces/dto/create-or-update-space.dto.js +5 -0
  75. package/server/applications/spaces/dto/create-or-update-space.dto.js.map +1 -1
  76. package/server/applications/spaces/guards/space.guard.js +3 -3
  77. package/server/applications/spaces/guards/space.guard.js.map +1 -1
  78. package/server/applications/spaces/models/space-props.model.js.map +1 -1
  79. package/server/applications/spaces/models/space.model.js.map +1 -1
  80. package/server/applications/spaces/schemas/space.interface.js.map +1 -1
  81. package/server/applications/spaces/schemas/spaces.schema.js +1 -0
  82. package/server/applications/spaces/schemas/spaces.schema.js.map +1 -1
  83. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  84. package/server/applications/spaces/services/spaces-manager.service.js +34 -31
  85. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  86. package/server/applications/spaces/services/spaces-queries.service.js +23 -7
  87. package/server/applications/spaces/services/spaces-queries.service.js.map +1 -1
  88. package/server/applications/spaces/services/spaces-scheduler.service.js +21 -20
  89. package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
  90. package/server/applications/spaces/spaces.controller.js +4 -2
  91. package/server/applications/spaces/spaces.controller.js.map +1 -1
  92. package/server/applications/spaces/utils/paths.js +14 -16
  93. package/server/applications/spaces/utils/paths.js.map +1 -1
  94. package/server/applications/sync/services/sync-manager.service.js +4 -3
  95. package/server/applications/sync/services/sync-manager.service.js.map +1 -1
  96. package/server/applications/sync/services/sync-paths-manager.service.js +1 -1
  97. package/server/applications/sync/services/sync-paths-manager.service.js.map +1 -1
  98. package/server/applications/sync/services/sync-paths-manager.service.spec.js +1 -1
  99. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  100. package/server/applications/sync/sync.controller.js +2 -1
  101. package/server/applications/sync/sync.controller.js.map +1 -1
  102. package/server/applications/users/constants/routes.js +5 -0
  103. package/server/applications/users/constants/routes.js.map +1 -1
  104. package/server/applications/users/constants/user.js +0 -16
  105. package/server/applications/users/constants/user.js.map +1 -1
  106. package/server/applications/users/dto/user-properties.dto.js +10 -0
  107. package/server/applications/users/dto/user-properties.dto.js.map +1 -1
  108. package/server/applications/users/models/user.model.js.map +1 -1
  109. package/server/applications/users/schemas/user.interface.js.map +1 -1
  110. package/server/applications/users/schemas/users.schema.js +3 -2
  111. package/server/applications/users/schemas/users.schema.js.map +1 -1
  112. package/server/applications/users/services/admin-users-manager.service.js +1 -0
  113. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  114. package/server/applications/users/services/admin-users-manager.service.spec.js +2 -1
  115. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  116. package/server/applications/users/services/users-manager.service.js +8 -2
  117. package/server/applications/users/services/users-manager.service.js.map +1 -1
  118. package/server/applications/users/services/users-manager.service.spec.js +1 -0
  119. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  120. package/server/applications/users/services/users-queries.service.js +18 -4
  121. package/server/applications/users/services/users-queries.service.js.map +1 -1
  122. package/server/applications/users/users.controller.js +15 -0
  123. package/server/applications/users/users.controller.js.map +1 -1
  124. package/server/applications/users/utils/test.js +2 -2
  125. package/server/applications/users/utils/test.js.map +1 -1
  126. package/server/applications/webdav/constants/routes.js +2 -2
  127. package/server/applications/webdav/constants/routes.js.map +1 -1
  128. package/server/applications/webdav/constants/webdav.js +2 -2
  129. package/server/applications/webdav/constants/webdav.js.map +1 -1
  130. package/server/applications/webdav/filters/webdav.filter.js +2 -2
  131. package/server/applications/webdav/filters/webdav.filter.js.map +1 -1
  132. package/server/applications/webdav/filters/webdav.filter.spec.js +2 -2
  133. package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -1
  134. package/server/applications/webdav/services/webdav-methods.service.js +3 -2
  135. package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
  136. package/server/applications/webdav/utils/webdav.js +1 -2
  137. package/server/applications/webdav/utils/webdav.js.map +1 -1
  138. package/server/authentication/auth.config.js +2 -2
  139. package/server/authentication/auth.config.js.map +1 -1
  140. package/server/authentication/guards/auth-basic.strategy.js +2 -2
  141. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  142. package/server/common/i18n.js +52 -0
  143. package/server/common/i18n.js.map +1 -0
  144. package/server/common/image.js +49 -33
  145. package/server/common/image.js.map +1 -1
  146. package/server/common/interfaces.js.map +1 -1
  147. package/server/common/shared.js +5 -2
  148. package/server/common/shared.js.map +1 -1
  149. package/server/configuration/config.validation.js +3 -3
  150. package/server/configuration/config.validation.js.map +1 -1
  151. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +8 -6
  152. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
  153. package/server/infrastructure/cache/adapters/redis-cache.adapter.js +22 -17
  154. package/server/infrastructure/cache/adapters/redis-cache.adapter.js.map +1 -1
  155. package/server/infrastructure/cache/cache.e2e-spec.js +1 -0
  156. package/server/infrastructure/cache/cache.e2e-spec.js.map +1 -1
  157. package/server/infrastructure/cache/cache.module.js +1 -14
  158. package/server/infrastructure/cache/cache.module.js.map +1 -1
  159. package/server/infrastructure/cache/services/cache.service.js.map +1 -1
  160. package/server/infrastructure/database/database.module.js +20 -1
  161. package/server/infrastructure/database/database.module.js.map +1 -1
  162. package/server/infrastructure/database/utils.js +48 -0
  163. package/server/infrastructure/database/utils.js.map +1 -1
  164. package/server/infrastructure/scheduler/scheduler.module.js +1 -1
  165. package/server/infrastructure/scheduler/scheduler.module.js.map +1 -1
  166. package/server/infrastructure/websocket/adapters/cluster.adapter.js +1 -3
  167. package/server/infrastructure/websocket/adapters/cluster.adapter.js.map +1 -1
  168. package/static/3rdpartylicenses.txt +137 -137
  169. package/static/chunk-2KLC4T2Z.js +1 -0
  170. package/static/chunk-373XVRXW.js +1 -0
  171. package/static/chunk-3GMLWAFZ.js +1 -0
  172. package/static/chunk-3XVM35O2.js +1 -0
  173. package/static/chunk-3YVRP3VM.js +2 -0
  174. package/static/chunk-5NMSIIQB.js +1 -0
  175. package/static/chunk-AF24EYXU.js +1 -0
  176. package/static/chunk-AKQVEHO6.js +2 -0
  177. package/static/{chunk-PTGDOWV3.js → chunk-AY2SZ3G6.js} +1 -1
  178. package/static/chunk-BCVX464U.js +2 -0
  179. package/static/{chunk-IPAC4VAF.js → chunk-BIKLW4YS.js} +1 -1
  180. package/static/chunk-C36MW4ME.js +562 -0
  181. package/static/chunk-CHJ64RJM.js +1 -0
  182. package/static/chunk-DKSEQTMX.js +1 -0
  183. package/static/chunk-DM4NXKEP.js +1 -0
  184. package/static/chunk-DPUVSXRB.js +1 -0
  185. package/static/chunk-DSWEWLXJ.js +1 -0
  186. package/static/chunk-FJE6BOFL.js +1 -0
  187. package/static/chunk-FZ3JPGYZ.js +1 -0
  188. package/static/chunk-GUGNR5TF.js +3 -0
  189. package/static/chunk-H6NE33VX.js +1 -0
  190. package/static/{chunk-DJYJ66UF.js → chunk-HAS5ZOTR.js} +1 -1
  191. package/static/chunk-HNQRZALS.js +1 -0
  192. package/static/chunk-JPT5WEAT.js +1 -0
  193. package/static/{chunk-QNJFQVYI.js → chunk-JSWCNGXJ.js} +1 -1
  194. package/static/chunk-KFJIQIGR.js +1 -0
  195. package/static/chunk-LNTUR3GU.js +1 -0
  196. package/static/chunk-LVM4QB22.js +1 -0
  197. package/static/chunk-M3XVNQZQ.js +1 -0
  198. package/static/{chunk-EVIE5F2U.js → chunk-MFLIJH6T.js} +1 -1
  199. package/static/{chunk-IQOALFYU.js → chunk-MSUHTBB2.js} +1 -1
  200. package/static/chunk-N3U6637P.js +1 -0
  201. package/static/chunk-NNV4OXSB.js +1 -0
  202. package/static/chunk-NO2LTNW3.js +1 -0
  203. package/static/chunk-OOGP4WSH.js +2 -0
  204. package/static/chunk-PB4AIT7O.js +1 -0
  205. package/static/chunk-PCWDQPOM.js +2 -0
  206. package/static/chunk-PGZZP5W3.js +1 -0
  207. package/static/chunk-PVDHBQRM.js +1 -0
  208. package/static/chunk-Q5KM7LTX.js +1 -0
  209. package/static/chunk-QHC6ZPQ4.js +1 -0
  210. package/static/chunk-QO6BTONN.js +1 -0
  211. package/static/chunk-QZU2S5CV.js +1 -0
  212. package/static/chunk-SBZ572Q4.js +2 -0
  213. package/static/chunk-SHIVUDP3.js +1 -0
  214. package/static/chunk-SLHTEGRU.js +1 -0
  215. package/static/{chunk-SH5EVL4E.js → chunk-SSFF27P2.js} +1 -1
  216. package/static/chunk-TPYBFZS5.js +1 -0
  217. package/static/chunk-UEQCWMXD.js +1 -0
  218. package/static/chunk-UG5DMXYO.js +1 -0
  219. package/static/chunk-UJPPR4MX.js +1 -0
  220. package/static/chunk-UNCPXHHT.js +1 -0
  221. package/static/chunk-URHTCJ7G.js +1 -0
  222. package/static/chunk-V3AT2BKP.js +1 -0
  223. package/static/chunk-VKK5BSLX.js +1 -0
  224. package/static/{chunk-SIPE37PA.js → chunk-VM4YX6Q7.js} +1 -1
  225. package/static/chunk-WJW7CT6G.js +27 -0
  226. package/static/{chunk-7ITZXYYJ.js → chunk-WLMNXRBS.js} +1 -1
  227. package/static/chunk-X5XGK6T7.js +4 -0
  228. package/static/chunk-YEKR5OPO.js +1 -0
  229. package/static/chunk-YW57T2PF.js +1 -0
  230. package/static/chunk-Z5J5F5SX.js +1 -0
  231. package/static/chunk-ZIJQRARU.js +1 -0
  232. package/static/chunk-ZPF2DSQV.js +1 -0
  233. package/static/chunk-ZTCRGJ6Y.js +7 -0
  234. package/static/index.html +2 -2
  235. package/static/main-VOL6OMJ5.js +9 -0
  236. package/static/scripts-WRDOQIU5.js +24 -0
  237. package/static/{styles-A5VYX3CE.css → styles-2C2UNCNB.css} +1 -1
  238. package/server/applications/spaces/interfaces/space-quota.interface.js +0 -10
  239. package/server/applications/spaces/interfaces/space-quota.interface.js.map +0 -1
  240. package/static/chunk-22EANI6R.js +0 -1
  241. package/static/chunk-3GFGJYMK.js +0 -1
  242. package/static/chunk-4YGJGZZZ.js +0 -1
  243. package/static/chunk-5K7HEX3C.js +0 -27
  244. package/static/chunk-5KLMS6A4.js +0 -1
  245. package/static/chunk-ATP3BFHV.js +0 -562
  246. package/static/chunk-BB4G55KE.js +0 -1
  247. package/static/chunk-EWKSX76T.js +0 -1
  248. package/static/chunk-FHLACA7V.js +0 -1
  249. package/static/chunk-GCATNU55.js +0 -1
  250. package/static/chunk-GYODPCIE.js +0 -1
  251. package/static/chunk-HZTFYLM5.js +0 -1
  252. package/static/chunk-JSUKJT6Z.js +0 -1
  253. package/static/chunk-JXZCNFW7.js +0 -1
  254. package/static/chunk-LTGFCQR7.js +0 -1
  255. package/static/chunk-LV3PYKWO.js +0 -1
  256. package/static/chunk-N2WFNW6M.js +0 -7
  257. package/static/chunk-ORMRCEGT.js +0 -1
  258. package/static/chunk-OUTBJSMW.js +0 -1
  259. package/static/chunk-RS2PX32L.js +0 -1
  260. package/static/chunk-RSSWH3S2.js +0 -1
  261. package/static/chunk-RTRJ3KFH.js +0 -1
  262. package/static/chunk-TKTCBDOG.js +0 -1
  263. package/static/chunk-V6K2N46L.js +0 -1
  264. package/static/chunk-XLCCZSQL.js +0 -4
  265. package/static/chunk-YPEH66GG.js +0 -1
  266. package/static/chunk-YPOIUQ57.js +0 -1
  267. package/static/chunk-ZKCFO2OA.js +0 -4
  268. package/static/main-MZ7HWZXO.js +0 -9
  269. package/static/scripts-VZVAP2P4.js +0 -30
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../backend/src/common/image.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { createCanvas, loadImage, PNGStream, registerFont } from 'canvas'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\nregisterFont(path.join(__dirname, 'fonts', 'avatar.ttf'), { family: 'Avatar' })\n\nexport const pngMimeType = 'image/png'\nexport const svgMimeType = 'image/svg+xml'\n\nexport async function generateThumbnail(filePath: string, size: number) {\n const image = await loadImage(filePath)\n let width = image.width\n let height = image.height\n\n // Calculate the new dimensions, maintaining the aspect ratio\n if (width > height) {\n if (width > size) {\n height *= size / width\n width = size\n }\n } else {\n if (height > size) {\n width *= size / height\n height = size\n }\n }\n // Set the canvas dimensions to the new dimensions\n const canvas = createCanvas(width, height)\n // Draw the resized image on the canvas\n const ctx = canvas.getContext('2d')\n ctx.drawImage(image, 0, 0, width, height)\n\n return canvas.createPNGStream({ compressionLevel: 0 })\n}\n\nexport function generateAvatar(initials: string): PNGStream {\n const canvas = createCanvas(256, 256)\n const ctx = canvas.getContext('2d')\n const text = initials\n const { backgroundColor, foregroundColor } = randomColor()\n\n // Properties\n ctx.quality = 'best'\n\n // Draw background\n ctx.fillStyle = backgroundColor\n ctx.fillRect(0, 0, canvas.width, canvas.height)\n\n // Draw text\n const height = 150\n ctx.font = `${height}px \"Avatar\"`\n ctx.fillStyle = foregroundColor\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.fillText(text, canvas.width / 2, canvas.height / 2.1)\n\n return canvas.createPNGStream()\n}\n\nexport async function convertImageToBase64(imgPath: string) {\n const base64String = await fs.readFile(imgPath, { encoding: 'base64' })\n return `data:image/png;base64,${base64String}`\n}\n\nfunction randomColor() {\n let color = ''\n while (color.length < 6) {\n /* sometimes the returned value does not have\n * the 6 digits needed, so we do it again until\n * it does\n */\n color = Math.floor(Math.random() * 16777215).toString(16)\n }\n const red = parseInt(color.substring(0, 2), 16)\n const green = parseInt(color.substring(2, 4), 16)\n const blue = parseInt(color.substring(4, 6), 16)\n const brightness = red * 0.299 + green * 0.587 + blue * 0.114\n\n return {\n backgroundColor: `#${color}`,\n foregroundColor: brightness > 180 ? '#000000' : '#ffffff'\n }\n}\n"],"names":["convertImageToBase64","generateAvatar","generateThumbnail","pngMimeType","svgMimeType","registerFont","path","join","__dirname","family","filePath","size","image","loadImage","width","height","canvas","createCanvas","ctx","getContext","drawImage","createPNGStream","compressionLevel","initials","text","backgroundColor","foregroundColor","randomColor","quality","fillStyle","fillRect","font","textAlign","textBaseline","fillText","imgPath","base64String","fs","readFile","encoding","color","length","Math","floor","random","toString","red","parseInt","substring","green","blue","brightness"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QA6DqBA;eAAAA;;QAxBNC;eAAAA;;QA1BMC;eAAAA;;QAHTC;eAAAA;;QACAC;eAAAA;;;wBAPoD;iEAClD;iEACE;;;;;;AAEjBC,IAAAA,oBAAY,EAACC,iBAAI,CAACC,IAAI,CAACC,WAAW,SAAS,eAAe;IAAEC,QAAQ;AAAS;AAEtE,MAAMN,cAAc;AACpB,MAAMC,cAAc;AAEpB,eAAeF,kBAAkBQ,QAAgB,EAAEC,IAAY;IACpE,MAAMC,QAAQ,MAAMC,IAAAA,iBAAS,EAACH;IAC9B,IAAII,QAAQF,MAAME,KAAK;IACvB,IAAIC,SAASH,MAAMG,MAAM;IAEzB,6DAA6D;IAC7D,IAAID,QAAQC,QAAQ;QAClB,IAAID,QAAQH,MAAM;YAChBI,UAAUJ,OAAOG;YACjBA,QAAQH;QACV;IACF,OAAO;QACL,IAAII,SAASJ,MAAM;YACjBG,SAASH,OAAOI;YAChBA,SAASJ;QACX;IACF;IACA,kDAAkD;IAClD,MAAMK,SAASC,IAAAA,oBAAY,EAACH,OAAOC;IACnC,uCAAuC;IACvC,MAAMG,MAAMF,OAAOG,UAAU,CAAC;IAC9BD,IAAIE,SAAS,CAACR,OAAO,GAAG,GAAGE,OAAOC;IAElC,OAAOC,OAAOK,eAAe,CAAC;QAAEC,kBAAkB;IAAE;AACtD;AAEO,SAASrB,eAAesB,QAAgB;IAC7C,MAAMP,SAASC,IAAAA,oBAAY,EAAC,KAAK;IACjC,MAAMC,MAAMF,OAAOG,UAAU,CAAC;IAC9B,MAAMK,OAAOD;IACb,MAAM,EAAEE,eAAe,EAAEC,eAAe,EAAE,GAAGC;IAE7C,aAAa;IACbT,IAAIU,OAAO,GAAG;IAEd,kBAAkB;IAClBV,IAAIW,SAAS,GAAGJ;IAChBP,IAAIY,QAAQ,CAAC,GAAG,GAAGd,OAAOF,KAAK,EAAEE,OAAOD,MAAM;IAE9C,YAAY;IACZ,MAAMA,SAAS;IACfG,IAAIa,IAAI,GAAG,GAAGhB,OAAO,WAAW,CAAC;IACjCG,IAAIW,SAAS,GAAGH;IAChBR,IAAIc,SAAS,GAAG;IAChBd,IAAIe,YAAY,GAAG;IACnBf,IAAIgB,QAAQ,CAACV,MAAMR,OAAOF,KAAK,GAAG,GAAGE,OAAOD,MAAM,GAAG;IAErD,OAAOC,OAAOK,eAAe;AAC/B;AAEO,eAAerB,qBAAqBmC,OAAe;IACxD,MAAMC,eAAe,MAAMC,iBAAE,CAACC,QAAQ,CAACH,SAAS;QAAEI,UAAU;IAAS;IACrE,OAAO,CAAC,sBAAsB,EAAEH,cAAc;AAChD;AAEA,SAAST;IACP,IAAIa,QAAQ;IACZ,MAAOA,MAAMC,MAAM,GAAG,EAAG;QACvB;;;KAGC,GACDD,QAAQE,KAAKC,KAAK,CAACD,KAAKE,MAAM,KAAK,UAAUC,QAAQ,CAAC;IACxD;IACA,MAAMC,MAAMC,SAASP,MAAMQ,SAAS,CAAC,GAAG,IAAI;IAC5C,MAAMC,QAAQF,SAASP,MAAMQ,SAAS,CAAC,GAAG,IAAI;IAC9C,MAAME,OAAOH,SAASP,MAAMQ,SAAS,CAAC,GAAG,IAAI;IAC7C,MAAMG,aAAaL,MAAM,QAAQG,QAAQ,QAAQC,OAAO;IAExD,OAAO;QACLzB,iBAAiB,CAAC,CAAC,EAAEe,OAAO;QAC5Bd,iBAAiByB,aAAa,MAAM,YAAY;IAClD;AACF"}
1
+ {"version":3,"sources":["../../../backend/src/common/image.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport sharp from 'sharp'\nimport { Resvg } from '@resvg/resvg-js'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\nexport const pngMimeType = 'image/png'\nexport const svgMimeType = 'image/svg+xml'\n\nexport async function generateThumbnail(filePath: string, size: number) {\n const image = sharp(filePath).rotate()\n let { width, height } = await image.metadata()\n\n if (!width || !height) throw new Error('Invalid image dimensions')\n\n // Calculate the new dimensions, maintaining the aspect ratio\n if (width > height) {\n if (width > size) {\n height = Math.round((height * size) / width)\n width = size\n }\n } else {\n if (height > size) {\n width = Math.round((width * size) / height)\n height = size\n }\n }\n\n return image.resize(width, height, { fit: 'inside' }).png({ compressionLevel: 0 }).toBuffer()\n}\n\nexport async function generateAvatar(initials: string): Promise<Buffer> {\n const width = 256\n const height = 256\n const { backgroundColor, foregroundColor } = randomColor()\n\n const fontPath = path.join(__dirname, 'fonts', 'avatar.ttf')\n const fontBase64 = (await fs.readFile(fontPath)).toString('base64')\n\n const svg = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">\n <style>\n @font-face {\n font-family: 'Avatar';\n src: url('data:font/ttf;base64,${fontBase64}') format('truetype');\n }\n text {\n font-family: 'Avatar', sans-serif;\n font-size: 150px;\n fill: ${foregroundColor};\n dominant-baseline: central;\n text-anchor: middle;\n }\n </style>\n <rect width=\"100%\" height=\"100%\" fill=\"${backgroundColor}\" />\n <text x=\"50%\" y=\"50%\">${initials}</text>\n </svg>\n `\n\n // Rasterize SVG to PNG\n const resvg = new Resvg(svg, {\n fitTo: { mode: 'width', value: width },\n font: {\n fontFiles: [fontPath],\n loadSystemFonts: false\n }\n })\n\n return resvg.render().asPng()\n}\n\nexport async function convertImageToBase64(imgPath: string) {\n const base64String = await fs.readFile(imgPath, { encoding: 'base64' })\n return `data:image/png;base64,${base64String}`\n}\n\nfunction randomColor() {\n let color = ''\n while (color.length < 6) {\n /* sometimes the returned value does not have\n * the 6 digits needed, so we do it again until\n * it does\n */\n color = Math.floor(Math.random() * 16777215).toString(16)\n }\n const red = parseInt(color.substring(0, 2), 16)\n const green = parseInt(color.substring(2, 4), 16)\n const blue = parseInt(color.substring(4, 6), 16)\n const brightness = red * 0.299 + green * 0.587 + blue * 0.114\n\n return {\n backgroundColor: `#${color}`,\n foregroundColor: brightness > 180 ? '#000000' : '#ffffff'\n }\n}\n"],"names":["convertImageToBase64","generateAvatar","generateThumbnail","pngMimeType","svgMimeType","filePath","size","image","sharp","rotate","width","height","metadata","Error","Math","round","resize","fit","png","compressionLevel","toBuffer","initials","backgroundColor","foregroundColor","randomColor","fontPath","path","join","__dirname","fontBase64","fs","readFile","toString","svg","resvg","Resvg","fitTo","mode","value","font","fontFiles","loadSystemFonts","render","asPng","imgPath","base64String","encoding","color","length","floor","random","red","parseInt","substring","green","blue","brightness"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAwEqBA;eAAAA;;QAxCAC;eAAAA;;QAtBAC;eAAAA;;QAHTC;eAAAA;;QACAC;eAAAA;;;8DANK;yBACI;iEACP;iEACE;;;;;;AAEV,MAAMD,cAAc;AACpB,MAAMC,cAAc;AAEpB,eAAeF,kBAAkBG,QAAgB,EAAEC,IAAY;IACpE,MAAMC,QAAQC,IAAAA,cAAK,EAACH,UAAUI,MAAM;IACpC,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAG,MAAMJ,MAAMK,QAAQ;IAE5C,IAAI,CAACF,SAAS,CAACC,QAAQ,MAAM,IAAIE,MAAM;IAEvC,6DAA6D;IAC7D,IAAIH,QAAQC,QAAQ;QAClB,IAAID,QAAQJ,MAAM;YAChBK,SAASG,KAAKC,KAAK,CAAC,AAACJ,SAASL,OAAQI;YACtCA,QAAQJ;QACV;IACF,OAAO;QACL,IAAIK,SAASL,MAAM;YACjBI,QAAQI,KAAKC,KAAK,CAAC,AAACL,QAAQJ,OAAQK;YACpCA,SAASL;QACX;IACF;IAEA,OAAOC,MAAMS,MAAM,CAACN,OAAOC,QAAQ;QAAEM,KAAK;IAAS,GAAGC,GAAG,CAAC;QAAEC,kBAAkB;IAAE,GAAGC,QAAQ;AAC7F;AAEO,eAAenB,eAAeoB,QAAgB;IACnD,MAAMX,QAAQ;IACd,MAAMC,SAAS;IACf,MAAM,EAAEW,eAAe,EAAEC,eAAe,EAAE,GAAGC;IAE7C,MAAMC,WAAWC,iBAAI,CAACC,IAAI,CAACC,WAAW,SAAS;IAC/C,MAAMC,aAAa,AAAC,CAAA,MAAMC,iBAAE,CAACC,QAAQ,CAACN,SAAQ,EAAGO,QAAQ,CAAC;IAE1D,MAAMC,MAAM,CAAC;iDACkC,EAAEvB,MAAM,UAAU,EAAEC,OAAO;;;;uCAIrC,EAAEkB,WAAW;;;;;cAKtC,EAAEN,gBAAgB;;;;;2CAKW,EAAED,gBAAgB;0BACnC,EAAED,SAAS;;EAEnC,CAAC;IAED,uBAAuB;IACvB,MAAMa,QAAQ,IAAIC,cAAK,CAACF,KAAK;QAC3BG,OAAO;YAAEC,MAAM;YAASC,OAAO5B;QAAM;QACrC6B,MAAM;YACJC,WAAW;gBAACf;aAAS;YACrBgB,iBAAiB;QACnB;IACF;IAEA,OAAOP,MAAMQ,MAAM,GAAGC,KAAK;AAC7B;AAEO,eAAe3C,qBAAqB4C,OAAe;IACxD,MAAMC,eAAe,MAAMf,iBAAE,CAACC,QAAQ,CAACa,SAAS;QAAEE,UAAU;IAAS;IACrE,OAAO,CAAC,sBAAsB,EAAED,cAAc;AAChD;AAEA,SAASrB;IACP,IAAIuB,QAAQ;IACZ,MAAOA,MAAMC,MAAM,GAAG,EAAG;QACvB;;;KAGC,GACDD,QAAQjC,KAAKmC,KAAK,CAACnC,KAAKoC,MAAM,KAAK,UAAUlB,QAAQ,CAAC;IACxD;IACA,MAAMmB,MAAMC,SAASL,MAAMM,SAAS,CAAC,GAAG,IAAI;IAC5C,MAAMC,QAAQF,SAASL,MAAMM,SAAS,CAAC,GAAG,IAAI;IAC9C,MAAME,OAAOH,SAASL,MAAMM,SAAS,CAAC,GAAG,IAAI;IAC7C,MAAMG,aAAaL,MAAM,QAAQG,QAAQ,QAAQC,OAAO;IAExD,OAAO;QACLjC,iBAAiB,CAAC,CAAC,EAAEyB,OAAO;QAC5BxB,iBAAiBiC,aAAa,MAAM,YAAY;IAClD;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../backend/src/common/interfaces.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][]\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
1
+ {"version":3,"sources":["../../../backend/src/common/interfaces.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][]\n\nexport interface StorageQuota {\n storageUsage: number\n storageQuota: number\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
@@ -2,8 +2,7 @@
2
2
  * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
3
  * This file is part of Sync-in | The open source file sync and share solution
4
4
  * See the LICENSE file for licensing details
5
- */ // eslint-disable-next-line no-control-regex
6
- "use strict";
5
+ */ "use strict";
7
6
  Object.defineProperty(exports, "__esModule", {
8
7
  value: true
9
8
  });
@@ -14,6 +13,9 @@ function _export(target, all) {
14
13
  });
15
14
  }
16
15
  _export(exports, {
16
+ get SERVER_NAME () {
17
+ return SERVER_NAME;
18
+ },
17
19
  get capitalizeString () {
18
20
  return capitalizeString;
19
21
  },
@@ -60,6 +62,7 @@ _export(exports, {
60
62
  return regExpPreventPathTraversal;
61
63
  }
62
64
  });
65
+ const SERVER_NAME = 'Sync-in';
63
66
  const regExpInvalidFileName = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:"/\\|?*\x00-\x1f\x80-\x9f]/;
64
67
  const regExpPreventPathTraversal = /^(\.\.(\/|\\|$))+/;
65
68
  const regExpNumberSuffix = /-\d+$/;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../backend/src/common/shared.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\n// eslint-disable-next-line no-control-regex\nexport const regExpInvalidFileName = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:\"/\\\\|?*\\x00-\\x1f\\x80-\\x9f]/\nexport const regExpPreventPathTraversal = /^(\\.\\.(\\/|\\\\|$))+/\nexport const regExpNumberSuffix = /-\\d+$/\nexport const forbiddenChars = '\\\\ / : * ? \" < > |'\n\nexport function isValidFileName(fileName: string) {\n if (regExpInvalidFileName.test(fileName)) {\n throw new Error('Forbidden characters')\n }\n}\n\nexport function currentTimeStamp(date?: Date, ms = false): number {\n return Math.floor((date ? date : new Date()).getTime() / (ms ? 1 : 1000))\n}\n\nexport function currentDate(value?: string): Date {\n return new Date((value ? value : new Date().toISOString()).split('T')[0])\n}\n\nexport function createSlug(input: string, replaceCount = false): string {\n const r = input\n .toLowerCase()\n .trim()\n .replace(/[\\s_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n if (replaceCount) return r.replace(regExpNumberSuffix, '')\n return r\n}\n\nexport function createLightSlug(input: string) {\n return input\n .toLowerCase()\n .trim()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n}\n\nexport function genPassword(length = 12) {\n const chars = '0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n let password = ''\n for (let i = 0; i <= length; i++) {\n const randomNumber = Math.floor(Math.random() * chars.length)\n password += chars.substring(randomNumber, randomNumber + 1)\n }\n return password\n}\n\nexport function popFromObject(key: string, object: any): any {\n const item = object[key]\n delete object[key]\n return item\n}\n\nexport function encodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => encodeURIComponent(e))\n .join('/')\n}\n\nexport function decodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => decodeURIComponent(e))\n .join('/')\n}\n\nexport function objectPropertyFromString(obj: any, property: string): any {\n const a = property.split('.')\n let o = obj\n for (let i = 0, n = a.length; i < n; i++) {\n const k = a[i]\n if (k in o) {\n o = o[k]\n } else {\n return null\n }\n }\n return o\n}\n\nexport function capitalizeString(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1)\n}\n"],"names":["capitalizeString","createLightSlug","createSlug","currentDate","currentTimeStamp","decodeUrl","encodeUrl","forbiddenChars","genPassword","isValidFileName","objectPropertyFromString","popFromObject","regExpInvalidFileName","regExpNumberSuffix","regExpPreventPathTraversal","fileName","test","Error","date","ms","Math","floor","Date","getTime","value","toISOString","split","input","replaceCount","r","toLowerCase","trim","replace","normalize","length","chars","password","i","randomNumber","random","substring","key","object","item","url","map","e","encodeURIComponent","join","decodeURIComponent","obj","property","a","o","n","k","charAt","toUpperCase","slice"],"mappings":"AAAA;;;;CAIC,GAED,4CAA4C;;;;;;;;;;;;QAoF5BA;eAAAA;;QApDAC;eAAAA;;QAZAC;eAAAA;;QAJAC;eAAAA;;QAJAC;eAAAA;;QAmDAC;eAAAA;;QAPAC;eAAAA;;QApDHC;eAAAA;;QAoCGC;eAAAA;;QAlCAC;eAAAA;;QAgEAC;eAAAA;;QApBAC;eAAAA;;QAjDHC;eAAAA;;QAEAC;eAAAA;;QADAC;eAAAA;;;AADN,MAAMF,wBAAwB;AAC9B,MAAME,6BAA6B;AACnC,MAAMD,qBAAqB;AAC3B,MAAMN,iBAAiB;AAEvB,SAASE,gBAAgBM,QAAgB;IAC9C,IAAIH,sBAAsBI,IAAI,CAACD,WAAW;QACxC,MAAM,IAAIE,MAAM;IAClB;AACF;AAEO,SAASb,iBAAiBc,IAAW,EAAEC,KAAK,KAAK;IACtD,OAAOC,KAAKC,KAAK,CAAC,AAACH,CAAAA,OAAOA,OAAO,IAAII,MAAK,EAAGC,OAAO,KAAMJ,CAAAA,KAAK,IAAI,IAAG;AACxE;AAEO,SAAShB,YAAYqB,KAAc;IACxC,OAAO,IAAIF,KAAK,AAACE,CAAAA,QAAQA,QAAQ,IAAIF,OAAOG,WAAW,EAAC,EAAGC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC1E;AAEO,SAASxB,WAAWyB,KAAa,EAAEC,eAAe,KAAK;IAC5D,MAAMC,IAAIF,MACPG,WAAW,GACXC,IAAI,GACJC,OAAO,CAAC,YAAY,KACpBA,OAAO,CAAC,YAAY,IACpBC,SAAS,CAAC,OACVD,OAAO,CAAC,oBAAoB;IAC/B,IAAIJ,cAAc,OAAOC,EAAEG,OAAO,CAACnB,oBAAoB;IACvD,OAAOgB;AACT;AAEO,SAAS5B,gBAAgB0B,KAAa;IAC3C,OAAOA,MACJG,WAAW,GACXC,IAAI,GACJE,SAAS,CAAC,OACVD,OAAO,CAAC,oBAAoB;AACjC;AAEO,SAASxB,YAAY0B,SAAS,EAAE;IACrC,MAAMC,QAAQ;IACd,IAAIC,WAAW;IACf,IAAK,IAAIC,IAAI,GAAGA,KAAKH,QAAQG,IAAK;QAChC,MAAMC,eAAelB,KAAKC,KAAK,CAACD,KAAKmB,MAAM,KAAKJ,MAAMD,MAAM;QAC5DE,YAAYD,MAAMK,SAAS,CAACF,cAAcA,eAAe;IAC3D;IACA,OAAOF;AACT;AAEO,SAASzB,cAAc8B,GAAW,EAAEC,MAAW;IACpD,MAAMC,OAAOD,MAAM,CAACD,IAAI;IACxB,OAAOC,MAAM,CAACD,IAAI;IAClB,OAAOE;AACT;AAEO,SAASrC,UAAUsC,GAAW;IACnC,OAAOA,IACJlB,KAAK,CAAC,KACNmB,GAAG,CAAC,CAACC,IAAMC,mBAAmBD,IAC9BE,IAAI,CAAC;AACV;AAEO,SAAS3C,UAAUuC,GAAW;IACnC,OAAOA,IACJlB,KAAK,CAAC,KACNmB,GAAG,CAAC,CAACC,IAAMG,mBAAmBH,IAC9BE,IAAI,CAAC;AACV;AAEO,SAAStC,yBAAyBwC,GAAQ,EAAEC,QAAgB;IACjE,MAAMC,IAAID,SAASzB,KAAK,CAAC;IACzB,IAAI2B,IAAIH;IACR,IAAK,IAAIb,IAAI,GAAGiB,IAAIF,EAAElB,MAAM,EAAEG,IAAIiB,GAAGjB,IAAK;QACxC,MAAMkB,IAAIH,CAAC,CAACf,EAAE;QACd,IAAIkB,KAAKF,GAAG;YACVA,IAAIA,CAAC,CAACE,EAAE;QACV,OAAO;YACL,OAAO;QACT;IACF;IACA,OAAOF;AACT;AAEO,SAASrD,iBAAiBwB,KAAa;IAC5C,OAAOA,MAAMgC,MAAM,CAAC,GAAGC,WAAW,KAAKjC,MAAMkC,KAAK,CAAC;AACrD"}
1
+ {"version":3,"sources":["../../../backend/src/common/shared.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const SERVER_NAME = 'Sync-in' as const\n\n// eslint-disable-next-line no-control-regex\nexport const regExpInvalidFileName = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:\"/\\\\|?*\\x00-\\x1f\\x80-\\x9f]/\nexport const regExpPreventPathTraversal = /^(\\.\\.(\\/|\\\\|$))+/\nexport const regExpNumberSuffix = /-\\d+$/\nexport const forbiddenChars = '\\\\ / : * ? \" < > |'\n\nexport function isValidFileName(fileName: string) {\n if (regExpInvalidFileName.test(fileName)) {\n throw new Error('Forbidden characters')\n }\n}\n\nexport function currentTimeStamp(date?: Date, ms = false): number {\n return Math.floor((date ? date : new Date()).getTime() / (ms ? 1 : 1000))\n}\n\nexport function currentDate(value?: string): Date {\n return new Date((value ? value : new Date().toISOString()).split('T')[0])\n}\n\nexport function createSlug(input: string, replaceCount = false): string {\n const r = input\n .toLowerCase()\n .trim()\n .replace(/[\\s_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n if (replaceCount) return r.replace(regExpNumberSuffix, '')\n return r\n}\n\nexport function createLightSlug(input: string) {\n return input\n .toLowerCase()\n .trim()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n}\n\nexport function genPassword(length = 12) {\n const chars = '0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n let password = ''\n for (let i = 0; i <= length; i++) {\n const randomNumber = Math.floor(Math.random() * chars.length)\n password += chars.substring(randomNumber, randomNumber + 1)\n }\n return password\n}\n\nexport function popFromObject(key: string, object: any): any {\n const item = object[key]\n delete object[key]\n return item\n}\n\nexport function encodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => encodeURIComponent(e))\n .join('/')\n}\n\nexport function decodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => decodeURIComponent(e))\n .join('/')\n}\n\nexport function objectPropertyFromString(obj: any, property: string): any {\n const a = property.split('.')\n let o = obj\n for (let i = 0, n = a.length; i < n; i++) {\n const k = a[i]\n if (k in o) {\n o = o[k]\n } else {\n return null\n }\n }\n return o\n}\n\nexport function capitalizeString(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1)\n}\n"],"names":["SERVER_NAME","capitalizeString","createLightSlug","createSlug","currentDate","currentTimeStamp","decodeUrl","encodeUrl","forbiddenChars","genPassword","isValidFileName","objectPropertyFromString","popFromObject","regExpInvalidFileName","regExpNumberSuffix","regExpPreventPathTraversal","fileName","test","Error","date","ms","Math","floor","Date","getTime","value","toISOString","split","input","replaceCount","r","toLowerCase","trim","replace","normalize","length","chars","password","i","randomNumber","random","substring","key","object","item","url","map","e","encodeURIComponent","join","decodeURIComponent","obj","property","a","o","n","k","charAt","toUpperCase","slice"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAEYA;eAAAA;;QAsFGC;eAAAA;;QApDAC;eAAAA;;QAZAC;eAAAA;;QAJAC;eAAAA;;QAJAC;eAAAA;;QAmDAC;eAAAA;;QAPAC;eAAAA;;QApDHC;eAAAA;;QAoCGC;eAAAA;;QAlCAC;eAAAA;;QAgEAC;eAAAA;;QApBAC;eAAAA;;QAjDHC;eAAAA;;QAEAC;eAAAA;;QADAC;eAAAA;;;AAJN,MAAMf,cAAc;AAGpB,MAAMa,wBAAwB;AAC9B,MAAME,6BAA6B;AACnC,MAAMD,qBAAqB;AAC3B,MAAMN,iBAAiB;AAEvB,SAASE,gBAAgBM,QAAgB;IAC9C,IAAIH,sBAAsBI,IAAI,CAACD,WAAW;QACxC,MAAM,IAAIE,MAAM;IAClB;AACF;AAEO,SAASb,iBAAiBc,IAAW,EAAEC,KAAK,KAAK;IACtD,OAAOC,KAAKC,KAAK,CAAC,AAACH,CAAAA,OAAOA,OAAO,IAAII,MAAK,EAAGC,OAAO,KAAMJ,CAAAA,KAAK,IAAI,IAAG;AACxE;AAEO,SAAShB,YAAYqB,KAAc;IACxC,OAAO,IAAIF,KAAK,AAACE,CAAAA,QAAQA,QAAQ,IAAIF,OAAOG,WAAW,EAAC,EAAGC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC1E;AAEO,SAASxB,WAAWyB,KAAa,EAAEC,eAAe,KAAK;IAC5D,MAAMC,IAAIF,MACPG,WAAW,GACXC,IAAI,GACJC,OAAO,CAAC,YAAY,KACpBA,OAAO,CAAC,YAAY,IACpBC,SAAS,CAAC,OACVD,OAAO,CAAC,oBAAoB;IAC/B,IAAIJ,cAAc,OAAOC,EAAEG,OAAO,CAACnB,oBAAoB;IACvD,OAAOgB;AACT;AAEO,SAAS5B,gBAAgB0B,KAAa;IAC3C,OAAOA,MACJG,WAAW,GACXC,IAAI,GACJE,SAAS,CAAC,OACVD,OAAO,CAAC,oBAAoB;AACjC;AAEO,SAASxB,YAAY0B,SAAS,EAAE;IACrC,MAAMC,QAAQ;IACd,IAAIC,WAAW;IACf,IAAK,IAAIC,IAAI,GAAGA,KAAKH,QAAQG,IAAK;QAChC,MAAMC,eAAelB,KAAKC,KAAK,CAACD,KAAKmB,MAAM,KAAKJ,MAAMD,MAAM;QAC5DE,YAAYD,MAAMK,SAAS,CAACF,cAAcA,eAAe;IAC3D;IACA,OAAOF;AACT;AAEO,SAASzB,cAAc8B,GAAW,EAAEC,MAAW;IACpD,MAAMC,OAAOD,MAAM,CAACD,IAAI;IACxB,OAAOC,MAAM,CAACD,IAAI;IAClB,OAAOE;AACT;AAEO,SAASrC,UAAUsC,GAAW;IACnC,OAAOA,IACJlB,KAAK,CAAC,KACNmB,GAAG,CAAC,CAACC,IAAMC,mBAAmBD,IAC9BE,IAAI,CAAC;AACV;AAEO,SAAS3C,UAAUuC,GAAW;IACnC,OAAOA,IACJlB,KAAK,CAAC,KACNmB,GAAG,CAAC,CAACC,IAAMG,mBAAmBH,IAC9BE,IAAI,CAAC;AACV;AAEO,SAAStC,yBAAyBwC,GAAQ,EAAEC,QAAgB;IACjE,MAAMC,IAAID,SAASzB,KAAK,CAAC;IACzB,IAAI2B,IAAIH;IACR,IAAK,IAAIb,IAAI,GAAGiB,IAAIF,EAAElB,MAAM,EAAEG,IAAIiB,GAAGjB,IAAK;QACxC,MAAMkB,IAAIH,CAAC,CAACf,EAAE;QACd,IAAIkB,KAAKF,GAAG;YACVA,IAAIA,CAAC,CAACE,EAAE;QACV,OAAO;YACL,OAAO;QACT;IACF;IACA,OAAOF;AACT;AAEO,SAASrD,iBAAiBwB,KAAa;IAC5C,OAAOA,MAAMgC,MAAM,CAAC,GAAGC,WAAW,KAAKjC,MAAMkC,KAAK,CAAC;AACrD"}
@@ -46,7 +46,7 @@ let ServerConfig = class ServerConfig {
46
46
  constructor(){
47
47
  this.host = '0.0.0.0';
48
48
  this.port = 8080;
49
- this.workers = 2;
49
+ this.workers = 1;
50
50
  this.trustProxy = 1;
51
51
  this.restartOnFailure = true;
52
52
  }
@@ -62,9 +62,9 @@ _ts_decorate([
62
62
  _ts_metadata("design:type", Number)
63
63
  ], ServerConfig.prototype, "port", void 0);
64
64
  _ts_decorate([
65
- (0, _classtransformer.Transform)(({ value })=>value === 0 || value === 'auto' ? (0, _nodeos.cpus)().length : Math.max(Number(value), 2)),
65
+ (0, _classtransformer.Transform)(({ value })=>value === 0 || value === 'auto' ? (0, _nodeos.cpus)().length : Math.max(Number(value), 1)),
66
66
  (0, _classvalidator.IsInt)(),
67
- (0, _classvalidator.Min)(2),
67
+ (0, _classvalidator.Min)(1),
68
68
  _ts_metadata("design:type", Number)
69
69
  ], ServerConfig.prototype, "workers", void 0);
70
70
  _ts_decorate([
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../backend/src/configuration/config.validation.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Transform, Type } from 'class-transformer'\nimport {\n IsBoolean,\n IsDefined,\n IsInt,\n IsIP,\n IsNotEmpty,\n IsNotEmptyObject,\n IsObject,\n IsOptional,\n IsString,\n Max,\n Min,\n ValidateNested\n} from 'class-validator'\nimport { cpus } from 'node:os'\nimport type { Level } from 'pino'\nimport { ApplicationsConfig } from '../applications/applications.config'\nimport { AuthConfig } from '../authentication/auth.config'\nimport { CacheConfig } from '../infrastructure/cache/cache.config'\nimport { MySQLConfig } from '../infrastructure/database/database.config'\nimport { MailerConfig } from '../infrastructure/mailer/mailer.config'\nimport { WebSocketConfig } from '../infrastructure/websocket/web-socket.config'\nimport { DEFAULT_LOG_FILE_PATH } from './config.constants'\n\nexport class ServerConfig {\n @IsIP()\n host: string = '0.0.0.0'\n\n @IsInt()\n @Min(1024)\n @Max(65535)\n port: number = 8080\n\n @Transform(({ value }) => (value === 0 || value === 'auto' ? cpus().length : Math.max(Number(value), 2)))\n @IsInt()\n @Min(2)\n workers: number = 2\n\n @IsOptional()\n trustProxy: boolean | string | number = 1\n\n @IsBoolean()\n restartOnFailure: boolean = true\n}\n\nexport class LoggerConfig {\n @IsString()\n @IsNotEmpty()\n level: Level = 'info'\n\n @IsBoolean()\n stdout: boolean = true\n\n @IsBoolean()\n colorize: boolean = true\n\n @IsOptional()\n @IsString()\n @Transform(({ value }) => value || DEFAULT_LOG_FILE_PATH)\n filePath: string = DEFAULT_LOG_FILE_PATH\n}\n\nexport class GlobalConfig {\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => ServerConfig)\n server: ServerConfig = new ServerConfig()\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => LoggerConfig)\n logger: LoggerConfig = new LoggerConfig()\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => MySQLConfig)\n mysql: MySQLConfig\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => CacheConfig)\n cache: CacheConfig = new CacheConfig()\n\n @IsOptional()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => WebSocketConfig)\n websocket: WebSocketConfig = new WebSocketConfig()\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => AuthConfig)\n auth: AuthConfig\n\n @IsOptional()\n @IsObject()\n @ValidateNested()\n @Type(() => MailerConfig)\n mail?: MailerConfig\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => ApplicationsConfig)\n applications: ApplicationsConfig\n}\n"],"names":["GlobalConfig","LoggerConfig","ServerConfig","host","port","workers","trustProxy","restartOnFailure","value","cpus","length","Math","max","Number","level","stdout","colorize","filePath","DEFAULT_LOG_FILE_PATH","server","logger","cache","CacheConfig","websocket","WebSocketConfig","MySQLConfig","AuthConfig","MailerConfig","ApplicationsConfig"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAiEYA;eAAAA;;QAjBAC;eAAAA;;QArBAC;eAAAA;;;kCAzBmB;gCAczB;wBACc;oCAEc;4BACR;6BACC;gCACA;8BACC;iCACG;iCACM;;;;;;;;;;AAE/B,IAAA,AAAMA,eAAN,MAAMA;;aAEXC,OAAe;aAKfC,OAAe;aAKfC,UAAkB;aAGlBC,aAAwC;aAGxCC,mBAA4B;;AAC9B;;;;;;;;;;;;sCAVc,EAAEC,KAAK,EAAE,GAAMA,UAAU,KAAKA,UAAU,SAASC,IAAAA,YAAI,IAAGC,MAAM,GAAGC,KAAKC,GAAG,CAACC,OAAOL,QAAQ;;;;;;;;;;;;;AAYhG,IAAA,AAAMP,eAAN,MAAMA;;aAGXa,QAAe;aAGfC,SAAkB;aAGlBC,WAAoB;aAKpBC,WAAmBC,sCAAqB;;AAC1C;;;;;;;;;;;;;;;;;sCAFc,EAAEV,KAAK,EAAE,GAAKA,SAASU,sCAAqB;;;AAInD,IAAA,AAAMlB,eAAN,MAAMA;;aAMXmB,SAAuB,IAAIjB;aAO3BkB,SAAuB,IAAInB;aAc3BoB,QAAqB,IAAIC,wBAAW;aAOpCC,YAA6B,IAAIC,gCAAe;;AAqBlD;;;;;;oCAlDctB;;;;;;;;oCAOAD;;;;;;;;oCAOAwB,2BAAW;;;;;;;;oCAOXH,wBAAW;;;;;;;;oCAOXE,gCAAe;;;;;;;;oCAOfE,sBAAU;;;;;;;oCAMVC,0BAAY;;;;;;;;oCAOZC,sCAAkB"}
1
+ {"version":3,"sources":["../../../backend/src/configuration/config.validation.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Transform, Type } from 'class-transformer'\nimport {\n IsBoolean,\n IsDefined,\n IsInt,\n IsIP,\n IsNotEmpty,\n IsNotEmptyObject,\n IsObject,\n IsOptional,\n IsString,\n Max,\n Min,\n ValidateNested\n} from 'class-validator'\nimport { cpus } from 'node:os'\nimport type { Level } from 'pino'\nimport { ApplicationsConfig } from '../applications/applications.config'\nimport { AuthConfig } from '../authentication/auth.config'\nimport { CacheConfig } from '../infrastructure/cache/cache.config'\nimport { MySQLConfig } from '../infrastructure/database/database.config'\nimport { MailerConfig } from '../infrastructure/mailer/mailer.config'\nimport { WebSocketConfig } from '../infrastructure/websocket/web-socket.config'\nimport { DEFAULT_LOG_FILE_PATH } from './config.constants'\n\nexport class ServerConfig {\n @IsIP()\n host: string = '0.0.0.0'\n\n @IsInt()\n @Min(1024)\n @Max(65535)\n port: number = 8080\n\n @Transform(({ value }) => (value === 0 || value === 'auto' ? cpus().length : Math.max(Number(value), 1)))\n @IsInt()\n @Min(1)\n workers: number = 1\n\n @IsOptional()\n trustProxy: boolean | string | number = 1\n\n @IsBoolean()\n restartOnFailure: boolean = true\n}\n\nexport class LoggerConfig {\n @IsString()\n @IsNotEmpty()\n level: Level = 'info'\n\n @IsBoolean()\n stdout: boolean = true\n\n @IsBoolean()\n colorize: boolean = true\n\n @IsOptional()\n @IsString()\n @Transform(({ value }) => value || DEFAULT_LOG_FILE_PATH)\n filePath: string = DEFAULT_LOG_FILE_PATH\n}\n\nexport class GlobalConfig {\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => ServerConfig)\n server: ServerConfig = new ServerConfig()\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => LoggerConfig)\n logger: LoggerConfig = new LoggerConfig()\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => MySQLConfig)\n mysql: MySQLConfig\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => CacheConfig)\n cache: CacheConfig = new CacheConfig()\n\n @IsOptional()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => WebSocketConfig)\n websocket: WebSocketConfig = new WebSocketConfig()\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => AuthConfig)\n auth: AuthConfig\n\n @IsOptional()\n @IsObject()\n @ValidateNested()\n @Type(() => MailerConfig)\n mail?: MailerConfig\n\n @IsDefined()\n @IsObject()\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => ApplicationsConfig)\n applications: ApplicationsConfig\n}\n"],"names":["GlobalConfig","LoggerConfig","ServerConfig","host","port","workers","trustProxy","restartOnFailure","value","cpus","length","Math","max","Number","level","stdout","colorize","filePath","DEFAULT_LOG_FILE_PATH","server","logger","cache","CacheConfig","websocket","WebSocketConfig","MySQLConfig","AuthConfig","MailerConfig","ApplicationsConfig"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAiEYA;eAAAA;;QAjBAC;eAAAA;;QArBAC;eAAAA;;;kCAzBmB;gCAczB;wBACc;oCAEc;4BACR;6BACC;gCACA;8BACC;iCACG;iCACM;;;;;;;;;;AAE/B,IAAA,AAAMA,eAAN,MAAMA;;aAEXC,OAAe;aAKfC,OAAe;aAKfC,UAAkB;aAGlBC,aAAwC;aAGxCC,mBAA4B;;AAC9B;;;;;;;;;;;;sCAVc,EAAEC,KAAK,EAAE,GAAMA,UAAU,KAAKA,UAAU,SAASC,IAAAA,YAAI,IAAGC,MAAM,GAAGC,KAAKC,GAAG,CAACC,OAAOL,QAAQ;;;;;;;;;;;;;AAYhG,IAAA,AAAMP,eAAN,MAAMA;;aAGXa,QAAe;aAGfC,SAAkB;aAGlBC,WAAoB;aAKpBC,WAAmBC,sCAAqB;;AAC1C;;;;;;;;;;;;;;;;;sCAFc,EAAEV,KAAK,EAAE,GAAKA,SAASU,sCAAqB;;;AAInD,IAAA,AAAMlB,eAAN,MAAMA;;aAMXmB,SAAuB,IAAIjB;aAO3BkB,SAAuB,IAAInB;aAc3BoB,QAAqB,IAAIC,wBAAW;aAOpCC,YAA6B,IAAIC,gCAAe;;AAqBlD;;;;;;oCAlDctB;;;;;;;;oCAOAD;;;;;;;;oCAOAwB,2BAAW;;;;;;;;oCAOXH,wBAAW;;;;;;;;oCAOXE,gCAAe;;;;;;;;oCAOfE,sBAAU;;;;;;;oCAMVC,0BAAY;;;;;;;;oCAOZC,sCAAkB"}
@@ -22,6 +22,7 @@ const _configenvironment = require("../../../configuration/config.environment");
22
22
  const _constants = require("../../database/constants");
23
23
  const _databaseinterface = require("../../database/interfaces/database.interface");
24
24
  const _utils = require("../../database/utils");
25
+ const _schedulerconstants = require("../../scheduler/scheduler.constants");
25
26
  const _mysqlcacheschema = require("../schemas/mysql-cache.schema");
26
27
  const _cacheservice = require("../services/cache.service");
27
28
  function _interop_require_default(obj) {
@@ -44,8 +45,8 @@ function _ts_param(paramIndex, decorator) {
44
45
  };
45
46
  }
46
47
  let MysqlCacheAdapter = class MysqlCacheAdapter {
47
- async initScheduler() {
48
- if (!_nodecluster.default.worker || _nodecluster.default.worker.id === 1) {
48
+ async onModuleInit() {
49
+ if (_nodecluster.default.isWorker && process.env[_schedulerconstants.SCHEDULER_ENV] === _schedulerconstants.SCHEDULER_STATE.ENABLED) {
49
50
  try {
50
51
  await this.db.execute(`SET GLOBAL event_scheduler = ON;`);
51
52
  await this.db.execute(`DROP EVENT IF EXISTS ${this.scheduledJobName};`);
@@ -62,6 +63,11 @@ let MysqlCacheAdapter = class MysqlCacheAdapter {
62
63
  }
63
64
  }
64
65
  }
66
+ async onModuleDestroy() {
67
+ if (this.scheduledJob) {
68
+ await this.scheduledJob.stop();
69
+ }
70
+ }
65
71
  async keys(pattern) {
66
72
  const ks = await this.db.select({
67
73
  key: _mysqlcacheschema.cache.key
@@ -117,9 +123,6 @@ let MysqlCacheAdapter = class MysqlCacheAdapter {
117
123
  genSlugKey(...args) {
118
124
  return (0, _shared.createSlug)(args.join(' '));
119
125
  }
120
- async quit() {
121
- this.logger.verbose(`${this.quit.name}`);
122
- }
123
126
  getTTL(ttl) {
124
127
  /* ttl (seconds):
125
128
  - 0 : infinite expiration
@@ -153,7 +156,6 @@ let MysqlCacheAdapter = class MysqlCacheAdapter {
153
156
  this.logger = new _common.Logger(_cacheservice.Cache.name.toUpperCase());
154
157
  this.whereNotExpired = ()=>(0, _drizzleorm.notBetween)(_mysqlcacheschema.cache.expiration, 0, (0, _shared.currentTimeStamp)());
155
158
  this.whereExpired = ()=>(0, _drizzleorm.between)(_mysqlcacheschema.cache.expiration, 0, (0, _shared.currentTimeStamp)());
156
- this.initScheduler().catch((e)=>this.logger.error(e));
157
159
  }
158
160
  };
159
161
  MysqlCacheAdapter = _ts_decorate([
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/infrastructure/cache/adapters/mysql-cache.adapter.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable, Logger } from '@nestjs/common'\nimport { SchedulerRegistry } from '@nestjs/schedule'\nimport { CronJob } from 'cron'\nimport { and, between, eq, exists, inArray, like, notBetween, SQL } from 'drizzle-orm'\nimport cluster from 'node:cluster'\nimport { createSlug, currentTimeStamp } from '../../../common/shared'\nimport { configuration } from '../../../configuration/config.environment'\nimport { DB_TOKEN_PROVIDER } from '../../database/constants'\nimport { DBSchema } from '../../database/interfaces/database.interface'\nimport { dbCheckAffectedRows } from '../../database/utils'\nimport { MysqlCache } from '../schemas/mysql-cache.interface'\nimport { cache } from '../schemas/mysql-cache.schema'\nimport { Cache } from '../services/cache.service'\n\n@Injectable()\nexport class MysqlCacheAdapter implements Cache {\n /* Useful SQL commands to stats the scheduler\n SHOW VARIABLES LIKE 'event_scheduler';\n SHOW EVENTS;\n */\n defaultTTL: number = configuration.cache.ttl\n infiniteExpiration = -1\n private scheduledJob: CronJob\n private readonly scheduledJobName = 'cache_expired_keys' as const\n private readonly scheduledJobInterval = 5 // minutes\n private readonly logger = new Logger(Cache.name.toUpperCase())\n\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly scheduler: SchedulerRegistry\n ) {\n this.initScheduler().catch((e: Error) => this.logger.error(e))\n }\n\n async initScheduler(): Promise<void> {\n if (!cluster.worker || cluster.worker.id === 1) {\n try {\n await this.db.execute(`SET GLOBAL event_scheduler = ON;`)\n await this.db.execute(`DROP EVENT IF EXISTS ${this.scheduledJobName};`)\n await this.db.execute(`CREATE EVENT IF NOT EXISTS ${this.scheduledJobName}\n ON SCHEDULE EVERY ${this.scheduledJobInterval} MINUTE\n DO DELETE FROM cache WHERE cache.expiration BETWEEN 0 AND UNIX_TIMESTAMP();`)\n this.logger.log(`Using MySQL scheduler`)\n } catch (e) {\n this.logger.error(`MySQL scheduler on '${e?.sql || e?.code}' : ${e.message || e}`)\n this.logger.warn(`Fallback to internal scheduler`)\n this.scheduledJob = new CronJob(`0 */${this.scheduledJobInterval} * * * *`, async () => await this.clearExpiredKeys())\n this.scheduler.addCronJob(this.scheduledJobName, this.scheduledJob)\n this.scheduledJob.start()\n }\n }\n }\n\n async keys(pattern: string): Promise<string[]> {\n const ks = await this.db\n .select({ key: cache.key })\n .from(cache)\n .where(and(like(cache.key, pattern.replaceAll('*', '%')), this.whereNotExpired()))\n return ks.map((k: { key: string }) => k.key)\n }\n\n async has(key: string): Promise<boolean> {\n const [r] = await this.db\n .select({ key: cache.key })\n .from(cache)\n .where(\n exists(\n this.db\n .select({ key: cache.key })\n .from(cache)\n .where(and(eq(cache.key, key), this.whereNotExpired()))\n )\n )\n return !!r\n }\n\n async get(key: string): Promise<any> {\n const [v]: { value: any }[] = await this.db\n .select({ value: cache.value })\n .from(cache)\n .where(and(eq(cache.key, key), this.whereNotExpired()))\n .limit(1)\n return v ? v.value : v\n }\n\n async mget(keys: string[]): Promise<any[]> {\n const vs: { value: any }[] = await this.db\n .select({ value: cache.value })\n .from(cache)\n .where(and(inArray(cache.key, keys), this.whereNotExpired()))\n return vs.map((v: { value: any }) => v.value)\n }\n\n async set(key: any, data: any, ttl?: number): Promise<boolean> {\n data = this.serialize(data)\n const exp = this.getTTL(ttl)\n try {\n await this.db\n .insert(cache)\n .values({ key: key, value: data, expiration: exp } as MysqlCache)\n .onDuplicateKeyUpdate({\n set: {\n value: data,\n expiration: exp\n } as Partial<MysqlCache>\n })\n return true\n } catch (e) {\n this.logger.error(`${this.set.name} - ${e}`)\n return false\n }\n }\n\n async del(key: string): Promise<boolean> {\n return dbCheckAffectedRows(await this.db.delete(cache).where(eq(cache.key, key)), 1, false)\n }\n\n async mdel(keys: string[]): Promise<boolean> {\n return dbCheckAffectedRows(await this.db.delete(cache).where(inArray(cache.key, keys)), keys.length, false)\n }\n\n genSlugKey(...args: any[]): string {\n return createSlug(args.join(' '))\n }\n\n async quit(): Promise<void> {\n this.logger.verbose(`${this.quit.name}`)\n }\n\n private readonly whereNotExpired: () => SQL = () => notBetween(cache.expiration, 0, currentTimeStamp())\n\n private readonly whereExpired: () => SQL = () => between(cache.expiration, 0, currentTimeStamp())\n\n private getTTL(ttl: number): number {\n /* ttl (seconds):\n - 0 : infinite expiration\n - undefined : default ttl\n */\n return ttl ? currentTimeStamp() + ttl : ttl === 0 ? this.infiniteExpiration : currentTimeStamp() + this.defaultTTL\n }\n\n private serialize(data: any) {\n if (data === undefined) {\n // undefined values are not handled by JSON serialization\n return null\n }\n return data\n }\n\n private async clearExpiredKeys() {\n try {\n await this.db.delete(cache).where(this.whereExpired())\n } catch (e) {\n this.logger.error(`${this.clearExpiredKeys.name} - ${e?.code || e}`)\n }\n }\n}\n"],"names":["MysqlCacheAdapter","initScheduler","cluster","worker","id","db","execute","scheduledJobName","scheduledJobInterval","logger","log","e","error","sql","code","message","warn","scheduledJob","CronJob","clearExpiredKeys","scheduler","addCronJob","start","keys","pattern","ks","select","key","cache","from","where","and","like","replaceAll","whereNotExpired","map","k","has","r","exists","eq","get","v","value","limit","mget","vs","inArray","set","data","ttl","serialize","exp","getTTL","insert","values","expiration","onDuplicateKeyUpdate","name","del","dbCheckAffectedRows","delete","mdel","length","genSlugKey","args","createSlug","join","quit","verbose","currentTimeStamp","infiniteExpiration","defaultTTL","undefined","whereExpired","configuration","Logger","Cache","toUpperCase","notBetween","between","catch"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/infrastructure/cache/adapters/mysql-cache.adapter.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable, Logger } from '@nestjs/common'\nimport { SchedulerRegistry } from '@nestjs/schedule'\nimport { CronJob } from 'cron'\nimport { and, between, eq, exists, inArray, like, notBetween, SQL } from 'drizzle-orm'\nimport cluster from 'node:cluster'\nimport { createSlug, currentTimeStamp } from '../../../common/shared'\nimport { configuration } from '../../../configuration/config.environment'\nimport { DB_TOKEN_PROVIDER } from '../../database/constants'\nimport { DBSchema } from '../../database/interfaces/database.interface'\nimport { dbCheckAffectedRows } from '../../database/utils'\nimport { SCHEDULER_ENV, SCHEDULER_STATE } from '../../scheduler/scheduler.constants'\nimport { MysqlCache } from '../schemas/mysql-cache.interface'\nimport { cache } from '../schemas/mysql-cache.schema'\nimport { Cache } from '../services/cache.service'\n\n@Injectable()\nexport class MysqlCacheAdapter implements Cache {\n /* Useful SQL commands to stats the scheduler\n SHOW VARIABLES LIKE 'event_scheduler';\n SHOW EVENTS;\n */\n defaultTTL: number = configuration.cache.ttl\n infiniteExpiration = -1\n private scheduledJob: CronJob\n private readonly scheduledJobName = 'cache_expired_keys' as const\n private readonly scheduledJobInterval = 5 // minutes\n private readonly logger = new Logger(Cache.name.toUpperCase())\n\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly scheduler: SchedulerRegistry\n ) {}\n\n async onModuleInit(): Promise<void> {\n if (cluster.isWorker && process.env[SCHEDULER_ENV] === SCHEDULER_STATE.ENABLED) {\n try {\n await this.db.execute(`SET GLOBAL event_scheduler = ON;`)\n await this.db.execute(`DROP EVENT IF EXISTS ${this.scheduledJobName};`)\n await this.db.execute(`CREATE EVENT IF NOT EXISTS ${this.scheduledJobName}\n ON SCHEDULE EVERY ${this.scheduledJobInterval} MINUTE\n DO DELETE FROM cache WHERE cache.expiration BETWEEN 0 AND UNIX_TIMESTAMP();`)\n this.logger.log(`Using MySQL scheduler`)\n } catch (e) {\n this.logger.error(`MySQL scheduler on '${e?.sql || e?.code}' : ${e.message || e}`)\n this.logger.warn(`Fallback to internal scheduler`)\n this.scheduledJob = new CronJob(`0 */${this.scheduledJobInterval} * * * *`, async () => await this.clearExpiredKeys())\n this.scheduler.addCronJob(this.scheduledJobName, this.scheduledJob)\n this.scheduledJob.start()\n }\n }\n }\n\n async onModuleDestroy(): Promise<void> {\n if (this.scheduledJob) {\n await this.scheduledJob.stop()\n }\n }\n\n async keys(pattern: string): Promise<string[]> {\n const ks = await this.db\n .select({ key: cache.key })\n .from(cache)\n .where(and(like(cache.key, pattern.replaceAll('*', '%')), this.whereNotExpired()))\n return ks.map((k: { key: string }) => k.key)\n }\n\n async has(key: string): Promise<boolean> {\n const [r] = await this.db\n .select({ key: cache.key })\n .from(cache)\n .where(\n exists(\n this.db\n .select({ key: cache.key })\n .from(cache)\n .where(and(eq(cache.key, key), this.whereNotExpired()))\n )\n )\n return !!r\n }\n\n async get(key: string): Promise<any> {\n const [v]: { value: any }[] = await this.db\n .select({ value: cache.value })\n .from(cache)\n .where(and(eq(cache.key, key), this.whereNotExpired()))\n .limit(1)\n return v ? v.value : v\n }\n\n async mget(keys: string[]): Promise<any[]> {\n const vs: { value: any }[] = await this.db\n .select({ value: cache.value })\n .from(cache)\n .where(and(inArray(cache.key, keys), this.whereNotExpired()))\n return vs.map((v: { value: any }) => v.value)\n }\n\n async set(key: string, data: unknown, ttl?: number): Promise<boolean> {\n data = this.serialize(data)\n const exp = this.getTTL(ttl)\n try {\n await this.db\n .insert(cache)\n .values({ key: key, value: data, expiration: exp } as MysqlCache)\n .onDuplicateKeyUpdate({\n set: {\n value: data,\n expiration: exp\n } as Partial<MysqlCache>\n })\n return true\n } catch (e) {\n this.logger.error(`${this.set.name} - ${e}`)\n return false\n }\n }\n\n async del(key: string): Promise<boolean> {\n return dbCheckAffectedRows(await this.db.delete(cache).where(eq(cache.key, key)), 1, false)\n }\n\n async mdel(keys: string[]): Promise<boolean> {\n return dbCheckAffectedRows(await this.db.delete(cache).where(inArray(cache.key, keys)), keys.length, false)\n }\n\n genSlugKey(...args: any[]): string {\n return createSlug(args.join(' '))\n }\n\n private readonly whereNotExpired: () => SQL = () => notBetween(cache.expiration, 0, currentTimeStamp())\n\n private readonly whereExpired: () => SQL = () => between(cache.expiration, 0, currentTimeStamp())\n\n private getTTL(ttl: number): number {\n /* ttl (seconds):\n - 0 : infinite expiration\n - undefined : default ttl\n */\n return ttl ? currentTimeStamp() + ttl : ttl === 0 ? this.infiniteExpiration : currentTimeStamp() + this.defaultTTL\n }\n\n private serialize(data: any) {\n if (data === undefined) {\n // undefined values are not handled by JSON serialization\n return null\n }\n return data\n }\n\n private async clearExpiredKeys() {\n try {\n await this.db.delete(cache).where(this.whereExpired())\n } catch (e) {\n this.logger.error(`${this.clearExpiredKeys.name} - ${e?.code || e}`)\n }\n }\n}\n"],"names":["MysqlCacheAdapter","onModuleInit","cluster","isWorker","process","env","SCHEDULER_ENV","SCHEDULER_STATE","ENABLED","db","execute","scheduledJobName","scheduledJobInterval","logger","log","e","error","sql","code","message","warn","scheduledJob","CronJob","clearExpiredKeys","scheduler","addCronJob","start","onModuleDestroy","stop","keys","pattern","ks","select","key","cache","from","where","and","like","replaceAll","whereNotExpired","map","k","has","r","exists","eq","get","v","value","limit","mget","vs","inArray","set","data","ttl","serialize","exp","getTTL","insert","values","expiration","onDuplicateKeyUpdate","name","del","dbCheckAffectedRows","delete","mdel","length","genSlugKey","args","createSlug","join","currentTimeStamp","infiniteExpiration","defaultTTL","undefined","whereExpired","configuration","Logger","Cache","toUpperCase","notBetween","between"],"mappings":"AAAA;;;;CAIC;;;;+BAkBYA;;;eAAAA;;;wBAhB8B;0BACT;sBACV;4BACiD;oEACrD;wBACyB;mCACf;2BACI;mCACT;uBACW;oCACW;kCAEzB;8BACA;;;;;;;;;;;;;;;;;;;;AAGf,IAAA,AAAMA,oBAAN,MAAMA;IAiBX,MAAMC,eAA8B;QAClC,IAAIC,oBAAO,CAACC,QAAQ,IAAIC,QAAQC,GAAG,CAACC,iCAAa,CAAC,KAAKC,mCAAe,CAACC,OAAO,EAAE;YAC9E,IAAI;gBACF,MAAM,IAAI,CAACC,EAAE,CAACC,OAAO,CAAC,CAAC,gCAAgC,CAAC;gBACxD,MAAM,IAAI,CAACD,EAAE,CAACC,OAAO,CAAC,CAAC,qBAAqB,EAAE,IAAI,CAACC,gBAAgB,CAAC,CAAC,CAAC;gBACtE,MAAM,IAAI,CAACF,EAAE,CAACC,OAAO,CAAC,CAAC,2BAA2B,EAAE,IAAI,CAACC,gBAAgB,CAAC;iDACjC,EAAE,IAAI,CAACC,oBAAoB,CAAC;0GAC6B,CAAC;gBACnG,IAAI,CAACC,MAAM,CAACC,GAAG,CAAC,CAAC,qBAAqB,CAAC;YACzC,EAAE,OAAOC,GAAG;gBACV,IAAI,CAACF,MAAM,CAACG,KAAK,CAAC,CAAC,oBAAoB,EAAED,GAAGE,OAAOF,GAAGG,KAAK,IAAI,EAAEH,EAAEI,OAAO,IAAIJ,GAAG;gBACjF,IAAI,CAACF,MAAM,CAACO,IAAI,CAAC,CAAC,8BAA8B,CAAC;gBACjD,IAAI,CAACC,YAAY,GAAG,IAAIC,aAAO,CAAC,CAAC,IAAI,EAAE,IAAI,CAACV,oBAAoB,CAAC,QAAQ,CAAC,EAAE,UAAY,MAAM,IAAI,CAACW,gBAAgB;gBACnH,IAAI,CAACC,SAAS,CAACC,UAAU,CAAC,IAAI,CAACd,gBAAgB,EAAE,IAAI,CAACU,YAAY;gBAClE,IAAI,CAACA,YAAY,CAACK,KAAK;YACzB;QACF;IACF;IAEA,MAAMC,kBAAiC;QACrC,IAAI,IAAI,CAACN,YAAY,EAAE;YACrB,MAAM,IAAI,CAACA,YAAY,CAACO,IAAI;QAC9B;IACF;IAEA,MAAMC,KAAKC,OAAe,EAAqB;QAC7C,MAAMC,KAAK,MAAM,IAAI,CAACtB,EAAE,CACrBuB,MAAM,CAAC;YAAEC,KAAKC,uBAAK,CAACD,GAAG;QAAC,GACxBE,IAAI,CAACD,uBAAK,EACVE,KAAK,CAACC,IAAAA,eAAG,EAACC,IAAAA,gBAAI,EAACJ,uBAAK,CAACD,GAAG,EAAEH,QAAQS,UAAU,CAAC,KAAK,OAAO,IAAI,CAACC,eAAe;QAChF,OAAOT,GAAGU,GAAG,CAAC,CAACC,IAAuBA,EAAET,GAAG;IAC7C;IAEA,MAAMU,IAAIV,GAAW,EAAoB;QACvC,MAAM,CAACW,EAAE,GAAG,MAAM,IAAI,CAACnC,EAAE,CACtBuB,MAAM,CAAC;YAAEC,KAAKC,uBAAK,CAACD,GAAG;QAAC,GACxBE,IAAI,CAACD,uBAAK,EACVE,KAAK,CACJS,IAAAA,kBAAM,EACJ,IAAI,CAACpC,EAAE,CACJuB,MAAM,CAAC;YAAEC,KAAKC,uBAAK,CAACD,GAAG;QAAC,GACxBE,IAAI,CAACD,uBAAK,EACVE,KAAK,CAACC,IAAAA,eAAG,EAACS,IAAAA,cAAE,EAACZ,uBAAK,CAACD,GAAG,EAAEA,MAAM,IAAI,CAACO,eAAe;QAG3D,OAAO,CAAC,CAACI;IACX;IAEA,MAAMG,IAAId,GAAW,EAAgB;QACnC,MAAM,CAACe,EAAE,GAAqB,MAAM,IAAI,CAACvC,EAAE,CACxCuB,MAAM,CAAC;YAAEiB,OAAOf,uBAAK,CAACe,KAAK;QAAC,GAC5Bd,IAAI,CAACD,uBAAK,EACVE,KAAK,CAACC,IAAAA,eAAG,EAACS,IAAAA,cAAE,EAACZ,uBAAK,CAACD,GAAG,EAAEA,MAAM,IAAI,CAACO,eAAe,KAClDU,KAAK,CAAC;QACT,OAAOF,IAAIA,EAAEC,KAAK,GAAGD;IACvB;IAEA,MAAMG,KAAKtB,IAAc,EAAkB;QACzC,MAAMuB,KAAuB,MAAM,IAAI,CAAC3C,EAAE,CACvCuB,MAAM,CAAC;YAAEiB,OAAOf,uBAAK,CAACe,KAAK;QAAC,GAC5Bd,IAAI,CAACD,uBAAK,EACVE,KAAK,CAACC,IAAAA,eAAG,EAACgB,IAAAA,mBAAO,EAACnB,uBAAK,CAACD,GAAG,EAAEJ,OAAO,IAAI,CAACW,eAAe;QAC3D,OAAOY,GAAGX,GAAG,CAAC,CAACO,IAAsBA,EAAEC,KAAK;IAC9C;IAEA,MAAMK,IAAIrB,GAAW,EAAEsB,IAAa,EAAEC,GAAY,EAAoB;QACpED,OAAO,IAAI,CAACE,SAAS,CAACF;QACtB,MAAMG,MAAM,IAAI,CAACC,MAAM,CAACH;QACxB,IAAI;YACF,MAAM,IAAI,CAAC/C,EAAE,CACVmD,MAAM,CAAC1B,uBAAK,EACZ2B,MAAM,CAAC;gBAAE5B,KAAKA;gBAAKgB,OAAOM;gBAAMO,YAAYJ;YAAI,GAChDK,oBAAoB,CAAC;gBACpBT,KAAK;oBACHL,OAAOM;oBACPO,YAAYJ;gBACd;YACF;YACF,OAAO;QACT,EAAE,OAAO3C,GAAG;YACV,IAAI,CAACF,MAAM,CAACG,KAAK,CAAC,GAAG,IAAI,CAACsC,GAAG,CAACU,IAAI,CAAC,GAAG,EAAEjD,GAAG;YAC3C,OAAO;QACT;IACF;IAEA,MAAMkD,IAAIhC,GAAW,EAAoB;QACvC,OAAOiC,IAAAA,0BAAmB,EAAC,MAAM,IAAI,CAACzD,EAAE,CAAC0D,MAAM,CAACjC,uBAAK,EAAEE,KAAK,CAACU,IAAAA,cAAE,EAACZ,uBAAK,CAACD,GAAG,EAAEA,OAAO,GAAG;IACvF;IAEA,MAAMmC,KAAKvC,IAAc,EAAoB;QAC3C,OAAOqC,IAAAA,0BAAmB,EAAC,MAAM,IAAI,CAACzD,EAAE,CAAC0D,MAAM,CAACjC,uBAAK,EAAEE,KAAK,CAACiB,IAAAA,mBAAO,EAACnB,uBAAK,CAACD,GAAG,EAAEJ,QAAQA,KAAKwC,MAAM,EAAE;IACvG;IAEAC,WAAW,GAAGC,IAAW,EAAU;QACjC,OAAOC,IAAAA,kBAAU,EAACD,KAAKE,IAAI,CAAC;IAC9B;IAMQd,OAAOH,GAAW,EAAU;QAClC;;;IAGA,GACA,OAAOA,MAAMkB,IAAAA,wBAAgB,MAAKlB,MAAMA,QAAQ,IAAI,IAAI,CAACmB,kBAAkB,GAAGD,IAAAA,wBAAgB,MAAK,IAAI,CAACE,UAAU;IACpH;IAEQnB,UAAUF,IAAS,EAAE;QAC3B,IAAIA,SAASsB,WAAW;YACtB,yDAAyD;YACzD,OAAO;QACT;QACA,OAAOtB;IACT;IAEA,MAAchC,mBAAmB;QAC/B,IAAI;YACF,MAAM,IAAI,CAACd,EAAE,CAAC0D,MAAM,CAACjC,uBAAK,EAAEE,KAAK,CAAC,IAAI,CAAC0C,YAAY;QACrD,EAAE,OAAO/D,GAAG;YACV,IAAI,CAACF,MAAM,CAACG,KAAK,CAAC,GAAG,IAAI,CAACO,gBAAgB,CAACyC,IAAI,CAAC,GAAG,EAAEjD,GAAGG,QAAQH,GAAG;QACrE;IACF;IAhIA,YACE,AAA4CN,EAAY,EACxD,AAAiBe,SAA4B,CAC7C;aAF4Cf,KAAAA;aAC3Be,YAAAA;QAbnB;;;EAGA,QACAoD,aAAqBG,gCAAa,CAAC7C,KAAK,CAACsB,GAAG;aAC5CmB,qBAAqB,CAAC;aAELhE,mBAAmB;aACnBC,uBAAuB,GAAE,UAAU;aACnCC,SAAS,IAAImE,cAAM,CAACC,mBAAK,CAACjB,IAAI,CAACkB,WAAW;aAwG1C1C,kBAA6B,IAAM2C,IAAAA,sBAAU,EAACjD,uBAAK,CAAC4B,UAAU,EAAE,GAAGY,IAAAA,wBAAgB;aAEnFI,eAA0B,IAAMM,IAAAA,mBAAO,EAAClD,uBAAK,CAAC4B,UAAU,EAAE,GAAGY,IAAAA,wBAAgB;IArG3F;AA8HL"}
@@ -27,16 +27,26 @@ function _ts_metadata(k, v) {
27
27
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
28
28
  }
29
29
  let RedisCacheAdapter = class RedisCacheAdapter {
30
+ async onModuleInit() {
31
+ this.client.on('error', (e)=>this.logger.error(e.message || e));
32
+ this.client.on('ready', ()=>this.logger.log(`Connected to Redis Server at ${this.client.options.url}`));
33
+ this.client.connect().catch((e)=>this.logger.error(e));
34
+ }
35
+ async onModuleDestroy() {
36
+ if (this.client?.isOpen) {
37
+ await this.client.close();
38
+ }
39
+ }
30
40
  async has(key) {
31
41
  return await this.client.exists(key) === 1;
32
42
  }
33
43
  async keys(pattern) {
34
44
  const matches = [];
35
- for await (const key of this.client.scanIterator({
45
+ for await (const keys of this.client.scanIterator({
36
46
  MATCH: pattern,
37
47
  COUNT: 100
38
48
  })){
39
- matches.push(key);
49
+ matches.push(...keys);
40
50
  }
41
51
  return matches;
42
52
  }
@@ -49,7 +59,10 @@ let RedisCacheAdapter = class RedisCacheAdapter {
49
59
  async set(key, data, ttl) {
50
60
  const exp = this.getTTL(ttl);
51
61
  return await this.client.set(key, this.serialize(data), {
52
- EX: exp === -1 ? undefined : exp
62
+ expiration: {
63
+ type: 'EX',
64
+ value: exp === -1 ? undefined : exp
65
+ }
53
66
  }) === 'OK';
54
67
  }
55
68
  async del(key) {
@@ -60,20 +73,16 @@ let RedisCacheAdapter = class RedisCacheAdapter {
60
73
  for (const key of keys){
61
74
  multi.unlink(key);
62
75
  }
63
- const results = await multi.exec();
64
- return results.indexOf(1) > -1;
76
+ const res = await multi.exec();
77
+ return Array.isArray(res) && res.some((r)=>typeof r === 'number' && r > 0);
65
78
  }
66
79
  genSlugKey(...args) {
67
80
  return (0, _shared.createSlug)(args.join(' '));
68
81
  }
69
- async quit() {
70
- await this.client.disconnect();
71
- this.logger.verbose(`${this.quit.name}`);
72
- }
73
82
  getTTL(ttl) {
74
83
  /* ttl (seconds):
75
- - 0 : infinite expiration
76
- - undefined : default ttl
84
+ - 0: infinite expiration
85
+ - undefined: default ttl
77
86
  */ return ttl ? ttl : ttl === 0 ? this.infiniteExpiration : this.defaultTTL;
78
87
  }
79
88
  serialize(data) {
@@ -94,8 +103,8 @@ let RedisCacheAdapter = class RedisCacheAdapter {
94
103
  this.logger = new _common.Logger(_cacheservice.Cache.name.toUpperCase());
95
104
  this.reconnectOptions = {
96
105
  maxAttempts: 3,
97
- minConnectDelay: 6000,
98
- maxConnectDelay: 30000
106
+ minConnectDelay: 1000,
107
+ maxConnectDelay: 2000
99
108
  };
100
109
  this.reconnectStrategy = (attempts)=>{
101
110
  if (attempts > this.reconnectOptions.maxAttempts) {
@@ -114,10 +123,6 @@ let RedisCacheAdapter = class RedisCacheAdapter {
114
123
  reconnectStrategy: this.reconnectStrategy
115
124
  }
116
125
  });
117
- this.client.connect().then(()=>{
118
- this.client.on('error', (e)=>this.logger.error(e.message || e));
119
- this.client.on('ready', ()=>this.logger.log(`Connected to Redis Server at ${this.client.options.url}`));
120
- });
121
126
  }
122
127
  };
123
128
  RedisCacheAdapter = _ts_decorate([
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/infrastructure/cache/adapters/redis-cache.adapter.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Injectable, Logger } from '@nestjs/common'\nimport { RedisClientOptions } from '@redis/client'\nimport { createClient, RedisClientType } from 'redis'\nimport { createSlug } from '../../../common/shared'\nimport { configuration } from '../../../configuration/config.environment'\nimport { Cache } from '../services/cache.service'\n\n@Injectable()\nexport class RedisCacheAdapter implements Cache {\n defaultTTL: number = configuration.cache.ttl\n infiniteExpiration = -1\n private readonly logger = new Logger(Cache.name.toUpperCase())\n private readonly client: RedisClientType\n private readonly reconnectOptions = { maxAttempts: 3, minConnectDelay: 6000, maxConnectDelay: 30000 }\n private readonly reconnectStrategy = (attempts: number): number => {\n if (attempts > this.reconnectOptions.maxAttempts) {\n this.logger.error('Too many retries on Redis server. Exiting')\n process.exit()\n } else {\n const wait: number = Math.min(this.reconnectOptions.minConnectDelay * Math.pow(2, attempts), this.reconnectOptions.maxConnectDelay)\n this.logger.warn(`Retrying connection to Redis server in ${wait / 1000}s`)\n return wait\n }\n }\n\n constructor() {\n this.client = createClient({\n url: configuration.cache.redis,\n socket: { noDelay: true, reconnectStrategy: this.reconnectStrategy }\n } satisfies RedisClientOptions)\n this.client.connect().then(() => {\n this.client.on('error', (e: Error) => this.logger.error(e.message || e))\n this.client.on('ready', () => this.logger.log(`Connected to Redis Server at ${this.client.options.url}`))\n })\n }\n\n async has(key: string): Promise<boolean> {\n return (await this.client.exists(key)) === 1\n }\n\n async keys(pattern: string): Promise<string[]> {\n const matches: string[] = []\n for await (const key of this.client.scanIterator({ MATCH: pattern, COUNT: 100 })) {\n matches.push(key)\n }\n return matches\n }\n\n async get(key: string): Promise<any> {\n return this.deserialize(await this.client.get(key))\n }\n\n async mget(keys: string[]): Promise<(any | undefined)[]> {\n return (await this.client.mGet(keys)).map((v) => this.deserialize(v))\n }\n\n async set(key: any, data: any, ttl?: number): Promise<boolean> {\n const exp = this.getTTL(ttl)\n return (await this.client.set(key, this.serialize(data), { EX: exp === -1 ? undefined : exp })) === 'OK'\n }\n\n async del(key: any): Promise<boolean> {\n return (await this.client.unlink(key)) > 0\n }\n\n async mdel(keys: string[]): Promise<boolean> {\n const multi = this.client.multi()\n for (const key of keys) {\n multi.unlink(key)\n }\n const results = await multi.exec()\n return results.indexOf(1) > -1\n }\n\n genSlugKey(...args: any[]): string {\n return createSlug(args.join(' '))\n }\n\n async quit(): Promise<void> {\n await this.client.disconnect()\n this.logger.verbose(`${this.quit.name}`)\n }\n\n private getTTL(ttl: number): number {\n /* ttl (seconds):\n - 0 : infinite expiration\n - undefined : default ttl\n */\n return ttl ? ttl : ttl === 0 ? this.infiniteExpiration : this.defaultTTL\n }\n\n private serialize(data: any) {\n if (data === undefined || data === null) {\n return 'null'\n }\n return JSON.stringify(data)\n }\n\n private deserialize(data: any) {\n if (data === null) {\n return undefined\n }\n return JSON.parse(data)\n }\n}\n"],"names":["RedisCacheAdapter","has","key","client","exists","keys","pattern","matches","scanIterator","MATCH","COUNT","push","get","deserialize","mget","mGet","map","v","set","data","ttl","exp","getTTL","serialize","EX","undefined","del","unlink","mdel","multi","results","exec","indexOf","genSlugKey","args","createSlug","join","quit","disconnect","logger","verbose","name","infiniteExpiration","defaultTTL","JSON","stringify","parse","configuration","cache","Logger","Cache","toUpperCase","reconnectOptions","maxAttempts","minConnectDelay","maxConnectDelay","reconnectStrategy","attempts","error","process","exit","wait","Math","min","pow","warn","createClient","url","redis","socket","noDelay","connect","then","on","e","message","log","options"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/infrastructure/cache/adapters/redis-cache.adapter.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Injectable, Logger } from '@nestjs/common'\nimport { RedisClientOptions } from '@redis/client'\nimport { createClient, RedisClientType } from 'redis'\nimport { createSlug } from '../../../common/shared'\nimport { configuration } from '../../../configuration/config.environment'\nimport { Cache } from '../services/cache.service'\n\n@Injectable()\nexport class RedisCacheAdapter implements Cache {\n defaultTTL: number = configuration.cache.ttl\n infiniteExpiration = -1\n private readonly logger = new Logger(Cache.name.toUpperCase())\n private readonly client: RedisClientType\n private readonly reconnectOptions = { maxAttempts: 3, minConnectDelay: 1000, maxConnectDelay: 2000 }\n\n constructor() {\n this.client = createClient({\n url: configuration.cache.redis,\n socket: { noDelay: true, reconnectStrategy: this.reconnectStrategy }\n } satisfies RedisClientOptions)\n }\n\n async onModuleInit() {\n this.client.on('error', (e: Error) => this.logger.error(e.message || e))\n this.client.on('ready', () => this.logger.log(`Connected to Redis Server at ${this.client.options.url}`))\n this.client.connect().catch((e: Error) => this.logger.error(e))\n }\n\n async onModuleDestroy() {\n if (this.client?.isOpen) {\n await this.client.close()\n }\n }\n\n async has(key: string): Promise<boolean> {\n return (await this.client.exists(key)) === 1\n }\n\n async keys(pattern: string): Promise<string[]> {\n const matches: string[] = []\n for await (const keys of this.client.scanIterator({ MATCH: pattern, COUNT: 100 })) {\n matches.push(...keys)\n }\n return matches\n }\n\n async get(key: string): Promise<any> {\n return this.deserialize(await this.client.get(key))\n }\n\n async mget(keys: string[]): Promise<(any | undefined)[]> {\n return (await this.client.mGet(keys)).map((v) => this.deserialize(v))\n }\n\n async set(key: string, data: unknown, ttl?: number): Promise<boolean> {\n const exp = this.getTTL(ttl)\n return (await this.client.set(key, this.serialize(data), { expiration: { type: 'EX', value: exp === -1 ? undefined : exp } })) === 'OK'\n }\n\n async del(key: any): Promise<boolean> {\n return (await this.client.unlink(key)) > 0\n }\n\n async mdel(keys: string[]): Promise<boolean> {\n const multi = this.client.multi()\n for (const key of keys) {\n multi.unlink(key)\n }\n const res = await multi.exec()\n return Array.isArray(res) && res.some((r) => typeof r === 'number' && r > 0)\n }\n\n genSlugKey(...args: any[]): string {\n return createSlug(args.join(' '))\n }\n\n private readonly reconnectStrategy = (attempts: number): number => {\n if (attempts > this.reconnectOptions.maxAttempts) {\n this.logger.error('Too many retries on Redis server. Exiting')\n process.exit()\n } else {\n const wait: number = Math.min(this.reconnectOptions.minConnectDelay * Math.pow(2, attempts), this.reconnectOptions.maxConnectDelay)\n this.logger.warn(`Retrying connection to Redis server in ${wait / 1000}s`)\n return wait\n }\n }\n\n private getTTL(ttl: number): number {\n /* ttl (seconds):\n - 0: infinite expiration\n - undefined: default ttl\n */\n return ttl ? ttl : ttl === 0 ? this.infiniteExpiration : this.defaultTTL\n }\n\n private serialize(data: any) {\n if (data === undefined || data === null) {\n return 'null'\n }\n return JSON.stringify(data)\n }\n\n private deserialize(data: any) {\n if (data === null) {\n return undefined\n }\n return JSON.parse(data)\n }\n}\n"],"names":["RedisCacheAdapter","onModuleInit","client","on","e","logger","error","message","log","options","url","connect","catch","onModuleDestroy","isOpen","close","has","key","exists","keys","pattern","matches","scanIterator","MATCH","COUNT","push","get","deserialize","mget","mGet","map","v","set","data","ttl","exp","getTTL","serialize","expiration","type","value","undefined","del","unlink","mdel","multi","res","exec","Array","isArray","some","r","genSlugKey","args","createSlug","join","infiniteExpiration","defaultTTL","JSON","stringify","parse","configuration","cache","Logger","Cache","name","toUpperCase","reconnectOptions","maxAttempts","minConnectDelay","maxConnectDelay","reconnectStrategy","attempts","process","exit","wait","Math","min","pow","warn","createClient","redis","socket","noDelay"],"mappings":"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"}
@@ -27,6 +27,7 @@ describe(_cacheservice.Cache.name, ()=>{
27
27
  'fatal'
28
28
  ]);
29
29
  cache = module.get(_cacheservice.Cache);
30
+ cache.onModuleInit();
30
31
  });
31
32
  afterAll(async ()=>{
32
33
  await module.close();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/infrastructure/cache/cache.e2e-spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { LoggerModule } from 'nestjs-pino'\nimport { setTimeout } from 'node:timers/promises'\nimport { DatabaseModule } from '../database/database.module'\nimport { CacheModule } from './cache.module'\nimport { Cache } from './services/cache.service'\n\ndescribe(Cache.name, () => {\n let module: TestingModule\n let cache: Cache\n\n beforeAll(async () => {\n module = await Test.createTestingModule({\n imports: [CacheModule, LoggerModule.forRoot(), DatabaseModule]\n }).compile()\n\n module.useLogger(['fatal'])\n cache = module.get<Cache>(Cache)\n })\n\n afterAll(async () => {\n await module.close()\n })\n\n it('should be defined', () => {\n expect(cache).toBeDefined()\n })\n\n it('should create the key & value', async () => {\n expect(await cache.set('foo', 'bar')).toBe(true)\n expect(await cache.set('undefined', undefined)).toBe(true)\n })\n\n it('should get all keys defined', async () => {\n expect(await cache.keys('*')).toEqual(expect.arrayContaining(['foo', 'undefined']))\n })\n\n it('should has (or not) the key', async () => {\n expect(await cache.has('bar')).toBe(false)\n expect(await cache.has('fo')).toBe(false)\n expect(await cache.has('foo')).toBe(true)\n expect(await cache.has('undefined')).toBe(true)\n })\n\n it('should get value from key', async () => {\n expect(await cache.get('foo')).toBe('bar')\n expect(await cache.get('undefined')).toBeNull()\n expect(await cache.get('unknown')).toBeUndefined()\n })\n\n it('should get values from keys', async () => {\n const values = await cache.mget(['foo', 'undefined'])\n expect(values).toHaveLength(2)\n expect(values[0]).toBe('bar')\n expect(values[1]).toBeNull()\n })\n\n it('should delete the key', async () => {\n expect(await cache.del('foo')).toBe(true)\n expect(await cache.has('foo')).toBe(false)\n expect(await cache.del('undefined')).toBe(true)\n expect(await cache.get('foo')).toBeUndefined()\n expect(await cache.del('unknown')).toBe(false)\n })\n\n it('should search & delete multiple keys', async () => {\n expect(await cache.set('foo', 'bar')).toBe(true)\n expect(await cache.set('foo2', 'bar2')).toBe(true)\n expect(await cache.keys('foo*')).toEqual(expect.arrayContaining(['foo', 'foo2']))\n expect(await cache.mdel(['foo', 'foo2'])).toBe(true)\n expect(await cache.keys('foo*')).toHaveLength(0)\n })\n\n it('should create the key & value with a TTL', async () => {\n expect(await cache.set('foo', 'bar', 1)).toBe(true)\n expect(await cache.get('foo')).toBe('bar')\n await setTimeout(2000)\n expect(await cache.has('foo')).toBe(false)\n expect(await cache.get('foo')).toBeUndefined()\n })\n\n it('should create a slug key from parameters', () => {\n expect(cache.genSlugKey('foo', 'BAR', 12341)).toBe('foo-bar-12341')\n })\n\n // it('should exit if maxConnectRetry is reached', () => {\n // const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {\n // throw new Error('process.exit')\n // })\n // expect(() => RedisCache.redisReconnectStrategy(RedisCache.redisReconnectOptions.maxAttempts + 1)).toThrow()\n // expect(mockExit).toHaveBeenCalledTimes(1)\n // mockExit.mockRestore()\n // })\n //\n // it('should not exit if maxConnectRetry is not reached', () => {\n // expect(RedisCache.redisReconnectStrategy(1)).toBeGreaterThan(0)\n // })\n})\n"],"names":["describe","Cache","name","module","cache","beforeAll","Test","createTestingModule","imports","CacheModule","LoggerModule","forRoot","DatabaseModule","compile","useLogger","get","afterAll","close","it","expect","toBeDefined","set","toBe","undefined","keys","toEqual","arrayContaining","has","toBeNull","toBeUndefined","values","mget","toHaveLength","del","mdel","setTimeout","genSlugKey"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../backend/src/infrastructure/cache/cache.e2e-spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { LoggerModule } from 'nestjs-pino'\nimport { setTimeout } from 'node:timers/promises'\nimport { DatabaseModule } from '../database/database.module'\nimport { CacheModule } from './cache.module'\nimport { Cache } from './services/cache.service'\n\ndescribe(Cache.name, () => {\n let module: TestingModule\n let cache: Cache\n\n beforeAll(async () => {\n module = await Test.createTestingModule({\n imports: [CacheModule, LoggerModule.forRoot(), DatabaseModule]\n }).compile()\n\n module.useLogger(['fatal'])\n cache = module.get<Cache>(Cache)\n cache.onModuleInit()\n })\n\n afterAll(async () => {\n await module.close()\n })\n\n it('should be defined', () => {\n expect(cache).toBeDefined()\n })\n\n it('should create the key & value', async () => {\n expect(await cache.set('foo', 'bar')).toBe(true)\n expect(await cache.set('undefined', undefined)).toBe(true)\n })\n\n it('should get all keys defined', async () => {\n expect(await cache.keys('*')).toEqual(expect.arrayContaining(['foo', 'undefined']))\n })\n\n it('should has (or not) the key', async () => {\n expect(await cache.has('bar')).toBe(false)\n expect(await cache.has('fo')).toBe(false)\n expect(await cache.has('foo')).toBe(true)\n expect(await cache.has('undefined')).toBe(true)\n })\n\n it('should get value from key', async () => {\n expect(await cache.get('foo')).toBe('bar')\n expect(await cache.get('undefined')).toBeNull()\n expect(await cache.get('unknown')).toBeUndefined()\n })\n\n it('should get values from keys', async () => {\n const values = await cache.mget(['foo', 'undefined'])\n expect(values).toHaveLength(2)\n expect(values[0]).toBe('bar')\n expect(values[1]).toBeNull()\n })\n\n it('should delete the key', async () => {\n expect(await cache.del('foo')).toBe(true)\n expect(await cache.has('foo')).toBe(false)\n expect(await cache.del('undefined')).toBe(true)\n expect(await cache.get('foo')).toBeUndefined()\n expect(await cache.del('unknown')).toBe(false)\n })\n\n it('should search & delete multiple keys', async () => {\n expect(await cache.set('foo', 'bar')).toBe(true)\n expect(await cache.set('foo2', 'bar2')).toBe(true)\n expect(await cache.keys('foo*')).toEqual(expect.arrayContaining(['foo', 'foo2']))\n expect(await cache.mdel(['foo', 'foo2'])).toBe(true)\n expect(await cache.keys('foo*')).toHaveLength(0)\n })\n\n it('should create the key & value with a TTL', async () => {\n expect(await cache.set('foo', 'bar', 1)).toBe(true)\n expect(await cache.get('foo')).toBe('bar')\n await setTimeout(2000)\n expect(await cache.has('foo')).toBe(false)\n expect(await cache.get('foo')).toBeUndefined()\n })\n\n it('should create a slug key from parameters', () => {\n expect(cache.genSlugKey('foo', 'BAR', 12341)).toBe('foo-bar-12341')\n })\n\n // it('should exit if maxConnectRetry is reached', () => {\n // const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {\n // throw new Error('process.exit')\n // })\n // expect(() => RedisCache.redisReconnectStrategy(RedisCache.redisReconnectOptions.maxAttempts + 1)).toThrow()\n // expect(mockExit).toHaveBeenCalledTimes(1)\n // mockExit.mockRestore()\n // })\n //\n // it('should not exit if maxConnectRetry is not reached', () => {\n // expect(RedisCache.redisReconnectStrategy(1)).toBeGreaterThan(0)\n // })\n})\n"],"names":["describe","Cache","name","module","cache","beforeAll","Test","createTestingModule","imports","CacheModule","LoggerModule","forRoot","DatabaseModule","compile","useLogger","get","onModuleInit","afterAll","close","it","expect","toBeDefined","set","toBe","undefined","keys","toEqual","arrayContaining","has","toBeNull","toBeUndefined","values","mget","toHaveLength","del","mdel","setTimeout","genSlugKey"],"mappings":"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"}
@@ -24,16 +24,7 @@ function _ts_decorate(decorators, target, key, desc) {
24
24
  else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
25
25
  return c > 3 && r && Object.defineProperty(target, key, r), r;
26
26
  }
27
- function _ts_metadata(k, v) {
28
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
29
- }
30
27
  let CacheModule = class CacheModule {
31
- async beforeApplicationShutdown() {
32
- await this.cache.quit();
33
- }
34
- constructor(cache){
35
- this.cache = cache;
36
- }
37
28
  };
38
29
  CacheModule = _ts_decorate([
39
30
  (0, _common.Global)(),
@@ -48,11 +39,7 @@ CacheModule = _ts_decorate([
48
39
  exports: [
49
40
  _cacheservice.Cache
50
41
  ]
51
- }),
52
- _ts_metadata("design:type", Function),
53
- _ts_metadata("design:paramtypes", [
54
- typeof _cacheservice.Cache === "undefined" ? Object : _cacheservice.Cache
55
- ])
42
+ })
56
43
  ], CacheModule);
57
44
 
58
45
  //# sourceMappingURL=cache.module.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/infrastructure/cache/cache.module.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { BeforeApplicationShutdown, Global, Module } from '@nestjs/common'\nimport { SchedulerRegistry } from '@nestjs/schedule'\nimport { configuration } from '../../configuration/config.environment'\nimport { MysqlCacheAdapter } from './adapters/mysql-cache.adapter'\nimport { RedisCacheAdapter } from './adapters/redis-cache.adapter'\nimport { Cache } from './services/cache.service'\n\n@Global()\n@Module({\n providers: [\n {\n provide: Cache,\n useClass: configuration.cache.adapter === 'mysql' ? MysqlCacheAdapter : RedisCacheAdapter\n },\n SchedulerRegistry\n ],\n exports: [Cache]\n})\nexport class CacheModule implements BeforeApplicationShutdown {\n constructor(private readonly cache: Cache) {}\n\n async beforeApplicationShutdown() {\n await this.cache.quit()\n }\n}\n"],"names":["CacheModule","beforeApplicationShutdown","cache","quit","providers","provide","Cache","useClass","configuration","adapter","MysqlCacheAdapter","RedisCacheAdapter","SchedulerRegistry","exports"],"mappings":"AAAA;;;;CAIC;;;;+BAoBYA;;;eAAAA;;;wBAlB6C;0BACxB;mCACJ;mCACI;mCACA;8BACZ;;;;;;;;;;AAaf,IAAA,AAAMA,cAAN,MAAMA;IAGX,MAAMC,4BAA4B;QAChC,MAAM,IAAI,CAACC,KAAK,CAACC,IAAI;IACvB;IAJA,YAAY,AAAiBD,KAAY,CAAE;aAAdA,QAAAA;IAAe;AAK9C;;;;QAfEE,WAAW;YACT;gBACEC,SAASC,mBAAK;gBACdC,UAAUC,gCAAa,CAACN,KAAK,CAACO,OAAO,KAAK,UAAUC,oCAAiB,GAAGC,oCAAiB;YAC3F;YACAC,2BAAiB;SAClB;QACDC,SAAS;YAACP,mBAAK;SAAC"}
1
+ {"version":3,"sources":["../../../../backend/src/infrastructure/cache/cache.module.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Global, Module } from '@nestjs/common'\nimport { SchedulerRegistry } from '@nestjs/schedule'\nimport { configuration } from '../../configuration/config.environment'\nimport { MysqlCacheAdapter } from './adapters/mysql-cache.adapter'\nimport { RedisCacheAdapter } from './adapters/redis-cache.adapter'\nimport { Cache } from './services/cache.service'\n\n@Global()\n@Module({\n providers: [\n {\n provide: Cache,\n useClass: configuration.cache.adapter === 'mysql' ? MysqlCacheAdapter : RedisCacheAdapter\n },\n SchedulerRegistry\n ],\n exports: [Cache]\n})\nexport class CacheModule {}\n"],"names":["CacheModule","providers","provide","Cache","useClass","configuration","cache","adapter","MysqlCacheAdapter","RedisCacheAdapter","SchedulerRegistry","exports"],"mappings":"AAAA;;;;CAIC;;;;+BAoBYA;;;eAAAA;;;wBAlBkB;0BACG;mCACJ;mCACI;mCACA;8BACZ;;;;;;;AAaf,IAAA,AAAMA,cAAN,MAAMA;AAAa;;;;QATxBC,WAAW;YACT;gBACEC,SAASC,mBAAK;gBACdC,UAAUC,gCAAa,CAACC,KAAK,CAACC,OAAO,KAAK,UAAUC,oCAAiB,GAAGC,oCAAiB;YAC3F;YACAC,2BAAiB;SAClB;QACDC,SAAS;YAACR,mBAAK;SAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/infrastructure/cache/services/cache.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport abstract class Cache {\n abstract defaultTTL: number\n\n abstract infiniteExpiration: number\n\n abstract has(key: string): Promise<boolean>\n\n /*\n pattern must use '*' as wildcard\n */\n abstract keys(pattern: string): Promise<string[]>\n\n abstract get(key: string): Promise<any>\n\n abstract mget(keys: string[]): Promise<any[]>\n\n /* ttl (seconds):\n - 0: infinite expiration\n - undefined: default ttl\n */\n abstract set(key: string, data: any, ttl?: number): Promise<boolean>\n\n abstract del(key: string): Promise<boolean>\n\n abstract mdel(keys: string[]): Promise<boolean>\n\n abstract genSlugKey(...args: any[]): string\n\n abstract quit(): Promise<void>\n}\n"],"names":["Cache"],"mappings":"AAAA;;;;CAIC;;;;+BAEqBA;;;eAAAA;;;AAAf,IAAA,AAAeA,QAAf,MAAeA;AA6BtB"}
1
+ {"version":3,"sources":["../../../../../backend/src/infrastructure/cache/services/cache.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { OnModuleDestroy, OnModuleInit } from '@nestjs/common'\n\nexport abstract class Cache implements OnModuleInit, OnModuleDestroy {\n abstract defaultTTL: number\n abstract infiniteExpiration: number\n\n abstract onModuleInit(): void\n\n abstract onModuleDestroy(): void\n\n abstract has(key: string): Promise<boolean>\n\n /*\n pattern must use '*' as wildcard\n */\n abstract keys(pattern: string): Promise<string[]>\n\n abstract get(key: string): Promise<any>\n\n abstract mget(keys: string[]): Promise<any[]>\n\n /* ttl (seconds):\n - 0: infinite expiration\n - undefined: default ttl\n */\n abstract set(key: string, data: unknown, ttl?: number): Promise<boolean>\n\n abstract del(key: string): Promise<boolean>\n\n abstract mdel(keys: string[]): Promise<boolean>\n\n abstract genSlugKey(...args: any[]): string\n}\n"],"names":["Cache"],"mappings":"AAAA;;;;CAIC;;;;+BAIqBA;;;eAAAA;;;AAAf,IAAA,AAAeA,QAAf,MAAeA;AA8BtB"}
@@ -65,7 +65,21 @@ function _ts_decorate(decorators, target, key, desc) {
65
65
  else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
66
66
  return c > 3 && r && Object.defineProperty(target, key, r), r;
67
67
  }
68
+ function _ts_metadata(k, v) {
69
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
70
+ }
71
+ function _ts_param(paramIndex, decorator) {
72
+ return function(target, key) {
73
+ decorator(target, key, paramIndex);
74
+ };
75
+ }
68
76
  let DatabaseModule = class DatabaseModule {
77
+ async beforeApplicationShutdown() {
78
+ await this.db.session.client.end();
79
+ }
80
+ constructor(db){
81
+ this.db = db;
82
+ }
69
83
  };
70
84
  DatabaseModule = _ts_decorate([
71
85
  (0, _common.Global)(),
@@ -88,7 +102,12 @@ DatabaseModule = _ts_decorate([
88
102
  })
89
103
  })
90
104
  ]
91
- })
105
+ }),
106
+ _ts_param(0, (0, _common.Inject)(_constants.DB_TOKEN_PROVIDER)),
107
+ _ts_metadata("design:type", Function),
108
+ _ts_metadata("design:paramtypes", [
109
+ Object
110
+ ])
92
111
  ], DatabaseModule);
93
112
 
94
113
  //# sourceMappingURL=database.module.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/infrastructure/database/database.module.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { DrizzleMySqlConfig, DrizzleMySqlModule } from '@knaadh/nestjs-drizzle-mysql2'\nimport { Global, Module } from '@nestjs/common'\nimport { configuration } from '../../configuration/config.environment'\nimport { DB_TOKEN_PROVIDER } from './constants'\nimport { DatabaseLogger } from './database.logger'\nimport * as schema from './schema'\n\n@Global()\n@Module({\n imports: [\n DrizzleMySqlModule.registerAsync({\n tag: DB_TOKEN_PROVIDER,\n useFactory: async (): Promise<DrizzleMySqlConfig> => ({\n mysql: {\n connection: 'pool',\n config: configuration.mysql.url\n },\n config: {\n schema: { ...schema },\n mode: 'default',\n logger: configuration.mysql.logQueries ? new DatabaseLogger() : false\n }\n })\n })\n ]\n})\nexport class DatabaseModule {}\n"],"names":["DatabaseModule","imports","DrizzleMySqlModule","registerAsync","tag","DB_TOKEN_PROVIDER","useFactory","mysql","connection","config","configuration","url","schema","mode","logger","logQueries","DatabaseLogger"],"mappings":"AAAA;;;;CAIC;;;;+BA4BYA;;;eAAAA;;;qCA1B0C;wBACxB;mCACD;2BACI;gCACH;gEACP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBjB,IAAA,AAAMA,iBAAN,MAAMA;AAAgB;;;;QAjB3BC,SAAS;YACPC,uCAAkB,CAACC,aAAa,CAAC;gBAC/BC,KAAKC,4BAAiB;gBACtBC,YAAY,UAA0C,CAAA;wBACpDC,OAAO;4BACLC,YAAY;4BACZC,QAAQC,gCAAa,CAACH,KAAK,CAACI,GAAG;wBACjC;wBACAF,QAAQ;4BACNG,QAAQ;gCAAE,GAAGA,OAAM;4BAAC;4BACpBC,MAAM;4BACNC,QAAQJ,gCAAa,CAACH,KAAK,CAACQ,UAAU,GAAG,IAAIC,8BAAc,KAAK;wBAClE;oBACF,CAAA;YACF;SACD"}
1
+ {"version":3,"sources":["../../../../backend/src/infrastructure/database/database.module.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { DrizzleMySqlConfig, DrizzleMySqlModule } from '@knaadh/nestjs-drizzle-mysql2'\nimport { BeforeApplicationShutdown, Global, Inject, Module } from '@nestjs/common'\nimport { MySql2Client } from 'drizzle-orm/mysql2'\nimport { configuration } from '../../configuration/config.environment'\nimport { DB_TOKEN_PROVIDER } from './constants'\nimport { DatabaseLogger } from './database.logger'\nimport type { DBSchema } from './interfaces/database.interface'\nimport * as schema from './schema'\n\n@Global()\n@Module({\n imports: [\n DrizzleMySqlModule.registerAsync({\n tag: DB_TOKEN_PROVIDER,\n useFactory: async (): Promise<DrizzleMySqlConfig> => ({\n mysql: {\n connection: 'pool',\n config: configuration.mysql.url\n },\n config: {\n schema: { ...schema },\n mode: 'default',\n logger: configuration.mysql.logQueries ? new DatabaseLogger() : false\n }\n })\n })\n ]\n})\nexport class DatabaseModule implements BeforeApplicationShutdown {\n constructor(@Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema & { session: { client: MySql2Client } }) {}\n\n async beforeApplicationShutdown() {\n await this.db.session.client.end()\n }\n}\n"],"names":["DatabaseModule","beforeApplicationShutdown","db","session","client","end","imports","DrizzleMySqlModule","registerAsync","tag","DB_TOKEN_PROVIDER","useFactory","mysql","connection","config","configuration","url","schema","mode","logger","logQueries","DatabaseLogger"],"mappings":"AAAA;;;;CAIC;;;;+BA8BYA;;;eAAAA;;;qCA5B0C;wBACW;mCAEpC;2BACI;gCACH;gEAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBjB,IAAA,AAAMA,iBAAN,MAAMA;IAGX,MAAMC,4BAA4B;QAChC,MAAM,IAAI,CAACC,EAAE,CAACC,OAAO,CAACC,MAAM,CAACC,GAAG;IAClC;IAJA,YAAY,AAA4CH,EAAoD,CAAE;aAAtDA,KAAAA;IAAuD;AAKjH;;;;QAvBEI,SAAS;YACPC,uCAAkB,CAACC,aAAa,CAAC;gBAC/BC,KAAKC,4BAAiB;gBACtBC,YAAY,UAA0C,CAAA;wBACpDC,OAAO;4BACLC,YAAY;4BACZC,QAAQC,gCAAa,CAACH,KAAK,CAACI,GAAG;wBACjC;wBACAF,QAAQ;4BACNG,QAAQ;gCAAE,GAAGA,OAAM;4BAAC;4BACpBC,MAAM;4BACNC,QAAQJ,gCAAa,CAACH,KAAK,CAACQ,UAAU,GAAG,IAAIC,8BAAc,KAAK;wBAClE;oBACF,CAAA;YACF;SACD"}