@sync-in/server 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/CHANGELOG.md +173 -58
  2. package/environment/environment.dist.yaml +6 -3
  3. package/migrations/0003_giant_luckman.sql +6 -0
  4. package/migrations/meta/0003_snapshot.json +2463 -0
  5. package/migrations/meta/_journal.json +7 -0
  6. package/package.json +19 -17
  7. package/server/app.bootstrap.js +5 -2
  8. package/server/app.bootstrap.js.map +1 -1
  9. package/server/app.constants.js +0 -4
  10. package/server/app.constants.js.map +1 -1
  11. package/server/app.service.js +7 -6
  12. package/server/app.service.js.map +1 -1
  13. package/server/applications/files/constants/only-office.js +12 -0
  14. package/server/applications/files/constants/only-office.js.map +1 -1
  15. package/server/applications/files/files.config.js +5 -0
  16. package/server/applications/files/files.config.js.map +1 -1
  17. package/server/applications/files/files.controller.js +12 -4
  18. package/server/applications/files/files.controller.js.map +1 -1
  19. package/server/applications/files/files.controller.spec.js +18 -4
  20. package/server/applications/files/files.controller.spec.js.map +1 -1
  21. package/server/applications/files/services/files-content-manager.service.js +6 -6
  22. package/server/applications/files/services/files-content-manager.service.js.map +1 -1
  23. package/server/applications/files/services/files-manager.service.js +4 -4
  24. package/server/applications/files/services/files-manager.service.js.map +1 -1
  25. package/server/applications/files/services/files-methods.service.js +4 -7
  26. package/server/applications/files/services/files-methods.service.js.map +1 -1
  27. package/server/applications/files/services/files-only-office-manager.service.js +2 -2
  28. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  29. package/server/applications/files/services/files-parser.service.js +6 -3
  30. package/server/applications/files/services/files-parser.service.js.map +1 -1
  31. package/server/applications/files/services/files-scheduler.service.js +51 -3
  32. package/server/applications/files/services/files-scheduler.service.js.map +1 -1
  33. package/server/applications/files/services/files-search-manager.service.js +4 -0
  34. package/server/applications/files/services/files-search-manager.service.js.map +1 -1
  35. package/server/applications/files/utils/doc-textify/adapters/pdf.js +6 -8
  36. package/server/applications/files/utils/doc-textify/adapters/pdf.js.map +1 -1
  37. package/server/applications/notifications/i18n/de.js +56 -0
  38. package/server/applications/notifications/i18n/de.js.map +1 -0
  39. package/server/applications/notifications/i18n/es.js +52 -0
  40. package/server/applications/notifications/i18n/es.js.map +1 -0
  41. package/server/applications/notifications/i18n/hi.js +52 -0
  42. package/server/applications/notifications/i18n/hi.js.map +1 -0
  43. package/server/applications/notifications/i18n/index.js +73 -8
  44. package/server/applications/notifications/i18n/index.js.map +1 -1
  45. package/server/applications/notifications/i18n/it.js +52 -0
  46. package/server/applications/notifications/i18n/it.js.map +1 -0
  47. package/server/applications/notifications/i18n/ja.js +52 -0
  48. package/server/applications/notifications/i18n/ja.js.map +1 -0
  49. package/server/applications/notifications/i18n/ko.js +52 -0
  50. package/server/applications/notifications/i18n/ko.js.map +1 -0
  51. package/server/applications/notifications/i18n/pl.js +52 -0
  52. package/server/applications/notifications/i18n/pl.js.map +1 -0
  53. package/server/applications/notifications/i18n/pt.js +52 -0
  54. package/server/applications/notifications/i18n/pt.js.map +1 -0
  55. package/server/applications/notifications/i18n/pt_br.js +52 -0
  56. package/server/applications/notifications/i18n/pt_br.js.map +1 -0
  57. package/server/applications/notifications/i18n/ru.js +52 -0
  58. package/server/applications/notifications/i18n/ru.js.map +1 -0
  59. package/server/applications/notifications/i18n/tr.js +52 -0
  60. package/server/applications/notifications/i18n/tr.js.map +1 -0
  61. package/server/applications/notifications/i18n/zh.js +52 -0
  62. package/server/applications/notifications/i18n/zh.js.map +1 -0
  63. package/server/applications/notifications/mails/models.js +6 -7
  64. package/server/applications/notifications/mails/models.js.map +1 -1
  65. package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
  66. package/server/applications/shares/dto/create-or-update-share.dto.js +11 -0
  67. package/server/applications/shares/dto/create-or-update-share.dto.js.map +1 -1
  68. package/server/applications/shares/interfaces/share-props.interface.js.map +1 -1
  69. package/server/applications/shares/schemas/share.interface.js.map +1 -1
  70. package/server/applications/shares/schemas/shares.schema.js +9 -0
  71. package/server/applications/shares/schemas/shares.schema.js.map +1 -1
  72. package/server/applications/shares/services/shares-manager.service.js +46 -17
  73. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  74. package/server/applications/shares/services/shares-queries.service.js +24 -5
  75. package/server/applications/shares/services/shares-queries.service.js.map +1 -1
  76. package/server/applications/spaces/constants/cache.js +4 -0
  77. package/server/applications/spaces/constants/cache.js.map +1 -1
  78. package/server/applications/spaces/dto/create-or-update-space.dto.js +5 -0
  79. package/server/applications/spaces/dto/create-or-update-space.dto.js.map +1 -1
  80. package/server/applications/spaces/guards/space.guard.js +3 -3
  81. package/server/applications/spaces/guards/space.guard.js.map +1 -1
  82. package/server/applications/spaces/models/space-props.model.js.map +1 -1
  83. package/server/applications/spaces/models/space.model.js.map +1 -1
  84. package/server/applications/spaces/schemas/space.interface.js.map +1 -1
  85. package/server/applications/spaces/schemas/spaces.schema.js +1 -0
  86. package/server/applications/spaces/schemas/spaces.schema.js.map +1 -1
  87. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  88. package/server/applications/spaces/services/spaces-manager.service.js +34 -31
  89. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  90. package/server/applications/spaces/services/spaces-queries.service.js +23 -7
  91. package/server/applications/spaces/services/spaces-queries.service.js.map +1 -1
  92. package/server/applications/spaces/services/spaces-scheduler.service.js +21 -20
  93. package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
  94. package/server/applications/spaces/spaces.controller.js +4 -2
  95. package/server/applications/spaces/spaces.controller.js.map +1 -1
  96. package/server/applications/spaces/utils/paths.js +14 -16
  97. package/server/applications/spaces/utils/paths.js.map +1 -1
  98. package/server/applications/sync/services/sync-manager.service.js +4 -3
  99. package/server/applications/sync/services/sync-manager.service.js.map +1 -1
  100. package/server/applications/sync/services/sync-paths-manager.service.js +1 -1
  101. package/server/applications/sync/services/sync-paths-manager.service.js.map +1 -1
  102. package/server/applications/sync/services/sync-paths-manager.service.spec.js +1 -1
  103. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  104. package/server/applications/sync/sync.controller.js +2 -1
  105. package/server/applications/sync/sync.controller.js.map +1 -1
  106. package/server/applications/users/constants/routes.js +5 -0
  107. package/server/applications/users/constants/routes.js.map +1 -1
  108. package/server/applications/users/constants/user.js +0 -16
  109. package/server/applications/users/constants/user.js.map +1 -1
  110. package/server/applications/users/dto/user-properties.dto.js +10 -0
  111. package/server/applications/users/dto/user-properties.dto.js.map +1 -1
  112. package/server/applications/users/models/user.model.js.map +1 -1
  113. package/server/applications/users/schemas/user.interface.js.map +1 -1
  114. package/server/applications/users/schemas/users.schema.js +3 -2
  115. package/server/applications/users/schemas/users.schema.js.map +1 -1
  116. package/server/applications/users/services/admin-users-manager.service.js +1 -0
  117. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  118. package/server/applications/users/services/admin-users-manager.service.spec.js +2 -1
  119. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  120. package/server/applications/users/services/users-manager.service.js +7 -2
  121. package/server/applications/users/services/users-manager.service.js.map +1 -1
  122. package/server/applications/users/services/users-manager.service.spec.js +1 -0
  123. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  124. package/server/applications/users/services/users-queries.service.js +18 -4
  125. package/server/applications/users/services/users-queries.service.js.map +1 -1
  126. package/server/applications/users/users.controller.js +15 -0
  127. package/server/applications/users/users.controller.js.map +1 -1
  128. package/server/applications/users/users.gateway.js +6 -0
  129. package/server/applications/users/users.gateway.js.map +1 -1
  130. package/server/applications/users/utils/test.js +2 -2
  131. package/server/applications/users/utils/test.js.map +1 -1
  132. package/server/applications/webdav/constants/routes.js +2 -2
  133. package/server/applications/webdav/constants/routes.js.map +1 -1
  134. package/server/applications/webdav/constants/webdav.js +2 -2
  135. package/server/applications/webdav/constants/webdav.js.map +1 -1
  136. package/server/applications/webdav/filters/webdav.filter.js +2 -2
  137. package/server/applications/webdav/filters/webdav.filter.js.map +1 -1
  138. package/server/applications/webdav/filters/webdav.filter.spec.js +2 -2
  139. package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -1
  140. package/server/applications/webdav/services/webdav-methods.service.js +3 -2
  141. package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
  142. package/server/applications/webdav/utils/webdav.js +1 -2
  143. package/server/applications/webdav/utils/webdav.js.map +1 -1
  144. package/server/authentication/auth.config.js +2 -2
  145. package/server/authentication/auth.config.js.map +1 -1
  146. package/server/authentication/guards/auth-basic.strategy.js +2 -2
  147. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  148. package/server/common/i18n.js +52 -0
  149. package/server/common/i18n.js.map +1 -0
  150. package/server/common/image.js +63 -43
  151. package/server/common/image.js.map +1 -1
  152. package/server/common/interfaces.js.map +1 -1
  153. package/server/common/shared.js +5 -2
  154. package/server/common/shared.js.map +1 -1
  155. package/server/configuration/config.validation.js +3 -3
  156. package/server/configuration/config.validation.js.map +1 -1
  157. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +8 -6
  158. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
  159. package/server/infrastructure/cache/adapters/redis-cache.adapter.js +22 -17
  160. package/server/infrastructure/cache/adapters/redis-cache.adapter.js.map +1 -1
  161. package/server/infrastructure/cache/cache.e2e-spec.js +1 -0
  162. package/server/infrastructure/cache/cache.e2e-spec.js.map +1 -1
  163. package/server/infrastructure/cache/cache.module.js +1 -14
  164. package/server/infrastructure/cache/cache.module.js.map +1 -1
  165. package/server/infrastructure/cache/services/cache.service.js.map +1 -1
  166. package/server/infrastructure/database/database.module.js +20 -1
  167. package/server/infrastructure/database/database.module.js.map +1 -1
  168. package/server/infrastructure/database/utils.js +48 -0
  169. package/server/infrastructure/database/utils.js.map +1 -1
  170. package/server/infrastructure/scheduler/scheduler.module.js +1 -1
  171. package/server/infrastructure/scheduler/scheduler.module.js.map +1 -1
  172. package/server/infrastructure/websocket/adapters/cluster.adapter.js +1 -3
  173. package/server/infrastructure/websocket/adapters/cluster.adapter.js.map +1 -1
  174. package/static/3rdpartylicenses.txt +137 -163
  175. package/static/chunk-2KLC4T2Z.js +1 -0
  176. package/static/chunk-2VMSXRCB.js +12 -0
  177. package/static/chunk-3GMLWAFZ.js +1 -0
  178. package/static/chunk-3OHSRRKH.js +4 -0
  179. package/static/chunk-3R4WKOHQ.js +1 -0
  180. package/static/{chunk-7ITZXYYJ.js → chunk-3R74L4UU.js} +1 -1
  181. package/static/chunk-3XVM35O2.js +1 -0
  182. package/static/chunk-3YVRP3VM.js +2 -0
  183. package/static/chunk-5NMSIIQB.js +1 -0
  184. package/static/chunk-5UKZLU5H.js +1 -0
  185. package/static/chunk-AF24EYXU.js +1 -0
  186. package/static/chunk-AKQVEHO6.js +2 -0
  187. package/static/chunk-BCVX464U.js +2 -0
  188. package/static/chunk-BQV4FRM6.js +1 -0
  189. package/static/{chunk-EVIE5F2U.js → chunk-CETH7UYS.js} +1 -1
  190. package/static/chunk-CHJ64RJM.js +1 -0
  191. package/static/chunk-DIT6W7VM.js +562 -0
  192. package/static/chunk-DKSEQTMX.js +1 -0
  193. package/static/chunk-DM4NXKEP.js +1 -0
  194. package/static/chunk-DPUVSXRB.js +1 -0
  195. package/static/chunk-DSWEWLXJ.js +1 -0
  196. package/static/chunk-FJE6BOFL.js +1 -0
  197. package/static/chunk-FZ3JPGYZ.js +1 -0
  198. package/static/chunk-IQSKQXC3.js +1 -0
  199. package/static/chunk-ITUFI2BJ.js +1 -0
  200. package/static/chunk-JPT5WEAT.js +1 -0
  201. package/static/chunk-LCTZJ537.js +1 -0
  202. package/static/chunk-LK2UCQJ6.js +1 -0
  203. package/static/chunk-LNTUR3GU.js +1 -0
  204. package/static/chunk-LP5TBXEN.js +7 -0
  205. package/static/{chunk-IPAC4VAF.js → chunk-LVSNIS5P.js} +1 -1
  206. package/static/{chunk-SIPE37PA.js → chunk-MTVSJTIW.js} +1 -1
  207. package/static/chunk-N3U6637P.js +1 -0
  208. package/static/chunk-NNV4OXSB.js +1 -0
  209. package/static/chunk-O6FYXVHI.js +1 -0
  210. package/static/chunk-OOGP4WSH.js +2 -0
  211. package/static/chunk-PB4AIT7O.js +1 -0
  212. package/static/chunk-PCWDQPOM.js +2 -0
  213. package/static/chunk-PNR6M34W.js +1 -0
  214. package/static/chunk-PVDHBQRM.js +1 -0
  215. package/static/chunk-Q5KM7LTX.js +1 -0
  216. package/static/chunk-QHC6ZPQ4.js +1 -0
  217. package/static/chunk-QMRBZHE4.js +1 -0
  218. package/static/chunk-QO6BTONN.js +1 -0
  219. package/static/chunk-QSJRY3TF.js +1 -0
  220. package/static/chunk-QUUIRSYT.js +1 -0
  221. package/static/chunk-RFH46UW3.js +1 -0
  222. package/static/{chunk-PTGDOWV3.js → chunk-RSXHRKM5.js} +1 -1
  223. package/static/chunk-RV3VZJPZ.js +1 -0
  224. package/static/{chunk-QNJFQVYI.js → chunk-S7HNXVRB.js} +1 -1
  225. package/static/chunk-SBZ572Q4.js +2 -0
  226. package/static/chunk-SJR5R3Y4.js +1 -0
  227. package/static/chunk-SLHTEGRU.js +1 -0
  228. package/static/{chunk-SH5EVL4E.js → chunk-SSFF27P2.js} +1 -1
  229. package/static/chunk-UNCPXHHT.js +1 -0
  230. package/static/chunk-URHTCJ7G.js +1 -0
  231. package/static/chunk-V3LHHZYN.js +1 -0
  232. package/static/{chunk-DJYJ66UF.js → chunk-VJTXJ43D.js} +1 -1
  233. package/static/chunk-VQQKMY2C.js +1 -0
  234. package/static/{chunk-IQOALFYU.js → chunk-WSSU2HXE.js} +1 -1
  235. package/static/chunk-XDZGW64M.js +3 -0
  236. package/static/chunk-XTRDKGKG.js +1 -0
  237. package/static/chunk-YLWTEC3X.js +1 -0
  238. package/static/chunk-Z5J5F5SX.js +1 -0
  239. package/static/chunk-ZIJQRARU.js +1 -0
  240. package/static/index.html +2 -2
  241. package/static/main-4H5BJY3J.js +9 -0
  242. package/static/scripts-WRDOQIU5.js +24 -0
  243. package/static/{styles-A5VYX3CE.css → styles-2C2UNCNB.css} +1 -1
  244. package/server/applications/spaces/interfaces/space-quota.interface.js +0 -10
  245. package/server/applications/spaces/interfaces/space-quota.interface.js.map +0 -1
  246. package/static/chunk-22EANI6R.js +0 -1
  247. package/static/chunk-3GFGJYMK.js +0 -1
  248. package/static/chunk-4YGJGZZZ.js +0 -1
  249. package/static/chunk-5K7HEX3C.js +0 -27
  250. package/static/chunk-5KLMS6A4.js +0 -1
  251. package/static/chunk-ATP3BFHV.js +0 -562
  252. package/static/chunk-BB4G55KE.js +0 -1
  253. package/static/chunk-EWKSX76T.js +0 -1
  254. package/static/chunk-FHLACA7V.js +0 -1
  255. package/static/chunk-GCATNU55.js +0 -1
  256. package/static/chunk-GYODPCIE.js +0 -1
  257. package/static/chunk-HZTFYLM5.js +0 -1
  258. package/static/chunk-JSUKJT6Z.js +0 -1
  259. package/static/chunk-JXZCNFW7.js +0 -1
  260. package/static/chunk-LTGFCQR7.js +0 -1
  261. package/static/chunk-LV3PYKWO.js +0 -1
  262. package/static/chunk-N2WFNW6M.js +0 -7
  263. package/static/chunk-ORMRCEGT.js +0 -1
  264. package/static/chunk-OUTBJSMW.js +0 -1
  265. package/static/chunk-RS2PX32L.js +0 -1
  266. package/static/chunk-RSSWH3S2.js +0 -1
  267. package/static/chunk-RTRJ3KFH.js +0 -1
  268. package/static/chunk-TKTCBDOG.js +0 -1
  269. package/static/chunk-V6K2N46L.js +0 -1
  270. package/static/chunk-XLCCZSQL.js +0 -4
  271. package/static/chunk-YPEH66GG.js +0 -1
  272. package/static/chunk-YPOIUQ57.js +0 -1
  273. package/static/chunk-ZKCFO2OA.js +0 -4
  274. package/static/main-MZ7HWZXO.js +0 -9
  275. package/static/scripts-VZVAP2P4.js +0 -30
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/spaces/utils/paths.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 { HttpStatus } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport path from 'node:path'\nimport { FileDBProps } from '../../files/interfaces/file-db-props.interface'\nimport { FileProps } from '../../files/interfaces/file-props.interface'\nimport { FileError } from '../../files/models/file-error'\nimport { UserModel } from '../../users/models/user.model'\nimport { CACHE_QUOTA_SPACE_PREFIX, CACHE_QUOTA_USER_PREFIX } from '../constants/cache'\nimport { SPACE_REPOSITORY } from '../constants/spaces'\nimport { SpaceEnv } from '../models/space-env.model'\nimport { SpaceModel } from '../models/space.model'\n\nexport async function IsRealPathIsDirAndExists(rPath: string) {\n try {\n const stats = await fs.stat(rPath)\n if (!stats.isDirectory()) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Location is not a directory')\n }\n } catch (e) {\n if (e instanceof FileError) {\n throw new FileError(e.httpCode, e.message)\n }\n if (e.code === 'ENOENT') {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n throw new FileError(HttpStatus.BAD_REQUEST, e.message)\n }\n}\n\nexport function realPathFromSpace(user: UserModel, space: SpaceEnv, withBasePath: true): string[]\nexport function realPathFromSpace(user: UserModel, space: SpaceEnv, withBasePath?: false): string\nexport function realPathFromSpace(user: UserModel, space: SpaceEnv, withBasePath: boolean = false): string | string[] {\n let bPath: string\n let fPath: string[]\n if (space.inPersonalSpace) {\n // personal user space (ignore root alias)\n bPath = UserModel.getRepositoryPath(user.login, space.inTrashRepository)\n fPath = space.paths\n } else if (space.root?.externalPath) {\n // external path from space or share\n bPath = space.root.externalPath\n if (space.inSharesRepository && space.root.file?.path) {\n // child share with an external path and file.id\n fPath = [...space.root.file.path.split('/'), ...space.paths]\n } else {\n fPath = space.paths\n }\n } else if (space.root.file?.path && space.root.owner?.login) {\n // space root linked to a file in a personal space\n bPath = path.join(UserModel.getRepositoryPath(space.root.owner.login, space.root.file.inTrash), space.root.file.path)\n fPath = space.paths\n } else if (space.root.file?.space?.id) {\n // share case\n if (space.root.file.root?.id) {\n // share linked to a file in a root space with an external path or directly to the root space\n bPath = path.join(space.root.file.root.externalPath, space.root.file.path || '')\n } else {\n // share linked to a file in a space\n bPath = path.join(SpaceModel.getRepositoryPath(space.root.file.space.alias, space.root.file.inTrash), space.root.file.path || '')\n }\n fPath = space.paths\n } else if (space.alias) {\n // space files (no root)\n bPath = SpaceModel.getRepositoryPath(space.alias, space.inTrashRepository)\n fPath = [space.root.alias, ...space.paths]\n } else {\n throw new FileError(HttpStatus.NOT_FOUND, 'Space root not found')\n }\n const rPath = path.resolve(bPath, ...fPath)\n // prevent path traversal\n if (!rPath.startsWith(bPath)) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Location is not allowed')\n }\n return withBasePath ? [bPath, rPath] : rPath\n}\n\nexport function realTrashPathFromSpace(user: UserModel, space: SpaceEnv) {\n if (space.inPersonalSpace) {\n // personal user space\n return UserModel.getTrashPath(user.login)\n } else if (space.root?.externalPath) {\n // external path from space or share\n if (space.root.file?.space?.alias) {\n // space case\n return SpaceModel.getTrashPath(space.root.file.space.alias)\n }\n // share case\n // todo: store the deleted files in the same path with .trash ?\n return null\n } else if (space.root?.file?.path && space.root.owner?.login) {\n // space root is linked to a file in a personal space\n return UserModel.getTrashPath(space.root.owner.login)\n } else if (space.root?.file?.space?.id) {\n // share linked to a space (with an external path or not)\n return SpaceModel.getTrashPath(space.root.file.space.alias)\n } else if (space.alias) {\n // space files (no root)\n return SpaceModel.getTrashPath(space.alias)\n } else {\n return null\n }\n}\n\nexport function realPathFromRootFile(f: FileProps): string {\n // get realpath\n if (f.origin) {\n // share case (the order of the tests is important)\n if (f.origin.ownerLogin) {\n return path.join(UserModel.getRepositoryPath(f.origin.ownerLogin, f.inTrash), f.path)\n } else if (f.root.externalPath) {\n // in case of share child from a share with external path, child share should have an external path and a fileId (file path)\n return path.join(f.root.externalPath, f.path || '')\n } else if (f.origin.spaceRootExternalPath) {\n return path.join(f.origin.spaceRootExternalPath, f.path)\n } else if (f.origin.spaceAlias) {\n return path.join(SpaceModel.getRepositoryPath(f.origin.spaceAlias, f.inTrash), f.path)\n }\n } else {\n // space case\n if (f.root.owner.login) {\n return path.join(UserModel.getRepositoryPath(f.root.owner.login, f.inTrash), f.path)\n } else if (f.root.externalPath) {\n return f.root.externalPath\n }\n }\n return undefined\n}\n\nexport function dbFileFromSpace(userId: number, space: SpaceEnv): FileDBProps {\n const dbFile: FileDBProps = {} as any\n dbFile.inTrash = space.repository === SPACE_REPOSITORY.TRASH\n if (space.inPersonalSpace) {\n // personal user space (ignore root alias)\n dbFile.ownerId = userId\n dbFile.path = path.join(...space.paths)\n dbFile.inTrash = space.inTrashRepository\n } else if (space.root?.externalPath) {\n // external path from space or share\n dbFile.spaceId = space.inSharesRepository ? null : space.id\n dbFile.spaceExternalRootId = space.inSharesRepository ? null : space.root.id\n if (space.inSharesRepository) {\n // in this case space.id is the share.id\n // if the `externalParentShareId` property is defined, it's an external child share that must use the parent id\n dbFile.shareExternalId = space.root?.externalParentShareId ? space.root.externalParentShareId : space.id\n } else {\n dbFile.shareExternalId = null\n }\n if (space.inSharesRepository && space.root.file?.path) {\n // child share with an external path and file.id\n dbFile.path = path.join(space.root.file.path, ...space.paths)\n } else {\n dbFile.path = path.join(...space.paths)\n }\n } else if (space.root.file?.path && space.root.owner?.login) {\n // space root linked to a file in a personal space\n dbFile.ownerId = space.root.owner.id\n dbFile.inTrash = space.root.file.inTrash\n dbFile.path = path.join(space.root.file.path, ...space.paths)\n } else if (space.root.file?.space?.id) {\n // share linked to a file in a space file or an external space root\n dbFile.spaceId = space.root.file.space.id\n dbFile.spaceExternalRootId = space.root.file.root?.id || null\n dbFile.shareExternalId = null\n if (space.root.file.id) {\n dbFile.inTrash = space.root.file.inTrash\n }\n dbFile.path = path.join(space.root.file.path || '', ...space.paths)\n } else if (space.id) {\n // space files (no root)\n dbFile.spaceId = space.id\n dbFile.spaceExternalRootId = null\n dbFile.path = path.join(space.root.alias, ...space.paths)\n dbFile.inTrash = space.inTrashRepository\n } else {\n throw new FileError(HttpStatus.NOT_FOUND, 'Space root not found')\n }\n return dbFile\n}\n\nexport function quotaKeyFromSpace(userId: number, space: SpaceEnv) {\n if (space.inPersonalSpace) {\n // personal user space\n return `${CACHE_QUOTA_USER_PREFIX}-${userId}`\n } else if (space.root?.externalPath) {\n // external paths are managed by admin, set a quota on a root is not intended\n return null\n } else if (space.root.file?.path && space.root.owner?.login) {\n // space root is linked on a user file\n return `${CACHE_QUOTA_USER_PREFIX}-${space.root.owner.id}`\n } else if (space.root.file?.space?.id) {\n if (space.root.file.root?.id) {\n // share linked to a root space with an external path, set a quota on a root is not intended\n return null\n } else {\n return `${CACHE_QUOTA_SPACE_PREFIX}-${space.root.file.space.id}`\n }\n } else if (space.id) {\n return `${CACHE_QUOTA_SPACE_PREFIX}-${space.id}`\n } else {\n throw new FileError(HttpStatus.NOT_FOUND, 'Space root not found')\n }\n}\n"],"names":["IsRealPathIsDirAndExists","dbFileFromSpace","quotaKeyFromSpace","realPathFromRootFile","realPathFromSpace","realTrashPathFromSpace","rPath","stats","fs","stat","isDirectory","FileError","HttpStatus","BAD_REQUEST","e","httpCode","message","code","NOT_FOUND","user","space","withBasePath","bPath","fPath","inPersonalSpace","UserModel","getRepositoryPath","login","inTrashRepository","paths","root","externalPath","inSharesRepository","file","path","split","owner","join","inTrash","id","SpaceModel","alias","resolve","startsWith","FORBIDDEN","getTrashPath","f","origin","ownerLogin","spaceRootExternalPath","spaceAlias","undefined","userId","dbFile","repository","SPACE_REPOSITORY","TRASH","ownerId","spaceId","spaceExternalRootId","shareExternalId","externalParentShareId","CACHE_QUOTA_USER_PREFIX","CACHE_QUOTA_SPACE_PREFIX"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/spaces/utils/paths.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 { HttpStatus } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport path from 'node:path'\nimport { FileDBProps } from '../../files/interfaces/file-db-props.interface'\nimport { FileProps } from '../../files/interfaces/file-props.interface'\nimport { FileError } from '../../files/models/file-error'\nimport { UserModel } from '../../users/models/user.model'\nimport { CACHE_QUOTA_SHARE_PREFIX, CACHE_QUOTA_SPACE_PREFIX, CACHE_QUOTA_USER_PREFIX } from '../constants/cache'\nimport { SPACE_REPOSITORY } from '../constants/spaces'\nimport { SpaceEnv } from '../models/space-env.model'\nimport { SpaceModel } from '../models/space.model'\n\nexport async function IsRealPathIsDirAndExists(rPath: string) {\n try {\n const stats = await fs.stat(rPath)\n if (!stats.isDirectory()) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Location is not a directory')\n }\n } catch (e) {\n if (e instanceof FileError) {\n throw new FileError(e.httpCode, e.message)\n }\n if (e.code === 'ENOENT') {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n throw new FileError(HttpStatus.BAD_REQUEST, e.message)\n }\n}\n\nexport function realPathFromSpace(user: UserModel, space: SpaceEnv, withBasePath: true): string[]\nexport function realPathFromSpace(user: UserModel, space: SpaceEnv, withBasePath?: false): string\nexport function realPathFromSpace(user: UserModel, space: SpaceEnv, withBasePath: boolean = false): string | string[] {\n let bPath: string\n let fPath: string[]\n if (space.inPersonalSpace) {\n // personal user space (ignore root alias)\n bPath = UserModel.getRepositoryPath(user.login, space.inTrashRepository)\n fPath = space.paths\n } else if (space.root?.externalPath) {\n // external path from space or share\n bPath = space.root.externalPath\n if (space.inSharesRepository && space.root.file?.path) {\n // child share with an external path and file.id\n fPath = [...space.root.file.path.split('/'), ...space.paths]\n } else {\n fPath = space.paths\n }\n } else if (space.root.file?.path && space.root.owner?.login) {\n // space root linked to a file in a personal space\n bPath = path.join(UserModel.getRepositoryPath(space.root.owner.login, space.root.file.inTrash), space.root.file.path)\n fPath = space.paths\n } else if (space.root.file?.space?.id) {\n // share case\n if (space.root.file.root?.id) {\n // share linked to a file in a root space with an external path or directly to the root space\n bPath = path.join(space.root.file.root.externalPath, space.root.file.path || '')\n } else {\n // share linked to a file in a space\n bPath = path.join(SpaceModel.getRepositoryPath(space.root.file.space.alias, space.root.file.inTrash), space.root.file.path || '')\n }\n fPath = space.paths\n } else if (space.alias) {\n // space files (no root)\n bPath = SpaceModel.getRepositoryPath(space.alias, space.inTrashRepository)\n fPath = [space.root.alias, ...space.paths]\n } else {\n throw new FileError(HttpStatus.NOT_FOUND, 'Space root not found')\n }\n const rPath = path.resolve(bPath, ...fPath)\n // prevent path traversal\n if (!rPath.startsWith(bPath)) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Location is not allowed')\n }\n return withBasePath ? [bPath, rPath] : rPath\n}\n\nexport function realTrashPathFromSpace(user: UserModel, space: SpaceEnv) {\n if (space.inPersonalSpace) {\n // personal user space\n return UserModel.getTrashPath(user.login)\n } else if (space.root?.externalPath) {\n // external path from space or share\n // space case: use the space trash\n if (space.root.file?.space?.alias) {\n return SpaceModel.getTrashPath(space.root.file.space.alias)\n } else if (space.inFilesRepository && !space.inSharesRepository) {\n return SpaceModel.getTrashPath(space.alias)\n }\n // share case: use the user's trash because this type of share has no owner\n return UserModel.getTrashPath(user.login)\n } else if (space.root?.file?.path && space.root.owner?.login) {\n // space root is linked to a file in a personal space\n return UserModel.getTrashPath(space.root.owner.login)\n } else if (space.root?.file?.space?.id) {\n // share linked to a space (with an external path or not)\n return SpaceModel.getTrashPath(space.root.file.space.alias)\n } else if (space.alias) {\n // space files (no root)\n return SpaceModel.getTrashPath(space.alias)\n }\n return null\n}\n\nexport function realPathFromRootFile(f: FileProps): string {\n // get realpath\n if (f.origin) {\n // share case (the order of the tests is important)\n if (f.origin.ownerLogin) {\n return path.join(UserModel.getRepositoryPath(f.origin.ownerLogin, f.inTrash), f.path)\n } else if (f.root.externalPath) {\n // in case of share child from a share with external path, child share should have an external path and a fileId (file path)\n return path.join(f.root.externalPath, f.path || '')\n } else if (f.origin.spaceRootExternalPath) {\n return path.join(f.origin.spaceRootExternalPath, f.path)\n } else if (f.origin.spaceAlias) {\n return path.join(SpaceModel.getRepositoryPath(f.origin.spaceAlias, f.inTrash), f.path)\n }\n } else {\n // space case\n if (f.root.owner.login) {\n return path.join(UserModel.getRepositoryPath(f.root.owner.login, f.inTrash), f.path)\n } else if (f.root.externalPath) {\n return f.root.externalPath\n }\n }\n return undefined\n}\n\nexport function dbFileFromSpace(userId: number, space: SpaceEnv): FileDBProps {\n const dbFile: FileDBProps = {} as any\n dbFile.inTrash = space.repository === SPACE_REPOSITORY.TRASH\n if (space.inPersonalSpace) {\n // personal user space (ignore root alias)\n dbFile.ownerId = userId\n dbFile.path = path.join(...space.paths)\n dbFile.inTrash = space.inTrashRepository\n } else if (space.root?.externalPath) {\n // external path from space or share\n dbFile.spaceId = space.inSharesRepository ? null : space.id\n dbFile.spaceExternalRootId = space.inSharesRepository ? null : space.root.id\n if (space.inSharesRepository) {\n // in this case space.id is the share.id\n // if the `externalParentShareId` property is defined, it's an external child share that must use the parent id\n dbFile.shareExternalId = space.root?.externalParentShareId ? space.root.externalParentShareId : space.id\n } else {\n dbFile.shareExternalId = null\n }\n if (space.inSharesRepository && space.root.file?.path) {\n // child share with an external path and file.id\n dbFile.path = path.join(space.root.file.path, ...space.paths)\n } else {\n dbFile.path = path.join(...space.paths)\n }\n } else if (space.root.file?.path && space.root.owner?.login) {\n // space root linked to a file in a personal space\n dbFile.ownerId = space.root.owner.id\n dbFile.inTrash = space.root.file.inTrash\n dbFile.path = path.join(space.root.file.path, ...space.paths)\n } else if (space.root.file?.space?.id) {\n // share linked to a file in a space file or an external space root\n dbFile.spaceId = space.root.file.space.id\n dbFile.spaceExternalRootId = space.root.file.root?.id || null\n dbFile.shareExternalId = null\n if (space.root.file.id) {\n dbFile.inTrash = space.root.file.inTrash\n }\n dbFile.path = path.join(space.root.file.path || '', ...space.paths)\n } else if (space.id) {\n // space files (no root)\n dbFile.spaceId = space.id\n dbFile.spaceExternalRootId = null\n dbFile.path = path.join(space.root.alias, ...space.paths)\n dbFile.inTrash = space.inTrashRepository\n } else {\n throw new FileError(HttpStatus.NOT_FOUND, 'Space root not found')\n }\n return dbFile\n}\n\nexport function quotaKeyFromSpace(userId: number, space: SpaceEnv) {\n if (space.inPersonalSpace) {\n // Personal user space\n return `${CACHE_QUOTA_USER_PREFIX}-${userId}`\n } else if (space.root?.externalPath) {\n // External paths used as shares or as space roots share the same quota as their origin\n if (space.inSharesRepository) {\n return `${CACHE_QUOTA_SHARE_PREFIX}-${space.root?.externalParentShareId || space.id}`\n }\n return `${CACHE_QUOTA_SPACE_PREFIX}-${space.id}`\n } else if (space.root.file?.path && space.root.owner?.login) {\n // Space root is linked on a user file\n return `${CACHE_QUOTA_USER_PREFIX}-${space.root.owner.id}`\n } else if (space.root.file?.space?.id) {\n return `${CACHE_QUOTA_SPACE_PREFIX}-${space.root.file.space.id}`\n } else if (space.id) {\n return `${CACHE_QUOTA_SPACE_PREFIX}-${space.id}`\n } else {\n throw new FileError(HttpStatus.NOT_FOUND, 'Space root not found')\n }\n}\n"],"names":["IsRealPathIsDirAndExists","dbFileFromSpace","quotaKeyFromSpace","realPathFromRootFile","realPathFromSpace","realTrashPathFromSpace","rPath","stats","fs","stat","isDirectory","FileError","HttpStatus","BAD_REQUEST","e","httpCode","message","code","NOT_FOUND","user","space","withBasePath","bPath","fPath","inPersonalSpace","UserModel","getRepositoryPath","login","inTrashRepository","paths","root","externalPath","inSharesRepository","file","path","split","owner","join","inTrash","id","SpaceModel","alias","resolve","startsWith","FORBIDDEN","getTrashPath","inFilesRepository","f","origin","ownerLogin","spaceRootExternalPath","spaceAlias","undefined","userId","dbFile","repository","SPACE_REPOSITORY","TRASH","ownerId","spaceId","spaceExternalRootId","shareExternalId","externalParentShareId","CACHE_QUOTA_USER_PREFIX","CACHE_QUOTA_SHARE_PREFIX","CACHE_QUOTA_SPACE_PREFIX"],"mappings":"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"}
@@ -149,7 +149,7 @@ let SyncManager = class SyncManager {
149
149
  throw new _common.HttpException('Space not found', _common.HttpStatus.NOT_FOUND);
150
150
  }
151
151
  if (space.quotaIsExceeded) {
152
- throw new _common.HttpException('Space quota is exceeded', _common.HttpStatus.INSUFFICIENT_STORAGE);
152
+ throw new _common.HttpException('Storage quota exceeded', _common.HttpStatus.INSUFFICIENT_STORAGE);
153
153
  }
154
154
  if (!await (0, _files.isPathExists)(space.realPath)) {
155
155
  throw new _common.HttpException(`Remote path not found : ${syncPathSettings.remotePath}`, _common.HttpStatus.NOT_FOUND);
@@ -272,12 +272,13 @@ let SyncManager = class SyncManager {
272
272
  }
273
273
  handleError(space, action, e, dstSpace) {
274
274
  this.logger.error(`unable to ${action} ${space.url}${dstSpace?.url ? ` -> ${dstSpace.url}` : ''} : ${e}`);
275
+ const errorMsg = e.message.split(',')[0];
275
276
  if (e instanceof _filelockerror.LockConflict) {
276
277
  throw new _common.HttpException('The file is locked', _common.HttpStatus.LOCKED);
277
278
  } else if (e instanceof _fileerror.FileError) {
278
- throw new _common.HttpException(e.message, e.httpCode);
279
+ throw new _common.HttpException(errorMsg, e.httpCode);
279
280
  }
280
- throw new _common.HttpException(e.message, _common.HttpStatus.INTERNAL_SERVER_ERROR);
281
+ throw new _common.HttpException(errorMsg, _common.HttpStatus.INTERNAL_SERVER_ERROR);
281
282
  }
282
283
  constructor(spacesManager, filesManager, syncQueries){
283
284
  this.spacesManager = spacesManager;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/sync/services/sync-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 fs from 'fs/promises'\nimport { Dirent, Stats } from 'node:fs'\nimport path from 'node:path'\nimport { regExpPathPattern } from '../../../common/functions'\nimport { FILE_OPERATION } from '../../files/constants/operations'\nimport { FileError } from '../../files/models/file-error'\nimport { LockConflict } from '../../files/models/file-lock-error'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { checksumFile, isPathExists, isPathIsDir, removeFiles, touchFile } from '../../files/utils/files'\nimport { SendFile } from '../../files/utils/send-file'\nimport { ParseDiffContext } from '../../spaces/interfaces/space-diff.interface'\nimport { FastifySpaceRequest } from '../../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { F_SPECIAL_STAT, F_STAT, SYNC_CHECKSUM_ALG, SYNC_DIFF_DONE } from '../constants/sync'\nimport { SyncCopyMoveDto, SyncDiffDto, SyncMakeDto, SyncPropsDto } from '../dtos/sync-operations.dto'\nimport { SyncUploadDto } from '../dtos/sync-upload.dto'\nimport { SyncFileSpecialStats, SyncFileStats } from '../interfaces/sync-diff.interface'\nimport { SyncPathSettings } from '../interfaces/sync-path.interface'\nimport { getTmpFilePath } from '../utils/functions'\nimport { SYNC_PATH_TO_SPACE_SEGMENTS } from '../utils/routes'\nimport { SyncQueries } from './sync-queries.service'\n\n@Injectable()\nexport class SyncManager {\n private readonly logger = new Logger(SyncManager.name)\n\n constructor(\n private readonly spacesManager: SpacesManager,\n private readonly filesManager: FilesManager,\n private readonly syncQueries: SyncQueries\n ) {}\n\n async download(req: FastifySpaceRequest, res: FastifyReply): Promise<StreamableFile> {\n const sendFile: SendFile = this.filesManager.sendFileFromSpace(req.space)\n try {\n await sendFile.checks()\n return await sendFile.stream(req, res)\n } catch (e) {\n this.handleError(req.space, req.method, e)\n }\n }\n\n async upload(req: FastifySpaceRequest, syncUploadDto: SyncUploadDto): Promise<{ ino: number }> {\n const tmpPath = getTmpFilePath(req.space.realPath)\n try {\n if (syncUploadDto.checksum) {\n const checksum = await this.filesManager.saveStream(req.user, req.space, req, { tmpPath: tmpPath, checksumAlg: SYNC_CHECKSUM_ALG })\n if (checksum !== syncUploadDto.checksum) {\n await removeFiles(tmpPath)\n this.handleError(req.space, req.method, new FileError(HttpStatus.BAD_REQUEST, 'checksums are not identical'))\n }\n } else {\n await this.filesManager.saveStream(req.user, req.space, req, { tmpPath: tmpPath })\n }\n const fileStats = await fs.stat(req.space.realPath)\n if (fileStats.size !== syncUploadDto.size) {\n await removeFiles(tmpPath)\n this.handleError(\n req.space,\n req.method,\n new FileError(HttpStatus.BAD_REQUEST, `sizes are not identical : ${fileStats.size} != ${syncUploadDto.size}`)\n )\n }\n // update mtime\n await touchFile(req.space.realPath, syncUploadDto.mtime)\n // return inode number\n return { ino: fileStats.ino }\n } catch (e) {\n this.handleError(req.space, req.method, e)\n }\n }\n\n async delete(req: FastifySpaceRequest): Promise<void> {\n try {\n return await this.filesManager.delete(req.user, req.space)\n } catch (e) {\n this.handleError(req.space, FILE_OPERATION.DELETE, e)\n }\n }\n\n async props(req: FastifySpaceRequest, syncPropsDto: SyncPropsDto): Promise<void> {\n try {\n await this.filesManager.touch(req.user, req.space, syncPropsDto.mtime, false)\n } catch (e) {\n this.handleError(req.space, FILE_OPERATION.TOUCH, e)\n }\n }\n\n async make(req: FastifySpaceRequest, syncMakeDto: SyncMakeDto): Promise<{ ino: number }> {\n try {\n if (syncMakeDto.type === 'directory') {\n await this.filesManager.mkDir(req.user, req.space, true)\n } else {\n await this.filesManager.mkFile(req.user, req.space, true)\n }\n await touchFile(req.space.realPath, syncMakeDto.mtime)\n return { ino: (await fs.stat(req.space.realPath)).ino }\n } catch (e) {\n this.handleError(req.space, `${FILE_OPERATION.MAKE} ${syncMakeDto.type}`, e)\n }\n }\n\n async copyMove(req: FastifySpaceRequest, syncCopyMoveDto: SyncCopyMoveDto, isMove: true): Promise<void>\n async copyMove(req: FastifySpaceRequest, syncCopyMoveDto: SyncCopyMoveDto, isMove: false): Promise<{ ino: number; mtime: number }>\n async copyMove(req: FastifySpaceRequest, syncCopyMoveDto: SyncCopyMoveDto, isMove: boolean): Promise<void | { ino: number; mtime: number }> {\n const dstSpace: SpaceEnv = await this.spacesManager.spaceEnv(req.user, SYNC_PATH_TO_SPACE_SEGMENTS(syncCopyMoveDto.destination))\n try {\n await this.filesManager.copyMove(req.user, req.space, dstSpace, isMove, true, true)\n if (!isMove) {\n if (syncCopyMoveDto.mtime) {\n // update mtime\n await touchFile(dstSpace.realPath, syncCopyMoveDto.mtime)\n }\n // return inode & mtime\n const stats = await fs.stat(dstSpace.realPath)\n return { ino: stats.ino, mtime: Math.floor(stats.mtime.getTime() / 1000) }\n }\n } catch (e) {\n this.handleError(req.space, isMove ? FILE_OPERATION.MOVE : FILE_OPERATION.COPY, e, dstSpace)\n }\n }\n\n async diff(user: UserModel, pathId: number, syncDiff: SyncDiffDto, res: FastifyReply): Promise<void> {\n if (!user.clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n const syncPathSettings: SyncPathSettings = await this.syncQueries.getPathSettings(user.clientId, pathId)\n if (!syncPathSettings) {\n throw new HttpException('Path not found', HttpStatus.NOT_FOUND)\n }\n let space: SpaceEnv\n try {\n space = await this.spacesManager.spaceEnv(user, SYNC_PATH_TO_SPACE_SEGMENTS(syncPathSettings.remotePath))\n } catch (e) {\n throw new HttpException(e.message, HttpStatus.BAD_REQUEST)\n }\n if (!space) {\n throw new HttpException('Space not found', HttpStatus.NOT_FOUND)\n }\n if (space.quotaIsExceeded) {\n throw new HttpException('Space quota is exceeded', HttpStatus.INSUFFICIENT_STORAGE)\n }\n if (!(await isPathExists(space.realPath))) {\n throw new HttpException(`Remote path not found : ${syncPathSettings.remotePath}`, HttpStatus.NOT_FOUND)\n }\n if (!(await isPathIsDir(space.realPath))) {\n throw new HttpException('Remote path must be a directory', HttpStatus.BAD_REQUEST)\n }\n // start\n res.raw.writeHead(200, {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Transfer-Encoding': 'chunked'\n })\n try {\n for await (const f of this.parseSyncPath(space, syncDiff)) {\n res.raw.write(`${JSON.stringify(f)}\\n`)\n }\n res.raw.write(SYNC_DIFF_DONE)\n } catch (e) {\n this.logger.error(`${this.diff.name} : ${e.message}`)\n res.raw.write(`${e.message}\\n`)\n res.status(HttpStatus.INTERNAL_SERVER_ERROR)\n }\n res.raw.end()\n }\n\n private async *parseSyncPath(space: SpaceEnv, syncDiff: SyncDiffDto): AsyncGenerator<Record<string, SyncFileStats | SyncFileSpecialStats>> {\n const context: ParseDiffContext = {\n regexBasePath: regExpPathPattern(space.realPath),\n syncDiff: syncDiff\n }\n yield* this.parseFiles(space.realPath, context)\n }\n\n private async *parseFiles(dir: string, ctx: ParseDiffContext): AsyncGenerator<Record<string, SyncFileStats | SyncFileSpecialStats>> {\n try {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const realPath = path.join(entry.parentPath, entry.name)\n if (!entry.isDirectory() && !entry.isFile()) {\n this.logger.log(`${this.parseFiles.name} - ignore special file: ${realPath}`)\n continue\n }\n if (entry.isDirectory()) {\n const dirStats: Record<string, SyncFileStats | SyncFileSpecialStats> = await this.analyzeFile(entry, ctx)\n if (dirStats !== null) {\n yield dirStats\n }\n yield* this.parseFiles(realPath, ctx)\n } else {\n const fileStats: Record<string, SyncFileStats | SyncFileSpecialStats> = await this.analyzeFile(entry, ctx)\n if (fileStats !== null) {\n yield fileStats\n }\n }\n }\n } catch (e) {\n this.logger.error(`${this.parseFiles.name} - unable to parse directory : ${dir} : ${e}`)\n throw new Error('Unable to parse path')\n }\n }\n\n private async analyzeFile(entry: Dirent, ctx: ParseDiffContext): Promise<Record<string, SyncFileStats | SyncFileSpecialStats>> {\n if (ctx.syncDiff.defaultFilters.has(entry.name)) {\n return null\n }\n\n const realPath = path.join(entry.parentPath, entry.name)\n const filePath = realPath.replace(ctx.regexBasePath, '')\n\n let stats: Stats\n try {\n stats = await fs.stat(realPath)\n } catch (e) {\n this.logger.warn(`${this.analyzeFile.name} - unable to get file stats : ${realPath} : ${e}`)\n return { [filePath]: [F_SPECIAL_STAT.ERROR, e.toString()] }\n }\n\n if (ctx.syncDiff.pathFilters && ctx.syncDiff.pathFilters.test(filePath)) {\n this.logger.verbose(`${this.analyzeFile.name} - ignore filtered file : ${realPath}`)\n return { [filePath]: [F_SPECIAL_STAT.FILTERED, stats.isDirectory()] }\n }\n\n const fileStats: SyncFileStats = [\n stats.isDirectory(),\n stats.isDirectory() ? 0 : stats.size,\n Math.floor(stats.mtime.getTime() / 1000),\n stats.ino,\n null\n ]\n if (ctx.syncDiff.secureDiff && !fileStats[F_STAT.IS_DIR]) {\n try {\n await this.checkSumFile(ctx, filePath, realPath, fileStats)\n } catch (e) {\n this.logger.error(`${this.analyzeFile.name} - file error : ${realPath} - ${e}`)\n return { [filePath]: [F_SPECIAL_STAT.ERROR, e.toString()] }\n }\n }\n return { [filePath]: fileStats }\n }\n\n private async checkSumFile(ctx: ParseDiffContext, filePath: string, realPath: string, fileStats: SyncFileStats): Promise<void> {\n if (!ctx.syncDiff.firstSync && ctx.syncDiff.snapshot.has(filePath)) {\n const snapFileStats: SyncFileStats = ctx.syncDiff.snapshot.get(filePath)\n if (\n snapFileStats[F_STAT.CHECKSUM] &&\n snapFileStats[F_STAT.MTIME] == fileStats[F_STAT.MTIME] &&\n snapFileStats[F_STAT.SIZE] == fileStats[F_STAT.SIZE] &&\n snapFileStats[F_STAT.INO] == fileStats[F_STAT.INO]\n ) {\n fileStats[F_STAT.CHECKSUM] = snapFileStats[F_STAT.CHECKSUM]\n return\n }\n }\n fileStats[F_STAT.CHECKSUM] = await checksumFile(realPath, SYNC_CHECKSUM_ALG)\n }\n\n private handleError(space: SpaceEnv, action: string, e: any, dstSpace?: SpaceEnv) {\n this.logger.error(`unable to ${action} ${space.url}${dstSpace?.url ? ` -> ${dstSpace.url}` : ''} : ${e}`)\n if (e instanceof LockConflict) {\n throw new HttpException('The file is locked', HttpStatus.LOCKED)\n } else if (e instanceof FileError) {\n throw new HttpException(e.message, e.httpCode)\n }\n throw new HttpException(e.message, HttpStatus.INTERNAL_SERVER_ERROR)\n }\n}\n"],"names":["SyncManager","download","req","res","sendFile","filesManager","sendFileFromSpace","space","checks","stream","e","handleError","method","upload","syncUploadDto","tmpPath","getTmpFilePath","realPath","checksum","saveStream","user","checksumAlg","SYNC_CHECKSUM_ALG","removeFiles","FileError","HttpStatus","BAD_REQUEST","fileStats","fs","stat","size","touchFile","mtime","ino","delete","FILE_OPERATION","DELETE","props","syncPropsDto","touch","TOUCH","make","syncMakeDto","type","mkDir","mkFile","MAKE","copyMove","syncCopyMoveDto","isMove","dstSpace","spacesManager","spaceEnv","SYNC_PATH_TO_SPACE_SEGMENTS","destination","stats","Math","floor","getTime","MOVE","COPY","diff","pathId","syncDiff","clientId","HttpException","syncPathSettings","syncQueries","getPathSettings","NOT_FOUND","remotePath","message","quotaIsExceeded","INSUFFICIENT_STORAGE","isPathExists","isPathIsDir","raw","writeHead","f","parseSyncPath","write","JSON","stringify","SYNC_DIFF_DONE","logger","error","name","status","INTERNAL_SERVER_ERROR","end","context","regexBasePath","regExpPathPattern","parseFiles","dir","ctx","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","isFile","log","dirStats","analyzeFile","Error","defaultFilters","has","filePath","replace","warn","F_SPECIAL_STAT","ERROR","toString","pathFilters","test","verbose","FILTERED","secureDiff","F_STAT","IS_DIR","checkSumFile","firstSync","snapshot","snapFileStats","get","CHECKSUM","MTIME","SIZE","INO","checksumFile","action","url","LockConflict","LOCKED","httpCode","Logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/sync/services/sync-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 fs from 'fs/promises'\nimport { Dirent, Stats } from 'node:fs'\nimport path from 'node:path'\nimport { regExpPathPattern } from '../../../common/functions'\nimport { FILE_OPERATION } from '../../files/constants/operations'\nimport { FileError } from '../../files/models/file-error'\nimport { LockConflict } from '../../files/models/file-lock-error'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { checksumFile, isPathExists, isPathIsDir, removeFiles, touchFile } from '../../files/utils/files'\nimport { SendFile } from '../../files/utils/send-file'\nimport { ParseDiffContext } from '../../spaces/interfaces/space-diff.interface'\nimport { FastifySpaceRequest } from '../../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { F_SPECIAL_STAT, F_STAT, SYNC_CHECKSUM_ALG, SYNC_DIFF_DONE } from '../constants/sync'\nimport { SyncCopyMoveDto, SyncDiffDto, SyncMakeDto, SyncPropsDto } from '../dtos/sync-operations.dto'\nimport { SyncUploadDto } from '../dtos/sync-upload.dto'\nimport { SyncFileSpecialStats, SyncFileStats } from '../interfaces/sync-diff.interface'\nimport { SyncPathSettings } from '../interfaces/sync-path.interface'\nimport { getTmpFilePath } from '../utils/functions'\nimport { SYNC_PATH_TO_SPACE_SEGMENTS } from '../utils/routes'\nimport { SyncQueries } from './sync-queries.service'\n\n@Injectable()\nexport class SyncManager {\n private readonly logger = new Logger(SyncManager.name)\n\n constructor(\n private readonly spacesManager: SpacesManager,\n private readonly filesManager: FilesManager,\n private readonly syncQueries: SyncQueries\n ) {}\n\n async download(req: FastifySpaceRequest, res: FastifyReply): Promise<StreamableFile> {\n const sendFile: SendFile = this.filesManager.sendFileFromSpace(req.space)\n try {\n await sendFile.checks()\n return await sendFile.stream(req, res)\n } catch (e) {\n this.handleError(req.space, req.method, e)\n }\n }\n\n async upload(req: FastifySpaceRequest, syncUploadDto: SyncUploadDto): Promise<{ ino: number }> {\n const tmpPath = getTmpFilePath(req.space.realPath)\n try {\n if (syncUploadDto.checksum) {\n const checksum = await this.filesManager.saveStream(req.user, req.space, req, { tmpPath: tmpPath, checksumAlg: SYNC_CHECKSUM_ALG })\n if (checksum !== syncUploadDto.checksum) {\n await removeFiles(tmpPath)\n this.handleError(req.space, req.method, new FileError(HttpStatus.BAD_REQUEST, 'checksums are not identical'))\n }\n } else {\n await this.filesManager.saveStream(req.user, req.space, req, { tmpPath: tmpPath })\n }\n const fileStats = await fs.stat(req.space.realPath)\n if (fileStats.size !== syncUploadDto.size) {\n await removeFiles(tmpPath)\n this.handleError(\n req.space,\n req.method,\n new FileError(HttpStatus.BAD_REQUEST, `sizes are not identical : ${fileStats.size} != ${syncUploadDto.size}`)\n )\n }\n // update mtime\n await touchFile(req.space.realPath, syncUploadDto.mtime)\n // return inode number\n return { ino: fileStats.ino }\n } catch (e) {\n this.handleError(req.space, req.method, e)\n }\n }\n\n async delete(req: FastifySpaceRequest): Promise<void> {\n try {\n return await this.filesManager.delete(req.user, req.space)\n } catch (e) {\n this.handleError(req.space, FILE_OPERATION.DELETE, e)\n }\n }\n\n async props(req: FastifySpaceRequest, syncPropsDto: SyncPropsDto): Promise<void> {\n try {\n await this.filesManager.touch(req.user, req.space, syncPropsDto.mtime, false)\n } catch (e) {\n this.handleError(req.space, FILE_OPERATION.TOUCH, e)\n }\n }\n\n async make(req: FastifySpaceRequest, syncMakeDto: SyncMakeDto): Promise<{ ino: number }> {\n try {\n if (syncMakeDto.type === 'directory') {\n await this.filesManager.mkDir(req.user, req.space, true)\n } else {\n await this.filesManager.mkFile(req.user, req.space, true)\n }\n await touchFile(req.space.realPath, syncMakeDto.mtime)\n return { ino: (await fs.stat(req.space.realPath)).ino }\n } catch (e) {\n this.handleError(req.space, `${FILE_OPERATION.MAKE} ${syncMakeDto.type}`, e)\n }\n }\n\n async copyMove(req: FastifySpaceRequest, syncCopyMoveDto: SyncCopyMoveDto, isMove: true): Promise<void>\n async copyMove(req: FastifySpaceRequest, syncCopyMoveDto: SyncCopyMoveDto, isMove: false): Promise<{ ino: number; mtime: number }>\n async copyMove(req: FastifySpaceRequest, syncCopyMoveDto: SyncCopyMoveDto, isMove: boolean): Promise<void | { ino: number; mtime: number }> {\n const dstSpace: SpaceEnv = await this.spacesManager.spaceEnv(req.user, SYNC_PATH_TO_SPACE_SEGMENTS(syncCopyMoveDto.destination))\n try {\n await this.filesManager.copyMove(req.user, req.space, dstSpace, isMove, true, true)\n if (!isMove) {\n if (syncCopyMoveDto.mtime) {\n // update mtime\n await touchFile(dstSpace.realPath, syncCopyMoveDto.mtime)\n }\n // return inode & mtime\n const stats = await fs.stat(dstSpace.realPath)\n return { ino: stats.ino, mtime: Math.floor(stats.mtime.getTime() / 1000) }\n }\n } catch (e) {\n this.handleError(req.space, isMove ? FILE_OPERATION.MOVE : FILE_OPERATION.COPY, e, dstSpace)\n }\n }\n\n async diff(user: UserModel, pathId: number, syncDiff: SyncDiffDto, res: FastifyReply): Promise<void> {\n if (!user.clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n const syncPathSettings: SyncPathSettings = await this.syncQueries.getPathSettings(user.clientId, pathId)\n if (!syncPathSettings) {\n throw new HttpException('Path not found', HttpStatus.NOT_FOUND)\n }\n let space: SpaceEnv\n try {\n space = await this.spacesManager.spaceEnv(user, SYNC_PATH_TO_SPACE_SEGMENTS(syncPathSettings.remotePath))\n } catch (e) {\n throw new HttpException(e.message, HttpStatus.BAD_REQUEST)\n }\n if (!space) {\n throw new HttpException('Space not found', HttpStatus.NOT_FOUND)\n }\n if (space.quotaIsExceeded) {\n throw new HttpException('Storage quota exceeded', HttpStatus.INSUFFICIENT_STORAGE)\n }\n if (!(await isPathExists(space.realPath))) {\n throw new HttpException(`Remote path not found : ${syncPathSettings.remotePath}`, HttpStatus.NOT_FOUND)\n }\n if (!(await isPathIsDir(space.realPath))) {\n throw new HttpException('Remote path must be a directory', HttpStatus.BAD_REQUEST)\n }\n // start\n res.raw.writeHead(200, {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Transfer-Encoding': 'chunked'\n })\n try {\n for await (const f of this.parseSyncPath(space, syncDiff)) {\n res.raw.write(`${JSON.stringify(f)}\\n`)\n }\n res.raw.write(SYNC_DIFF_DONE)\n } catch (e) {\n this.logger.error(`${this.diff.name} : ${e.message}`)\n res.raw.write(`${e.message}\\n`)\n res.status(HttpStatus.INTERNAL_SERVER_ERROR)\n }\n res.raw.end()\n }\n\n private async *parseSyncPath(space: SpaceEnv, syncDiff: SyncDiffDto): AsyncGenerator<Record<string, SyncFileStats | SyncFileSpecialStats>> {\n const context: ParseDiffContext = {\n regexBasePath: regExpPathPattern(space.realPath),\n syncDiff: syncDiff\n }\n yield* this.parseFiles(space.realPath, context)\n }\n\n private async *parseFiles(dir: string, ctx: ParseDiffContext): AsyncGenerator<Record<string, SyncFileStats | SyncFileSpecialStats>> {\n try {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const realPath = path.join(entry.parentPath, entry.name)\n if (!entry.isDirectory() && !entry.isFile()) {\n this.logger.log(`${this.parseFiles.name} - ignore special file: ${realPath}`)\n continue\n }\n if (entry.isDirectory()) {\n const dirStats: Record<string, SyncFileStats | SyncFileSpecialStats> = await this.analyzeFile(entry, ctx)\n if (dirStats !== null) {\n yield dirStats\n }\n yield* this.parseFiles(realPath, ctx)\n } else {\n const fileStats: Record<string, SyncFileStats | SyncFileSpecialStats> = await this.analyzeFile(entry, ctx)\n if (fileStats !== null) {\n yield fileStats\n }\n }\n }\n } catch (e) {\n this.logger.error(`${this.parseFiles.name} - unable to parse directory : ${dir} : ${e}`)\n throw new Error('Unable to parse path')\n }\n }\n\n private async analyzeFile(entry: Dirent, ctx: ParseDiffContext): Promise<Record<string, SyncFileStats | SyncFileSpecialStats>> {\n if (ctx.syncDiff.defaultFilters.has(entry.name)) {\n return null\n }\n\n const realPath = path.join(entry.parentPath, entry.name)\n const filePath = realPath.replace(ctx.regexBasePath, '')\n\n let stats: Stats\n try {\n stats = await fs.stat(realPath)\n } catch (e) {\n this.logger.warn(`${this.analyzeFile.name} - unable to get file stats : ${realPath} : ${e}`)\n return { [filePath]: [F_SPECIAL_STAT.ERROR, e.toString()] }\n }\n\n if (ctx.syncDiff.pathFilters && ctx.syncDiff.pathFilters.test(filePath)) {\n this.logger.verbose(`${this.analyzeFile.name} - ignore filtered file : ${realPath}`)\n return { [filePath]: [F_SPECIAL_STAT.FILTERED, stats.isDirectory()] }\n }\n\n const fileStats: SyncFileStats = [\n stats.isDirectory(),\n stats.isDirectory() ? 0 : stats.size,\n Math.floor(stats.mtime.getTime() / 1000),\n stats.ino,\n null\n ]\n if (ctx.syncDiff.secureDiff && !fileStats[F_STAT.IS_DIR]) {\n try {\n await this.checkSumFile(ctx, filePath, realPath, fileStats)\n } catch (e) {\n this.logger.error(`${this.analyzeFile.name} - file error : ${realPath} - ${e}`)\n return { [filePath]: [F_SPECIAL_STAT.ERROR, e.toString()] }\n }\n }\n return { [filePath]: fileStats }\n }\n\n private async checkSumFile(ctx: ParseDiffContext, filePath: string, realPath: string, fileStats: SyncFileStats): Promise<void> {\n if (!ctx.syncDiff.firstSync && ctx.syncDiff.snapshot.has(filePath)) {\n const snapFileStats: SyncFileStats = ctx.syncDiff.snapshot.get(filePath)\n if (\n snapFileStats[F_STAT.CHECKSUM] &&\n snapFileStats[F_STAT.MTIME] == fileStats[F_STAT.MTIME] &&\n snapFileStats[F_STAT.SIZE] == fileStats[F_STAT.SIZE] &&\n snapFileStats[F_STAT.INO] == fileStats[F_STAT.INO]\n ) {\n fileStats[F_STAT.CHECKSUM] = snapFileStats[F_STAT.CHECKSUM]\n return\n }\n }\n fileStats[F_STAT.CHECKSUM] = await checksumFile(realPath, SYNC_CHECKSUM_ALG)\n }\n\n private handleError(space: SpaceEnv, action: string, e: any, dstSpace?: SpaceEnv) {\n this.logger.error(`unable to ${action} ${space.url}${dstSpace?.url ? ` -> ${dstSpace.url}` : ''} : ${e}`)\n const errorMsg = e.message.split(',')[0]\n if (e instanceof LockConflict) {\n throw new HttpException('The file is locked', HttpStatus.LOCKED)\n } else if (e instanceof FileError) {\n throw new HttpException(errorMsg, e.httpCode)\n }\n throw new HttpException(errorMsg, HttpStatus.INTERNAL_SERVER_ERROR)\n }\n}\n"],"names":["SyncManager","download","req","res","sendFile","filesManager","sendFileFromSpace","space","checks","stream","e","handleError","method","upload","syncUploadDto","tmpPath","getTmpFilePath","realPath","checksum","saveStream","user","checksumAlg","SYNC_CHECKSUM_ALG","removeFiles","FileError","HttpStatus","BAD_REQUEST","fileStats","fs","stat","size","touchFile","mtime","ino","delete","FILE_OPERATION","DELETE","props","syncPropsDto","touch","TOUCH","make","syncMakeDto","type","mkDir","mkFile","MAKE","copyMove","syncCopyMoveDto","isMove","dstSpace","spacesManager","spaceEnv","SYNC_PATH_TO_SPACE_SEGMENTS","destination","stats","Math","floor","getTime","MOVE","COPY","diff","pathId","syncDiff","clientId","HttpException","syncPathSettings","syncQueries","getPathSettings","NOT_FOUND","remotePath","message","quotaIsExceeded","INSUFFICIENT_STORAGE","isPathExists","isPathIsDir","raw","writeHead","f","parseSyncPath","write","JSON","stringify","SYNC_DIFF_DONE","logger","error","name","status","INTERNAL_SERVER_ERROR","end","context","regexBasePath","regExpPathPattern","parseFiles","dir","ctx","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","isFile","log","dirStats","analyzeFile","Error","defaultFilters","has","filePath","replace","warn","F_SPECIAL_STAT","ERROR","toString","pathFilters","test","verbose","FILTERED","secureDiff","F_STAT","IS_DIR","checkSumFile","firstSync","snapshot","snapFileStats","get","CHECKSUM","MTIME","SIZE","INO","checksumFile","action","url","errorMsg","split","LockConflict","LOCKED","httpCode","Logger"],"mappings":"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"}
