@sync-in/server 1.3.9 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +5 -3
- package/environment/environment.dist.yaml +2 -0
- package/package.json +6 -6
- package/server/app.bootstrap.js +9 -0
- package/server/app.bootstrap.js.map +1 -1
- package/server/app.service.spec.js +44 -19
- package/server/app.service.spec.js.map +1 -1
- package/server/applications/comments/comments.controller.spec.js +103 -4
- package/server/applications/comments/comments.controller.spec.js.map +1 -1
- package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
- package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
- package/server/applications/files/constants/files.js +0 -23
- package/server/applications/files/constants/files.js.map +1 -1
- package/server/applications/files/constants/only-office.js +8 -0
- package/server/applications/files/constants/only-office.js.map +1 -1
- package/server/applications/files/constants/routes.js +6 -1
- package/server/applications/files/constants/routes.js.map +1 -1
- package/server/applications/files/files-only-office.controller.js +11 -0
- package/server/applications/files/files-only-office.controller.js.map +1 -1
- package/server/applications/files/files-only-office.controller.spec.js +97 -3
- package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
- package/server/applications/files/files-tasks.controller.spec.js +91 -1
- package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
- package/server/applications/files/files.config.js +5 -0
- package/server/applications/files/files.config.js.map +1 -1
- package/server/applications/files/files.controller.spec.js +268 -46
- package/server/applications/files/files.controller.spec.js.map +1 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
- package/server/applications/files/guards/files-only-office.strategy.js +0 -1
- package/server/applications/files/guards/files-only-office.strategy.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +5 -0
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/links/links.controller.spec.js +91 -58
- package/server/applications/links/links.controller.spec.js.map +1 -1
- package/server/applications/links/services/links-manager.service.js +4 -6
- package/server/applications/links/services/links-manager.service.js.map +1 -1
- package/server/applications/links/services/links-manager.service.spec.js +378 -14
- package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
- package/server/applications/links/services/links-queries.service.js +1 -1
- package/server/applications/links/services/links-queries.service.js.map +1 -1
- package/server/applications/notifications/notifications.controller.spec.js +56 -1
- package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
- package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
- package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
- package/server/applications/spaces/guards/space.guard.spec.js +153 -18
- package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
- package/server/applications/spaces/services/spaces-browser.service.js +7 -7
- package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
- package/server/applications/spaces/services/spaces-manager.service.js +17 -17
- package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
- package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
- package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
- package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
- package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
- package/server/applications/sync/utils/routes.js +1 -1
- package/server/applications/sync/utils/routes.js.map +1 -1
- package/server/applications/users/guards/permissions.guard.js +4 -4
- package/server/applications/users/guards/permissions.guard.js.map +1 -1
- package/server/applications/users/guards/permissions.guard.spec.js +6 -6
- package/server/applications/users/guards/permissions.guard.spec.js.map +1 -1
- package/server/applications/users/guards/roles.guard.js +1 -1
- package/server/applications/users/guards/roles.guard.js.map +1 -1
- package/server/applications/users/models/user.model.js +1 -1
- package/server/applications/users/models/user.model.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +22 -24
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +1 -1
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +938 -49
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
- package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
- package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
- package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
- package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
- package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
- package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
- package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
- package/server/applications/webdav/webdav.controller.js +2 -2
- package/server/applications/webdav/webdav.controller.js.map +1 -1
- package/server/authentication/guards/auth-basic.guard.js.map +1 -1
- package/server/authentication/guards/auth-basic.guard.spec.js +38 -2
- package/server/authentication/guards/auth-basic.guard.spec.js.map +1 -1
- package/server/authentication/guards/auth-basic.strategy.js +0 -1
- package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
- package/server/authentication/guards/auth-digest.guard.js +1 -2
- package/server/authentication/guards/auth-digest.guard.js.map +1 -1
- package/server/authentication/guards/auth-local.guard.js.map +1 -1
- package/server/authentication/guards/auth-local.guard.spec.js +7 -5
- package/server/authentication/guards/auth-local.guard.spec.js.map +1 -1
- package/server/authentication/guards/auth-local.strategy.js +0 -1
- package/server/authentication/guards/auth-local.strategy.js.map +1 -1
- package/server/authentication/guards/auth-token-access.guard.spec.js +30 -0
- package/server/authentication/guards/auth-token-access.guard.spec.js.map +1 -1
- package/server/authentication/guards/auth-token-access.strategy.js +0 -1
- package/server/authentication/guards/auth-token-access.strategy.js.map +1 -1
- package/server/authentication/guards/auth-token-refresh.strategy.js +0 -1
- package/server/authentication/guards/auth-token-refresh.strategy.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-database.service.js +1 -1
- package/server/authentication/services/auth-methods/auth-method-database.service.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-database.service.spec.js +8 -6
- package/server/authentication/services/auth-methods/auth-method-database.service.spec.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-ldap.service.js +2 -2
- package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +500 -5
- package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
- package/server/configuration/config.loader.js +0 -3
- package/server/configuration/config.loader.js.map +1 -1
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
- package/server/infrastructure/context/services/context-manager.service.spec.js +98 -0
- package/server/infrastructure/context/services/context-manager.service.spec.js.map +1 -0
- package/server/infrastructure/database/constants.js +0 -1
- package/server/infrastructure/database/constants.js.map +1 -1
- package/server/infrastructure/database/scripts/seed/usersgroups.js +3 -3
- package/server/infrastructure/database/scripts/seed/usersgroups.js.map +1 -1
- package/server/infrastructure/mailer/mailer.service.js +20 -19
- package/server/infrastructure/mailer/mailer.service.js.map +1 -1
- package/server/infrastructure/mailer/mailer.service.spec.js +176 -0
- package/server/infrastructure/mailer/mailer.service.spec.js.map +1 -0
- package/static/3rdpartylicenses.txt +26 -26
- package/static/assets/pdfjs/build/pdf.mjs +1177 -255
- package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
- package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
- package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
- package/static/assets/pdfjs/version +1 -1
- package/static/assets/pdfjs/web/debugger.css +31 -0
- package/static/assets/pdfjs/web/debugger.mjs +144 -2
- package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
- package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
- package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
- package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
- package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
- package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
- package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
- package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
- package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
- package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
- package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
- package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
- package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
- package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
- package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
- package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
- package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
- package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
- package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
- package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
- package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
- package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
- package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
- package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/viewer.css +649 -120
- package/static/assets/pdfjs/web/viewer.html +19 -0
- package/static/assets/pdfjs/web/viewer.mjs +489 -38
- package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
- package/static/chunk-22EANI6R.js +1 -0
- package/static/{chunk-KFM544CA.js → chunk-2UWN7IQF.js} +1 -1
- package/static/{chunk-N3T57OCA.js → chunk-2VSPDSJS.js} +1 -1
- package/static/{chunk-HUWQHCUX.js → chunk-34UZ7SYI.js} +1 -1
- package/static/{chunk-MWFRZBJD.js → chunk-45UQJGGY.js} +1 -1
- package/static/{chunk-LYTD6AJE.js → chunk-5TEXH3LJ.js} +1 -1
- package/static/{chunk-4KESSWTF.js → chunk-66FMKVJX.js} +1 -1
- package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
- package/static/chunk-CK4BY2NX.js +27 -0
- package/static/{chunk-QTW62OKJ.js → chunk-CSBDAY77.js} +1 -1
- package/static/{chunk-XUZSYWRF.js → chunk-CXXPLBDZ.js} +1 -1
- package/static/{chunk-ZTXJC5IC.js → chunk-EILQG525.js} +1 -1
- package/static/{chunk-FJFNDK67.js → chunk-ENWABUR4.js} +1 -1
- package/static/{chunk-WL65GYD5.js → chunk-FR4AOLYL.js} +4 -4
- package/static/chunk-HW2H3ISM.js +559 -0
- package/static/{chunk-BW5PQAKK.js → chunk-HYMDGBZL.js} +1 -1
- package/static/{chunk-WLPYIJFI.js → chunk-IML5UYQG.js} +1 -1
- package/static/{chunk-Z5X7LVMZ.js → chunk-IPSMJHMQ.js} +1 -1
- package/static/{chunk-3S4WNZ2T.js → chunk-JVCWYSNP.js} +1 -1
- package/static/{chunk-CLSVDV7J.js → chunk-KGPCIUD2.js} +1 -1
- package/static/{chunk-O4AQBQBF.js → chunk-KQZJSEM3.js} +1 -1
- package/static/{chunk-MK7WZG3F.js → chunk-NPEMJJIU.js} +1 -1
- package/static/{chunk-4TEHM3AS.js → chunk-OEFBC4GG.js} +1 -1
- package/static/{chunk-O67RFAWU.js → chunk-P734A3XZ.js} +1 -1
- package/static/{chunk-SRLMFJ7C.js → chunk-RASR4CK6.js} +1 -1
- package/static/{chunk-S5WXHO6D.js → chunk-RFMOUC22.js} +1 -1
- package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
- package/static/{chunk-3FX6ISDY.js → chunk-SBOQGGZX.js} +1 -1
- package/static/{chunk-NV2MEIWP.js → chunk-SJAFPXQV.js} +1 -1
- package/static/{chunk-PYSFXLMV.js → chunk-XTYGMF2V.js} +1 -1
- package/static/{chunk-ZFKCGL6X.js → chunk-YCWMV2YR.js} +1 -1
- package/static/{chunk-LB7B5RIV.js → chunk-YGD22MWQ.js} +1 -1
- package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
- package/static/{chunk-SKDQM65G.js → chunk-ZVY37DKS.js} +1 -1
- package/static/index.html +2 -2
- package/static/main-N5CZRHAO.js +7 -0
- package/static/styles-FYUSO6OJ.css +1 -0
- package/static/chunk-AY2GOSJ2.js +0 -24
- package/static/chunk-RSNLYAN6.js +0 -560
- package/static/chunk-ZZ3LHYOY.js +0 -1
- package/static/main-RREKR34B.js +0 -10
- package/static/styles-3DONJ2Z4.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
|
|
2
|
+
## [1.5.0](https://github.com/Sync-in/server/compare/v1.4.0...v1.5.0) (2025-09-07)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **files:** optimize document opening to avoid extra API calls ([bf57d93](https://github.com/Sync-in/server/commit/bf57d93dcaea312328db9f1f5290e46471d2f638))
|
|
8
|
+
* **frontend:files:** display count for multiple selected files and open sidebar pasteboard when adding files ([39feccd](https://github.com/Sync-in/server/commit/39feccd3d89f29cdc4effb2bb4c016c7c1258729))
|
|
9
|
+
* **frontend:spaces:** enable keyboard navigation when files are selected in list mode ([7e38ce2](https://github.com/Sync-in/server/commit/7e38ce29fbfe11b84ccd7824aea1e43ae46e0d0f))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* **backend:links:** increment nbAccess even when no limit is set ([d6d2e74](https://github.com/Sync-in/server/commit/d6d2e7425c16510ee9e15107a02f21d2038be89f))
|
|
15
|
+
* **frontend:spaces:** prevent false positives when checking external location ([f1fdd0d](https://github.com/Sync-in/server/commit/f1fdd0d4088e98f4e24f4a4c18cf6f67e3e5d0d4))
|
|
16
|
+
|
|
17
|
+
### Performance
|
|
18
|
+
* **docker:** only change application data ownership ([6e88991](https://github.com/Sync-in/server/commit/6e889915fedf613030e43919e637d7888aea94a1))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## [1.4.0](https://github.com/Sync-in/server/compare/v1.3.9...v1.4.0) (2025-08-26)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* **backend:webdav:** add temporary hook for Joplin sync compatibility (laurent22/joplin[#12249](https://github.com/Sync-in/server/issues/12249)) ([fc22a7d](https://github.com/Sync-in/server/commit/fc22a7d828f99abe65423d03418fe397ab45d7b0))
|
|
27
|
+
* **backend:files:** add showHiddenFiles option to toggle visibility of dotfiles ([ed47fbf](https://github.com/Sync-in/server/commit/ed47fbf3fe7fe5b66868489c319d3c438fde0dbf))
|
|
28
|
+
* **backend:files:** allow markdown files to be edited with onlyOffice ([c3d9d85](https://github.com/Sync-in/server/commit/c3d9d85d3f1dc90f4afae8db8ce9d128c8ecadf2))
|
|
29
|
+
* **frontend:spaces:** open documents in edit mode on double-click ([d6ef175](https://github.com/Sync-in/server/commit/d6ef175d951b4e11ce78d280e4982e3ed8a4bb3f))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* **backend:users:** ensure permission guards correctly evaluate array permissions ([c27dc7b](https://github.com/Sync-in/server/commit/c27dc7b7ac20293febca17d18ae8608d61eb1b44))
|
|
35
|
+
|
|
2
36
|
## [1.3.9](https://github.com/Sync-in/server/compare/v1.3.8...v1.3.9) (2025-08-22)
|
|
3
37
|
|
|
4
38
|
|
package/README.md
CHANGED
|
@@ -14,9 +14,11 @@ _Welcome to the official Sync-in server repository!_
|
|
|
14
14
|
- 📦 [Deploy with NPM](https://sync-in.com/docs/setup-guide/npm)
|
|
15
15
|
|
|
16
16
|
<a href="#-license"><img src="https://img.shields.io/badge/Licence-AGPL%20v3.0-green.svg" alt="License"/></a>
|
|
17
|
-
<a href="https://
|
|
18
|
-
<a href="https://www.npmjs.com/package/@sync-in/server" target="_blank"><img src="https://img.shields.io/npm/d18m/@sync-in/server.svg?logo=npm&label=NPM%20Downloads&color=cb3837" alt="NPM"/></a>
|
|
17
|
+
<a href="https://github.com/Sync-in/server/releases" target="_blank"><img src="https://img.shields.io/github/v/release/Sync-in/server?sort=semver&display_name=tag&style=flat&logo=github&label=Release" alt="GitHub Release"/></a>
|
|
19
18
|
<a href="https://hub.docker.com/r/syncin/server" target="_blank"><img src="https://img.shields.io/docker/pulls/syncin/server?logo=docker&label=Docker%20Hub%20Pulls" alt="Docker pulls"/></a>
|
|
19
|
+
<a href="https://www.npmjs.com/package/@sync-in/server" target="_blank"><img src="https://img.shields.io/npm/d18m/@sync-in/server.svg?logo=npm&label=NPM%20Downloads&color=cb3837" alt="NPM"/></a>
|
|
20
|
+
<a href="https://discord.gg/qhJyzwaymT" target="_blank"><img src="https://img.shields.io/discord/1391081837849346088?logo=discord&label=Discord" alt="Discord"/></a>
|
|
21
|
+
<a href="https://deepwiki.com/Sync-in/server"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
|
|
20
22
|
|
|
21
23
|
The **Sync-in Server** is designed to run on your own infrastructure, it gives you **full control over your data** while offering a modern,
|
|
22
24
|
intuitive interface for both internal and external users.
|
|
@@ -90,7 +92,7 @@ If you find it useful, you can:
|
|
|
90
92
|
## 🤝 Contributing
|
|
91
93
|
Before submitting your pull request, please confirm the following:
|
|
92
94
|
|
|
93
|
-
- ✅ I have read and followed the [contribution guide](
|
|
95
|
+
- ✅ I have read and followed the [contribution guide](CONTRIBUTING.md).
|
|
94
96
|
- ✅ I am submitting this pull request in good faith and to help improve Sync-in.
|
|
95
97
|
|
|
96
98
|
---
|
|
@@ -81,6 +81,8 @@ applications:
|
|
|
81
81
|
dataPath: /home/sync-in
|
|
82
82
|
# Default to 5 GB if not specified
|
|
83
83
|
maxUploadSize: 5368709120
|
|
84
|
+
# Show files starting with a dot in the file explorer (default: false)
|
|
85
|
+
showHiddenFiles: false
|
|
84
86
|
onlyoffice:
|
|
85
87
|
enabled: false
|
|
86
88
|
# for an external server (e.g: https://onlyoffice.domain.com), remember the url must be accessible from browser !
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sync-in/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "The secure, open-source platform for file storage, sharing, collaboration, and sync",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Johan Legrand",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"dependencies": {
|
|
75
75
|
"@fastify/cookie": "11.0.2",
|
|
76
76
|
"@fastify/helmet": "13.0.1",
|
|
77
|
-
"@fastify/multipart": "9.
|
|
77
|
+
"@fastify/multipart": "9.2.1",
|
|
78
78
|
"@fastify/send": "4.1.0",
|
|
79
79
|
"@fastify/static": "8.2.0",
|
|
80
80
|
"@knaadh/nestjs-drizzle-mysql2": "1.2.0",
|
|
@@ -98,21 +98,21 @@
|
|
|
98
98
|
"class-validator": "0.14.2",
|
|
99
99
|
"deepmerge": "4.3.1",
|
|
100
100
|
"drizzle-kit": "0.31.4",
|
|
101
|
-
"drizzle-orm": "0.44.
|
|
101
|
+
"drizzle-orm": "0.44.5",
|
|
102
102
|
"fast-xml-parser": "5.2.5",
|
|
103
103
|
"fs-extra": "11.3.1",
|
|
104
104
|
"html-to-text": "9.0.5",
|
|
105
105
|
"js-yaml": "4.1.0",
|
|
106
106
|
"ldapts": "8.0.9",
|
|
107
107
|
"mime-types": "3.0.1",
|
|
108
|
-
"mysql2": "3.14.
|
|
108
|
+
"mysql2": "3.14.4",
|
|
109
109
|
"nestjs-pino": "4.4.0",
|
|
110
|
-
"nodemailer": "7.0.
|
|
110
|
+
"nodemailer": "7.0.6",
|
|
111
111
|
"passport-http": "0.3.0",
|
|
112
112
|
"passport-jwt": "4.0.1",
|
|
113
113
|
"passport-local": "1.0.0",
|
|
114
114
|
"passport": "0.7.0",
|
|
115
|
-
"pdfjs-dist": "5.4.
|
|
115
|
+
"pdfjs-dist": "5.4.149",
|
|
116
116
|
"pino-pretty": "13.1.1",
|
|
117
117
|
"redis": "4.7.1",
|
|
118
118
|
"sax": "1.4.1",
|
package/server/app.bootstrap.js
CHANGED
|
@@ -22,6 +22,7 @@ const _nestjspino = require("nestjs-pino");
|
|
|
22
22
|
const _appconstants = require("./app.constants");
|
|
23
23
|
const _appmodule = require("./app.module");
|
|
24
24
|
const _applicationsconstants = require("./applications/applications.constants");
|
|
25
|
+
const _routes = require("./applications/webdav/constants/routes");
|
|
25
26
|
const _configconstants = require("./configuration/config.constants");
|
|
26
27
|
const _configenvironment = require("./configuration/config.environment");
|
|
27
28
|
const _websocketadapter = require("./infrastructure/websocket/adapters/web-socket.adapter");
|
|
@@ -60,6 +61,14 @@ async function appBootstrap() {
|
|
|
60
61
|
fastifyInstance.addContentTypeParser('*', {
|
|
61
62
|
bodyLimit: 0
|
|
62
63
|
}, (_req, _payload, done)=>done(null));
|
|
64
|
+
// Joplin clients send incorrect `Content-Type` headers when syncing over WebDAV (issue: https://github.com/laurent22/joplin/issues/122499)
|
|
65
|
+
// This hook intercepts matching requests and sets `application/octet-stream` to ensure compatibility and successful sync.
|
|
66
|
+
// todo: remove it when fixed on Joplin side
|
|
67
|
+
fastifyInstance.addHook('onRequest', async (req, _reply)=>{
|
|
68
|
+
if ((req.headers['user-agent'] || '').indexOf('Joplin') !== -1 && req.originalUrl.startsWith(_routes.WEBDAV_SPACES[_routes.WEBDAV_NS.WEBDAV].route)) {
|
|
69
|
+
req.headers['content-type'] = 'application/octet-stream';
|
|
70
|
+
}
|
|
71
|
+
});
|
|
63
72
|
/* INTERCEPTORS */ app.useGlobalInterceptors(new _nestjspino.LoggerErrorInterceptor(), new _common.ClassSerializerInterceptor(app.get(_core.Reflector), {
|
|
64
73
|
excludePrefixes: [
|
|
65
74
|
'_'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../backend/src/app.bootstrap.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 fastifyCookie from '@fastify/cookie'\nimport fastifyHelmet from '@fastify/helmet'\nimport multipart from '@fastify/multipart'\nimport { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'\nimport { NestFactory, Reflector } from '@nestjs/core'\nimport { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { FastifyRequest } from 'fastify'\nimport { Logger, LoggerErrorInterceptor } from 'nestjs-pino'\nimport { CONTENT_SECURITY_POLICY } from './app.constants'\nimport { AppModule } from './app.module'\nimport { HTTP_WEBDAV_METHOD } from './applications/applications.constants'\nimport { IS_TEST_ENV, STATIC_PATH } from './configuration/config.constants'\nimport { configuration } from './configuration/config.environment'\nimport { WebSocketAdapter } from './infrastructure/websocket/adapters/web-socket.adapter'\n\nexport async function appBootstrap(): Promise<NestFastifyApplication> {\n /* APP */\n const fastifyAdapter = new FastifyAdapter({\n logger: false,\n trustProxy: configuration.server.trustProxy,\n ignoreTrailingSlash: true,\n maxParamLength: 256,\n bodyLimit: 26214400 /* 25 MB */\n })\n const app: NestFastifyApplication = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter, {\n bufferLogs: true\n })\n\n /* Fastify instance */\n const fastifyInstance = fastifyAdapter.getInstance()\n\n /* LOGGER */\n app.useLogger(IS_TEST_ENV ? ['fatal'] : app.get(Logger))\n\n /* PARSER */\n // xml body parser is used for webdav methods\n app.useBodyParser(['application/xml', 'text/xml'])\n // add webdav methods\n for (const method of Object.values(HTTP_WEBDAV_METHOD)) {\n fastifyInstance.addHttpMethod(method, { hasBody: true })\n }\n // '*' body parser allow binary data as stream (unlimited body size)\n fastifyInstance.addContentTypeParser('*', { bodyLimit: 0 }, (_req: FastifyRequest, _payload: FastifyRequest['raw'], done) => done(null))\n\n /* INTERCEPTORS */\n app.useGlobalInterceptors(\n new LoggerErrorInterceptor(),\n new ClassSerializerInterceptor(app.get(Reflector), {\n excludePrefixes: ['_']\n })\n )\n /* VALIDATION */\n app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }))\n\n /* STATIC */\n app.useStaticAssets({ root: STATIC_PATH, prefixAvoidTrailingSlash: true })\n\n /* SECURITY */\n await app.register(fastifyHelmet, { contentSecurityPolicy: CONTENT_SECURITY_POLICY(configuration.applications.files.onlyoffice.externalServer) })\n\n /* COOKIES */\n // we use csrf secret to unsign csrf cookie\n await app.register(fastifyCookie, {\n secret: configuration.auth.token.csrf.secret,\n parseOptions: {\n secure: 'auto',\n sameSite: configuration.auth.sameSite,\n httpOnly: true\n }\n })\n\n /* UPLOAD */\n await app.register(multipart, {\n preservePath: true,\n limits: { parts: Infinity, fileSize: configuration.applications.files.maxUploadSize }\n })\n\n /* WEBSOCKET */\n if (!IS_TEST_ENV) {\n const webSocketAdapter = new WebSocketAdapter(app)\n await webSocketAdapter.initAdapter()\n app.useWebSocketAdapter(webSocketAdapter)\n }\n\n return app\n}\n"],"names":["appBootstrap","fastifyAdapter","FastifyAdapter","logger","trustProxy","configuration","server","ignoreTrailingSlash","maxParamLength","bodyLimit","app","NestFactory","create","AppModule","bufferLogs","fastifyInstance","getInstance","useLogger","IS_TEST_ENV","get","Logger","useBodyParser","method","Object","values","HTTP_WEBDAV_METHOD","addHttpMethod","hasBody","addContentTypeParser","_req","_payload","done","useGlobalInterceptors","LoggerErrorInterceptor","ClassSerializerInterceptor","Reflector","excludePrefixes","useGlobalPipes","ValidationPipe","transform","whitelist","useStaticAssets","root","STATIC_PATH","prefixAvoidTrailingSlash","register","fastifyHelmet","contentSecurityPolicy","CONTENT_SECURITY_POLICY","applications","files","onlyoffice","externalServer","fastifyCookie","secret","auth","token","csrf","parseOptions","secure","sameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"AAAA;;;;CAIC;;;;+
|
|
1
|
+
{"version":3,"sources":["../../backend/src/app.bootstrap.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 fastifyCookie from '@fastify/cookie'\nimport fastifyHelmet from '@fastify/helmet'\nimport multipart from '@fastify/multipart'\nimport { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'\nimport { NestFactory, Reflector } from '@nestjs/core'\nimport { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { FastifyRequest } from 'fastify'\nimport { Logger, LoggerErrorInterceptor } from 'nestjs-pino'\nimport { CONTENT_SECURITY_POLICY } from './app.constants'\nimport { AppModule } from './app.module'\nimport { HTTP_WEBDAV_METHOD } from './applications/applications.constants'\nimport { WEBDAV_NS, WEBDAV_SPACES } from './applications/webdav/constants/routes'\nimport { IS_TEST_ENV, STATIC_PATH } from './configuration/config.constants'\nimport { configuration } from './configuration/config.environment'\nimport { WebSocketAdapter } from './infrastructure/websocket/adapters/web-socket.adapter'\n\nexport async function appBootstrap(): Promise<NestFastifyApplication> {\n /* APP */\n const fastifyAdapter = new FastifyAdapter({\n logger: false,\n trustProxy: configuration.server.trustProxy,\n ignoreTrailingSlash: true,\n maxParamLength: 256,\n bodyLimit: 26214400 /* 25 MB */\n })\n const app: NestFastifyApplication = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter, {\n bufferLogs: true\n })\n\n /* Fastify instance */\n const fastifyInstance = fastifyAdapter.getInstance()\n\n /* LOGGER */\n app.useLogger(IS_TEST_ENV ? ['fatal'] : app.get(Logger))\n\n /* PARSER */\n // xml body parser is used for webdav methods\n app.useBodyParser(['application/xml', 'text/xml'])\n // add webdav methods\n for (const method of Object.values(HTTP_WEBDAV_METHOD)) {\n fastifyInstance.addHttpMethod(method, { hasBody: true })\n }\n // '*' body parser allow binary data as stream (unlimited body size)\n fastifyInstance.addContentTypeParser('*', { bodyLimit: 0 }, (_req: FastifyRequest, _payload: FastifyRequest['raw'], done) => done(null))\n\n // Joplin clients send incorrect `Content-Type` headers when syncing over WebDAV (issue: https://github.com/laurent22/joplin/issues/122499)\n // This hook intercepts matching requests and sets `application/octet-stream` to ensure compatibility and successful sync.\n // todo: remove it when fixed on Joplin side\n fastifyInstance.addHook('onRequest', async (req, _reply) => {\n if ((req.headers['user-agent'] || '').indexOf('Joplin') !== -1 && req.originalUrl.startsWith(WEBDAV_SPACES[WEBDAV_NS.WEBDAV].route)) {\n req.headers['content-type'] = 'application/octet-stream'\n }\n })\n\n /* INTERCEPTORS */\n app.useGlobalInterceptors(\n new LoggerErrorInterceptor(),\n new ClassSerializerInterceptor(app.get(Reflector), {\n excludePrefixes: ['_']\n })\n )\n /* VALIDATION */\n app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }))\n\n /* STATIC */\n app.useStaticAssets({ root: STATIC_PATH, prefixAvoidTrailingSlash: true })\n\n /* SECURITY */\n await app.register(fastifyHelmet, { contentSecurityPolicy: CONTENT_SECURITY_POLICY(configuration.applications.files.onlyoffice.externalServer) })\n\n /* COOKIES */\n // we use csrf secret to unsign csrf cookie\n await app.register(fastifyCookie, {\n secret: configuration.auth.token.csrf.secret,\n parseOptions: {\n secure: 'auto',\n sameSite: configuration.auth.sameSite,\n httpOnly: true\n }\n })\n\n /* UPLOAD */\n await app.register(multipart, {\n preservePath: true,\n limits: { parts: Infinity, fileSize: configuration.applications.files.maxUploadSize }\n })\n\n /* WEBSOCKET */\n if (!IS_TEST_ENV) {\n const webSocketAdapter = new WebSocketAdapter(app)\n await webSocketAdapter.initAdapter()\n app.useWebSocketAdapter(webSocketAdapter)\n }\n\n return app\n}\n"],"names":["appBootstrap","fastifyAdapter","FastifyAdapter","logger","trustProxy","configuration","server","ignoreTrailingSlash","maxParamLength","bodyLimit","app","NestFactory","create","AppModule","bufferLogs","fastifyInstance","getInstance","useLogger","IS_TEST_ENV","get","Logger","useBodyParser","method","Object","values","HTTP_WEBDAV_METHOD","addHttpMethod","hasBody","addContentTypeParser","_req","_payload","done","addHook","req","_reply","headers","indexOf","originalUrl","startsWith","WEBDAV_SPACES","WEBDAV_NS","WEBDAV","route","useGlobalInterceptors","LoggerErrorInterceptor","ClassSerializerInterceptor","Reflector","excludePrefixes","useGlobalPipes","ValidationPipe","transform","whitelist","useStaticAssets","root","STATIC_PATH","prefixAvoidTrailingSlash","register","fastifyHelmet","contentSecurityPolicy","CONTENT_SECURITY_POLICY","applications","files","onlyoffice","externalServer","fastifyCookie","secret","auth","token","csrf","parseOptions","secure","sameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"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"}
|
|
@@ -15,11 +15,15 @@ const _nodeprocess = /*#__PURE__*/ _interop_require_default(require("node:proces
|
|
|
15
15
|
const _appservice = require("./app.service");
|
|
16
16
|
const _configconstants = require("./configuration/config.constants");
|
|
17
17
|
const _configenvironment = require("./configuration/config.environment");
|
|
18
|
+
const _clusteradapter = require("@socket.io/cluster-adapter");
|
|
18
19
|
function _interop_require_default(obj) {
|
|
19
20
|
return obj && obj.__esModule ? obj : {
|
|
20
21
|
default: obj
|
|
21
22
|
};
|
|
22
23
|
}
|
|
24
|
+
jest.mock('@socket.io/cluster-adapter', ()=>({
|
|
25
|
+
setupPrimary: jest.fn()
|
|
26
|
+
}));
|
|
23
27
|
describe(_appservice.AppService.name, ()=>{
|
|
24
28
|
let appService;
|
|
25
29
|
beforeAll(async ()=>{
|
|
@@ -32,36 +36,59 @@ describe(_appservice.AppService.name, ()=>{
|
|
|
32
36
|
expect(appService).toBeDefined();
|
|
33
37
|
});
|
|
34
38
|
it('should clusterize', ()=>{
|
|
39
|
+
// --- MASTER, adapter='cluster' -> covers setupPrimary()
|
|
40
|
+
_configenvironment.configuration.websocket.adapter = 'cluster';
|
|
35
41
|
_configenvironment.configuration.server.restartOnFailure = true;
|
|
36
|
-
const
|
|
42
|
+
const bootstrap = jest.fn();
|
|
43
|
+
// IMPORTANT: do NOT call bootstrap() from fork mock
|
|
44
|
+
const fakeWorker = {
|
|
37
45
|
process: {
|
|
38
46
|
pid: 1
|
|
39
47
|
}
|
|
40
|
-
}
|
|
41
|
-
_nodecluster.default.fork = jest.fn(()=>
|
|
48
|
+
};
|
|
49
|
+
_nodecluster.default.fork = jest.fn(()=>fakeWorker);
|
|
42
50
|
const spyExit = jest.spyOn(_nodecluster.default, 'on');
|
|
43
|
-
|
|
44
|
-
expect(
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
// 1) master path (cluster.isPrimary true by default)
|
|
52
|
+
expect(()=>_appservice.AppService.clusterize(bootstrap)).not.toThrow();
|
|
53
|
+
// setupPrimary() must have run once (covers the “line 21” site)
|
|
54
|
+
expect(_clusteradapter.setupPrimary).toHaveBeenCalledTimes(1);
|
|
55
|
+
// fork called exactly workers times
|
|
56
|
+
expect(_nodecluster.default.fork.mock.calls.length).toBe(_configenvironment.configuration.server.workers);
|
|
57
|
+
// --- Test exit handler with ONLY ONE registered handler
|
|
58
|
+
// TRUE branch: restart twice -> fork called +2
|
|
59
|
+
const forkCallsAfterMaster = _nodecluster.default.fork.mock.calls.length;
|
|
47
60
|
_appservice.AppService.schedulerPID = 1;
|
|
48
61
|
_nodecluster.default.emit('exit', {
|
|
49
62
|
process: {
|
|
50
63
|
pid: 1
|
|
51
64
|
}
|
|
52
|
-
}, 1,
|
|
65
|
+
}, 1, 'SIGKILL');
|
|
53
66
|
_appservice.AppService.schedulerPID = 0;
|
|
54
67
|
_nodecluster.default.emit('exit', {
|
|
55
68
|
process: {
|
|
56
|
-
pid:
|
|
69
|
+
pid: 2
|
|
70
|
+
}
|
|
71
|
+
}, 1, 'SIGKILL');
|
|
72
|
+
expect(_nodecluster.default.fork.mock.calls.length).toBe(forkCallsAfterMaster + 2);
|
|
73
|
+
// FALSE branch: no restart -> fork unchanged
|
|
74
|
+
_configenvironment.configuration.server.restartOnFailure = false;
|
|
75
|
+
const forkCallsAfterTrue = _nodecluster.default.fork.mock.calls.length;
|
|
76
|
+
_nodecluster.default.emit('exit', {
|
|
77
|
+
process: {
|
|
78
|
+
pid: 3
|
|
57
79
|
}
|
|
58
|
-
}, 1,
|
|
59
|
-
expect(
|
|
60
|
-
|
|
80
|
+
}, 1, 'SIGKILL');
|
|
81
|
+
expect(_nodecluster.default.fork.mock.calls.length).toBe(forkCallsAfterTrue);
|
|
82
|
+
// --- MASTER again, adapter != 'cluster' -> covers the FALSE side of the adapter check
|
|
83
|
+
_configenvironment.configuration.websocket.adapter = null;
|
|
84
|
+
expect(()=>_appservice.AppService.clusterize(bootstrap)).not.toThrow();
|
|
85
|
+
// setupPrimary should NOT be called again
|
|
86
|
+
expect(_clusteradapter.setupPrimary).toHaveBeenCalledTimes(1);
|
|
87
|
+
// --- WORKER path (else branch): bootstrap should be called exactly once here
|
|
61
88
|
jest.replaceProperty(_nodecluster.default, 'isPrimary', false);
|
|
62
|
-
|
|
63
|
-
expect(()=>_appservice.AppService.clusterize(
|
|
64
|
-
expect(
|
|
89
|
+
bootstrap.mockClear(); // isolate bootstrap count for a worker branch
|
|
90
|
+
expect(()=>_appservice.AppService.clusterize(bootstrap)).not.toThrow();
|
|
91
|
+
expect(bootstrap).toHaveBeenCalledTimes(1);
|
|
65
92
|
spyExit.mockClear();
|
|
66
93
|
});
|
|
67
94
|
it(`should use ${_configconstants.ENVIRONMENT_PREFIX} environment variables to override the configuration`, ()=>{
|
|
@@ -82,12 +109,10 @@ describe(_appservice.AppService.name, ()=>{
|
|
|
82
109
|
expect(conf.logger.colorize).toBe(false);
|
|
83
110
|
expect(conf.applications.files.maxUploadSize).toBe(8888);
|
|
84
111
|
expect(conf.auth.token.access.secret).toBe('fooBAR8888');
|
|
85
|
-
//
|
|
112
|
+
// clean up secret file
|
|
86
113
|
_nodefs.default.promises.rm(tmpSecretFile, {
|
|
87
114
|
force: true
|
|
88
|
-
}).catch(
|
|
89
|
-
console.error(e);
|
|
90
|
-
});
|
|
115
|
+
}).catch(console.error);
|
|
91
116
|
});
|
|
92
117
|
});
|
|
93
118
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../backend/src/app.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Logger } from '@nestjs/common'\nimport cluster from 'node:cluster'\nimport fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { AppService } from './app.service'\nimport { ENVIRONMENT_PREFIX } from './configuration/config.constants'\nimport { configuration, exportConfiguration } from './configuration/config.environment'\n\ndescribe(AppService.name, () => {\n let appService: AppService\n\n beforeAll(async () => {\n appService = new AppService()\n Logger.overrideLogger(['fatal'])\n })\n\n it('should be defined', () => {\n expect(appService).toBeDefined()\n })\n\n it('should clusterize', () => {\n configuration.server.restartOnFailure = true\n const
|
|
1
|
+
{"version":3,"sources":["../../backend/src/app.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Logger } from '@nestjs/common'\nimport cluster from 'node:cluster'\nimport fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { AppService } from './app.service'\nimport { ENVIRONMENT_PREFIX } from './configuration/config.constants'\nimport { configuration, exportConfiguration } from './configuration/config.environment'\njest.mock('@socket.io/cluster-adapter', () => ({\n setupPrimary: jest.fn()\n}))\nimport { setupPrimary } from '@socket.io/cluster-adapter'\n\ndescribe(AppService.name, () => {\n let appService: AppService\n\n beforeAll(async () => {\n appService = new AppService()\n Logger.overrideLogger(['fatal'])\n })\n\n it('should be defined', () => {\n expect(appService).toBeDefined()\n })\n\n it('should clusterize', () => {\n // --- MASTER, adapter='cluster' -> covers setupPrimary()\n configuration.websocket.adapter = 'cluster'\n configuration.server.restartOnFailure = true\n\n const bootstrap = jest.fn()\n\n // IMPORTANT: do NOT call bootstrap() from fork mock\n const fakeWorker = { process: { pid: 1 } } as any\n cluster.fork = jest.fn(() => fakeWorker)\n\n const spyExit = jest.spyOn(cluster, 'on')\n\n // 1) master path (cluster.isPrimary true by default)\n expect(() => AppService.clusterize(bootstrap)).not.toThrow()\n\n // setupPrimary() must have run once (covers the “line 21” site)\n expect(setupPrimary).toHaveBeenCalledTimes(1)\n\n // fork called exactly workers times\n expect((cluster.fork as jest.Mock).mock.calls.length).toBe(configuration.server.workers)\n\n // --- Test exit handler with ONLY ONE registered handler\n // TRUE branch: restart twice -> fork called +2\n const forkCallsAfterMaster = (cluster.fork as jest.Mock).mock.calls.length\n AppService.schedulerPID = 1\n cluster.emit('exit', { process: { pid: 1 } } as any, 1 as any, 'SIGKILL' as any)\n AppService.schedulerPID = 0\n cluster.emit('exit', { process: { pid: 2 } } as any, 1 as any, 'SIGKILL' as any)\n expect((cluster.fork as jest.Mock).mock.calls.length).toBe(forkCallsAfterMaster + 2)\n\n // FALSE branch: no restart -> fork unchanged\n configuration.server.restartOnFailure = false\n const forkCallsAfterTrue = (cluster.fork as jest.Mock).mock.calls.length\n cluster.emit('exit', { process: { pid: 3 } } as any, 1 as any, 'SIGKILL' as any)\n expect((cluster.fork as jest.Mock).mock.calls.length).toBe(forkCallsAfterTrue)\n\n // --- MASTER again, adapter != 'cluster' -> covers the FALSE side of the adapter check\n configuration.websocket.adapter = null\n expect(() => AppService.clusterize(bootstrap)).not.toThrow()\n // setupPrimary should NOT be called again\n expect(setupPrimary).toHaveBeenCalledTimes(1)\n\n // --- WORKER path (else branch): bootstrap should be called exactly once here\n jest.replaceProperty(cluster, 'isPrimary', false)\n bootstrap.mockClear() // isolate bootstrap count for a worker branch\n expect(() => AppService.clusterize(bootstrap)).not.toThrow()\n expect(bootstrap).toHaveBeenCalledTimes(1)\n\n spyExit.mockClear()\n })\n\n it(`should use ${ENVIRONMENT_PREFIX} environment variables to override the configuration`, () => {\n let conf = exportConfiguration()\n expect(conf.logger.stdout).toBe(true)\n expect(conf.logger.colorize).toBe(true)\n const tmpSecretFile = path.join(os.tmpdir(), 'secret')\n fs.writeFileSync(tmpSecretFile, 'fooBAR8888')\n process.env[`${ENVIRONMENT_PREFIX}APPLICATIONS_FILES_ONLYOFFICE_SECRET`] = 'fooBAR'\n process.env[`${ENVIRONMENT_PREFIX}LOGGER_STDOUT`] = 'false'\n process.env[`${ENVIRONMENT_PREFIX}LOGGER_COLORIZE`] = '\"false\"'\n process.env[`${ENVIRONMENT_PREFIX}APPLICATIONS_FILES_MAXUPLOADSIZE`] = '8888'\n // docker compose secret file\n process.env[`${ENVIRONMENT_PREFIX}AUTH_TOKEN_ACCESS_SECRET_FILE`] = tmpSecretFile\n conf = exportConfiguration(true)\n expect(conf.applications.files.onlyoffice.secret).toBe('fooBAR')\n expect(conf.logger.stdout).toBe(false)\n expect(conf.logger.colorize).toBe(false)\n expect(conf.applications.files.maxUploadSize).toBe(8888)\n expect(conf.auth.token.access.secret).toBe('fooBAR8888')\n // clean up secret file\n fs.promises.rm(tmpSecretFile, { force: true }).catch(console.error)\n })\n})\n"],"names":["jest","mock","setupPrimary","fn","describe","AppService","name","appService","beforeAll","Logger","overrideLogger","it","expect","toBeDefined","configuration","websocket","adapter","server","restartOnFailure","bootstrap","fakeWorker","process","pid","cluster","fork","spyExit","spyOn","clusterize","not","toThrow","toHaveBeenCalledTimes","calls","length","toBe","workers","forkCallsAfterMaster","schedulerPID","emit","forkCallsAfterTrue","replaceProperty","mockClear","ENVIRONMENT_PREFIX","conf","exportConfiguration","logger","stdout","colorize","tmpSecretFile","path","join","os","tmpdir","fs","writeFileSync","env","applications","files","onlyoffice","secret","maxUploadSize","auth","token","access","promises","rm","force","catch","console","error"],"mappings":"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"}
|
|
@@ -22,7 +22,33 @@ const _commentscontroller = require("./comments.controller");
|
|
|
22
22
|
const _commentsmanagerservice = require("./services/comments-manager.service");
|
|
23
23
|
const _commentsqueriesservice = require("./services/comments-queries.service");
|
|
24
24
|
describe(_commentscontroller.CommentsController.name, ()=>{
|
|
25
|
-
let
|
|
25
|
+
let commentsController;
|
|
26
|
+
let commentsManager;
|
|
27
|
+
const user = {
|
|
28
|
+
id: 'user-1'
|
|
29
|
+
};
|
|
30
|
+
const space = {
|
|
31
|
+
id: 'space-1'
|
|
32
|
+
};
|
|
33
|
+
const commentsSample = [
|
|
34
|
+
{
|
|
35
|
+
id: 'c1'
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'c2'
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
const commentSample = {
|
|
42
|
+
id: 'c1',
|
|
43
|
+
text: 'hello'
|
|
44
|
+
};
|
|
45
|
+
const commentsManagerMock = {
|
|
46
|
+
getComments: jest.fn(),
|
|
47
|
+
createComment: jest.fn(),
|
|
48
|
+
updateComment: jest.fn(),
|
|
49
|
+
deleteComment: jest.fn(),
|
|
50
|
+
getRecents: jest.fn()
|
|
51
|
+
};
|
|
26
52
|
beforeAll(async ()=>{
|
|
27
53
|
const module = await _testing.Test.createTestingModule({
|
|
28
54
|
controllers: [
|
|
@@ -42,7 +68,10 @@ describe(_commentscontroller.CommentsController.name, ()=>{
|
|
|
42
68
|
useValue: {}
|
|
43
69
|
},
|
|
44
70
|
_contextmanagerservice.ContextManager,
|
|
45
|
-
|
|
71
|
+
{
|
|
72
|
+
provide: _commentsmanagerservice.CommentsManager,
|
|
73
|
+
useValue: commentsManagerMock
|
|
74
|
+
},
|
|
46
75
|
_commentsqueriesservice.CommentsQueries,
|
|
47
76
|
_spacesmanagerservice.SpacesManager,
|
|
48
77
|
_spacesqueriesservice.SpacesQueries,
|
|
@@ -53,10 +82,80 @@ describe(_commentscontroller.CommentsController.name, ()=>{
|
|
|
53
82
|
_linksqueriesservice.LinksQueries
|
|
54
83
|
]
|
|
55
84
|
}).compile();
|
|
56
|
-
|
|
85
|
+
commentsController = module.get(_commentscontroller.CommentsController);
|
|
86
|
+
commentsManager = module.get(_commentsmanagerservice.CommentsManager);
|
|
87
|
+
});
|
|
88
|
+
beforeEach(()=>{
|
|
89
|
+
jest.clearAllMocks();
|
|
57
90
|
});
|
|
58
91
|
it('should be defined', ()=>{
|
|
59
|
-
expect(
|
|
92
|
+
expect(commentsController).toBeDefined();
|
|
93
|
+
});
|
|
94
|
+
it('getFromSpace calls CommentsManager.getComments and returns the list', async ()=>{
|
|
95
|
+
commentsManager.getComments.mockResolvedValueOnce(commentsSample);
|
|
96
|
+
const res = await commentsController.getFromSpace(user, space);
|
|
97
|
+
expect(commentsManager.getComments).toHaveBeenCalledTimes(1);
|
|
98
|
+
expect(commentsManager.getComments).toHaveBeenCalledWith(user, space);
|
|
99
|
+
expect(res).toEqual(commentsSample);
|
|
100
|
+
});
|
|
101
|
+
it('createFromSpace calls CommentsManager.createComment and returns the created comment', async ()=>{
|
|
102
|
+
const dto = {
|
|
103
|
+
text: 'new comment'
|
|
104
|
+
};
|
|
105
|
+
commentsManager.createComment.mockResolvedValueOnce(commentSample);
|
|
106
|
+
const res = await commentsController.createFromSpace(user, space, dto);
|
|
107
|
+
expect(commentsManager.createComment).toHaveBeenCalledTimes(1);
|
|
108
|
+
expect(commentsManager.createComment).toHaveBeenCalledWith(user, space, dto);
|
|
109
|
+
expect(res).toEqual(commentSample);
|
|
110
|
+
});
|
|
111
|
+
it('updateFromSpace calls CommentsManager.updateComment and returns the updated comment', async ()=>{
|
|
112
|
+
const dto = {
|
|
113
|
+
id: 'c1',
|
|
114
|
+
text: 'updated'
|
|
115
|
+
};
|
|
116
|
+
const updated = {
|
|
117
|
+
id: 'c1',
|
|
118
|
+
text: 'updated'
|
|
119
|
+
};
|
|
120
|
+
commentsManager.updateComment.mockResolvedValueOnce(updated);
|
|
121
|
+
const res = await commentsController.updateFromSpace(user, space, dto);
|
|
122
|
+
expect(commentsManager.updateComment).toHaveBeenCalledTimes(1);
|
|
123
|
+
expect(commentsManager.updateComment).toHaveBeenCalledWith(user, space, dto);
|
|
124
|
+
expect(res).toEqual(updated);
|
|
125
|
+
});
|
|
126
|
+
it('deleteFromSpace calls CommentsManager.deleteComment', async ()=>{
|
|
127
|
+
const dto = {
|
|
128
|
+
id: 'c1'
|
|
129
|
+
};
|
|
130
|
+
commentsManager.deleteComment.mockResolvedValueOnce(undefined);
|
|
131
|
+
await expect(commentsController.deleteFromSpace(user, space, dto)).resolves.toBeUndefined();
|
|
132
|
+
expect(commentsManager.deleteComment).toHaveBeenCalledTimes(1);
|
|
133
|
+
expect(commentsManager.deleteComment).toHaveBeenCalledWith(user, space, dto);
|
|
134
|
+
});
|
|
135
|
+
it('getRecents calls CommentsManager.getRecents with the provided limit', async ()=>{
|
|
136
|
+
const recents = [
|
|
137
|
+
{
|
|
138
|
+
id: 'r1'
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
commentsManager.getRecents.mockResolvedValueOnce(recents);
|
|
142
|
+
const res = await commentsController.getRecents(user, 5);
|
|
143
|
+
expect(commentsManager.getRecents).toHaveBeenCalledTimes(1);
|
|
144
|
+
expect(commentsManager.getRecents).toHaveBeenCalledWith(user, 5);
|
|
145
|
+
expect(res).toEqual(recents);
|
|
146
|
+
});
|
|
147
|
+
it('getRecents uses the default limit (10) when not provided', async ()=>{
|
|
148
|
+
const recents = [
|
|
149
|
+
{
|
|
150
|
+
id: 'r2'
|
|
151
|
+
}
|
|
152
|
+
];
|
|
153
|
+
commentsManager.getRecents.mockResolvedValueOnce(recents);
|
|
154
|
+
// Call with undefined to trigger the parameter default value
|
|
155
|
+
const res = await commentsController.getRecents(user, undefined);
|
|
156
|
+
expect(commentsManager.getRecents).toHaveBeenCalledTimes(1);
|
|
157
|
+
expect(commentsManager.getRecents).toHaveBeenCalledWith(user, 10);
|
|
158
|
+
expect(res).toEqual(recents);
|
|
60
159
|
});
|
|
61
160
|
});
|
|
62
161
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/comments/comments.controller.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../infrastructure/database/constants'\nimport { FilesQueries } from '../files/services/files-queries.service'\nimport { LinksQueries } from '../links/services/links-queries.service'\nimport { NotificationsManager } from '../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../shares/services/shares-manager.service'\nimport { SharesQueries } from '../shares/services/shares-queries.service'\nimport { SpacesManager } from '../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../spaces/services/spaces-queries.service'\nimport { UsersQueries } from '../users/services/users-queries.service'\nimport { CommentsController } from './comments.controller'\nimport { CommentsManager } from './services/comments-manager.service'\nimport { CommentsQueries } from './services/comments-queries.service'\n\ndescribe(CommentsController.name, () => {\n let
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/comments/comments.controller.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../infrastructure/database/constants'\nimport { FilesQueries } from '../files/services/files-queries.service'\nimport { LinksQueries } from '../links/services/links-queries.service'\nimport { NotificationsManager } from '../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../shares/services/shares-manager.service'\nimport { SharesQueries } from '../shares/services/shares-queries.service'\nimport { SpacesManager } from '../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../spaces/services/spaces-queries.service'\nimport { UsersQueries } from '../users/services/users-queries.service'\nimport { CommentsController } from './comments.controller'\nimport { CommentsManager } from './services/comments-manager.service'\nimport { CommentsQueries } from './services/comments-queries.service'\n\ndescribe(CommentsController.name, () => {\n let commentsController: CommentsController\n let commentsManager: jest.Mocked<CommentsManager>\n\n const user: any = { id: 'user-1' }\n const space: any = { id: 'space-1' }\n\n const commentsSample = [{ id: 'c1' }, { id: 'c2' }] as any\n const commentSample = { id: 'c1', text: 'hello' } as any\n\n const commentsManagerMock: jest.Mocked<CommentsManager> = {\n getComments: jest.fn(),\n createComment: jest.fn(),\n updateComment: jest.fn(),\n deleteComment: jest.fn(),\n getRecents: jest.fn()\n } as any\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n controllers: [CommentsController],\n providers: [\n { provide: NotificationsManager, useValue: {} },\n { provide: DB_TOKEN_PROVIDER, useValue: {} },\n { provide: Cache, useValue: {} },\n ContextManager,\n { provide: CommentsManager, useValue: commentsManagerMock },\n CommentsQueries,\n SpacesManager,\n SpacesQueries,\n FilesQueries,\n SharesManager,\n SharesQueries,\n UsersQueries,\n LinksQueries\n ]\n }).compile()\n\n commentsController = module.get<CommentsController>(CommentsController)\n commentsManager = module.get(CommentsManager)\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('should be defined', () => {\n expect(commentsController).toBeDefined()\n })\n\n it('getFromSpace calls CommentsManager.getComments and returns the list', async () => {\n commentsManager.getComments.mockResolvedValueOnce(commentsSample)\n\n const res = await commentsController.getFromSpace(user, space)\n\n expect(commentsManager.getComments).toHaveBeenCalledTimes(1)\n expect(commentsManager.getComments).toHaveBeenCalledWith(user, space)\n expect(res).toEqual(commentsSample)\n })\n\n it('createFromSpace calls CommentsManager.createComment and returns the created comment', async () => {\n const dto: any = { text: 'new comment' }\n commentsManager.createComment.mockResolvedValueOnce(commentSample)\n\n const res = await commentsController.createFromSpace(user, space, dto)\n\n expect(commentsManager.createComment).toHaveBeenCalledTimes(1)\n expect(commentsManager.createComment).toHaveBeenCalledWith(user, space, dto)\n expect(res).toEqual(commentSample)\n })\n\n it('updateFromSpace calls CommentsManager.updateComment and returns the updated comment', async () => {\n const dto: any = { id: 'c1', text: 'updated' }\n const updated = { id: 'c1', text: 'updated' } as any\n commentsManager.updateComment.mockResolvedValueOnce(updated)\n\n const res = await commentsController.updateFromSpace(user, space, dto)\n\n expect(commentsManager.updateComment).toHaveBeenCalledTimes(1)\n expect(commentsManager.updateComment).toHaveBeenCalledWith(user, space, dto)\n expect(res).toEqual(updated)\n })\n\n it('deleteFromSpace calls CommentsManager.deleteComment', async () => {\n const dto: any = { id: 'c1' }\n commentsManager.deleteComment.mockResolvedValueOnce(undefined)\n\n await expect(commentsController.deleteFromSpace(user, space, dto)).resolves.toBeUndefined()\n\n expect(commentsManager.deleteComment).toHaveBeenCalledTimes(1)\n expect(commentsManager.deleteComment).toHaveBeenCalledWith(user, space, dto)\n })\n\n it('getRecents calls CommentsManager.getRecents with the provided limit', async () => {\n const recents = [{ id: 'r1' }] as any\n commentsManager.getRecents.mockResolvedValueOnce(recents)\n\n const res = await commentsController.getRecents(user, 5 as any)\n\n expect(commentsManager.getRecents).toHaveBeenCalledTimes(1)\n expect(commentsManager.getRecents).toHaveBeenCalledWith(user, 5)\n expect(res).toEqual(recents)\n })\n\n it('getRecents uses the default limit (10) when not provided', async () => {\n const recents = [{ id: 'r2' }] as any\n commentsManager.getRecents.mockResolvedValueOnce(recents)\n\n // Call with undefined to trigger the parameter default value\n const res = await commentsController.getRecents(user, undefined as any)\n\n expect(commentsManager.getRecents).toHaveBeenCalledTimes(1)\n expect(commentsManager.getRecents).toHaveBeenCalledWith(user, 10)\n expect(res).toEqual(recents)\n })\n})\n"],"names":["describe","CommentsController","name","commentsController","commentsManager","user","id","space","commentsSample","commentSample","text","commentsManagerMock","getComments","jest","fn","createComment","updateComment","deleteComment","getRecents","beforeAll","module","Test","createTestingModule","controllers","providers","provide","NotificationsManager","useValue","DB_TOKEN_PROVIDER","Cache","ContextManager","CommentsManager","CommentsQueries","SpacesManager","SpacesQueries","FilesQueries","SharesManager","SharesQueries","UsersQueries","LinksQueries","compile","get","beforeEach","clearAllMocks","it","expect","toBeDefined","mockResolvedValueOnce","res","getFromSpace","toHaveBeenCalledTimes","toHaveBeenCalledWith","toEqual","dto","createFromSpace","updated","updateFromSpace","undefined","deleteFromSpace","resolves","toBeUndefined","recents"],"mappings":"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"}
|