@sync-in/server 1.9.1 → 1.9.6

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 (177) hide show
  1. package/CHANGELOG.md +24 -8
  2. package/package.json +12 -12
  3. package/server/applications/files/interfaces/only-office-config.interface.js.map +1 -1
  4. package/server/applications/files/services/files-manager.service.js +2 -2
  5. package/server/applications/files/services/files-manager.service.js.map +1 -1
  6. package/server/applications/files/services/files-methods.service.spec.js +2 -4
  7. package/server/applications/files/services/files-methods.service.spec.js.map +1 -1
  8. package/server/applications/files/services/files-recents.service.js +4 -0
  9. package/server/applications/files/services/files-recents.service.js.map +1 -1
  10. package/server/applications/files/services/files-scheduler.service.js +23 -4
  11. package/server/applications/files/services/files-scheduler.service.js.map +1 -1
  12. package/server/applications/files/services/files-tasks-manager.service.js +1 -1
  13. package/server/applications/files/services/files-tasks-manager.service.js.map +1 -1
  14. package/server/applications/files/utils/send-file.js +18 -9
  15. package/server/applications/files/utils/send-file.js.map +1 -1
  16. package/server/applications/files/utils/url-file.js +6 -6
  17. package/server/applications/files/utils/url-file.js.map +1 -1
  18. package/server/applications/links/services/links-manager.service.js +1 -1
  19. package/server/applications/links/services/links-manager.service.js.map +1 -1
  20. package/server/applications/shares/interfaces/share-props.interface.js.map +1 -1
  21. package/server/applications/shares/services/shares-manager.service.js +6 -4
  22. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  23. package/server/applications/spaces/services/spaces-manager.service.js +15 -12
  24. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  25. package/server/applications/spaces/services/spaces-scheduler.service.js +9 -1
  26. package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
  27. package/server/applications/users/services/admin-users-manager.service.js +4 -0
  28. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  29. package/server/applications/users/users.controller.js +4 -1
  30. package/server/applications/users/users.controller.js.map +1 -1
  31. package/static/assets/pdfjs/build/pdf.mjs +35 -20
  32. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  33. package/static/assets/pdfjs/build/pdf.sandbox.mjs +2 -2
  34. package/static/assets/pdfjs/build/pdf.worker.mjs +1488 -52
  35. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  36. package/static/assets/pdfjs/version +1 -1
  37. package/static/assets/pdfjs/web/locale/be/viewer.ftl +2 -12
  38. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +4 -0
  39. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +0 -15
  40. package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -4
  41. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +4 -14
  42. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +2 -12
  43. package/static/assets/pdfjs/web/locale/da/viewer.ftl +2 -12
  44. package/static/assets/pdfjs/web/locale/de/viewer.ftl +0 -12
  45. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +0 -12
  46. package/static/assets/pdfjs/web/locale/el/viewer.ftl +2 -12
  47. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +0 -12
  48. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +0 -12
  49. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +2 -12
  50. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +0 -12
  51. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +2 -12
  52. package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +2 -12
  53. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -12
  54. package/static/assets/pdfjs/web/locale/eu/viewer.ftl +0 -12
  55. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +0 -12
  56. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +0 -12
  57. package/static/assets/pdfjs/web/locale/fur/viewer.ftl +0 -12
  58. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +0 -12
  59. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +2 -12
  60. package/static/assets/pdfjs/web/locale/he/viewer.ftl +0 -12
  61. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +0 -12
  62. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +0 -12
  63. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -15
  64. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +0 -12
  65. package/static/assets/pdfjs/web/locale/id/viewer.ftl +0 -15
  66. package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -15
  67. package/static/assets/pdfjs/web/locale/it/viewer.ftl +2 -14
  68. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +7 -2
  69. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +0 -12
  70. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +0 -12
  71. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +3 -12
  72. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +0 -12
  73. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +2 -12
  74. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +0 -12
  75. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +0 -12
  76. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +4 -12
  77. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +2 -12
  78. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +2 -12
  79. package/static/assets/pdfjs/web/locale/rm/viewer.ftl +0 -12
  80. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +2 -14
  81. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +0 -12
  82. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -1
  83. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +0 -12
  84. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +2 -12
  85. package/static/assets/pdfjs/web/locale/sq/viewer.ftl +2 -12
  86. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +0 -12
  87. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +2 -12
  88. package/static/assets/pdfjs/web/locale/th/viewer.ftl +0 -12
  89. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +2 -12
  90. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +0 -12
  91. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +2 -12
  92. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +0 -12
  93. package/static/assets/pdfjs/web/viewer.css +53 -41
  94. package/static/assets/pdfjs/web/viewer.html +493 -132
  95. package/static/assets/pdfjs/web/viewer.mjs +225 -150
  96. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  97. package/static/{chunk-LYZGJZNP.js → chunk-25PWAXTJ.js} +1 -1
  98. package/static/{chunk-YMAN4LIU.js → chunk-2CAAJBRO.js} +1 -1
  99. package/static/{chunk-GRLHFXGB.js → chunk-2F42MZQ5.js} +1 -1
  100. package/static/{chunk-6B3GGAV3.js → chunk-2U5VKTML.js} +1 -1
  101. package/static/{chunk-HKRGIRKB.js → chunk-3AR5VNJE.js} +1 -1
  102. package/static/chunk-3WS72A6C.js +1 -0
  103. package/static/chunk-4GBA6EJ4.js +1 -0
  104. package/static/{chunk-FNOTGWRW.js → chunk-4ZKAVMB4.js} +1 -1
  105. package/static/{chunk-XQGPSNQB.js → chunk-5ATJIR5S.js} +1 -1
  106. package/static/{chunk-HMOB6XC5.js → chunk-5GIWZKNS.js} +1 -1
  107. package/static/{chunk-ZCOWBVOT.js → chunk-5HYSNQR4.js} +1 -1
  108. package/static/{chunk-BHZEPHRI.js → chunk-5KVI243T.js} +1 -1
  109. package/static/{chunk-Q556XB3S.js → chunk-5NFH4E2B.js} +1 -1
  110. package/static/{chunk-XCLK7NJL.js → chunk-7H5O4BLV.js} +1 -1
  111. package/static/{chunk-RDNTK4YH.js → chunk-7HL5Z6PF.js} +1 -1
  112. package/static/{chunk-V6FA5QY4.js → chunk-7QYALK5T.js} +1 -1
  113. package/static/{chunk-GNZPP2VO.js → chunk-ANH4VNOS.js} +1 -1
  114. package/static/{chunk-EIYRBM4J.js → chunk-AYYJZMBE.js} +1 -1
  115. package/static/chunk-B2A4HNDC.js +1 -0
  116. package/static/{chunk-NOPACN4F.js → chunk-B4TDS6AQ.js} +1 -1
  117. package/static/chunk-BJARRIS6.js +562 -0
  118. package/static/{chunk-PXRT4L57.js → chunk-BVKDW5XO.js} +1 -1
  119. package/static/{chunk-7CKHC72R.js → chunk-BX3QZ7IL.js} +1 -1
  120. package/static/{chunk-MIA5YBOI.js → chunk-C5T7RZSD.js} +1 -1
  121. package/static/{chunk-ACUF7IKP.js → chunk-CHMDM2ZW.js} +1 -1
  122. package/static/{chunk-U4RW6XG5.js → chunk-CUC7R6C2.js} +1 -1
  123. package/static/{chunk-XOF4UW3S.js → chunk-D6QWQHWE.js} +1 -1
  124. package/static/{chunk-6NEBGCAZ.js → chunk-DK2LAJEL.js} +1 -1
  125. package/static/{chunk-C3AAEQKW.js → chunk-DQAQUSVW.js} +1 -1
  126. package/static/{chunk-NN4ONTOT.js → chunk-DU4Q4RWJ.js} +1 -1
  127. package/static/{chunk-M4XL3JN5.js → chunk-E5C4QRNQ.js} +2 -2
  128. package/static/{chunk-BU4ZICZR.js → chunk-EPDWJEPD.js} +1 -1
  129. package/static/{chunk-I2S3XPC5.js → chunk-FCR5AEHR.js} +2 -2
  130. package/static/{chunk-4PZPHJ7L.js → chunk-FEQUP26G.js} +1 -1
  131. package/static/{chunk-ZXXHFBGL.js → chunk-FSGT46LM.js} +1 -1
  132. package/static/{chunk-QMHUIHSR.js → chunk-GENTF6JM.js} +1 -1
  133. package/static/{chunk-DQ3GEMPM.js → chunk-GLPKRULI.js} +1 -1
  134. package/static/{chunk-AZ5TF5Y3.js → chunk-GRV44RYI.js} +1 -1
  135. package/static/{chunk-JY2I3HGL.js → chunk-GYYJ4FWN.js} +1 -1
  136. package/static/{chunk-ERDZ7IVF.js → chunk-HB5DC7RJ.js} +1 -1
  137. package/static/{chunk-DJDRX53V.js → chunk-HLKZCMKV.js} +1 -1
  138. package/static/{chunk-HNMGPG72.js → chunk-IBC7CFBQ.js} +1 -1
  139. package/static/{chunk-5E3TYOL3.js → chunk-IIKL33TV.js} +1 -1
  140. package/static/{chunk-TGLJFALR.js → chunk-JYHTSSKW.js} +1 -1
  141. package/static/{chunk-VQJYCYWI.js → chunk-KAAFVHYE.js} +1 -1
  142. package/static/{chunk-VK7XMFVE.js → chunk-KWKZN53T.js} +1 -1
  143. package/static/{chunk-KDEEERWZ.js → chunk-LBXOAKBD.js} +1 -1
  144. package/static/{chunk-Y5RLD72B.js → chunk-LFAQLJZK.js} +1 -1
  145. package/static/chunk-MGMDT4VN.js +1 -0
  146. package/static/chunk-MWUUM2NK.js +13 -0
  147. package/static/{chunk-JMYAD7E2.js → chunk-NHMYAVJK.js} +1 -1
  148. package/static/{chunk-HHWXIK2M.js → chunk-NQCKX2AD.js} +1 -1
  149. package/static/{chunk-HCSWO7BO.js → chunk-O233BXWK.js} +1 -1
  150. package/static/{chunk-2TB2INBF.js → chunk-ODAQRAPO.js} +1 -1
  151. package/static/{chunk-RK2ONYTL.js → chunk-OVUMPMVM.js} +1 -1
  152. package/static/chunk-Q6B4OVER.js +5 -0
  153. package/static/{chunk-3YDYZLF7.js → chunk-QKMN3S4M.js} +1 -1
  154. package/static/{chunk-23UUFZSR.js → chunk-QUUQOBTF.js} +1 -1
  155. package/static/chunk-QV5LQKTS.js +1 -0
  156. package/static/{chunk-NKGKBQBX.js → chunk-S4UTSOPV.js} +1 -1
  157. package/static/{chunk-5S6KPQRA.js → chunk-SF6Q6VRC.js} +1 -1
  158. package/static/{chunk-BODMMLVB.js → chunk-TOCCCZP2.js} +1 -1
  159. package/static/{chunk-3WLBVJ2S.js → chunk-UO7ATVQG.js} +1 -1
  160. package/static/{chunk-AADK5D2H.js → chunk-X5UDV4ZB.js} +1 -1
  161. package/static/{chunk-S2VBGI6Q.js → chunk-XIQXRSZ2.js} +1 -1
  162. package/static/chunk-YYTDPI5S.js +1 -0
  163. package/static/{chunk-EL6QL4TP.js → chunk-Z2KBIZ5D.js} +1 -1
  164. package/static/{chunk-K657XPXA.js → chunk-ZCOEP4O2.js} +1 -1
  165. package/static/index.html +2 -2
  166. package/static/main-ODUA232E.js +11 -0
  167. package/static/{styles-Q4OZOSSK.css → styles-S5HVK4H5.css} +1 -1
  168. package/static/chunk-5XUIPWOH.js +0 -1
  169. package/static/chunk-EDJAISWO.js +0 -13
  170. package/static/chunk-H6WOTGQ5.js +0 -1
  171. package/static/chunk-HC7F57NA.js +0 -1
  172. package/static/chunk-IOIBQGHN.js +0 -562
  173. package/static/chunk-J6YSFHLZ.js +0 -1
  174. package/static/chunk-JWPXQOS3.js +0 -5
  175. package/static/chunk-QVFPHTOH.js +0 -1
  176. package/static/chunk-YCTCESL4.js +0 -1
  177. package/static/main-56PZQ6TJ.js +0 -11
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-scheduler.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 { Inject, Injectable, Logger } from '@nestjs/common'\nimport { Cron, CronExpression, Timeout } from '@nestjs/schedule'\nimport { isNotNull, sql } from 'drizzle-orm'\nimport { unionAll } from 'drizzle-orm/mysql-core'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { configuration } from '../../../configuration/config.environment'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { getTablesWithFileIdColumn } from '../../../infrastructure/database/utils'\nimport { USER_ROLE } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { users } from '../../users/schemas/users.schema'\nimport { CACHE_TASK_PREFIX } from '../constants/cache'\nimport { FileTask, FileTaskStatus } from '../models/file-task'\nimport { filesRecents } from '../schemas/files-recents.schema'\nimport { files } from '../schemas/files.schema'\nimport { dirHasChildren, isPathExists, removeFiles } from '../utils/files'\nimport { FilesContentManager } from './files-content-manager.service'\nimport { FilesTasksManager } from './files-tasks-manager.service'\n\n@Injectable()\nexport class FilesScheduler {\n private readonly logger = new Logger(FilesScheduler.name)\n\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly cache: Cache,\n private readonly filesContentManager: FilesContentManager\n ) {}\n\n @Timeout(30000)\n async cleanupInterruptedTasks(): Promise<void> {\n this.logger.log(`${this.cleanupInterruptedTasks.name} - START`)\n try {\n let nb = 0\n const keys = await this.cache.keys(`${CACHE_TASK_PREFIX}-*`)\n for (const key of keys) {\n const task = await this.cache.get(key)\n if (task && task.status === FileTaskStatus.PENDING) {\n task.status = FileTaskStatus.ERROR\n task.result = 'Interrupted'\n nb++\n this.cache.set(key, task).catch((e: Error) => this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`))\n }\n }\n this.logger.log(`${this.cleanupInterruptedTasks.name} - ${nb} tasks cleaned : END`)\n } catch (e) {\n this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`)\n }\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)\n async cleanupUserTaskFiles(): Promise<void> {\n this.logger.log(`${this.cleanupUserTaskFiles.name} - START`)\n try {\n for (const user of await this.db\n .select({\n id: users.id,\n login: users.login,\n role: users.role\n })\n .from(users)) {\n const userTasksPath = UserModel.getTasksPath(user.login, user.role === USER_ROLE.GUEST, user.role === USER_ROLE.LINK)\n if (!(await isPathExists(userTasksPath))) {\n continue\n }\n if (await dirHasChildren(userTasksPath, false)) {\n const cacheKey = FilesTasksManager.getCacheKey(user.id)\n const keys = await this.cache.keys(cacheKey)\n const excludeFiles = (await this.cache.mget(keys))\n .filter((task: FileTask) => task && task.status === FileTaskStatus.PENDING && task.props.compressInDirectory === false)\n .map((task: FileTask) => task.name)\n for (const f of (await fs.readdir(userTasksPath)).filter((f: string) => excludeFiles.indexOf(f) === -1)) {\n try {\n removeFiles(path.join(userTasksPath, f)).catch((e: Error) => this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - unable to remove ${path.join(userTasksPath, f)} : ${e}`)\n }\n }\n }\n }\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`)\n }\n this.logger.log(`${this.cleanupUserTaskFiles.name} - END`)\n }\n\n @Timeout(30000)\n @Cron(CronExpression.EVERY_8_HOURS)\n async clearRecentFiles(): Promise<void> {\n this.logger.log(`${this.clearRecentFiles.name} - START`)\n const keepNumber = 100\n let nbCleared = 0\n try {\n for (const fk of [filesRecents.ownerId, filesRecents.spaceId, filesRecents.shareId]) {\n const [r] = await this.db.execute(sql`\n DELETE\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL\n AND id NOT IN (SELECT id\n FROM (SELECT id,\n ROW_NUMBER() OVER (PARTITION BY ${fk} ORDER BY ${filesRecents.mtime}) AS rn\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL) AS ranked\n WHERE ranked.rn <= ${keepNumber})\n `)\n nbCleared += r.affectedRows\n }\n } catch (e) {\n this.logger.error(`${this.clearRecentFiles.name} - ${e}`)\n }\n this.logger.log(`${this.clearRecentFiles.name} - ${nbCleared} records cleared - END`)\n }\n\n @Timeout(120000)\n @Cron(CronExpression.EVERY_4_HOURS)\n async indexContentFiles(): Promise<void> {\n // Conditional loading of file content indexing\n if (!configuration.applications.files.contentIndexing) return\n this.logger.log(`${this.indexContentFiles.name} - START`)\n await this.filesContentManager.parseAndIndexAllFiles()\n this.logger.log(`${this.indexContentFiles.name} - END`)\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_4AM)\n async deleteOrphanFiles() {\n this.logger.log(`${this.deleteOrphanFiles.name} - START`)\n const selects: any[] = []\n for (const table of getTablesWithFileIdColumn()) {\n selects.push(this.db.selectDistinct({ id: table.fileId }).from(table).where(isNotNull(table.fileId)))\n }\n if (selects.length === 0) {\n this.logger.warn(`${this.deleteOrphanFiles.name} - no tables with fileId column`)\n return\n }\n const unionSub = (selects.length === 1 ? selects[0] : unionAll(...(selects as [any, any, ...any[]]))).as('u')\n // Debug\n // const [preview] = (await this.db.execute(sql`\n // SELECT f.id\n // FROM ${files} AS f\n // LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id\n // WHERE ${unionSub.id} IS NULL\n // `)) as any[]\n // console.log(preview.length, preview)\n const deleteQuery = sql`\n DELETE f\n FROM ${files} AS f\n LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id\n WHERE ${unionSub.id} IS NULL\n `\n try {\n await this.db.transaction(async (tx) => {\n const [r] = await tx.execute(deleteQuery)\n this.logger.log(`${this.deleteOrphanFiles.name} - files: ${r.affectedRows}`)\n })\n } catch (e) {\n this.logger.log(`${this.deleteOrphanFiles.name} - ${e}`)\n }\n this.logger.log(`${this.deleteOrphanFiles.name} - END`)\n }\n}\n"],"names":["FilesScheduler","cleanupInterruptedTasks","logger","log","name","nb","keys","cache","CACHE_TASK_PREFIX","key","task","get","status","FileTaskStatus","PENDING","ERROR","result","set","catch","e","error","cleanupUserTaskFiles","user","db","select","id","users","login","role","from","userTasksPath","UserModel","getTasksPath","USER_ROLE","GUEST","LINK","isPathExists","dirHasChildren","cacheKey","FilesTasksManager","getCacheKey","excludeFiles","mget","filter","props","compressInDirectory","map","f","fs","readdir","indexOf","removeFiles","path","join","clearRecentFiles","keepNumber","nbCleared","fk","filesRecents","ownerId","spaceId","shareId","r","execute","sql","mtime","affectedRows","indexContentFiles","configuration","applications","files","contentIndexing","filesContentManager","parseAndIndexAllFiles","deleteOrphanFiles","selects","table","getTablesWithFileIdColumn","push","selectDistinct","fileId","where","isNotNull","length","warn","unionSub","unionAll","as","deleteQuery","transaction","tx","Logger","EVERY_DAY_AT_MIDNIGHT","EVERY_8_HOURS","EVERY_4_HOURS","EVERY_DAY_AT_4AM"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-scheduler.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 { Inject, Injectable, Logger } from '@nestjs/common'\nimport { Cron, CronExpression, Timeout } from '@nestjs/schedule'\nimport { isNotNull, sql } from 'drizzle-orm'\nimport { unionAll } from 'drizzle-orm/mysql-core'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { configuration } from '../../../configuration/config.environment'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { getTablesWithFileIdColumn } from '../../../infrastructure/database/utils'\nimport { USER_ROLE } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { users } from '../../users/schemas/users.schema'\nimport { CACHE_TASK_PREFIX } from '../constants/cache'\nimport { FileTask, FileTaskStatus } from '../models/file-task'\nimport { filesRecents } from '../schemas/files-recents.schema'\nimport { files } from '../schemas/files.schema'\nimport { dirHasChildren, isPathExists, removeFiles } from '../utils/files'\nimport { FilesContentManager } from './files-content-manager.service'\nimport { FilesTasksManager } from './files-tasks-manager.service'\n\n@Injectable()\nexport class FilesScheduler {\n private readonly logger = new Logger(FilesScheduler.name)\n\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly cache: Cache,\n private readonly filesContentManager: FilesContentManager\n ) {}\n\n @Timeout(30_000)\n async onStartup(): Promise<void> {\n try {\n await this.cleanupInterruptedTasks()\n await this.clearRecentFiles()\n } catch (e) {\n this.logger.error(e)\n }\n }\n\n @Timeout(180_000)\n async afterStartup(): Promise<void> {\n try {\n await this.indexContentFiles()\n } catch (e) {\n this.logger.error(e)\n }\n }\n\n async cleanupInterruptedTasks(): Promise<void> {\n this.logger.log(`${this.cleanupInterruptedTasks.name} - START`)\n try {\n let nb = 0\n const keys = await this.cache.keys(`${CACHE_TASK_PREFIX}-*`)\n for (const key of keys) {\n const task = await this.cache.get(key)\n if (task && task.status === FileTaskStatus.PENDING) {\n task.status = FileTaskStatus.ERROR\n task.result = 'Interrupted'\n nb++\n this.cache.set(key, task).catch((e: Error) => this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`))\n }\n }\n this.logger.log(`${this.cleanupInterruptedTasks.name} - ${nb} tasks cleaned : END`)\n } catch (e) {\n this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`)\n }\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)\n async cleanupUserTaskFiles(): Promise<void> {\n this.logger.log(`${this.cleanupUserTaskFiles.name} - START`)\n try {\n for (const user of await this.db\n .select({\n id: users.id,\n login: users.login,\n role: users.role\n })\n .from(users)) {\n const userTasksPath = UserModel.getTasksPath(user.login, user.role === USER_ROLE.GUEST, user.role === USER_ROLE.LINK)\n if (!(await isPathExists(userTasksPath))) {\n continue\n }\n if (await dirHasChildren(userTasksPath, false)) {\n const cacheKey = FilesTasksManager.getCacheKey(user.id)\n const keys = await this.cache.keys(cacheKey)\n const excludeFiles = (await this.cache.mget(keys))\n .filter((task: FileTask) => task && task.status === FileTaskStatus.PENDING && task.props.compressInDirectory === false)\n .map((task: FileTask) => task.name)\n for (const f of (await fs.readdir(userTasksPath)).filter((f: string) => excludeFiles.indexOf(f) === -1)) {\n try {\n removeFiles(path.join(userTasksPath, f)).catch((e: Error) => this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - unable to remove ${path.join(userTasksPath, f)} : ${e}`)\n }\n }\n }\n }\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`)\n }\n this.logger.log(`${this.cleanupUserTaskFiles.name} - END`)\n }\n\n @Cron(CronExpression.EVERY_8_HOURS)\n async clearRecentFiles(): Promise<void> {\n this.logger.log(`${this.clearRecentFiles.name} - START`)\n const keepNumber = 100\n let nbCleared = 0\n try {\n for (const fk of [filesRecents.ownerId, filesRecents.spaceId, filesRecents.shareId]) {\n const [r] = await this.db.execute(sql`\n DELETE\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL\n AND id NOT IN (SELECT id\n FROM (SELECT id,\n ROW_NUMBER() OVER (PARTITION BY ${fk} ORDER BY ${filesRecents.mtime}) AS rn\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL) AS ranked\n WHERE ranked.rn <= ${keepNumber})\n `)\n nbCleared += r.affectedRows\n }\n } catch (e) {\n this.logger.error(`${this.clearRecentFiles.name} - ${e}`)\n }\n this.logger.log(`${this.clearRecentFiles.name} - ${nbCleared} records cleared - END`)\n }\n\n @Cron(CronExpression.EVERY_4_HOURS)\n async indexContentFiles(): Promise<void> {\n // Conditional loading of file content indexing\n if (!configuration.applications.files.contentIndexing) return\n this.logger.log(`${this.indexContentFiles.name} - START`)\n await this.filesContentManager.parseAndIndexAllFiles()\n this.logger.log(`${this.indexContentFiles.name} - END`)\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_4AM)\n async deleteOrphanFiles() {\n this.logger.log(`${this.deleteOrphanFiles.name} - START`)\n const selects: any[] = []\n for (const table of getTablesWithFileIdColumn()) {\n selects.push(this.db.selectDistinct({ id: table.fileId }).from(table).where(isNotNull(table.fileId)))\n }\n if (selects.length === 0) {\n this.logger.warn(`${this.deleteOrphanFiles.name} - no tables with fileId column`)\n return\n }\n const unionSub = (selects.length === 1 ? selects[0] : unionAll(...(selects as [any, any, ...any[]]))).as('u')\n // Debug\n // const [preview] = (await this.db.execute(sql`\n // SELECT f.id\n // FROM ${files} AS f\n // LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id\n // WHERE ${unionSub.id} IS NULL\n // `)) as any[]\n // console.log(preview.length, preview)\n const deleteQuery = sql`\n DELETE f\n FROM ${files} AS f\n LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id\n WHERE ${unionSub.id} IS NULL\n `\n try {\n await this.db.transaction(async (tx) => {\n const [r] = await tx.execute(deleteQuery)\n this.logger.log(`${this.deleteOrphanFiles.name} - files: ${r.affectedRows}`)\n })\n } catch (e) {\n this.logger.log(`${this.deleteOrphanFiles.name} - ${e}`)\n }\n this.logger.log(`${this.deleteOrphanFiles.name} - END`)\n }\n}\n"],"names":["FilesScheduler","onStartup","cleanupInterruptedTasks","clearRecentFiles","e","logger","error","afterStartup","indexContentFiles","log","name","nb","keys","cache","CACHE_TASK_PREFIX","key","task","get","status","FileTaskStatus","PENDING","ERROR","result","set","catch","cleanupUserTaskFiles","user","db","select","id","users","login","role","from","userTasksPath","UserModel","getTasksPath","USER_ROLE","GUEST","LINK","isPathExists","dirHasChildren","cacheKey","FilesTasksManager","getCacheKey","excludeFiles","mget","filter","props","compressInDirectory","map","f","fs","readdir","indexOf","removeFiles","path","join","keepNumber","nbCleared","fk","filesRecents","ownerId","spaceId","shareId","r","execute","sql","mtime","affectedRows","configuration","applications","files","contentIndexing","filesContentManager","parseAndIndexAllFiles","deleteOrphanFiles","selects","table","getTablesWithFileIdColumn","push","selectDistinct","fileId","where","isNotNull","length","warn","unionSub","unionAll","as","deleteQuery","transaction","tx","Logger","EVERY_DAY_AT_MIDNIGHT","EVERY_8_HOURS","EVERY_4_HOURS","EVERY_DAY_AT_4AM"],"mappings":"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"}
@@ -104,7 +104,7 @@ let FilesTasksManager = class FilesTasksManager {
104
104
  throw new _common.HttpException('Not applicable', _common.HttpStatus.BAD_REQUEST);
105
105
  }
106
106
  const rPath = _nodepath.default.join(user.tasksPath, task.name);
107
- const sendFile = new _sendfile.SendFile(rPath, true);
107
+ const sendFile = new _sendfile.SendFile(rPath);
108
108
  try {
109
109
  await sendFile.checks();
110
110
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-tasks-manager.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 { HttpException, HttpStatus, Injectable, Logger, StreamableFile } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport crypto from 'node:crypto'\nimport path from 'node:path'\nimport { setTimeout } from 'node:timers/promises'\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { UserModel } from '../../users/models/user.model'\nimport { CACHE_TASK_PREFIX, CACHE_TASK_TTL } from '../constants/cache'\nimport { FILE_OPERATION } from '../constants/operations'\nimport { FileTaskEvent } from '../events/file-task-event'\nimport { FileTask, FileTaskProps, FileTaskStatus } from '../models/file-task'\nimport { countDirEntries, dirName, fileName, fileSize, isPathIsDir, removeFiles } from '../utils/files'\nimport { SendFile } from '../utils/send-file'\nimport { FilesMethods } from './files-methods.service'\n\n@Injectable()\nexport class FilesTasksManager {\n // task cache key = `ftask-$(userId}-${taskId}` => FileTask\n private readonly logger = new Logger(FilesTasksManager.name)\n private readonly watchInterval = 1000\n private tasksWatcher: Record<string, any> = {}\n\n constructor(\n private readonly cache: Cache,\n private readonly filesMethods: FilesMethods\n ) {\n FileTaskEvent.on('startWatch', async (space: SpaceEnv, taskType: FILE_OPERATION, rPath: string) =>\n this.startWatch(space, taskType, rPath, dirName(space.url))\n )\n }\n\n static getCacheKey(userId: number, taskId?: string): string {\n return `${CACHE_TASK_PREFIX}-${userId}-${taskId || '*'}`\n }\n\n async createTask(type: FILE_OPERATION, user: UserModel, space: SpaceEnv, dto: any, method: string): Promise<FileTask> {\n const taskId: string = crypto.randomUUID()\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const newTask = new FileTask(taskId, type, dirName(space.url), fileName(space.url))\n await this.storeTask(cacheKey, newTask)\n space.task = { cacheKey: cacheKey, props: {} }\n this.filesMethods[method](user, space, dto)\n .then((data: any) => {\n this.logger.debug(`${this.createTask.name} - ${newTask.name} : ${method} done`)\n this.setTaskDone(cacheKey, FileTaskStatus.SUCCESS, data).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n .catch((e: HttpException | any) => {\n this.logger.error(`${this.createTask.name} - ${newTask.name} : ${method} : ${e}`)\n this.setTaskDone(cacheKey, FileTaskStatus.ERROR, e.message).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n return newTask\n }\n\n async getTasks(userId: number, taskId?: string): Promise<FileTask | FileTask[]> {\n const cacheKey = FilesTasksManager.getCacheKey(userId, taskId)\n if (taskId) {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) return task\n throw new HttpException('Task not found', HttpStatus.NOT_FOUND)\n } else {\n const keys = await this.cache.keys(cacheKey)\n return keys.length ? await this.cache.mget(keys) : []\n }\n }\n\n async deleteTasks(user: UserModel, taskId?: string): Promise<void> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n let keys: string[]\n if (taskId) {\n keys = [cacheKey]\n } else {\n keys = await this.cache.keys(cacheKey)\n }\n if (!keys.length) return\n for (const key of keys) {\n const task: FileTask = await this.cache.get(key)\n if (!task || task.status === FileTaskStatus.PENDING) continue\n if (task.props.compressInDirectory === false) {\n // delete task file\n const rPath = path.join(user.tasksPath, task.name)\n removeFiles(rPath).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n // clear watcher\n this.stopWatch(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n // remove from cache\n this.cache.del(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n }\n\n async downloadArchive(user: UserModel, taskId: string, req: FastifyAuthenticatedRequest, res: FastifyReply): Promise<StreamableFile> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const task: FileTask = await this.cache.get(cacheKey)\n if (!task || task.status !== FileTaskStatus.SUCCESS || task.props.compressInDirectory !== false) {\n throw new HttpException('Not applicable', HttpStatus.BAD_REQUEST)\n }\n const rPath = path.join(user.tasksPath, task.name)\n const sendFile = new SendFile(rPath, true)\n try {\n await sendFile.checks()\n } catch (e) {\n throw new HttpException(e.message, e.httpCode)\n }\n return await sendFile.stream(req, res)\n }\n\n private async storeTask(cacheKey: string, task: FileTask) {\n task.startedAt = currentTimeStamp(null, true)\n task.status = FileTaskStatus.PENDING\n try {\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n } catch (e) {\n this.logger.error(`${this.storeTask.name} - ${e}`)\n }\n }\n\n private async setTaskDone(cacheKey: string, status: FileTaskStatus, result: any): Promise<void> {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) {\n task.status = status\n task.endedAt = currentTimeStamp(null, true)\n if (result) {\n if (typeof result === 'string') {\n task.result = result\n } else {\n Object.assign(task, result)\n }\n }\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n }\n await this.stopWatch(cacheKey)\n }\n\n private async updateTask(cacheKey: string, props?: FileTaskProps, task?: Partial<FileTask>): Promise<void> {\n let ftask: FileTask = await this.cache.get(cacheKey)\n if (ftask) {\n if (task) ftask = { ...ftask, ...task }\n if (props) ftask.props = { ...ftask.props, ...props }\n await this.cache.set(cacheKey, ftask, CACHE_TASK_TTL)\n } else {\n await this.stopWatch(cacheKey)\n }\n }\n\n private async startWatch(space: SpaceEnv, taskType: FILE_OPERATION, rPath: string, taskPath?: string): Promise<void> {\n if (!space.task?.cacheKey || space.task.cacheKey in this.tasksWatcher) return\n this.logger.verbose(`${this.startWatch.name} - ${space.task.cacheKey}`)\n this.updateTask(space.task.cacheKey, space.task?.props, {\n name: fileName(rPath),\n path: taskPath\n }).catch((e: Error) => this.logger.error(`${this.startWatch.name} - ${e}`))\n switch (taskType) {\n case FILE_OPERATION.COMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DECOMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDecompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DOWNLOAD:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDownloadTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.COPY:\n case FILE_OPERATION.MOVE:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCopyMoveTask(space, rPath), this.watchInterval)\n return\n default:\n this.logger.warn(`${this.startWatch.name} - unknown task type ${taskType}`)\n return\n }\n }\n\n private async stopWatch(cacheKey: string): Promise<void> {\n if (!(cacheKey in this.tasksWatcher)) return\n await setTimeout(this.watchInterval)\n clearInterval(this.tasksWatcher[cacheKey])\n delete this.tasksWatcher[cacheKey]\n }\n\n private async updateCompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props.size = await fileSize(rPath)\n await this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDecompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props = await countDirEntries(rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDecompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDecompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDownloadTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n await this.calcSizeAndProgressTask(space, rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDownloadTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDownloadTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateCopyMoveTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n if (await isPathIsDir(rPath)) {\n space.task.props = await countDirEntries(rPath)\n } else {\n await this.calcSizeAndProgressTask(space, rPath)\n }\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async calcSizeAndProgressTask(space: SpaceEnv, rPath: string) {\n space.task.props.size = await fileSize(rPath)\n if (space.task.props.totalSize) {\n space.task.props.progress = (100 * space.task.props.size) / space.task.props.totalSize\n }\n }\n}\n"],"names":["FilesTasksManager","getCacheKey","userId","taskId","CACHE_TASK_PREFIX","createTask","type","user","space","dto","method","crypto","randomUUID","cacheKey","id","newTask","FileTask","dirName","url","fileName","storeTask","task","props","filesMethods","then","data","logger","debug","name","setTaskDone","FileTaskStatus","SUCCESS","catch","e","error","ERROR","message","getTasks","cache","get","HttpException","HttpStatus","NOT_FOUND","keys","length","mget","deleteTasks","key","status","PENDING","compressInDirectory","rPath","path","join","tasksPath","removeFiles","stopWatch","del","downloadArchive","req","res","BAD_REQUEST","sendFile","SendFile","checks","httpCode","stream","startedAt","currentTimeStamp","set","CACHE_TASK_TTL","result","endedAt","Object","assign","updateTask","ftask","startWatch","taskType","taskPath","tasksWatcher","verbose","FILE_OPERATION","COMPRESS","setInterval","updateCompressTask","watchInterval","DECOMPRESS","updateDecompressTask","DOWNLOAD","updateDownloadTask","COPY","MOVE","updateCopyMoveTask","warn","setTimeout","clearInterval","size","fileSize","countDirEntries","calcSizeAndProgressTask","isPathIsDir","totalSize","progress","Logger","FileTaskEvent","on"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-tasks-manager.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 { HttpException, HttpStatus, Injectable, Logger, StreamableFile } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport crypto from 'node:crypto'\nimport path from 'node:path'\nimport { setTimeout } from 'node:timers/promises'\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { UserModel } from '../../users/models/user.model'\nimport { CACHE_TASK_PREFIX, CACHE_TASK_TTL } from '../constants/cache'\nimport { FILE_OPERATION } from '../constants/operations'\nimport { FileTaskEvent } from '../events/file-task-event'\nimport { FileTask, FileTaskProps, FileTaskStatus } from '../models/file-task'\nimport { countDirEntries, dirName, fileName, fileSize, isPathIsDir, removeFiles } from '../utils/files'\nimport { SendFile } from '../utils/send-file'\nimport { FilesMethods } from './files-methods.service'\n\n@Injectable()\nexport class FilesTasksManager {\n // task cache key = `ftask-$(userId}-${taskId}` => FileTask\n private readonly logger = new Logger(FilesTasksManager.name)\n private readonly watchInterval = 1000\n private tasksWatcher: Record<string, any> = {}\n\n constructor(\n private readonly cache: Cache,\n private readonly filesMethods: FilesMethods\n ) {\n FileTaskEvent.on('startWatch', async (space: SpaceEnv, taskType: FILE_OPERATION, rPath: string) =>\n this.startWatch(space, taskType, rPath, dirName(space.url))\n )\n }\n\n static getCacheKey(userId: number, taskId?: string): string {\n return `${CACHE_TASK_PREFIX}-${userId}-${taskId || '*'}`\n }\n\n async createTask(type: FILE_OPERATION, user: UserModel, space: SpaceEnv, dto: any, method: string): Promise<FileTask> {\n const taskId: string = crypto.randomUUID()\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const newTask = new FileTask(taskId, type, dirName(space.url), fileName(space.url))\n await this.storeTask(cacheKey, newTask)\n space.task = { cacheKey: cacheKey, props: {} }\n this.filesMethods[method](user, space, dto)\n .then((data: any) => {\n this.logger.debug(`${this.createTask.name} - ${newTask.name} : ${method} done`)\n this.setTaskDone(cacheKey, FileTaskStatus.SUCCESS, data).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n .catch((e: HttpException | any) => {\n this.logger.error(`${this.createTask.name} - ${newTask.name} : ${method} : ${e}`)\n this.setTaskDone(cacheKey, FileTaskStatus.ERROR, e.message).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n return newTask\n }\n\n async getTasks(userId: number, taskId?: string): Promise<FileTask | FileTask[]> {\n const cacheKey = FilesTasksManager.getCacheKey(userId, taskId)\n if (taskId) {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) return task\n throw new HttpException('Task not found', HttpStatus.NOT_FOUND)\n } else {\n const keys = await this.cache.keys(cacheKey)\n return keys.length ? await this.cache.mget(keys) : []\n }\n }\n\n async deleteTasks(user: UserModel, taskId?: string): Promise<void> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n let keys: string[]\n if (taskId) {\n keys = [cacheKey]\n } else {\n keys = await this.cache.keys(cacheKey)\n }\n if (!keys.length) return\n for (const key of keys) {\n const task: FileTask = await this.cache.get(key)\n if (!task || task.status === FileTaskStatus.PENDING) continue\n if (task.props.compressInDirectory === false) {\n // delete task file\n const rPath = path.join(user.tasksPath, task.name)\n removeFiles(rPath).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n // clear watcher\n this.stopWatch(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n // remove from cache\n this.cache.del(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n }\n\n async downloadArchive(user: UserModel, taskId: string, req: FastifyAuthenticatedRequest, res: FastifyReply): Promise<StreamableFile> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const task: FileTask = await this.cache.get(cacheKey)\n if (!task || task.status !== FileTaskStatus.SUCCESS || task.props.compressInDirectory !== false) {\n throw new HttpException('Not applicable', HttpStatus.BAD_REQUEST)\n }\n const rPath = path.join(user.tasksPath, task.name)\n const sendFile = new SendFile(rPath)\n try {\n await sendFile.checks()\n } catch (e) {\n throw new HttpException(e.message, e.httpCode)\n }\n return await sendFile.stream(req, res)\n }\n\n private async storeTask(cacheKey: string, task: FileTask) {\n task.startedAt = currentTimeStamp(null, true)\n task.status = FileTaskStatus.PENDING\n try {\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n } catch (e) {\n this.logger.error(`${this.storeTask.name} - ${e}`)\n }\n }\n\n private async setTaskDone(cacheKey: string, status: FileTaskStatus, result: any): Promise<void> {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) {\n task.status = status\n task.endedAt = currentTimeStamp(null, true)\n if (result) {\n if (typeof result === 'string') {\n task.result = result\n } else {\n Object.assign(task, result)\n }\n }\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n }\n await this.stopWatch(cacheKey)\n }\n\n private async updateTask(cacheKey: string, props?: FileTaskProps, task?: Partial<FileTask>): Promise<void> {\n let ftask: FileTask = await this.cache.get(cacheKey)\n if (ftask) {\n if (task) ftask = { ...ftask, ...task }\n if (props) ftask.props = { ...ftask.props, ...props }\n await this.cache.set(cacheKey, ftask, CACHE_TASK_TTL)\n } else {\n await this.stopWatch(cacheKey)\n }\n }\n\n private async startWatch(space: SpaceEnv, taskType: FILE_OPERATION, rPath: string, taskPath?: string): Promise<void> {\n if (!space.task?.cacheKey || space.task.cacheKey in this.tasksWatcher) return\n this.logger.verbose(`${this.startWatch.name} - ${space.task.cacheKey}`)\n this.updateTask(space.task.cacheKey, space.task?.props, {\n name: fileName(rPath),\n path: taskPath\n }).catch((e: Error) => this.logger.error(`${this.startWatch.name} - ${e}`))\n switch (taskType) {\n case FILE_OPERATION.COMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DECOMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDecompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DOWNLOAD:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDownloadTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.COPY:\n case FILE_OPERATION.MOVE:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCopyMoveTask(space, rPath), this.watchInterval)\n return\n default:\n this.logger.warn(`${this.startWatch.name} - unknown task type ${taskType}`)\n return\n }\n }\n\n private async stopWatch(cacheKey: string): Promise<void> {\n if (!(cacheKey in this.tasksWatcher)) return\n await setTimeout(this.watchInterval)\n clearInterval(this.tasksWatcher[cacheKey])\n delete this.tasksWatcher[cacheKey]\n }\n\n private async updateCompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props.size = await fileSize(rPath)\n await this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDecompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props = await countDirEntries(rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDecompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDecompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDownloadTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n await this.calcSizeAndProgressTask(space, rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDownloadTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDownloadTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateCopyMoveTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n if (await isPathIsDir(rPath)) {\n space.task.props = await countDirEntries(rPath)\n } else {\n await this.calcSizeAndProgressTask(space, rPath)\n }\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async calcSizeAndProgressTask(space: SpaceEnv, rPath: string) {\n space.task.props.size = await fileSize(rPath)\n if (space.task.props.totalSize) {\n space.task.props.progress = (100 * space.task.props.size) / space.task.props.totalSize\n }\n }\n}\n"],"names":["FilesTasksManager","getCacheKey","userId","taskId","CACHE_TASK_PREFIX","createTask","type","user","space","dto","method","crypto","randomUUID","cacheKey","id","newTask","FileTask","dirName","url","fileName","storeTask","task","props","filesMethods","then","data","logger","debug","name","setTaskDone","FileTaskStatus","SUCCESS","catch","e","error","ERROR","message","getTasks","cache","get","HttpException","HttpStatus","NOT_FOUND","keys","length","mget","deleteTasks","key","status","PENDING","compressInDirectory","rPath","path","join","tasksPath","removeFiles","stopWatch","del","downloadArchive","req","res","BAD_REQUEST","sendFile","SendFile","checks","httpCode","stream","startedAt","currentTimeStamp","set","CACHE_TASK_TTL","result","endedAt","Object","assign","updateTask","ftask","startWatch","taskType","taskPath","tasksWatcher","verbose","FILE_OPERATION","COMPRESS","setInterval","updateCompressTask","watchInterval","DECOMPRESS","updateDecompressTask","DOWNLOAD","updateDownloadTask","COPY","MOVE","updateCopyMoveTask","warn","setTimeout","clearInterval","size","fileSize","countDirEntries","calcSizeAndProgressTask","isPathIsDir","totalSize","progress","Logger","FileTaskEvent","on"],"mappings":"AAAA;;;;CAIC;;;;+BAsBYA;;;eAAAA;;;wBApBiE;mEAE3D;iEACF;0BACU;wBAGM;8BACX;uBAG4B;4BACnB;+BACD;0BAC0B;uBAC+B;0BAC9D;qCACI;;;;;;;;;;;;;;;AAGtB,IAAA,AAAMA,oBAAN,MAAMA;IAeX,OAAOC,YAAYC,MAAc,EAAEC,MAAe,EAAU;QAC1D,OAAO,GAAGC,wBAAiB,CAAC,CAAC,EAAEF,OAAO,CAAC,EAAEC,UAAU,KAAK;IAC1D;IAEA,MAAME,WAAWC,IAAoB,EAAEC,IAAe,EAAEC,KAAe,EAAEC,GAAQ,EAAEC,MAAc,EAAqB;QACpH,MAAMP,SAAiBQ,mBAAM,CAACC,UAAU;QACxC,MAAMC,WAAWb,kBAAkBC,WAAW,CAACM,KAAKO,EAAE,EAAEX;QACxD,MAAMY,UAAU,IAAIC,kBAAQ,CAACb,QAAQG,MAAMW,IAAAA,cAAO,EAACT,MAAMU,GAAG,GAAGC,IAAAA,eAAQ,EAACX,MAAMU,GAAG;QACjF,MAAM,IAAI,CAACE,SAAS,CAACP,UAAUE;QAC/BP,MAAMa,IAAI,GAAG;YAAER,UAAUA;YAAUS,OAAO,CAAC;QAAE;QAC7C,IAAI,CAACC,YAAY,CAACb,OAAO,CAACH,MAAMC,OAAOC,KACpCe,IAAI,CAAC,CAACC;YACL,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACtB,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEb,QAAQa,IAAI,CAAC,GAAG,EAAElB,OAAO,KAAK,CAAC;YAC9E,IAAI,CAACmB,WAAW,CAAChB,UAAUiB,wBAAc,CAACC,OAAO,EAAEN,MAAMO,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC7B,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEK,GAAG;QACjI,GACCD,KAAK,CAAC,CAACC;YACN,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC7B,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEb,QAAQa,IAAI,CAAC,GAAG,EAAElB,OAAO,GAAG,EAAEuB,GAAG;YAChF,IAAI,CAACJ,WAAW,CAAChB,UAAUiB,wBAAc,CAACK,KAAK,EAAEF,EAAEG,OAAO,EAAEJ,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC7B,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEK,GAAG;QACpI;QACF,OAAOlB;IACT;IAEA,MAAMsB,SAASnC,MAAc,EAAEC,MAAe,EAAkC;QAC9E,MAAMU,WAAWb,kBAAkBC,WAAW,CAACC,QAAQC;QACvD,IAAIA,QAAQ;YACV,MAAMkB,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAAC1B;YAC5C,IAAIQ,MAAM,OAAOA;YACjB,MAAM,IAAImB,qBAAa,CAAC,kBAAkBC,kBAAU,CAACC,SAAS;QAChE,OAAO;YACL,MAAMC,OAAO,MAAM,IAAI,CAACL,KAAK,CAACK,IAAI,CAAC9B;YACnC,OAAO8B,KAAKC,MAAM,GAAG,MAAM,IAAI,CAACN,KAAK,CAACO,IAAI,CAACF,QAAQ,EAAE;QACvD;IACF;IAEA,MAAMG,YAAYvC,IAAe,EAAEJ,MAAe,EAAiB;QACjE,MAAMU,WAAWb,kBAAkBC,WAAW,CAACM,KAAKO,EAAE,EAAEX;QACxD,IAAIwC;QACJ,IAAIxC,QAAQ;YACVwC,OAAO;gBAAC9B;aAAS;QACnB,OAAO;YACL8B,OAAO,MAAM,IAAI,CAACL,KAAK,CAACK,IAAI,CAAC9B;QAC/B;QACA,IAAI,CAAC8B,KAAKC,MAAM,EAAE;QAClB,KAAK,MAAMG,OAAOJ,KAAM;YACtB,MAAMtB,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAACQ;YAC5C,IAAI,CAAC1B,QAAQA,KAAK2B,MAAM,KAAKlB,wBAAc,CAACmB,OAAO,EAAE;YACrD,IAAI5B,KAAKC,KAAK,CAAC4B,mBAAmB,KAAK,OAAO;gBAC5C,mBAAmB;gBACnB,MAAMC,QAAQC,iBAAI,CAACC,IAAI,CAAC9C,KAAK+C,SAAS,EAAEjC,KAAKO,IAAI;gBACjD2B,IAAAA,kBAAW,EAACJ,OAAOnB,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACY,WAAW,CAAClB,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC5F;YACA,gBAAgB;YAChB,IAAI,CAACuB,SAAS,CAACT,KAAKf,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACY,WAAW,CAAClB,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC3F,oBAAoB;YACpB,IAAI,CAACK,KAAK,CAACmB,GAAG,CAACV,KAAKf,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACY,WAAW,CAAClB,IAAI,CAAC,GAAG,EAAEK,GAAG;QAC7F;IACF;IAEA,MAAMyB,gBAAgBnD,IAAe,EAAEJ,MAAc,EAAEwD,GAAgC,EAAEC,GAAiB,EAA2B;QACnI,MAAM/C,WAAWb,kBAAkBC,WAAW,CAACM,KAAKO,EAAE,EAAEX;QACxD,MAAMkB,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAAC1B;QAC5C,IAAI,CAACQ,QAAQA,KAAK2B,MAAM,KAAKlB,wBAAc,CAACC,OAAO,IAAIV,KAAKC,KAAK,CAAC4B,mBAAmB,KAAK,OAAO;YAC/F,MAAM,IAAIV,qBAAa,CAAC,kBAAkBC,kBAAU,CAACoB,WAAW;QAClE;QACA,MAAMV,QAAQC,iBAAI,CAACC,IAAI,CAAC9C,KAAK+C,SAAS,EAAEjC,KAAKO,IAAI;QACjD,MAAMkC,WAAW,IAAIC,kBAAQ,CAACZ;QAC9B,IAAI;YACF,MAAMW,SAASE,MAAM;QACvB,EAAE,OAAO/B,GAAG;YACV,MAAM,IAAIO,qBAAa,CAACP,EAAEG,OAAO,EAAEH,EAAEgC,QAAQ;QAC/C;QACA,OAAO,MAAMH,SAASI,MAAM,CAACP,KAAKC;IACpC;IAEA,MAAcxC,UAAUP,QAAgB,EAAEQ,IAAc,EAAE;QACxDA,KAAK8C,SAAS,GAAGC,IAAAA,wBAAgB,EAAC,MAAM;QACxC/C,KAAK2B,MAAM,GAAGlB,wBAAc,CAACmB,OAAO;QACpC,IAAI;YACF,MAAM,IAAI,CAACX,KAAK,CAAC+B,GAAG,CAACxD,UAAUQ,MAAMiD,qBAAc;QACrD,EAAE,OAAOrC,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACd,SAAS,CAACQ,IAAI,CAAC,GAAG,EAAEK,GAAG;QACnD;IACF;IAEA,MAAcJ,YAAYhB,QAAgB,EAAEmC,MAAsB,EAAEuB,MAAW,EAAiB;QAC9F,MAAMlD,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAAC1B;QAC5C,IAAIQ,MAAM;YACRA,KAAK2B,MAAM,GAAGA;YACd3B,KAAKmD,OAAO,GAAGJ,IAAAA,wBAAgB,EAAC,MAAM;YACtC,IAAIG,QAAQ;gBACV,IAAI,OAAOA,WAAW,UAAU;oBAC9BlD,KAAKkD,MAAM,GAAGA;gBAChB,OAAO;oBACLE,OAAOC,MAAM,CAACrD,MAAMkD;gBACtB;YACF;YACA,MAAM,IAAI,CAACjC,KAAK,CAAC+B,GAAG,CAACxD,UAAUQ,MAAMiD,qBAAc;QACrD;QACA,MAAM,IAAI,CAACd,SAAS,CAAC3C;IACvB;IAEA,MAAc8D,WAAW9D,QAAgB,EAAES,KAAqB,EAAED,IAAwB,EAAiB;QACzG,IAAIuD,QAAkB,MAAM,IAAI,CAACtC,KAAK,CAACC,GAAG,CAAC1B;QAC3C,IAAI+D,OAAO;YACT,IAAIvD,MAAMuD,QAAQ;gBAAE,GAAGA,KAAK;gBAAE,GAAGvD,IAAI;YAAC;YACtC,IAAIC,OAAOsD,MAAMtD,KAAK,GAAG;gBAAE,GAAGsD,MAAMtD,KAAK;gBAAE,GAAGA,KAAK;YAAC;YACpD,MAAM,IAAI,CAACgB,KAAK,CAAC+B,GAAG,CAACxD,UAAU+D,OAAON,qBAAc;QACtD,OAAO;YACL,MAAM,IAAI,CAACd,SAAS,CAAC3C;QACvB;IACF;IAEA,MAAcgE,WAAWrE,KAAe,EAAEsE,QAAwB,EAAE3B,KAAa,EAAE4B,QAAiB,EAAiB;QACnH,IAAI,CAACvE,MAAMa,IAAI,EAAER,YAAYL,MAAMa,IAAI,CAACR,QAAQ,IAAI,IAAI,CAACmE,YAAY,EAAE;QACvE,IAAI,CAACtD,MAAM,CAACuD,OAAO,CAAC,GAAG,IAAI,CAACJ,UAAU,CAACjD,IAAI,CAAC,GAAG,EAAEpB,MAAMa,IAAI,CAACR,QAAQ,EAAE;QACtE,IAAI,CAAC8D,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,EAAEC,OAAO;YACtDM,MAAMT,IAAAA,eAAQ,EAACgC;YACfC,MAAM2B;QACR,GAAG/C,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC2C,UAAU,CAACjD,IAAI,CAAC,GAAG,EAAEK,GAAG;QACzE,OAAQ6C;YACN,KAAKI,0BAAc,CAACC,QAAQ;gBAC1B,IAAI,CAACH,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACC,kBAAkB,CAAC7E,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC1H;YACF,KAAKJ,0BAAc,CAACK,UAAU;gBAC5B,IAAI,CAACP,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACI,oBAAoB,CAAChF,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC5H;YACF,KAAKJ,0BAAc,CAACO,QAAQ;gBAC1B,IAAI,CAACT,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACM,kBAAkB,CAAClF,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC1H;YACF,KAAKJ,0BAAc,CAACS,IAAI;YACxB,KAAKT,0BAAc,CAACU,IAAI;gBACtB,IAAI,CAACZ,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACS,kBAAkB,CAACrF,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC1H;YACF;gBACE,IAAI,CAAC5D,MAAM,CAACoE,IAAI,CAAC,GAAG,IAAI,CAACjB,UAAU,CAACjD,IAAI,CAAC,qBAAqB,EAAEkD,UAAU;gBAC1E;QACJ;IACF;IAEA,MAActB,UAAU3C,QAAgB,EAAiB;QACvD,IAAI,CAAEA,CAAAA,YAAY,IAAI,CAACmE,YAAY,AAAD,GAAI;QACtC,MAAMe,IAAAA,oBAAU,EAAC,IAAI,CAACT,aAAa;QACnCU,cAAc,IAAI,CAAChB,YAAY,CAACnE,SAAS;QACzC,OAAO,IAAI,CAACmE,YAAY,CAACnE,SAAS;IACpC;IAEA,MAAcwE,mBAAmB7E,KAAe,EAAE2C,KAAa,EAAiB;QAC9E,IAAI;YACF3C,MAAMa,IAAI,CAACC,KAAK,CAAC2E,IAAI,GAAG,MAAMC,IAAAA,eAAQ,EAAC/C;YACvC,MAAM,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACmD,kBAAkB,CAACzD,IAAI,CAAC,GAAG,EAAEK,GAAG;QAC7I,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACmD,kBAAkB,CAACzD,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC1D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAc2E,qBAAqBhF,KAAe,EAAE2C,KAAa,EAAiB;QAChF,IAAI;YACF3C,MAAMa,IAAI,CAACC,KAAK,GAAG,MAAM6E,IAAAA,sBAAe,EAAChD;YACzC,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACsD,oBAAoB,CAAC5D,IAAI,CAAC,GAAG,EAAEK,GAAG;QACzI,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACsD,oBAAoB,CAAC5D,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC5D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAc6E,mBAAmBlF,KAAe,EAAE2C,KAAa,EAAiB;QAC9E,IAAI;YACF,MAAM,IAAI,CAACiD,uBAAuB,CAAC5F,OAAO2C;YAC1C,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACwD,kBAAkB,CAAC9D,IAAI,CAAC,GAAG,EAAEK,GAAG;QACvI,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACwD,kBAAkB,CAAC9D,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC1D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAcgF,mBAAmBrF,KAAe,EAAE2C,KAAa,EAAiB;QAC9E,IAAI;YACF,IAAI,MAAMkD,IAAAA,kBAAW,EAAClD,QAAQ;gBAC5B3C,MAAMa,IAAI,CAACC,KAAK,GAAG,MAAM6E,IAAAA,sBAAe,EAAChD;YAC3C,OAAO;gBACL,MAAM,IAAI,CAACiD,uBAAuB,CAAC5F,OAAO2C;YAC5C;YACA,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC2D,kBAAkB,CAACjE,IAAI,CAAC,GAAG,EAAEK,GAAG;QACvI,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC2D,kBAAkB,CAACjE,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC1D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAcuF,wBAAwB5F,KAAe,EAAE2C,KAAa,EAAE;QACpE3C,MAAMa,IAAI,CAACC,KAAK,CAAC2E,IAAI,GAAG,MAAMC,IAAAA,eAAQ,EAAC/C;QACvC,IAAI3C,MAAMa,IAAI,CAACC,KAAK,CAACgF,SAAS,EAAE;YAC9B9F,MAAMa,IAAI,CAACC,KAAK,CAACiF,QAAQ,GAAG,AAAC,MAAM/F,MAAMa,IAAI,CAACC,KAAK,CAAC2E,IAAI,GAAIzF,MAAMa,IAAI,CAACC,KAAK,CAACgF,SAAS;QACxF;IACF;IA5MA,YACE,AAAiBhE,KAAY,EAC7B,AAAiBf,YAA0B,CAC3C;aAFiBe,QAAAA;aACAf,eAAAA;QAPnB,2DAA2D;aAC1CG,SAAS,IAAI8E,cAAM,CAACxG,kBAAkB4B,IAAI;aAC1C0D,gBAAgB;aACzBN,eAAoC,CAAC;QAM3CyB,4BAAa,CAACC,EAAE,CAAC,cAAc,OAAOlG,OAAiBsE,UAA0B3B,QAC/E,IAAI,CAAC0B,UAAU,CAACrE,OAAOsE,UAAU3B,OAAOlC,IAAAA,cAAO,EAACT,MAAMU,GAAG;IAE7D;AAsMF"}
@@ -6,10 +6,18 @@
6
6
  Object.defineProperty(exports, "__esModule", {
7
7
  value: true
8
8
  });
9
- Object.defineProperty(exports, "SendFile", {
10
- enumerable: true,
11
- get: function() {
9
+ function _export(target, all) {
10
+ for(var name in all)Object.defineProperty(target, name, {
11
+ enumerable: true,
12
+ get: Object.getOwnPropertyDescriptor(all, name).get
13
+ });
14
+ }
15
+ _export(exports, {
16
+ get SendFile () {
12
17
  return SendFile;
18
+ },
19
+ get makeContentDispositionAttachment () {
20
+ return makeContentDispositionAttachment;
13
21
  }
14
22
  });
15
23
  const _send = require("@fastify/send");
@@ -17,6 +25,10 @@ const _common = require("@nestjs/common");
17
25
  const _files = require("../constants/files");
18
26
  const _fileerror = require("../models/file-error");
19
27
  const _files1 = require("./files");
28
+ function makeContentDispositionAttachment(fileName) {
29
+ const downloadName = fileName.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
30
+ return `attachment; filename="${downloadName}";filename*=UTF-8''${fileName}`;
31
+ }
20
32
  let SendFile = class SendFile {
21
33
  async checks() {
22
34
  if (!await (0, _files1.isPathExists)(this.filePath)) {
@@ -40,10 +52,8 @@ let SendFile = class SendFile {
40
52
  if (sendResult.metadata['path'] === undefined) {
41
53
  throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Location not found');
42
54
  }
43
- if (this.asAttachment) {
44
- const downloadName = this.fileName.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
45
- sendResult.headers['content-disposition'] = `attachment; filename="${downloadName}";filename*=UTF-8''${this.fileName}`;
46
- }
55
+ // Force file to be downloaded as an attachment
56
+ sendResult.headers['content-disposition'] = makeContentDispositionAttachment(this.fileName);
47
57
  res.headers(sendResult.headers);
48
58
  res.status(sendResult.statusCode);
49
59
  // sendStream.once('stream', () => console.log(`Sending: ${this.fileName}`))
@@ -51,7 +61,7 @@ let SendFile = class SendFile {
51
61
  // sendStream.once('error', (e: Error) => console.error(`Transfer error : ${this.fileName} - ${e}`))
52
62
  return new _common.StreamableFile(sendResult.stream);
53
63
  }
54
- constructor(filePath, asAttachment = true, downloadName = '', sendOptions = {
64
+ constructor(filePath, downloadName = '', sendOptions = {
55
65
  acceptRanges: true,
56
66
  etag: true,
57
67
  dotfiles: 'allow',
@@ -62,7 +72,6 @@ let SendFile = class SendFile {
62
72
  highWaterMark: _files.DEFAULT_HIGH_WATER_MARK
63
73
  }){
64
74
  this.filePath = filePath;
65
- this.asAttachment = asAttachment;
66
75
  this.downloadName = downloadName;
67
76
  this.sendOptions = sendOptions;
68
77
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/utils/send-file.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 { send, SendOptions, SendResult } from '@fastify/send'\nimport { HttpStatus, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { DEFAULT_HIGH_WATER_MARK } from '../constants/files'\nimport { FileError } from '../models/file-error'\nimport { fileName, isPathExists, isPathIsDir, isPathIsReadable } from './files'\n\nexport class SendFile {\n private fileName: string\n\n constructor(\n private readonly filePath: string,\n private readonly asAttachment = true,\n private readonly downloadName = '',\n private readonly sendOptions: SendOptions = {\n acceptRanges: true,\n etag: true,\n dotfiles: 'allow',\n lastModified: true,\n cacheControl: true,\n maxAge: 0,\n index: false,\n highWaterMark: DEFAULT_HIGH_WATER_MARK\n }\n ) {}\n\n async checks() {\n if (!(await isPathExists(this.filePath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (await isPathIsDir(this.filePath)) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'The location is a directory')\n }\n if (!(await isPathIsReadable(this.filePath))) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'The location is not readable')\n }\n }\n\n async stream(req: FastifyRequest, res: FastifyReply): Promise<StreamableFile> {\n // SendStream manages HEAD (no including body in response) & GET request (with body)\n // Ranges, LastModified, Etag are also handled\n // Send function uses decodeURIComponent, but filePath is already decoded: we need to encode it again before passing it.\n const encodedFilePath = encodeURIComponent(this.filePath)\n this.fileName = encodeURIComponent(this.downloadName ? this.downloadName : fileName(this.filePath))\n const sendResult: SendResult = await send(req.raw, encodedFilePath, this.sendOptions)\n // Check if the path was correctly validated\n if (sendResult.metadata['path'] === undefined) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Location not found')\n }\n if (this.asAttachment) {\n const downloadName = this.fileName.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n sendResult.headers['content-disposition'] = `attachment; filename=\"${downloadName}\";filename*=UTF-8''${this.fileName}`\n }\n res.headers(sendResult.headers)\n res.status(sendResult.statusCode)\n // sendStream.once('stream', () => console.log(`Sending: ${this.fileName}`))\n // sendStream.once('end', () => console.log(`Received: ${this.fileName}`))\n // sendStream.once('error', (e: Error) => console.error(`Transfer error : ${this.fileName} - ${e}`))\n return new StreamableFile(sendResult.stream)\n }\n}\n"],"names":["SendFile","checks","isPathExists","filePath","FileError","HttpStatus","NOT_FOUND","isPathIsDir","BAD_REQUEST","isPathIsReadable","METHOD_NOT_ALLOWED","stream","req","res","encodedFilePath","encodeURIComponent","fileName","downloadName","sendResult","send","raw","sendOptions","metadata","undefined","asAttachment","normalize","replace","headers","status","statusCode","StreamableFile","acceptRanges","etag","dotfiles","lastModified","cacheControl","maxAge","index","highWaterMark","DEFAULT_HIGH_WATER_MARK"],"mappings":"AAAA;;;;CAIC;;;;+BASYA;;;eAAAA;;;sBAPiC;wBACH;uBAEH;2BACd;wBAC4C;AAE/D,IAAA,AAAMA,WAAN,MAAMA;IAmBX,MAAMC,SAAS;QACb,IAAI,CAAE,MAAMC,IAAAA,oBAAY,EAAC,IAAI,CAACC,QAAQ,GAAI;YACxC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACC,SAAS,EAAE;QAC5C;QACA,IAAI,MAAMC,IAAAA,mBAAW,EAAC,IAAI,CAACJ,QAAQ,GAAG;YACpC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,IAAI,CAAE,MAAMC,IAAAA,wBAAgB,EAAC,IAAI,CAACN,QAAQ,GAAI;YAC5C,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACK,kBAAkB,EAAE;QACrD;IACF;IAEA,MAAMC,OAAOC,GAAmB,EAAEC,GAAiB,EAA2B;QAC5E,oFAAoF;QACpF,8CAA8C;QAC9C,wHAAwH;QACxH,MAAMC,kBAAkBC,mBAAmB,IAAI,CAACZ,QAAQ;QACxD,IAAI,CAACa,QAAQ,GAAGD,mBAAmB,IAAI,CAACE,YAAY,GAAG,IAAI,CAACA,YAAY,GAAGD,IAAAA,gBAAQ,EAAC,IAAI,CAACb,QAAQ;QACjG,MAAMe,aAAyB,MAAMC,IAAAA,UAAI,EAACP,IAAIQ,GAAG,EAAEN,iBAAiB,IAAI,CAACO,WAAW;QACpF,4CAA4C;QAC5C,IAAIH,WAAWI,QAAQ,CAAC,OAAO,KAAKC,WAAW;YAC7C,MAAM,IAAInB,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,IAAI,IAAI,CAACgB,YAAY,EAAE;YACrB,MAAMP,eAAe,IAAI,CAACD,QAAQ,CAACS,SAAS,CAAC,OAAOC,OAAO,CAAC,oBAAoB;YAChFR,WAAWS,OAAO,CAAC,sBAAsB,GAAG,CAAC,sBAAsB,EAAEV,aAAa,mBAAmB,EAAE,IAAI,CAACD,QAAQ,EAAE;QACxH;QACAH,IAAIc,OAAO,CAACT,WAAWS,OAAO;QAC9Bd,IAAIe,MAAM,CAACV,WAAWW,UAAU;QAChC,4EAA4E;QAC5E,0EAA0E;QAC1E,oGAAoG;QACpG,OAAO,IAAIC,sBAAc,CAACZ,WAAWP,MAAM;IAC7C;IAjDA,YACE,AAAiBR,QAAgB,EACjC,AAAiBqB,eAAe,IAAI,EACpC,AAAiBP,eAAe,EAAE,EAClC,AAAiBI,cAA2B;QAC1CU,cAAc;QACdC,MAAM;QACNC,UAAU;QACVC,cAAc;QACdC,cAAc;QACdC,QAAQ;QACRC,OAAO;QACPC,eAAeC,8BAAuB;IACxC,CAAC,CACD;aAbiBpC,WAAAA;aACAqB,eAAAA;aACAP,eAAAA;aACAI,cAAAA;IAUhB;AAoCL"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/utils/send-file.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 { send, SendOptions, SendResult } from '@fastify/send'\nimport { HttpStatus, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { DEFAULT_HIGH_WATER_MARK } from '../constants/files'\nimport { FileError } from '../models/file-error'\nimport { fileName, isPathExists, isPathIsDir, isPathIsReadable } from './files'\n\nexport function makeContentDispositionAttachment(fileName: string) {\n const downloadName = fileName.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n return `attachment; filename=\"${downloadName}\";filename*=UTF-8''${fileName}`\n}\n\nexport class SendFile {\n private fileName: string\n\n constructor(\n private readonly filePath: string,\n private readonly downloadName = '',\n private readonly sendOptions: SendOptions = {\n acceptRanges: true,\n etag: true,\n dotfiles: 'allow',\n lastModified: true,\n cacheControl: true,\n maxAge: 0,\n index: false,\n highWaterMark: DEFAULT_HIGH_WATER_MARK\n }\n ) {}\n\n async checks() {\n if (!(await isPathExists(this.filePath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (await isPathIsDir(this.filePath)) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'The location is a directory')\n }\n if (!(await isPathIsReadable(this.filePath))) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'The location is not readable')\n }\n }\n\n async stream(req: FastifyRequest, res: FastifyReply): Promise<StreamableFile> {\n // SendStream manages HEAD (no including body in response) & GET request (with body)\n // Ranges, LastModified, Etag are also handled\n // Send function uses decodeURIComponent, but filePath is already decoded: we need to encode it again before passing it.\n const encodedFilePath = encodeURIComponent(this.filePath)\n this.fileName = encodeURIComponent(this.downloadName ? this.downloadName : fileName(this.filePath))\n const sendResult: SendResult = await send(req.raw, encodedFilePath, this.sendOptions)\n // Check if the path was correctly validated\n if (sendResult.metadata['path'] === undefined) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Location not found')\n }\n // Force file to be downloaded as an attachment\n sendResult.headers['content-disposition'] = makeContentDispositionAttachment(this.fileName)\n res.headers(sendResult.headers)\n res.status(sendResult.statusCode)\n // sendStream.once('stream', () => console.log(`Sending: ${this.fileName}`))\n // sendStream.once('end', () => console.log(`Received: ${this.fileName}`))\n // sendStream.once('error', (e: Error) => console.error(`Transfer error : ${this.fileName} - ${e}`))\n return new StreamableFile(sendResult.stream)\n }\n}\n"],"names":["SendFile","makeContentDispositionAttachment","fileName","downloadName","normalize","replace","checks","isPathExists","filePath","FileError","HttpStatus","NOT_FOUND","isPathIsDir","BAD_REQUEST","isPathIsReadable","METHOD_NOT_ALLOWED","stream","req","res","encodedFilePath","encodeURIComponent","sendResult","send","raw","sendOptions","metadata","undefined","headers","status","statusCode","StreamableFile","acceptRanges","etag","dotfiles","lastModified","cacheControl","maxAge","index","highWaterMark","DEFAULT_HIGH_WATER_MARK"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAcYA;eAAAA;;QALGC;eAAAA;;;sBAP8B;wBACH;uBAEH;2BACd;wBAC4C;AAE/D,SAASA,iCAAiCC,QAAgB;IAC/D,MAAMC,eAAeD,SAASE,SAAS,CAAC,OAAOC,OAAO,CAAC,oBAAoB;IAC3E,OAAO,CAAC,sBAAsB,EAAEF,aAAa,mBAAmB,EAAED,UAAU;AAC9E;AAEO,IAAA,AAAMF,WAAN,MAAMA;IAkBX,MAAMM,SAAS;QACb,IAAI,CAAE,MAAMC,IAAAA,oBAAY,EAAC,IAAI,CAACC,QAAQ,GAAI;YACxC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACC,SAAS,EAAE;QAC5C;QACA,IAAI,MAAMC,IAAAA,mBAAW,EAAC,IAAI,CAACJ,QAAQ,GAAG;YACpC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,IAAI,CAAE,MAAMC,IAAAA,wBAAgB,EAAC,IAAI,CAACN,QAAQ,GAAI;YAC5C,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACK,kBAAkB,EAAE;QACrD;IACF;IAEA,MAAMC,OAAOC,GAAmB,EAAEC,GAAiB,EAA2B;QAC5E,oFAAoF;QACpF,8CAA8C;QAC9C,wHAAwH;QACxH,MAAMC,kBAAkBC,mBAAmB,IAAI,CAACZ,QAAQ;QACxD,IAAI,CAACN,QAAQ,GAAGkB,mBAAmB,IAAI,CAACjB,YAAY,GAAG,IAAI,CAACA,YAAY,GAAGD,IAAAA,gBAAQ,EAAC,IAAI,CAACM,QAAQ;QACjG,MAAMa,aAAyB,MAAMC,IAAAA,UAAI,EAACL,IAAIM,GAAG,EAAEJ,iBAAiB,IAAI,CAACK,WAAW;QACpF,4CAA4C;QAC5C,IAAIH,WAAWI,QAAQ,CAAC,OAAO,KAAKC,WAAW;YAC7C,MAAM,IAAIjB,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,+CAA+C;QAC/CQ,WAAWM,OAAO,CAAC,sBAAsB,GAAG1B,iCAAiC,IAAI,CAACC,QAAQ;QAC1FgB,IAAIS,OAAO,CAACN,WAAWM,OAAO;QAC9BT,IAAIU,MAAM,CAACP,WAAWQ,UAAU;QAChC,4EAA4E;QAC5E,0EAA0E;QAC1E,oGAAoG;QACpG,OAAO,IAAIC,sBAAc,CAACT,WAAWL,MAAM;IAC7C;IA9CA,YACE,AAAiBR,QAAgB,EACjC,AAAiBL,eAAe,EAAE,EAClC,AAAiBqB,cAA2B;QAC1CO,cAAc;QACdC,MAAM;QACNC,UAAU;QACVC,cAAc;QACdC,cAAc;QACdC,QAAQ;QACRC,OAAO;QACPC,eAAeC,8BAAuB;IACxC,CAAC,CACD;aAZiB/B,WAAAA;aACAL,eAAAA;aACAqB,cAAAA;IAUhB;AAkCL"}
@@ -1,8 +1,4 @@
1
- /*
2
- * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
- * This file is part of Sync-in | The open source file sync and share solution
4
- * See the LICENSE file for licensing details
5
- */ "use strict";
1
+ "use strict";
6
2
  Object.defineProperty(exports, "__esModule", {
7
3
  value: true
8
4
  });
@@ -12,7 +8,11 @@ Object.defineProperty(exports, "regExpPrivateIP", {
12
8
  return regExpPrivateIP;
13
9
  }
14
10
  });
15
- const parts = [
11
+ /*
12
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
13
+ * This file is part of Sync-in | The open source file sync and share solution
14
+ * See the LICENSE file for licensing details
15
+ */ const parts = [
16
16
  // IPv4 loopback (127.0.0.0/8)
17
17
  '127\\.(?:\\d{1,3}\\.){2}\\d{1,3}',
18
18
  // IPv4 link-local (169.254.0.0/16)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/utils/url-file.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\nconst parts = [\n // IPv4 loopback (127.0.0.0/8)\n '127\\\\.(?:\\\\d{1,3}\\\\.){2}\\\\d{1,3}',\n // IPv4 link-local (169.254.0.0/16)\n '169\\\\.254\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 Carrier-grade NAT (100.64.0.0/10)\n '100\\\\.(?:6[4-9]|[7-9]\\\\d|1[01]\\\\d|12[0-7])\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 private (10.0.0.0/8)\n '10\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 private (192.168.0.0/16)\n '192\\\\.168\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 private (172.16.0.0/12)\n '172\\\\.(?:1[6-9]|2\\\\d|3[0-1])\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 & IPv6 loopback\n '::1',\n '::',\n '0.0.0.0',\n // IPv6 Unique Local Address (fc00::/7)\n 'f[cd][0-9a-f]{2}:[0-9a-f:]+',\n // IPv6 link-local (fe80::/10)\n 'fe[89ab][0-9a-f]{2}:[0-9a-f:]+'\n]\n\nexport const regExpPrivateIP = new RegExp(`^(?:${parts.join('|')})$`, 'i')\n"],"names":["regExpPrivateIP","parts","RegExp","join"],"mappings":"AAAA;;;;CAIC;;;;+BAyBYA;;;eAAAA;;;AAvBb,MAAMC,QAAQ;IACZ,8BAA8B;IAC9B;IACA,mCAAmC;IACnC;IACA,yCAAyC;IACzC;IACA,4BAA4B;IAC5B;IACA,gCAAgC;IAChC;IACA,+BAA+B;IAC/B;IACA,uBAAuB;IACvB;IACA;IACA;IACA,uCAAuC;IACvC;IACA,8BAA8B;IAC9B;CACD;AAEM,MAAMD,kBAAkB,IAAIE,OAAO,CAAC,IAAI,EAAED,MAAME,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/utils/url-file.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\nconst parts = [\n // IPv4 loopback (127.0.0.0/8)\n '127\\\\.(?:\\\\d{1,3}\\\\.){2}\\\\d{1,3}',\n // IPv4 link-local (169.254.0.0/16)\n '169\\\\.254\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 Carrier-grade NAT (100.64.0.0/10)\n '100\\\\.(?:6[4-9]|[7-9]\\\\d|1[01]\\\\d|12[0-7])\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 private (10.0.0.0/8)\n '10\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 private (192.168.0.0/16)\n '192\\\\.168\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 private (172.16.0.0/12)\n '172\\\\.(?:1[6-9]|2\\\\d|3[0-1])\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}',\n // IPv4 & IPv6 loopback\n '::1',\n '::',\n '0.0.0.0',\n // IPv6 Unique Local Address (fc00::/7)\n 'f[cd][0-9a-f]{2}:[0-9a-f:]+',\n // IPv6 link-local (fe80::/10)\n 'fe[89ab][0-9a-f]{2}:[0-9a-f:]+'\n]\n\nexport const regExpPrivateIP = new RegExp(`^(?:${parts.join('|')})$`, 'i')\n"],"names":["regExpPrivateIP","parts","RegExp","join"],"mappings":";;;;+BA6BaA;;;eAAAA;;;AA7Bb;;;;CAIC,GAED,MAAMC,QAAQ;IACZ,8BAA8B;IAC9B;IACA,mCAAmC;IACnC;IACA,yCAAyC;IACzC;IACA,4BAA4B;IAC5B;IACA,gCAAgC;IAChC;IACA,+BAA+B;IAC/B;IACA,uBAAuB;IACvB;IACA;IACA;IACA,uCAAuC;IACvC;IACA,8BAA8B;IAC9B;CACD;AAEM,MAAMD,kBAAkB,IAAIE,OAAO,CAAC,IAAI,EAAED,MAAME,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE"}
@@ -62,7 +62,7 @@ let LinksManager = class LinksManager {
62
62
  this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) downloading ${spaceLink.share.name}`);
63
63
  this.incrementLinkNbAccess(link);
64
64
  const spaceEnv = await this.spaceEnvFromLink(user, spaceLink);
65
- const sendFile = this.filesManager.sendFileFromSpace(spaceEnv, true, spaceLink.share.name);
65
+ const sendFile = this.filesManager.sendFileFromSpace(spaceEnv, spaceLink.share.name);
66
66
  try {
67
67
  await sendFile.checks();
68
68
  return await sendFile.stream(req, res);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/links/services/links-manager.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 { HttpException, HttpStatus, Injectable, Logger, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { LoginResponseDto } from '../../../authentication/dto/login-response.dto'\nimport { JwtIdentityPayload } from '../../../authentication/interfaces/jwt-payload.interface'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { SendFile } from '../../files/utils/send-file'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { UserPasswordDto } from '../../users/dto/user-properties.dto'\nimport { UserModel } from '../../users/models/user.model'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { getAvatarBase64 } from '../../users/utils/avatar'\nimport { LINK_ERROR } from '../constants/links'\nimport { LinkAsUser } from '../interfaces/link-guest.interface'\nimport { SpaceLink } from '../interfaces/link-space.interface'\nimport { LinksQueries } from './links-queries.service'\n\n@Injectable()\nexport class LinksManager {\n private logger = new Logger(LinksManager.name)\n\n constructor(\n private readonly authManager: AuthManager,\n private readonly usersManager: UsersManager,\n private readonly filesManager: FilesManager,\n private readonly spacesManager: SpacesManager,\n private readonly linksQueries: LinksQueries\n ) {}\n\n async linkValidation(identity: JwtIdentityPayload, uuid: string): Promise<{ ok: boolean; error: string | true; link: SpaceLink }> {\n const [_link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkValidation.name} - ${uuid} : ${check}`)\n }\n const spaceLink: SpaceLink = ok ? await this.linksQueries.spaceLink(uuid) : null\n if (spaceLink?.owner?.login) {\n spaceLink.owner.avatar = await getAvatarBase64(spaceLink.owner.login)\n // for security reasons\n delete spaceLink.owner.login\n }\n return { ok: ok, error: ok ? null : check, link: spaceLink }\n }\n\n async linkAccess(identity: JwtIdentityPayload, uuid: string, req: FastifyRequest, res: FastifyReply): Promise<StreamableFile | LoginResponseDto> {\n const [link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkAccess.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const user = new UserModel(link.user)\n const spaceLink: SpaceLink = await this.linksQueries.spaceLink(uuid)\n if (!spaceLink.space && !spaceLink.share.isDir) {\n // download the file (authentication has been verified before)\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) downloading ${spaceLink.share.name}`)\n this.incrementLinkNbAccess(link)\n const spaceEnv: SpaceEnv = await this.spaceEnvFromLink(user, spaceLink)\n const sendFile: SendFile = this.filesManager.sendFileFromSpace(spaceEnv, true, spaceLink.share.name)\n try {\n await sendFile.checks()\n return await sendFile.stream(req, res)\n } catch (e) {\n this.logger.error(`${this.linkAccess.name} - unable to send file : ${e}`)\n throw new HttpException('Unable to download file', HttpStatus.INTERNAL_SERVER_ERROR)\n }\n } else if (link.user.id !== identity.id) {\n // authenticate user to allow access to the directory\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) is logged`)\n this.incrementLinkNbAccess(link)\n this.usersManager.updateAccesses(user, req.ip, true).catch((e: Error) => this.logger.error(`${this.linkAccess.name} - ${e}`))\n return this.authManager.setCookies(user, res)\n }\n // already authenticated\n }\n\n async linkAuthentication(identity: JwtIdentityPayload, uuid: string, linkPasswordDto: UserPasswordDto, req: FastifyRequest, res: FastifyReply) {\n const [link, check, ok] = await this.linkEnv(identity, uuid, true)\n if (!ok) {\n this.logger.warn(`${this.linkAuthentication.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const authSuccess: boolean = await this.usersManager.compareUserPassword(link.user.id, linkPasswordDto.password)\n const user = new UserModel(link.user)\n this.usersManager.updateAccesses(user, req.ip, authSuccess).catch((e: Error) => this.logger.error(`${this.linkAuthentication.name} - ${e}`))\n if (!authSuccess) {\n this.logger.warn(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) : auth failed`)\n throw new HttpException(LINK_ERROR.UNAUTHORIZED, HttpStatus.FORBIDDEN)\n }\n // authenticate user to allow access\n this.logger.log(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) is logged`)\n return this.authManager.setCookies(user, res)\n }\n\n private spaceEnvFromLink(user: UserModel, link: SpaceLink): Promise<SpaceEnv> {\n return this.spacesManager.spaceEnv(user, [\n link.space ? SPACE_REPOSITORY.FILES : SPACE_REPOSITORY.SHARES,\n link.space ? link.space.alias : link.share.alias\n ])\n }\n\n private async linkEnv(identity: JwtIdentityPayload, uuid: string, ignoreAuth: boolean = false): Promise<[LinkAsUser, string | true, boolean]> {\n const link: LinkAsUser = await this.linksQueries.linkFromUUID(uuid)\n const check: string | true = this.checkLink(identity, link, ignoreAuth)\n const ok: boolean = check === true\n return [link, check, ok]\n }\n\n private checkLink(identity: JwtIdentityPayload, link: LinkAsUser, ignoreAuth: boolean = false): string | true {\n if (!link) {\n return LINK_ERROR.NOT_FOUND\n }\n if (!link.user.isActive) {\n return LINK_ERROR.DISABLED\n }\n if (link.limitAccess !== 0 && link.nbAccess >= link.limitAccess) {\n return LINK_ERROR.EXCEEDED\n }\n if (link.expiresAt && new Date() >= link.expiresAt) {\n return LINK_ERROR.EXPIRED\n }\n if (!ignoreAuth && link.requireAuth && link.user.id !== identity.id) {\n return LINK_ERROR.UNAUTHORIZED\n }\n return true\n }\n\n private incrementLinkNbAccess(link: LinkAsUser) {\n this.linksQueries.incrementLinkNbAccess(link.uuid).catch((e: Error) => this.logger.error(`${this.incrementLinkNbAccess.name} - ${e}`))\n }\n}\n"],"names":["LinksManager","linkValidation","identity","uuid","_link","check","ok","linkEnv","logger","warn","name","spaceLink","linksQueries","owner","login","avatar","getAvatarBase64","error","link","linkAccess","req","res","user","id","HttpException","HttpStatus","BAD_REQUEST","UserModel","space","share","isDir","log","incrementLinkNbAccess","spaceEnv","spaceEnvFromLink","sendFile","filesManager","sendFileFromSpace","checks","stream","e","INTERNAL_SERVER_ERROR","usersManager","updateAccesses","ip","catch","authManager","setCookies","linkAuthentication","linkPasswordDto","authSuccess","compareUserPassword","password","LINK_ERROR","UNAUTHORIZED","FORBIDDEN","spacesManager","SPACE_REPOSITORY","FILES","SHARES","alias","ignoreAuth","linkFromUUID","checkLink","NOT_FOUND","isActive","DISABLED","limitAccess","nbAccess","EXCEEDED","expiresAt","Date","EXPIRED","requireAuth","Logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/links/services/links-manager.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 { HttpException, HttpStatus, Injectable, Logger, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { LoginResponseDto } from '../../../authentication/dto/login-response.dto'\nimport { JwtIdentityPayload } from '../../../authentication/interfaces/jwt-payload.interface'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { SendFile } from '../../files/utils/send-file'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { UserPasswordDto } from '../../users/dto/user-properties.dto'\nimport { UserModel } from '../../users/models/user.model'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { getAvatarBase64 } from '../../users/utils/avatar'\nimport { LINK_ERROR } from '../constants/links'\nimport { LinkAsUser } from '../interfaces/link-guest.interface'\nimport { SpaceLink } from '../interfaces/link-space.interface'\nimport { LinksQueries } from './links-queries.service'\n\n@Injectable()\nexport class LinksManager {\n private logger = new Logger(LinksManager.name)\n\n constructor(\n private readonly authManager: AuthManager,\n private readonly usersManager: UsersManager,\n private readonly filesManager: FilesManager,\n private readonly spacesManager: SpacesManager,\n private readonly linksQueries: LinksQueries\n ) {}\n\n async linkValidation(identity: JwtIdentityPayload, uuid: string): Promise<{ ok: boolean; error: string | true; link: SpaceLink }> {\n const [_link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkValidation.name} - ${uuid} : ${check}`)\n }\n const spaceLink: SpaceLink = ok ? await this.linksQueries.spaceLink(uuid) : null\n if (spaceLink?.owner?.login) {\n spaceLink.owner.avatar = await getAvatarBase64(spaceLink.owner.login)\n // for security reasons\n delete spaceLink.owner.login\n }\n return { ok: ok, error: ok ? null : check, link: spaceLink }\n }\n\n async linkAccess(identity: JwtIdentityPayload, uuid: string, req: FastifyRequest, res: FastifyReply): Promise<StreamableFile | LoginResponseDto> {\n const [link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkAccess.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const user = new UserModel(link.user)\n const spaceLink: SpaceLink = await this.linksQueries.spaceLink(uuid)\n if (!spaceLink.space && !spaceLink.share.isDir) {\n // download the file (authentication has been verified before)\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) downloading ${spaceLink.share.name}`)\n this.incrementLinkNbAccess(link)\n const spaceEnv: SpaceEnv = await this.spaceEnvFromLink(user, spaceLink)\n const sendFile: SendFile = this.filesManager.sendFileFromSpace(spaceEnv, spaceLink.share.name)\n try {\n await sendFile.checks()\n return await sendFile.stream(req, res)\n } catch (e) {\n this.logger.error(`${this.linkAccess.name} - unable to send file : ${e}`)\n throw new HttpException('Unable to download file', HttpStatus.INTERNAL_SERVER_ERROR)\n }\n } else if (link.user.id !== identity.id) {\n // authenticate user to allow access to the directory\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) is logged`)\n this.incrementLinkNbAccess(link)\n this.usersManager.updateAccesses(user, req.ip, true).catch((e: Error) => this.logger.error(`${this.linkAccess.name} - ${e}`))\n return this.authManager.setCookies(user, res)\n }\n // already authenticated\n }\n\n async linkAuthentication(identity: JwtIdentityPayload, uuid: string, linkPasswordDto: UserPasswordDto, req: FastifyRequest, res: FastifyReply) {\n const [link, check, ok] = await this.linkEnv(identity, uuid, true)\n if (!ok) {\n this.logger.warn(`${this.linkAuthentication.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const authSuccess: boolean = await this.usersManager.compareUserPassword(link.user.id, linkPasswordDto.password)\n const user = new UserModel(link.user)\n this.usersManager.updateAccesses(user, req.ip, authSuccess).catch((e: Error) => this.logger.error(`${this.linkAuthentication.name} - ${e}`))\n if (!authSuccess) {\n this.logger.warn(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) : auth failed`)\n throw new HttpException(LINK_ERROR.UNAUTHORIZED, HttpStatus.FORBIDDEN)\n }\n // authenticate user to allow access\n this.logger.log(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) is logged`)\n return this.authManager.setCookies(user, res)\n }\n\n private spaceEnvFromLink(user: UserModel, link: SpaceLink): Promise<SpaceEnv> {\n return this.spacesManager.spaceEnv(user, [\n link.space ? SPACE_REPOSITORY.FILES : SPACE_REPOSITORY.SHARES,\n link.space ? link.space.alias : link.share.alias\n ])\n }\n\n private async linkEnv(identity: JwtIdentityPayload, uuid: string, ignoreAuth: boolean = false): Promise<[LinkAsUser, string | true, boolean]> {\n const link: LinkAsUser = await this.linksQueries.linkFromUUID(uuid)\n const check: string | true = this.checkLink(identity, link, ignoreAuth)\n const ok: boolean = check === true\n return [link, check, ok]\n }\n\n private checkLink(identity: JwtIdentityPayload, link: LinkAsUser, ignoreAuth: boolean = false): string | true {\n if (!link) {\n return LINK_ERROR.NOT_FOUND\n }\n if (!link.user.isActive) {\n return LINK_ERROR.DISABLED\n }\n if (link.limitAccess !== 0 && link.nbAccess >= link.limitAccess) {\n return LINK_ERROR.EXCEEDED\n }\n if (link.expiresAt && new Date() >= link.expiresAt) {\n return LINK_ERROR.EXPIRED\n }\n if (!ignoreAuth && link.requireAuth && link.user.id !== identity.id) {\n return LINK_ERROR.UNAUTHORIZED\n }\n return true\n }\n\n private incrementLinkNbAccess(link: LinkAsUser) {\n this.linksQueries.incrementLinkNbAccess(link.uuid).catch((e: Error) => this.logger.error(`${this.incrementLinkNbAccess.name} - ${e}`))\n }\n}\n"],"names":["LinksManager","linkValidation","identity","uuid","_link","check","ok","linkEnv","logger","warn","name","spaceLink","linksQueries","owner","login","avatar","getAvatarBase64","error","link","linkAccess","req","res","user","id","HttpException","HttpStatus","BAD_REQUEST","UserModel","space","share","isDir","log","incrementLinkNbAccess","spaceEnv","spaceEnvFromLink","sendFile","filesManager","sendFileFromSpace","checks","stream","e","INTERNAL_SERVER_ERROR","usersManager","updateAccesses","ip","catch","authManager","setCookies","linkAuthentication","linkPasswordDto","authSuccess","compareUserPassword","password","LINK_ERROR","UNAUTHORIZED","FORBIDDEN","spacesManager","SPACE_REPOSITORY","FILES","SHARES","alias","ignoreAuth","linkFromUUID","checkLink","NOT_FOUND","isActive","DISABLED","limitAccess","nbAccess","EXCEEDED","expiresAt","Date","EXPIRED","requireAuth","Logger"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/shares/interfaces/share-props.interface.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 */\nimport type { FileSpace } from '../../files/interfaces/file-space.interface'\nimport type { Member } from '../../users/interfaces/member.interface'\nimport type { Share } from '../schemas/share.interface'\n\nexport class ShareProps\n implements\n Pick<\n Share,\n | 'id'\n | 'ownerId'\n | 'name'\n | 'alias'\n | 'enabled'\n | 'description'\n | 'externalPath'\n | 'createdAt'\n | 'modifiedAt'\n | 'disabledAt'\n | 'storageUsage'\n | 'storageQuota'\n | 'storageIndexing'\n >\n{\n id: number\n ownerId: number\n alias: string\n name: string\n description: string\n enabled: boolean\n externalPath: string\n storageUsage: number\n storageQuota: number\n storageIndexing: boolean\n createdAt: Date\n modifiedAt: Date\n disabledAt: Date\n parent: Pick<Share, 'id' | 'ownerId' | 'alias' | 'name'>\n file: FileSpace\n\n // Extra properties\n members: Member[] = []\n}\n"],"names":["ShareProps","members"],"mappings":"AAAA;;;;CAIC;;;;+BAKYA;;;eAAAA;;;AAAN,IAAA,AAAMA,aAAN,MAAMA;;QAmCX,mBAAmB;aACnBC,UAAoB,EAAE;;AACxB"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/shares/interfaces/share-props.interface.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 */\nimport type { FileSpace } from '../../files/interfaces/file-space.interface'\nimport type { Member } from '../../users/interfaces/member.interface'\nimport type { Share } from '../schemas/share.interface'\n\nexport class ShareProps implements Pick<\n Share,\n | 'id'\n | 'ownerId'\n | 'name'\n | 'alias'\n | 'enabled'\n | 'description'\n | 'externalPath'\n | 'createdAt'\n | 'modifiedAt'\n | 'disabledAt'\n | 'storageUsage'\n | 'storageQuota'\n | 'storageIndexing'\n> {\n id: number\n ownerId: number\n alias: string\n name: string\n description: string\n enabled: boolean\n externalPath: string\n storageUsage: number\n storageQuota: number\n storageIndexing: boolean\n createdAt: Date\n modifiedAt: Date\n disabledAt: Date\n parent: Pick<Share, 'id' | 'ownerId' | 'alias' | 'name'>\n file: FileSpace\n\n // Extra properties\n members: Member[] = []\n}\n"],"names":["ShareProps","members"],"mappings":"AAAA;;;;CAIC;;;;+BAKYA;;;eAAAA;;;AAAN,IAAA,AAAMA,aAAN,MAAMA;;QAgCX,mBAAmB;aACnBC,UAAoB,EAAE;;AACxB"}
@@ -654,12 +654,14 @@ let SharesManager = class SharesManager {
654
654
  storageUsage: size,
655
655
  storageQuota: share.storageQuota
656
656
  };
657
- this.sharesQueries.cache.set(`${_cache.CACHE_QUOTA_SHARE_PREFIX}-${share.id}`, shareQuota, _cache.CACHE_QUOTA_TTL).catch((e)=>this.logger.error(`${this.updateSharesExternalPathQuota.name} - ${e}`));
657
+ this.sharesQueries.cache.set(`${_cache.CACHE_QUOTA_SHARE_PREFIX}-${share.id}`, shareQuota, _cache.CACHE_QUOTA_TTL).catch((e)=>this.logger.error(`${this.updateSharesExternalPathQuota.name} - share *${share.alias}* (${share.id}) : ${e}`));
658
658
  if (share.storageUsage !== shareQuota.storageUsage) {
659
- this.logger.log(`${this.updateSharesExternalPathQuota.name} - share *${share.alias}* (${share.id}) : storage usage updated : ${shareQuota.storageUsage}`);
660
- await this.sharesQueries.updateShare(share.id, {
659
+ this.sharesQueries.updateShare(share.id, {
661
660
  storageUsage: shareQuota.storageUsage
662
- });
661
+ }).then((updated)=>updated && this.logger.log(`${this.updateSharesExternalPathQuota.name} - share *${share.alias}* (${share.id}) - storage usage updated : ${shareQuota.storageUsage}`));
662
+ }
663
+ if (shareId) {
664
+ return shareQuota;
663
665
  }
664
666
  }
665
667
  }