@@ -40,7 +40,7 @@ let SyncPathsManager = class SyncPathsManager {
40
40
  throw new _common.HttpException('Client id is missing', _common.HttpStatus.BAD_REQUEST);
41
41
  }
42
42
  if (req.space.quotaIsExceeded) {
43
- throw new _common.HttpException('Space quota is exceeded', _common.HttpStatus.INSUFFICIENT_STORAGE);
43
+ throw new _common.HttpException('Storage quota exceeded', _common.HttpStatus.INSUFFICIENT_STORAGE);
44
44
  }
45
45
  if (!await (0, _files.isPathExists)(req.space.realPath)) {
46
46
  throw new _common.HttpException(`Remote path not found : ${syncPathDto.remotePath}`, _common.HttpStatus.NOT_FOUND);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/sync/services/sync-paths-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 } from '@nestjs/common'\nimport { ACTION } from '../../../common/constants'\nimport { currentTimeStamp } from '../../../common/shared'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport type { FileProps } from '../../files/interfaces/file-props.interface'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { getProps, isPathExists, isPathIsDir } from '../../files/utils/files'\nimport { NOTIFICATION_APP, NOTIFICATION_APP_EVENT } from '../../notifications/constants/notifications'\nimport { NotificationContent } from '../../notifications/interfaces/notification-properties.interface'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { FastifySpaceRequest } from '../../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { getEnvPermissions } from '../../spaces/utils/permissions'\nimport { UserModel } from '../../users/models/user.model'\nimport { SYNC_PATH_REPOSITORY } from '../constants/sync'\nimport { SyncPathDto, SyncPathUpdateDto } from '../dtos/sync-path.dto'\nimport { SyncDBProps, SyncPathSettings } from '../interfaces/sync-path.interface'\nimport { SyncClient } from '../schemas/sync-client.interface'\nimport { SYNC_PATH_TO_SPACE_SEGMENTS } from '../utils/routes'\nimport { SyncQueries } from './sync-queries.service'\n\n@Injectable()\nexport class SyncPathsManager {\n private readonly logger = new Logger(SyncPathsManager.name)\n\n constructor(\n private readonly contextManager: ContextManager,\n private readonly spacesManager: SpacesManager,\n private readonly filesQueries: FilesQueries,\n private readonly syncQueries: SyncQueries,\n private readonly notificationsManager: NotificationsManager\n ) {}\n\n async createPath(req: FastifySpaceRequest, syncPathDto: SyncPathDto): Promise<{ id: number; permissions: string }> {\n if (!req.user.clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n if (req.space.quotaIsExceeded) {\n throw new HttpException('Space quota is exceeded', HttpStatus.INSUFFICIENT_STORAGE)\n }\n if (!(await isPathExists(req.space.realPath))) {\n throw new HttpException(`Remote path not found : ${syncPathDto.remotePath}`, HttpStatus.NOT_FOUND)\n }\n if (!(await isPathIsDir(req.space.realPath))) {\n throw new HttpException('Remote path must be a directory', HttpStatus.BAD_REQUEST)\n }\n const client: SyncClient = await this.syncQueries.getClient(req.user.clientId, req.user.id)\n if (!client) {\n throw new HttpException('Client not found', HttpStatus.NOT_FOUND)\n }\n const syncDBProps: SyncDBProps = await this.getDBProps(req.space)\n\n // important : ensures the right remote path is used and stored\n syncPathDto.remotePath = req.params['*']\n // add permissions (skip end point protection using getEnvPermission)\n syncPathDto.permissions = getEnvPermissions(req.space, req.space.root)\n const pathId = await this.syncQueries.createPath(client.id, syncDBProps, syncPathDto)\n return { id: pathId, permissions: syncPathDto.permissions }\n }\n\n async deletePath(user: UserModel, pathId: number, clientId?: string): Promise<void> {\n clientId = user.clientId || clientId\n if (!clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n if (!(await this.syncQueries.clientExistsForOwner(user.id, clientId))) {\n throw new HttpException('You are not allowed to do this action', HttpStatus.FORBIDDEN)\n }\n try {\n await this.syncQueries.deletePath(clientId, pathId)\n } catch (e) {\n this.logger.error(`${this.deletePath.name} - ${e}`)\n throw new HttpException('Unable to remove path', HttpStatus.BAD_REQUEST)\n }\n }\n\n async updatePath(user: UserModel, clientId: string, pathId: number, syncPathUpdateDto: SyncPathUpdateDto): Promise<SyncPathSettings> {\n if (!(await this.syncQueries.clientExistsForOwner(user.id, clientId))) {\n throw new HttpException('You are not allowed to do this action', HttpStatus.FORBIDDEN)\n }\n const syncPathSettings: SyncPathSettings = await this.syncQueries.getPathSettings(clientId, pathId)\n if (!syncPathSettings) {\n throw new HttpException('Sync path not found', HttpStatus.NOT_FOUND)\n }\n // delete possible id\n delete syncPathUpdateDto.id\n // update current path settings\n Object.assign(syncPathSettings, syncPathUpdateDto)\n syncPathSettings.timestamp = currentTimeStamp()\n try {\n await this.syncQueries.updatePathSettings(clientId, pathId, syncPathSettings)\n } catch (e) {\n this.logger.error(`${this.updatePath.name} - ${e}`)\n throw new HttpException('Unable to update path', HttpStatus.INTERNAL_SERVER_ERROR)\n } finally {\n // clear cache\n this.syncQueries.clearCachePathSettings(clientId, pathId)\n }\n return syncPathSettings\n }\n\n async updatePaths(\n user: UserModel,\n syncPathsDto: SyncPathDto[]\n ): Promise<{\n add: SyncPathSettings[]\n update: Partial<Record<keyof SyncPathSettings, any>>[]\n delete: number[]\n }> {\n /* Update the client or server paths */\n if (!user.clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n if (!(await this.syncQueries.clientExistsForOwner(user.id, user.clientId))) {\n throw new HttpException('You are not allowed to do this action', HttpStatus.FORBIDDEN)\n }\n const clientPathIds: number[] = syncPathsDto.map((p) => p.id)\n const serverPathIds: number[] = []\n\n const clientDiff: { add: SyncPathSettings[]; update: Partial<Record<keyof SyncPathSettings, any>>[]; delete: number[] } = {\n add: [],\n update: [],\n delete: []\n }\n const serverPaths: { id: number; settings: SyncPathSettings; remotePath: string }[] = await this.syncQueries.getPaths(user.clientId)\n for (const serverPath of serverPaths) {\n if (!serverPath.remotePath) {\n // unable to determine path, will be stored as deleted\n continue\n }\n let space: SpaceEnv\n try {\n space = await this.spacesManager.spaceEnv(user, SYNC_PATH_TO_SPACE_SEGMENTS(serverPath.remotePath), true)\n } catch (e) {\n throw new HttpException(e.message, HttpStatus.BAD_REQUEST)\n }\n if (!space) {\n // removed or inaccessible space, the path will be stored as deleted\n continue\n }\n serverPathIds.push(serverPath.id)\n if (clientPathIds.indexOf(serverPath.id) === -1) {\n // path exists on server but not on client, add it to client\n clientDiff.add.push({ ...serverPath.settings, id: serverPath.id, remotePath: serverPath.remotePath, permissions: space.envPermissions })\n continue\n }\n\n // path exists on both server and client side\n const clientPath: SyncPathDto = syncPathsDto.find((p) => p.id === serverPath.id)\n // remotePath and permissions settings are only managed by server\n const updateClientInfo: { remotePath?: string; permissions?: string } = {\n ...(serverPath.remotePath !== clientPath.remotePath && { remotePath: serverPath.remotePath }),\n ...(space.envPermissions !== clientPath.permissions && { permissions: space.envPermissions })\n }\n const clientNewer = clientPath.timestamp > serverPath.settings.timestamp\n const serverNewer = clientPath.timestamp < serverPath.settings.timestamp\n const hasUpdates = Object.keys(updateClientInfo).length > 0\n\n let updatedSettings: SyncPathSettings = { ...serverPath.settings, ...updateClientInfo }\n\n if (clientNewer) {\n updatedSettings = { ...clientPath, ...updateClientInfo }\n } else if (serverNewer) {\n clientDiff.update.push({ id: clientPath.id, ...serverPath.settings, ...updateClientInfo })\n }\n\n if (clientNewer || hasUpdates || serverPath.settings.lastSync !== clientPath.lastSync) {\n this.syncQueries\n .updatePathSettings(user.clientId, clientPath.id, { ...updatedSettings, lastSync: clientPath.lastSync })\n .catch((e: Error) => this.logger.error(`${this.updatePaths.name} - ${e}`))\n }\n\n if (!clientNewer && hasUpdates) {\n clientDiff.update.push({ id: clientPath.id, ...updateClientInfo })\n }\n }\n // path does not exist on server side\n clientDiff.delete = clientPathIds.filter((cid) => serverPathIds.indexOf(cid) === -1)\n for (const cPathId of clientDiff.delete) {\n const cPath: SyncPathDto = syncPathsDto.find((p) => p.id === cPathId)\n this.notify(user.id, ACTION.DELETE, cPath.remotePath).catch((e: Error) => this.logger.error(`${this.updatePaths.name} - ${e}`))\n }\n // clear cache\n clientDiff.update.forEach((path) => this.syncQueries.clearCachePathSettings(user.clientId, path.id))\n return clientDiff\n }\n\n private async getDBProps(space: SpaceEnv): Promise<SyncDBProps> {\n if (space.inSharesList) {\n throw new HttpException('Sync all shares is not supported, you must select a sub-directory', HttpStatus.BAD_REQUEST)\n } else if (space.inPersonalSpace) {\n if (space.paths.length) {\n return { ownerId: space.dbFile.ownerId, fileId: await this.getOrCreateFileId(space) }\n } else {\n return { ownerId: space.dbFile.ownerId }\n }\n } else if (space.inFilesRepository) {\n if (!space?.root?.alias) {\n // The synchronization direction should be adapted for each root depending on the permissions, this is not yet supported\n throw new HttpException('Sync all space is not yet supported, you must select a sub-directory', HttpStatus.BAD_REQUEST)\n }\n if (space.root.id && !space.paths.length) {\n return { spaceId: space.id, spaceRootId: space.root.id }\n } else {\n return { spaceId: space.id, spaceRootId: space?.root?.id || null, fileId: await this.getOrCreateFileId(space) }\n }\n } else if (space.inSharesRepository) {\n if (space.paths.length) {\n return { shareId: space.id, fileId: await this.getOrCreateFileId(space) }\n } else {\n return { shareId: space.id }\n }\n }\n }\n\n private async getOrCreateFileId(space: SpaceEnv): Promise<number> {\n const fileProps: FileProps = await getProps(space.realPath, space.dbFile.path)\n let fileId: number = await this.filesQueries.getSpaceFileId(fileProps, space.dbFile)\n if (!fileId) {\n fileId = await this.filesQueries.getOrCreateSpaceFile(fileId, { ...fileProps, id: undefined }, space.dbFile)\n }\n return fileId\n }\n\n private async notify(userId: number, action: ACTION, remotePath: string) {\n const notification: NotificationContent = {\n app: NOTIFICATION_APP.SYNC,\n event: NOTIFICATION_APP_EVENT.SYNC[action],\n element: remotePath,\n url: [...SYNC_PATH_REPOSITORY[remotePath.split('/').at(0)], ...remotePath.split('/').slice(1, -1)].join('/')\n }\n this.notificationsManager\n .create([userId], notification, {\n currentUrl: this.contextManager.get('headerOriginUrl'),\n action: action\n })\n .catch((e: Error) => this.logger.error(`${this.notify.name} - ${e}`))\n }\n}\n"],"names":["SyncPathsManager","createPath","req","syncPathDto","user","clientId","HttpException","HttpStatus","BAD_REQUEST","space","quotaIsExceeded","INSUFFICIENT_STORAGE","isPathExists","realPath","remotePath","NOT_FOUND","isPathIsDir","client","syncQueries","getClient","id","syncDBProps","getDBProps","params","permissions","getEnvPermissions","root","pathId","deletePath","clientExistsForOwner","FORBIDDEN","e","logger","error","name","updatePath","syncPathUpdateDto","syncPathSettings","getPathSettings","Object","assign","timestamp","currentTimeStamp","updatePathSettings","INTERNAL_SERVER_ERROR","clearCachePathSettings","updatePaths","syncPathsDto","clientPathIds","map","p","serverPathIds","clientDiff","add","update","delete","serverPaths","getPaths","serverPath","spacesManager","spaceEnv","SYNC_PATH_TO_SPACE_SEGMENTS","message","push","indexOf","settings","envPermissions","clientPath","find","updateClientInfo","clientNewer","serverNewer","hasUpdates","keys","length","updatedSettings","lastSync","catch","filter","cid","cPathId","cPath","notify","ACTION","DELETE","forEach","path","inSharesList","inPersonalSpace","paths","ownerId","dbFile","fileId","getOrCreateFileId","inFilesRepository","alias","spaceId","spaceRootId","inSharesRepository","shareId","fileProps","getProps","filesQueries","getSpaceFileId","getOrCreateSpaceFile","undefined","userId","action","notification","app","NOTIFICATION_APP","SYNC","event","NOTIFICATION_APP_EVENT","element","url","SYNC_PATH_REPOSITORY","split","at","slice","join","notificationsManager","create","currentUrl","contextManager","get","Logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/sync/services/sync-paths-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 } from '@nestjs/common'\nimport { ACTION } from '../../../common/constants'\nimport { currentTimeStamp } from '../../../common/shared'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport type { FileProps } from '../../files/interfaces/file-props.interface'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { getProps, isPathExists, isPathIsDir } from '../../files/utils/files'\nimport { NOTIFICATION_APP, NOTIFICATION_APP_EVENT } from '../../notifications/constants/notifications'\nimport { NotificationContent } from '../../notifications/interfaces/notification-properties.interface'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { FastifySpaceRequest } from '../../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { getEnvPermissions } from '../../spaces/utils/permissions'\nimport { UserModel } from '../../users/models/user.model'\nimport { SYNC_PATH_REPOSITORY } from '../constants/sync'\nimport { SyncPathDto, SyncPathUpdateDto } from '../dtos/sync-path.dto'\nimport { SyncDBProps, SyncPathSettings } from '../interfaces/sync-path.interface'\nimport { SyncClient } from '../schemas/sync-client.interface'\nimport { SYNC_PATH_TO_SPACE_SEGMENTS } from '../utils/routes'\nimport { SyncQueries } from './sync-queries.service'\n\n@Injectable()\nexport class SyncPathsManager {\n private readonly logger = new Logger(SyncPathsManager.name)\n\n constructor(\n private readonly contextManager: ContextManager,\n private readonly spacesManager: SpacesManager,\n private readonly filesQueries: FilesQueries,\n private readonly syncQueries: SyncQueries,\n private readonly notificationsManager: NotificationsManager\n ) {}\n\n async createPath(req: FastifySpaceRequest, syncPathDto: SyncPathDto): Promise<{ id: number; permissions: string }> {\n if (!req.user.clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n if (req.space.quotaIsExceeded) {\n throw new HttpException('Storage quota exceeded', HttpStatus.INSUFFICIENT_STORAGE)\n }\n if (!(await isPathExists(req.space.realPath))) {\n throw new HttpException(`Remote path not found : ${syncPathDto.remotePath}`, HttpStatus.NOT_FOUND)\n }\n if (!(await isPathIsDir(req.space.realPath))) {\n throw new HttpException('Remote path must be a directory', HttpStatus.BAD_REQUEST)\n }\n const client: SyncClient = await this.syncQueries.getClient(req.user.clientId, req.user.id)\n if (!client) {\n throw new HttpException('Client not found', HttpStatus.NOT_FOUND)\n }\n const syncDBProps: SyncDBProps = await this.getDBProps(req.space)\n\n // important : ensures the right remote path is used and stored\n syncPathDto.remotePath = req.params['*']\n // add permissions (skip end point protection using getEnvPermission)\n syncPathDto.permissions = getEnvPermissions(req.space, req.space.root)\n const pathId = await this.syncQueries.createPath(client.id, syncDBProps, syncPathDto)\n return { id: pathId, permissions: syncPathDto.permissions }\n }\n\n async deletePath(user: UserModel, pathId: number, clientId?: string): Promise<void> {\n clientId = user.clientId || clientId\n if (!clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n if (!(await this.syncQueries.clientExistsForOwner(user.id, clientId))) {\n throw new HttpException('You are not allowed to do this action', HttpStatus.FORBIDDEN)\n }\n try {\n await this.syncQueries.deletePath(clientId, pathId)\n } catch (e) {\n this.logger.error(`${this.deletePath.name} - ${e}`)\n throw new HttpException('Unable to remove path', HttpStatus.BAD_REQUEST)\n }\n }\n\n async updatePath(user: UserModel, clientId: string, pathId: number, syncPathUpdateDto: SyncPathUpdateDto): Promise<SyncPathSettings> {\n if (!(await this.syncQueries.clientExistsForOwner(user.id, clientId))) {\n throw new HttpException('You are not allowed to do this action', HttpStatus.FORBIDDEN)\n }\n const syncPathSettings: SyncPathSettings = await this.syncQueries.getPathSettings(clientId, pathId)\n if (!syncPathSettings) {\n throw new HttpException('Sync path not found', HttpStatus.NOT_FOUND)\n }\n // delete possible id\n delete syncPathUpdateDto.id\n // update current path settings\n Object.assign(syncPathSettings, syncPathUpdateDto)\n syncPathSettings.timestamp = currentTimeStamp()\n try {\n await this.syncQueries.updatePathSettings(clientId, pathId, syncPathSettings)\n } catch (e) {\n this.logger.error(`${this.updatePath.name} - ${e}`)\n throw new HttpException('Unable to update path', HttpStatus.INTERNAL_SERVER_ERROR)\n } finally {\n // clear cache\n this.syncQueries.clearCachePathSettings(clientId, pathId)\n }\n return syncPathSettings\n }\n\n async updatePaths(\n user: UserModel,\n syncPathsDto: SyncPathDto[]\n ): Promise<{\n add: SyncPathSettings[]\n update: Partial<Record<keyof SyncPathSettings, any>>[]\n delete: number[]\n }> {\n /* Update the client or server paths */\n if (!user.clientId) {\n throw new HttpException('Client id is missing', HttpStatus.BAD_REQUEST)\n }\n if (!(await this.syncQueries.clientExistsForOwner(user.id, user.clientId))) {\n throw new HttpException('You are not allowed to do this action', HttpStatus.FORBIDDEN)\n }\n const clientPathIds: number[] = syncPathsDto.map((p) => p.id)\n const serverPathIds: number[] = []\n\n const clientDiff: { add: SyncPathSettings[]; update: Partial<Record<keyof SyncPathSettings, any>>[]; delete: number[] } = {\n add: [],\n update: [],\n delete: []\n }\n const serverPaths: { id: number; settings: SyncPathSettings; remotePath: string }[] = await this.syncQueries.getPaths(user.clientId)\n for (const serverPath of serverPaths) {\n if (!serverPath.remotePath) {\n // unable to determine path, will be stored as deleted\n continue\n }\n let space: SpaceEnv\n try {\n space = await this.spacesManager.spaceEnv(user, SYNC_PATH_TO_SPACE_SEGMENTS(serverPath.remotePath), true)\n } catch (e) {\n throw new HttpException(e.message, HttpStatus.BAD_REQUEST)\n }\n if (!space) {\n // removed or inaccessible space, the path will be stored as deleted\n continue\n }\n serverPathIds.push(serverPath.id)\n if (clientPathIds.indexOf(serverPath.id) === -1) {\n // path exists on server but not on client, add it to client\n clientDiff.add.push({ ...serverPath.settings, id: serverPath.id, remotePath: serverPath.remotePath, permissions: space.envPermissions })\n continue\n }\n\n // path exists on both server and client side\n const clientPath: SyncPathDto = syncPathsDto.find((p) => p.id === serverPath.id)\n // remotePath and permissions settings are only managed by server\n const updateClientInfo: { remotePath?: string; permissions?: string } = {\n ...(serverPath.remotePath !== clientPath.remotePath && { remotePath: serverPath.remotePath }),\n ...(space.envPermissions !== clientPath.permissions && { permissions: space.envPermissions })\n }\n const clientNewer = clientPath.timestamp > serverPath.settings.timestamp\n const serverNewer = clientPath.timestamp < serverPath.settings.timestamp\n const hasUpdates = Object.keys(updateClientInfo).length > 0\n\n let updatedSettings: SyncPathSettings = { ...serverPath.settings, ...updateClientInfo }\n\n if (clientNewer) {\n updatedSettings = { ...clientPath, ...updateClientInfo }\n } else if (serverNewer) {\n clientDiff.update.push({ id: clientPath.id, ...serverPath.settings, ...updateClientInfo })\n }\n\n if (clientNewer || hasUpdates || serverPath.settings.lastSync !== clientPath.lastSync) {\n this.syncQueries\n .updatePathSettings(user.clientId, clientPath.id, { ...updatedSettings, lastSync: clientPath.lastSync })\n .catch((e: Error) => this.logger.error(`${this.updatePaths.name} - ${e}`))\n }\n\n if (!clientNewer && hasUpdates) {\n clientDiff.update.push({ id: clientPath.id, ...updateClientInfo })\n }\n }\n // path does not exist on server side\n clientDiff.delete = clientPathIds.filter((cid) => serverPathIds.indexOf(cid) === -1)\n for (const cPathId of clientDiff.delete) {\n const cPath: SyncPathDto = syncPathsDto.find((p) => p.id === cPathId)\n this.notify(user.id, ACTION.DELETE, cPath.remotePath).catch((e: Error) => this.logger.error(`${this.updatePaths.name} - ${e}`))\n }\n // clear cache\n clientDiff.update.forEach((path) => this.syncQueries.clearCachePathSettings(user.clientId, path.id))\n return clientDiff\n }\n\n private async getDBProps(space: SpaceEnv): Promise<SyncDBProps> {\n if (space.inSharesList) {\n throw new HttpException('Sync all shares is not supported, you must select a sub-directory', HttpStatus.BAD_REQUEST)\n } else if (space.inPersonalSpace) {\n if (space.paths.length) {\n return { ownerId: space.dbFile.ownerId, fileId: await this.getOrCreateFileId(space) }\n } else {\n return { ownerId: space.dbFile.ownerId }\n }\n } else if (space.inFilesRepository) {\n if (!space?.root?.alias) {\n // The synchronization direction should be adapted for each root depending on the permissions, this is not yet supported\n throw new HttpException('Sync all space is not yet supported, you must select a sub-directory', HttpStatus.BAD_REQUEST)\n }\n if (space.root.id && !space.paths.length) {\n return { spaceId: space.id, spaceRootId: space.root.id }\n } else {\n return { spaceId: space.id, spaceRootId: space?.root?.id || null, fileId: await this.getOrCreateFileId(space) }\n }\n } else if (space.inSharesRepository) {\n if (space.paths.length) {\n return { shareId: space.id, fileId: await this.getOrCreateFileId(space) }\n } else {\n return { shareId: space.id }\n }\n }\n }\n\n private async getOrCreateFileId(space: SpaceEnv): Promise<number> {\n const fileProps: FileProps = await getProps(space.realPath, space.dbFile.path)\n let fileId: number = await this.filesQueries.getSpaceFileId(fileProps, space.dbFile)\n if (!fileId) {\n fileId = await this.filesQueries.getOrCreateSpaceFile(fileId, { ...fileProps, id: undefined }, space.dbFile)\n }\n return fileId\n }\n\n private async notify(userId: number, action: ACTION, remotePath: string) {\n const notification: NotificationContent = {\n app: NOTIFICATION_APP.SYNC,\n event: NOTIFICATION_APP_EVENT.SYNC[action],\n element: remotePath,\n url: [...SYNC_PATH_REPOSITORY[remotePath.split('/').at(0)], ...remotePath.split('/').slice(1, -1)].join('/')\n }\n this.notificationsManager\n .create([userId], notification, {\n currentUrl: this.contextManager.get('headerOriginUrl'),\n action: action\n })\n .catch((e: Error) => this.logger.error(`${this.notify.name} - ${e}`))\n }\n}\n"],"names":["SyncPathsManager","createPath","req","syncPathDto","user","clientId","HttpException","HttpStatus","BAD_REQUEST","space","quotaIsExceeded","INSUFFICIENT_STORAGE","isPathExists","realPath","remotePath","NOT_FOUND","isPathIsDir","client","syncQueries","getClient","id","syncDBProps","getDBProps","params","permissions","getEnvPermissions","root","pathId","deletePath","clientExistsForOwner","FORBIDDEN","e","logger","error","name","updatePath","syncPathUpdateDto","syncPathSettings","getPathSettings","Object","assign","timestamp","currentTimeStamp","updatePathSettings","INTERNAL_SERVER_ERROR","clearCachePathSettings","updatePaths","syncPathsDto","clientPathIds","map","p","serverPathIds","clientDiff","add","update","delete","serverPaths","getPaths","serverPath","spacesManager","spaceEnv","SYNC_PATH_TO_SPACE_SEGMENTS","message","push","indexOf","settings","envPermissions","clientPath","find","updateClientInfo","clientNewer","serverNewer","hasUpdates","keys","length","updatedSettings","lastSync","catch","filter","cid","cPathId","cPath","notify","ACTION","DELETE","forEach","path","inSharesList","inPersonalSpace","paths","ownerId","dbFile","fileId","getOrCreateFileId","inFilesRepository","alias","spaceId","spaceRootId","inSharesRepository","shareId","fileProps","getProps","filesQueries","getSpaceFileId","getOrCreateSpaceFile","undefined","userId","action","notification","app","NOTIFICATION_APP","SYNC","event","NOTIFICATION_APP_EVENT","element","url","SYNC_PATH_REPOSITORY","split","at","slice","join","notificationsManager","create","currentUrl","contextManager","get","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAyBYA;;;eAAAA;;;wBAvBiD;2BACvC;wBACU;uCACF;qCAEF;uBACuB;+BACK;6CAEpB;sCAGP;6BACI;sBAEG;wBAIO;oCAChB;;;;;;;;;;AAGrB,IAAA,AAAMA,mBAAN,MAAMA;IAWX,MAAMC,WAAWC,GAAwB,EAAEC,WAAwB,EAAgD;QACjH,IAAI,CAACD,IAAIE,IAAI,CAACC,QAAQ,EAAE;YACtB,MAAM,IAAIC,qBAAa,CAAC,wBAAwBC,kBAAU,CAACC,WAAW;QACxE;QACA,IAAIN,IAAIO,KAAK,CAACC,eAAe,EAAE;YAC7B,MAAM,IAAIJ,qBAAa,CAAC,0BAA0BC,kBAAU,CAACI,oBAAoB;QACnF;QACA,IAAI,CAAE,MAAMC,IAAAA,mBAAY,EAACV,IAAIO,KAAK,CAACI,QAAQ,GAAI;YAC7C,MAAM,IAAIP,qBAAa,CAAC,CAAC,wBAAwB,EAAEH,YAAYW,UAAU,EAAE,EAAEP,kBAAU,CAACQ,SAAS;QACnG;QACA,IAAI,CAAE,MAAMC,IAAAA,kBAAW,EAACd,IAAIO,KAAK,CAACI,QAAQ,GAAI;YAC5C,MAAM,IAAIP,qBAAa,CAAC,mCAAmCC,kBAAU,CAACC,WAAW;QACnF;QACA,MAAMS,SAAqB,MAAM,IAAI,CAACC,WAAW,CAACC,SAAS,CAACjB,IAAIE,IAAI,CAACC,QAAQ,EAAEH,IAAIE,IAAI,CAACgB,EAAE;QAC1F,IAAI,CAACH,QAAQ;YACX,MAAM,IAAIX,qBAAa,CAAC,oBAAoBC,kBAAU,CAACQ,SAAS;QAClE;QACA,MAAMM,cAA2B,MAAM,IAAI,CAACC,UAAU,CAACpB,IAAIO,KAAK;QAEhE,+DAA+D;QAC/DN,YAAYW,UAAU,GAAGZ,IAAIqB,MAAM,CAAC,IAAI;QACxC,qEAAqE;QACrEpB,YAAYqB,WAAW,GAAGC,IAAAA,8BAAiB,EAACvB,IAAIO,KAAK,EAAEP,IAAIO,KAAK,CAACiB,IAAI;QACrE,MAAMC,SAAS,MAAM,IAAI,CAACT,WAAW,CAACjB,UAAU,CAACgB,OAAOG,EAAE,EAAEC,aAAalB;QACzE,OAAO;YAAEiB,IAAIO;YAAQH,aAAarB,YAAYqB,WAAW;QAAC;IAC5D;IAEA,MAAMI,WAAWxB,IAAe,EAAEuB,MAAc,EAAEtB,QAAiB,EAAiB;QAClFA,WAAWD,KAAKC,QAAQ,IAAIA;QAC5B,IAAI,CAACA,UAAU;YACb,MAAM,IAAIC,qBAAa,CAAC,wBAAwBC,kBAAU,CAACC,WAAW;QACxE;QACA,IAAI,CAAE,MAAM,IAAI,CAACU,WAAW,CAACW,oBAAoB,CAACzB,KAAKgB,EAAE,EAAEf,WAAY;YACrE,MAAM,IAAIC,qBAAa,CAAC,yCAAyCC,kBAAU,CAACuB,SAAS;QACvF;QACA,IAAI;YACF,MAAM,IAAI,CAACZ,WAAW,CAACU,UAAU,CAACvB,UAAUsB;QAC9C,EAAE,OAAOI,GAAG;YACV,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACL,UAAU,CAACM,IAAI,CAAC,GAAG,EAAEH,GAAG;YAClD,MAAM,IAAIzB,qBAAa,CAAC,yBAAyBC,kBAAU,CAACC,WAAW;QACzE;IACF;IAEA,MAAM2B,WAAW/B,IAAe,EAAEC,QAAgB,EAAEsB,MAAc,EAAES,iBAAoC,EAA6B;QACnI,IAAI,CAAE,MAAM,IAAI,CAAClB,WAAW,CAACW,oBAAoB,CAACzB,KAAKgB,EAAE,EAAEf,WAAY;YACrE,MAAM,IAAIC,qBAAa,CAAC,yCAAyCC,kBAAU,CAACuB,SAAS;QACvF;QACA,MAAMO,mBAAqC,MAAM,IAAI,CAACnB,WAAW,CAACoB,eAAe,CAACjC,UAAUsB;QAC5F,IAAI,CAACU,kBAAkB;YACrB,MAAM,IAAI/B,qBAAa,CAAC,uBAAuBC,kBAAU,CAACQ,SAAS;QACrE;QACA,qBAAqB;QACrB,OAAOqB,kBAAkBhB,EAAE;QAC3B,+BAA+B;QAC/BmB,OAAOC,MAAM,CAACH,kBAAkBD;QAChCC,iBAAiBI,SAAS,GAAGC,IAAAA,wBAAgB;QAC7C,IAAI;YACF,MAAM,IAAI,CAACxB,WAAW,CAACyB,kBAAkB,CAACtC,UAAUsB,QAAQU;QAC9D,EAAE,OAAON,GAAG;YACV,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACE,UAAU,CAACD,IAAI,CAAC,GAAG,EAAEH,GAAG;YAClD,MAAM,IAAIzB,qBAAa,CAAC,yBAAyBC,kBAAU,CAACqC,qBAAqB;QACnF,SAAU;YACR,cAAc;YACd,IAAI,CAAC1B,WAAW,CAAC2B,sBAAsB,CAACxC,UAAUsB;QACpD;QACA,OAAOU;IACT;IAEA,MAAMS,YACJ1C,IAAe,EACf2C,YAA2B,EAK1B;QACD,qCAAqC,GACrC,IAAI,CAAC3C,KAAKC,QAAQ,EAAE;YAClB,MAAM,IAAIC,qBAAa,CAAC,wBAAwBC,kBAAU,CAACC,WAAW;QACxE;QACA,IAAI,CAAE,MAAM,IAAI,CAACU,WAAW,CAACW,oBAAoB,CAACzB,KAAKgB,EAAE,EAAEhB,KAAKC,QAAQ,GAAI;YAC1E,MAAM,IAAIC,qBAAa,CAAC,yCAAyCC,kBAAU,CAACuB,SAAS;QACvF;QACA,MAAMkB,gBAA0BD,aAAaE,GAAG,CAAC,CAACC,IAAMA,EAAE9B,EAAE;QAC5D,MAAM+B,gBAA0B,EAAE;QAElC,MAAMC,aAAoH;YACxHC,KAAK,EAAE;YACPC,QAAQ,EAAE;YACVC,QAAQ,EAAE;QACZ;QACA,MAAMC,cAAgF,MAAM,IAAI,CAACtC,WAAW,CAACuC,QAAQ,CAACrD,KAAKC,QAAQ;QACnI,KAAK,MAAMqD,cAAcF,YAAa;YACpC,IAAI,CAACE,WAAW5C,UAAU,EAAE;gBAE1B;YACF;YACA,IAAIL;YACJ,IAAI;gBACFA,QAAQ,MAAM,IAAI,CAACkD,aAAa,CAACC,QAAQ,CAACxD,MAAMyD,IAAAA,mCAA2B,EAACH,WAAW5C,UAAU,GAAG;YACtG,EAAE,OAAOiB,GAAG;gBACV,MAAM,IAAIzB,qBAAa,CAACyB,EAAE+B,OAAO,EAAEvD,kBAAU,CAACC,WAAW;YAC3D;YACA,IAAI,CAACC,OAAO;gBAEV;YACF;YACA0C,cAAcY,IAAI,CAACL,WAAWtC,EAAE;YAChC,IAAI4B,cAAcgB,OAAO,CAACN,WAAWtC,EAAE,MAAM,CAAC,GAAG;gBAC/C,4DAA4D;gBAC5DgC,WAAWC,GAAG,CAACU,IAAI,CAAC;oBAAE,GAAGL,WAAWO,QAAQ;oBAAE7C,IAAIsC,WAAWtC,EAAE;oBAAEN,YAAY4C,WAAW5C,UAAU;oBAAEU,aAAaf,MAAMyD,cAAc;gBAAC;gBACtI;YACF;YAEA,6CAA6C;YAC7C,MAAMC,aAA0BpB,aAAaqB,IAAI,CAAC,CAAClB,IAAMA,EAAE9B,EAAE,KAAKsC,WAAWtC,EAAE;YAC/E,iEAAiE;YACjE,MAAMiD,mBAAkE;gBACtE,GAAIX,WAAW5C,UAAU,KAAKqD,WAAWrD,UAAU,IAAI;oBAAEA,YAAY4C,WAAW5C,UAAU;gBAAC,CAAC;gBAC5F,GAAIL,MAAMyD,cAAc,KAAKC,WAAW3C,WAAW,IAAI;oBAAEA,aAAaf,MAAMyD,cAAc;gBAAC,CAAC;YAC9F;YACA,MAAMI,cAAcH,WAAW1B,SAAS,GAAGiB,WAAWO,QAAQ,CAACxB,SAAS;YACxE,MAAM8B,cAAcJ,WAAW1B,SAAS,GAAGiB,WAAWO,QAAQ,CAACxB,SAAS;YACxE,MAAM+B,aAAajC,OAAOkC,IAAI,CAACJ,kBAAkBK,MAAM,GAAG;YAE1D,IAAIC,kBAAoC;gBAAE,GAAGjB,WAAWO,QAAQ;gBAAE,GAAGI,gBAAgB;YAAC;YAEtF,IAAIC,aAAa;gBACfK,kBAAkB;oBAAE,GAAGR,UAAU;oBAAE,GAAGE,gBAAgB;gBAAC;YACzD,OAAO,IAAIE,aAAa;gBACtBnB,WAAWE,MAAM,CAACS,IAAI,CAAC;oBAAE3C,IAAI+C,WAAW/C,EAAE;oBAAE,GAAGsC,WAAWO,QAAQ;oBAAE,GAAGI,gBAAgB;gBAAC;YAC1F;YAEA,IAAIC,eAAeE,cAAcd,WAAWO,QAAQ,CAACW,QAAQ,KAAKT,WAAWS,QAAQ,EAAE;gBACrF,IAAI,CAAC1D,WAAW,CACbyB,kBAAkB,CAACvC,KAAKC,QAAQ,EAAE8D,WAAW/C,EAAE,EAAE;oBAAE,GAAGuD,eAAe;oBAAEC,UAAUT,WAAWS,QAAQ;gBAAC,GACrGC,KAAK,CAAC,CAAC9C,IAAa,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACa,WAAW,CAACZ,IAAI,CAAC,GAAG,EAAEH,GAAG;YAC5E;YAEA,IAAI,CAACuC,eAAeE,YAAY;gBAC9BpB,WAAWE,MAAM,CAACS,IAAI,CAAC;oBAAE3C,IAAI+C,WAAW/C,EAAE;oBAAE,GAAGiD,gBAAgB;gBAAC;YAClE;QACF;QACA,qCAAqC;QACrCjB,WAAWG,MAAM,GAAGP,cAAc8B,MAAM,CAAC,CAACC,MAAQ5B,cAAca,OAAO,CAACe,SAAS,CAAC;QAClF,KAAK,MAAMC,WAAW5B,WAAWG,MAAM,CAAE;YACvC,MAAM0B,QAAqBlC,aAAaqB,IAAI,CAAC,CAAClB,IAAMA,EAAE9B,EAAE,KAAK4D;YAC7D,IAAI,CAACE,MAAM,CAAC9E,KAAKgB,EAAE,EAAE+D,iBAAM,CAACC,MAAM,EAAEH,MAAMnE,UAAU,EAAE+D,KAAK,CAAC,CAAC9C,IAAa,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACa,WAAW,CAACZ,IAAI,CAAC,GAAG,EAAEH,GAAG;QAC/H;QACA,cAAc;QACdqB,WAAWE,MAAM,CAAC+B,OAAO,CAAC,CAACC,OAAS,IAAI,CAACpE,WAAW,CAAC2B,sBAAsB,CAACzC,KAAKC,QAAQ,EAAEiF,KAAKlE,EAAE;QAClG,OAAOgC;IACT;IAEA,MAAc9B,WAAWb,KAAe,EAAwB;QAC9D,IAAIA,MAAM8E,YAAY,EAAE;YACtB,MAAM,IAAIjF,qBAAa,CAAC,qEAAqEC,kBAAU,CAACC,WAAW;QACrH,OAAO,IAAIC,MAAM+E,eAAe,EAAE;YAChC,IAAI/E,MAAMgF,KAAK,CAACf,MAAM,EAAE;gBACtB,OAAO;oBAAEgB,SAASjF,MAAMkF,MAAM,CAACD,OAAO;oBAAEE,QAAQ,MAAM,IAAI,CAACC,iBAAiB,CAACpF;gBAAO;YACtF,OAAO;gBACL,OAAO;oBAAEiF,SAASjF,MAAMkF,MAAM,CAACD,OAAO;gBAAC;YACzC;QACF,OAAO,IAAIjF,MAAMqF,iBAAiB,EAAE;YAClC,IAAI,CAACrF,OAAOiB,MAAMqE,OAAO;gBACvB,wHAAwH;gBACxH,MAAM,IAAIzF,qBAAa,CAAC,wEAAwEC,kBAAU,CAACC,WAAW;YACxH;YACA,IAAIC,MAAMiB,IAAI,CAACN,EAAE,IAAI,CAACX,MAAMgF,KAAK,CAACf,MAAM,EAAE;gBACxC,OAAO;oBAAEsB,SAASvF,MAAMW,EAAE;oBAAE6E,aAAaxF,MAAMiB,IAAI,CAACN,EAAE;gBAAC;YACzD,OAAO;gBACL,OAAO;oBAAE4E,SAASvF,MAAMW,EAAE;oBAAE6E,aAAaxF,OAAOiB,MAAMN,MAAM;oBAAMwE,QAAQ,MAAM,IAAI,CAACC,iBAAiB,CAACpF;gBAAO;YAChH;QACF,OAAO,IAAIA,MAAMyF,kBAAkB,EAAE;YACnC,IAAIzF,MAAMgF,KAAK,CAACf,MAAM,EAAE;gBACtB,OAAO;oBAAEyB,SAAS1F,MAAMW,EAAE;oBAAEwE,QAAQ,MAAM,IAAI,CAACC,iBAAiB,CAACpF;gBAAO;YAC1E,OAAO;gBACL,OAAO;oBAAE0F,SAAS1F,MAAMW,EAAE;gBAAC;YAC7B;QACF;IACF;IAEA,MAAcyE,kBAAkBpF,KAAe,EAAmB;QAChE,MAAM2F,YAAuB,MAAMC,IAAAA,eAAQ,EAAC5F,MAAMI,QAAQ,EAAEJ,MAAMkF,MAAM,CAACL,IAAI;QAC7E,IAAIM,SAAiB,MAAM,IAAI,CAACU,YAAY,CAACC,cAAc,CAACH,WAAW3F,MAAMkF,MAAM;QACnF,IAAI,CAACC,QAAQ;YACXA,SAAS,MAAM,IAAI,CAACU,YAAY,CAACE,oBAAoB,CAACZ,QAAQ;gBAAE,GAAGQ,SAAS;gBAAEhF,IAAIqF;YAAU,GAAGhG,MAAMkF,MAAM;QAC7G;QACA,OAAOC;IACT;IAEA,MAAcV,OAAOwB,MAAc,EAAEC,MAAc,EAAE7F,UAAkB,EAAE;QACvE,MAAM8F,eAAoC;YACxCC,KAAKC,+BAAgB,CAACC,IAAI;YAC1BC,OAAOC,qCAAsB,CAACF,IAAI,CAACJ,OAAO;YAC1CO,SAASpG;YACTqG,KAAK;mBAAIC,0BAAoB,CAACtG,WAAWuG,KAAK,CAAC,KAAKC,EAAE,CAAC,GAAG;mBAAKxG,WAAWuG,KAAK,CAAC,KAAKE,KAAK,CAAC,GAAG,CAAC;aAAG,CAACC,IAAI,CAAC;QAC1G;QACA,IAAI,CAACC,oBAAoB,CACtBC,MAAM,CAAC;YAAChB;SAAO,EAAEE,cAAc;YAC9Be,YAAY,IAAI,CAACC,cAAc,CAACC,GAAG,CAAC;YACpClB,QAAQA;QACV,GACC9B,KAAK,CAAC,CAAC9C,IAAa,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACiD,MAAM,CAAChD,IAAI,CAAC,GAAG,EAAEH,GAAG;IACvE;IApNA,YACE,AAAiB6F,cAA8B,EAC/C,AAAiBjE,aAA4B,EAC7C,AAAiB2C,YAA0B,EAC3C,AAAiBpF,WAAwB,EACzC,AAAiBuG,oBAA0C,CAC3D;aALiBG,iBAAAA;aACAjE,gBAAAA;aACA2C,eAAAA;aACApF,cAAAA;aACAuG,uBAAAA;aAPFzF,SAAS,IAAI8F,cAAM,CAAC9H,iBAAiBkC,IAAI;IAQvD;AA+ML"}
@@ -173,7 +173,7 @@ describe(_syncpathsmanagerservice.SyncPathsManager.name, ()=>{
173
173
  message: 'Client id is missing'
174
174
  });
175
175
  });
176
- it('should throw INSUFFICIENT_STORAGE when space quota is exceeded', async ()=>{
176
+ it('should throw INSUFFICIENT_STORAGE when storage quota is exceeded', async ()=>{
177
177
  const req = baseReq();
178
178
  req.space.quotaIsExceeded = true;
179
179
  await expect(service.createPath(req, {