@sync-in/server 1.6.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +169 -55
- package/environment/environment.dist.yaml +14 -5
- package/migrations/0003_giant_luckman.sql +6 -0
- package/migrations/meta/0003_snapshot.json +2463 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +16 -15
- package/server/app.bootstrap.js +1 -0
- package/server/app.bootstrap.js.map +1 -1
- package/server/app.constants.js +0 -4
- package/server/app.constants.js.map +1 -1
- package/server/app.service.js +7 -6
- package/server/app.service.js.map +1 -1
- package/server/applications/files/constants/only-office.js +12 -0
- package/server/applications/files/constants/only-office.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/services/files-content-manager.service.js +6 -6
- package/server/applications/files/services/files-content-manager.service.js.map +1 -1
- package/server/applications/files/services/files-manager.service.js +4 -4
- package/server/applications/files/services/files-manager.service.js.map +1 -1
- package/server/applications/files/services/files-methods.service.js +5 -3
- package/server/applications/files/services/files-methods.service.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +2 -2
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/files/services/files-parser.service.js +6 -3
- package/server/applications/files/services/files-parser.service.js.map +1 -1
- package/server/applications/files/services/files-scheduler.service.js +51 -3
- package/server/applications/files/services/files-scheduler.service.js.map +1 -1
- package/server/applications/files/services/files-search-manager.service.js +4 -0
- package/server/applications/files/services/files-search-manager.service.js.map +1 -1
- package/server/applications/files/utils/doc-textify/adapters/pdf.js +10 -1
- package/server/applications/files/utils/doc-textify/adapters/pdf.js.map +1 -1
- package/server/applications/notifications/i18n/de.js +56 -0
- package/server/applications/notifications/i18n/de.js.map +1 -0
- package/server/applications/notifications/i18n/es.js +52 -0
- package/server/applications/notifications/i18n/es.js.map +1 -0
- package/server/applications/notifications/i18n/hi.js +52 -0
- package/server/applications/notifications/i18n/hi.js.map +1 -0
- package/server/applications/notifications/i18n/index.js +73 -8
- package/server/applications/notifications/i18n/index.js.map +1 -1
- package/server/applications/notifications/i18n/it.js +52 -0
- package/server/applications/notifications/i18n/it.js.map +1 -0
- package/server/applications/notifications/i18n/ja.js +52 -0
- package/server/applications/notifications/i18n/ja.js.map +1 -0
- package/server/applications/notifications/i18n/ko.js +52 -0
- package/server/applications/notifications/i18n/ko.js.map +1 -0
- package/server/applications/notifications/i18n/pl.js +52 -0
- package/server/applications/notifications/i18n/pl.js.map +1 -0
- package/server/applications/notifications/i18n/pt.js +52 -0
- package/server/applications/notifications/i18n/pt.js.map +1 -0
- package/server/applications/notifications/i18n/pt_br.js +52 -0
- package/server/applications/notifications/i18n/pt_br.js.map +1 -0
- package/server/applications/notifications/i18n/ru.js +52 -0
- package/server/applications/notifications/i18n/ru.js.map +1 -0
- package/server/applications/notifications/i18n/tr.js +52 -0
- package/server/applications/notifications/i18n/tr.js.map +1 -0
- package/server/applications/notifications/i18n/zh.js +52 -0
- package/server/applications/notifications/i18n/zh.js.map +1 -0
- package/server/applications/notifications/mails/models.js +6 -7
- package/server/applications/notifications/mails/models.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
- package/server/applications/shares/dto/create-or-update-share.dto.js +11 -0
- package/server/applications/shares/dto/create-or-update-share.dto.js.map +1 -1
- package/server/applications/shares/interfaces/share-props.interface.js.map +1 -1
- package/server/applications/shares/schemas/share.interface.js.map +1 -1
- package/server/applications/shares/schemas/shares.schema.js +9 -0
- package/server/applications/shares/schemas/shares.schema.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.js +46 -17
- package/server/applications/shares/services/shares-manager.service.js.map +1 -1
- package/server/applications/shares/services/shares-queries.service.js +24 -5
- package/server/applications/shares/services/shares-queries.service.js.map +1 -1
- package/server/applications/spaces/constants/cache.js +4 -0
- package/server/applications/spaces/constants/cache.js.map +1 -1
- package/server/applications/spaces/dto/create-or-update-space.dto.js +5 -0
- package/server/applications/spaces/dto/create-or-update-space.dto.js.map +1 -1
- package/server/applications/spaces/guards/space.guard.js +3 -3
- package/server/applications/spaces/guards/space.guard.js.map +1 -1
- package/server/applications/spaces/models/space-props.model.js.map +1 -1
- package/server/applications/spaces/models/space.model.js.map +1 -1
- package/server/applications/spaces/schemas/space.interface.js.map +1 -1
- package/server/applications/spaces/schemas/spaces.schema.js +1 -0
- package/server/applications/spaces/schemas/spaces.schema.js.map +1 -1
- package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
- package/server/applications/spaces/services/spaces-manager.service.js +34 -31
- package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
- package/server/applications/spaces/services/spaces-queries.service.js +23 -7
- package/server/applications/spaces/services/spaces-queries.service.js.map +1 -1
- package/server/applications/spaces/services/spaces-scheduler.service.js +21 -20
- package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
- package/server/applications/spaces/spaces.controller.js +4 -2
- package/server/applications/spaces/spaces.controller.js.map +1 -1
- package/server/applications/spaces/utils/paths.js +14 -16
- package/server/applications/spaces/utils/paths.js.map +1 -1
- package/server/applications/sync/services/sync-manager.service.js +4 -3
- package/server/applications/sync/services/sync-manager.service.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.js +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
- package/server/applications/sync/sync.controller.js +2 -1
- package/server/applications/sync/sync.controller.js.map +1 -1
- package/server/applications/users/constants/routes.js +5 -0
- package/server/applications/users/constants/routes.js.map +1 -1
- package/server/applications/users/constants/user.js +0 -16
- package/server/applications/users/constants/user.js.map +1 -1
- package/server/applications/users/dto/user-properties.dto.js +10 -0
- package/server/applications/users/dto/user-properties.dto.js.map +1 -1
- package/server/applications/users/models/user.model.js.map +1 -1
- package/server/applications/users/schemas/user.interface.js.map +1 -1
- package/server/applications/users/schemas/users.schema.js +3 -2
- package/server/applications/users/schemas/users.schema.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +1 -0
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +2 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +8 -2
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +1 -0
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-queries.service.js +18 -4
- package/server/applications/users/services/users-queries.service.js.map +1 -1
- package/server/applications/users/users.controller.js +15 -0
- package/server/applications/users/users.controller.js.map +1 -1
- package/server/applications/users/utils/test.js +2 -2
- package/server/applications/users/utils/test.js.map +1 -1
- package/server/applications/webdav/constants/routes.js +2 -2
- package/server/applications/webdav/constants/routes.js.map +1 -1
- package/server/applications/webdav/constants/webdav.js +2 -2
- package/server/applications/webdav/constants/webdav.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.js +2 -2
- package/server/applications/webdav/filters/webdav.filter.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.spec.js +2 -2
- package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -1
- package/server/applications/webdav/services/webdav-methods.service.js +3 -2
- package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
- package/server/applications/webdav/utils/webdav.js +1 -2
- package/server/applications/webdav/utils/webdav.js.map +1 -1
- package/server/authentication/auth.config.js +17 -2
- package/server/authentication/auth.config.js.map +1 -1
- package/server/authentication/constants/auth-ldap.js +2 -1
- package/server/authentication/constants/auth-ldap.js.map +1 -1
- package/server/authentication/guards/auth-basic.strategy.js +4 -2
- package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
- package/server/authentication/guards/auth-local.strategy.js +2 -0
- package/server/authentication/guards/auth-local.strategy.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-ldap.service.js +75 -32
- 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 +2 -1
- package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
- package/server/common/i18n.js +52 -0
- package/server/common/i18n.js.map +1 -0
- package/server/common/image.js +49 -33
- package/server/common/image.js.map +1 -1
- package/server/common/interfaces.js.map +1 -1
- package/server/common/shared.js +5 -2
- package/server/common/shared.js.map +1 -1
- package/server/configuration/config.validation.js +3 -3
- package/server/configuration/config.validation.js.map +1 -1
- package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +8 -6
- package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
- package/server/infrastructure/cache/adapters/redis-cache.adapter.js +22 -17
- package/server/infrastructure/cache/adapters/redis-cache.adapter.js.map +1 -1
- package/server/infrastructure/cache/cache.e2e-spec.js +1 -0
- package/server/infrastructure/cache/cache.e2e-spec.js.map +1 -1
- package/server/infrastructure/cache/cache.module.js +1 -14
- package/server/infrastructure/cache/cache.module.js.map +1 -1
- package/server/infrastructure/cache/services/cache.service.js.map +1 -1
- package/server/infrastructure/database/database.module.js +20 -1
- package/server/infrastructure/database/database.module.js.map +1 -1
- package/server/infrastructure/database/utils.js +48 -0
- package/server/infrastructure/database/utils.js.map +1 -1
- package/server/infrastructure/scheduler/scheduler.module.js +1 -1
- package/server/infrastructure/scheduler/scheduler.module.js.map +1 -1
- package/server/infrastructure/websocket/adapters/cluster.adapter.js +1 -3
- package/server/infrastructure/websocket/adapters/cluster.adapter.js.map +1 -1
- package/static/3rdpartylicenses.txt +137 -137
- package/static/chunk-2KLC4T2Z.js +1 -0
- package/static/chunk-373XVRXW.js +1 -0
- package/static/chunk-3GMLWAFZ.js +1 -0
- package/static/chunk-3XVM35O2.js +1 -0
- package/static/chunk-3YVRP3VM.js +2 -0
- package/static/chunk-5NMSIIQB.js +1 -0
- package/static/chunk-AF24EYXU.js +1 -0
- package/static/chunk-AKQVEHO6.js +2 -0
- package/static/{chunk-LUWQFIWR.js → chunk-AY2SZ3G6.js} +1 -1
- package/static/chunk-BCVX464U.js +2 -0
- package/static/{chunk-IPAC4VAF.js → chunk-BIKLW4YS.js} +1 -1
- package/static/chunk-C36MW4ME.js +562 -0
- package/static/chunk-CHJ64RJM.js +1 -0
- package/static/chunk-DKSEQTMX.js +1 -0
- package/static/chunk-DM4NXKEP.js +1 -0
- package/static/chunk-DPUVSXRB.js +1 -0
- package/static/chunk-DSWEWLXJ.js +1 -0
- package/static/chunk-FJE6BOFL.js +1 -0
- package/static/chunk-FZ3JPGYZ.js +1 -0
- package/static/chunk-GUGNR5TF.js +3 -0
- package/static/chunk-H6NE33VX.js +1 -0
- package/static/{chunk-S75P2FFI.js → chunk-HAS5ZOTR.js} +1 -1
- package/static/chunk-HNQRZALS.js +1 -0
- package/static/chunk-JPT5WEAT.js +1 -0
- package/static/{chunk-ZQQPUYLU.js → chunk-JSWCNGXJ.js} +1 -1
- package/static/chunk-KFJIQIGR.js +1 -0
- package/static/chunk-LNTUR3GU.js +1 -0
- package/static/chunk-LVM4QB22.js +1 -0
- package/static/chunk-M3XVNQZQ.js +1 -0
- package/static/{chunk-AWQ2YTVC.js → chunk-MFLIJH6T.js} +1 -1
- package/static/{chunk-IQOALFYU.js → chunk-MSUHTBB2.js} +1 -1
- package/static/chunk-N3U6637P.js +1 -0
- package/static/chunk-NNV4OXSB.js +1 -0
- package/static/chunk-NO2LTNW3.js +1 -0
- package/static/chunk-OOGP4WSH.js +2 -0
- package/static/chunk-PB4AIT7O.js +1 -0
- package/static/chunk-PCWDQPOM.js +2 -0
- package/static/chunk-PGZZP5W3.js +1 -0
- package/static/chunk-PVDHBQRM.js +1 -0
- package/static/chunk-Q5KM7LTX.js +1 -0
- package/static/chunk-QHC6ZPQ4.js +1 -0
- package/static/chunk-QO6BTONN.js +1 -0
- package/static/chunk-QZU2S5CV.js +1 -0
- package/static/chunk-SBZ572Q4.js +2 -0
- package/static/chunk-SHIVUDP3.js +1 -0
- package/static/chunk-SLHTEGRU.js +1 -0
- package/static/{chunk-SH5EVL4E.js → chunk-SSFF27P2.js} +1 -1
- package/static/chunk-TPYBFZS5.js +1 -0
- package/static/chunk-UEQCWMXD.js +1 -0
- package/static/chunk-UG5DMXYO.js +1 -0
- package/static/chunk-UJPPR4MX.js +1 -0
- package/static/chunk-UNCPXHHT.js +1 -0
- package/static/chunk-URHTCJ7G.js +1 -0
- package/static/chunk-V3AT2BKP.js +1 -0
- package/static/chunk-VKK5BSLX.js +1 -0
- package/static/{chunk-7DN7ZAPU.js → chunk-VM4YX6Q7.js} +1 -1
- package/static/chunk-WJW7CT6G.js +27 -0
- package/static/{chunk-7ITZXYYJ.js → chunk-WLMNXRBS.js} +1 -1
- package/static/chunk-X5XGK6T7.js +4 -0
- package/static/chunk-YEKR5OPO.js +1 -0
- package/static/chunk-YW57T2PF.js +1 -0
- package/static/chunk-Z5J5F5SX.js +1 -0
- package/static/chunk-ZIJQRARU.js +1 -0
- package/static/chunk-ZPF2DSQV.js +1 -0
- package/static/chunk-ZTCRGJ6Y.js +7 -0
- package/static/index.html +2 -2
- package/static/main-VOL6OMJ5.js +9 -0
- package/static/scripts-WRDOQIU5.js +24 -0
- package/static/{styles-A5VYX3CE.css → styles-2C2UNCNB.css} +1 -1
- package/server/applications/spaces/interfaces/space-quota.interface.js +0 -10
- package/server/applications/spaces/interfaces/space-quota.interface.js.map +0 -1
- package/static/chunk-22EANI6R.js +0 -1
- package/static/chunk-27YQB3TE.js +0 -1
- package/static/chunk-2I4CUFUA.js +0 -1
- package/static/chunk-2MTM6SWN.js +0 -4
- package/static/chunk-34MKICK5.js +0 -27
- package/static/chunk-5O3DIUU3.js +0 -1
- package/static/chunk-6NMVZIIT.js +0 -1
- package/static/chunk-7FUM3JGM.js +0 -1
- package/static/chunk-7P27WBGC.js +0 -4
- package/static/chunk-ATP3BFHV.js +0 -562
- package/static/chunk-DSOE3FEP.js +0 -1
- package/static/chunk-EFKMBLRE.js +0 -1
- package/static/chunk-FUFKVHPU.js +0 -1
- package/static/chunk-HCDLWTMW.js +0 -7
- package/static/chunk-JASU3CIH.js +0 -1
- package/static/chunk-JQ5FTO2M.js +0 -1
- package/static/chunk-JUNZFADM.js +0 -1
- package/static/chunk-JXZCNFW7.js +0 -1
- package/static/chunk-LJUKI4SQ.js +0 -1
- package/static/chunk-ORMRCEGT.js +0 -1
- package/static/chunk-Q7D6RN4N.js +0 -1
- package/static/chunk-QJX6ITLW.js +0 -1
- package/static/chunk-QQ6UQQBR.js +0 -1
- package/static/chunk-RTRJ3KFH.js +0 -1
- package/static/chunk-S2HDY3OL.js +0 -1
- package/static/chunk-T3EYFSVZ.js +0 -1
- package/static/chunk-U34OZUZ7.js +0 -1
- package/static/chunk-Y7EH7G5K.js +0 -1
- package/static/main-7SQDDVMD.js +0 -9
- package/static/scripts-VZVAP2P4.js +0 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sync-in/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "The secure, open-source platform for file storage, sharing, collaboration, and sync",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Johan Legrand",
|
|
@@ -76,47 +76,48 @@
|
|
|
76
76
|
"@fastify/helmet": "13.0.2",
|
|
77
77
|
"@fastify/multipart": "9.2.1",
|
|
78
78
|
"@fastify/send": "4.1.0",
|
|
79
|
-
"@fastify/static": "8.
|
|
79
|
+
"@fastify/static": "8.3.0",
|
|
80
80
|
"@knaadh/nestjs-drizzle-mysql2": "1.2.0",
|
|
81
81
|
"@lukeed/ms": "2.0.2",
|
|
82
82
|
"@nestjs/axios": "4.0.1",
|
|
83
|
-
"@nestjs/common": "11.1.
|
|
83
|
+
"@nestjs/common": "11.1.7",
|
|
84
84
|
"@nestjs/config": "4.0.2",
|
|
85
|
-
"@nestjs/core": "11.1.
|
|
86
|
-
"@nestjs/jwt": "11.0.
|
|
85
|
+
"@nestjs/core": "11.1.7",
|
|
86
|
+
"@nestjs/jwt": "11.0.1",
|
|
87
87
|
"@nestjs/passport": "11.0.5",
|
|
88
|
-
"@nestjs/platform-fastify": "11.1.
|
|
89
|
-
"@nestjs/platform-socket.io": "11.1.
|
|
88
|
+
"@nestjs/platform-fastify": "11.1.7",
|
|
89
|
+
"@nestjs/platform-socket.io": "11.1.7",
|
|
90
90
|
"@nestjs/schedule": "6.0.1",
|
|
91
|
-
"@nestjs/websockets": "11.1.
|
|
92
|
-
"@
|
|
91
|
+
"@nestjs/websockets": "11.1.7",
|
|
92
|
+
"@resvg/resvg-js": "2.6.2",
|
|
93
|
+
"@socket.io/cluster-adapter": "0.3.0",
|
|
93
94
|
"@socket.io/redis-adapter": "8.3.0",
|
|
94
95
|
"archiver": "7.0.1",
|
|
95
96
|
"bcryptjs": "3.0.2",
|
|
96
|
-
"canvas": "3.2.0",
|
|
97
97
|
"class-transformer": "0.5.1",
|
|
98
98
|
"class-validator": "0.14.2",
|
|
99
99
|
"deepmerge": "4.3.1",
|
|
100
100
|
"drizzle-kit": "0.31.5",
|
|
101
|
-
"drizzle-orm": "0.44.
|
|
101
|
+
"drizzle-orm": "0.44.7",
|
|
102
102
|
"fast-xml-parser": "5.3.0",
|
|
103
103
|
"fs-extra": "11.3.2",
|
|
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.15.
|
|
108
|
+
"mysql2": "3.15.3",
|
|
109
109
|
"nestjs-pino": "4.4.1",
|
|
110
|
-
"nodemailer": "7.0.
|
|
110
|
+
"nodemailer": "7.0.10",
|
|
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
115
|
"pdfjs-dist": "5.4.296",
|
|
116
|
-
"pino-pretty": "13.1.
|
|
116
|
+
"pino-pretty": "13.1.2",
|
|
117
117
|
"qrcode-generator": "2.0.4",
|
|
118
|
-
"redis": "
|
|
118
|
+
"redis": "5.9.0",
|
|
119
119
|
"sax": "1.4.1",
|
|
120
|
+
"sharp": "0.34.4",
|
|
120
121
|
"socket.io": "4.8.1",
|
|
121
122
|
"tar": "7.5.1",
|
|
122
123
|
"time2fa": "1.4.2",
|
package/server/app.bootstrap.js
CHANGED
|
@@ -42,6 +42,7 @@ async function appBootstrap() {
|
|
|
42
42
|
const app = await _core.NestFactory.create(_appmodule.AppModule, fastifyAdapter, {
|
|
43
43
|
bufferLogs: true
|
|
44
44
|
});
|
|
45
|
+
/* NestJS starts listening for shutdown hooks */ app.enableShutdownHooks();
|
|
45
46
|
/* Fastify instance */ const fastifyInstance = fastifyAdapter.getInstance();
|
|
46
47
|
/* LOGGER */ app.useLogger(_configconstants.IS_TEST_ENV ? [
|
|
47
48
|
'fatal'
|
|
@@ -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 { 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.cookieSameSite,\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","cookieSameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"AAAA;;;;CAIC;;;;+BAkBqBA;;;eAAAA;;;+DAhBI;+DACA;kEACJ;wBACqC;sBACpB;iCACgB;4BAER;8BACP;2BACd;uCACS;wBACM;iCACA;mCACX;kCACG;;;;;;AAE1B,eAAeA;IACpB,OAAO,GACP,MAAMC,iBAAiB,IAAIC,+BAAc,CAAC;QACxCC,QAAQ;QACRC,YAAYC,gCAAa,CAACC,MAAM,CAACF,UAAU;QAC3CG,qBAAqB;QACrBC,gBAAgB;QAChBC,WAAW,SAAS,SAAS;IAC/B;IACA,MAAMC,MAA8B,MAAMC,iBAAW,CAACC,MAAM,CAAyBC,oBAAS,EAAEZ,gBAAgB;QAC9Ga,YAAY;IACd;IAEA,oBAAoB,GACpB,MAAMC,
|
|
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 /* NestJS starts listening for shutdown hooks */\n app.enableShutdownHooks()\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.cookieSameSite,\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","enableShutdownHooks","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","cookieSameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"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"}
|
package/server/app.constants.js
CHANGED
|
@@ -18,12 +18,8 @@ _export(exports, {
|
|
|
18
18
|
},
|
|
19
19
|
get CONTENT_SECURITY_POLICY () {
|
|
20
20
|
return CONTENT_SECURITY_POLICY;
|
|
21
|
-
},
|
|
22
|
-
get SERVER_NAME () {
|
|
23
|
-
return SERVER_NAME;
|
|
24
21
|
}
|
|
25
22
|
});
|
|
26
|
-
const SERVER_NAME = 'Sync-in';
|
|
27
23
|
const CONTENT_SECURITY_POLICY = (onlyOfficeServer)=>({
|
|
28
24
|
useDefaults: false,
|
|
29
25
|
directives: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../backend/src/app.constants.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const
|
|
1
|
+
{"version":3,"sources":["../../backend/src/app.constants.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const CONTENT_SECURITY_POLICY = (onlyOfficeServer: string) => ({\n useDefaults: false,\n directives: {\n defaultSrc: [\"'self'\", onlyOfficeServer || ''],\n scriptSrc: [\"'self'\", \"'unsafe-inline'\", onlyOfficeServer || ''],\n styleSrc: [\"'self'\", \"'unsafe-inline'\"],\n imgSrc: [\"'self'\", 'data:'],\n fontSrc: [\"'self'\"]\n }\n})\n\nexport const CONNECT_ERROR_CODE = new Set(['ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'])\n"],"names":["CONNECT_ERROR_CODE","CONTENT_SECURITY_POLICY","onlyOfficeServer","useDefaults","directives","defaultSrc","scriptSrc","styleSrc","imgSrc","fontSrc","Set"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAaYA;eAAAA;;QAXAC;eAAAA;;;AAAN,MAAMA,0BAA0B,CAACC,mBAA8B,CAAA;QACpEC,aAAa;QACbC,YAAY;YACVC,YAAY;gBAAC;gBAAUH,oBAAoB;aAAG;YAC9CI,WAAW;gBAAC;gBAAU;gBAAmBJ,oBAAoB;aAAG;YAChEK,UAAU;gBAAC;gBAAU;aAAkB;YACvCC,QAAQ;gBAAC;gBAAU;aAAQ;YAC3BC,SAAS;gBAAC;aAAS;QACrB;IACF,CAAA;AAEO,MAAMT,qBAAqB,IAAIU,IAAI;IAAC;IAAgB;IAAa;CAAY"}
|
package/server/app.service.js
CHANGED
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "AppService", {
|
|
|
15
15
|
const _common = require("@nestjs/common");
|
|
16
16
|
const _clusteradapter = require("@socket.io/cluster-adapter");
|
|
17
17
|
const _nodecluster = /*#__PURE__*/ _interop_require_default(require("node:cluster"));
|
|
18
|
+
const _nodeos = require("node:os");
|
|
18
19
|
const _nodeprocess = /*#__PURE__*/ _interop_require_default(require("node:process"));
|
|
19
20
|
const _configenvironment = require("./configuration/config.environment");
|
|
20
21
|
const _schedulerconstants = require("./infrastructure/scheduler/scheduler.constants");
|
|
@@ -36,21 +37,21 @@ let AppService = class AppService {
|
|
|
36
37
|
// setup connections between the workers
|
|
37
38
|
(0, _clusteradapter.setupPrimary)();
|
|
38
39
|
}
|
|
39
|
-
AppService.logger.log(`
|
|
40
|
-
AppService.logger.log(`Master
|
|
40
|
+
AppService.logger.log(`Workers: ${_configenvironment.configuration.server.workers} / CPU cores: ${(0, _nodeos.cpus)().length}`);
|
|
41
|
+
AppService.logger.log(`[Master:${_nodeprocess.default.pid}] started`);
|
|
41
42
|
for(let i = 0; i < _configenvironment.configuration.server.workers; i++){
|
|
42
43
|
AppService.forkProcess(i === _configenvironment.configuration.server.workers - 1);
|
|
43
44
|
}
|
|
44
45
|
_nodecluster.default.on('exit', (worker, code, signal)=>{
|
|
45
|
-
AppService.logger.log(`Worker
|
|
46
|
+
AppService.logger.log(`[Worker:${worker.process.pid}] (code: ${code}, signal: ${signal}) died.`);
|
|
46
47
|
if (_configenvironment.configuration.server.restartOnFailure) {
|
|
47
48
|
const isScheduler = worker.process.pid === AppService.schedulerPID;
|
|
48
|
-
AppService.logger.log(`
|
|
49
|
+
AppService.logger.log(`[Worker:${worker.process.pid}] restarting ${isScheduler ? `(with Scheduler)` : ''}...`);
|
|
49
50
|
AppService.forkProcess(isScheduler);
|
|
50
51
|
}
|
|
51
52
|
});
|
|
52
53
|
} else {
|
|
53
|
-
AppService.logger.log(`
|
|
54
|
+
AppService.logger.log(`[Worker:${_nodeprocess.default.pid}] started`);
|
|
54
55
|
bootstrap();
|
|
55
56
|
}
|
|
56
57
|
}
|
|
@@ -60,7 +61,7 @@ let AppService = class AppService {
|
|
|
60
61
|
});
|
|
61
62
|
if (isScheduler) {
|
|
62
63
|
AppService.schedulerPID = w.process.pid;
|
|
63
|
-
AppService.logger.log(`
|
|
64
|
+
AppService.logger.log(`[Worker:${w.process.pid}] Scheduler role enabled`);
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../backend/src/app.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 { Injectable, Logger } from '@nestjs/common'\nimport { setupPrimary } from '@socket.io/cluster-adapter'\nimport cluster, { Worker } from 'node:cluster'\nimport process from 'node:process'\nimport { configuration } from './configuration/config.environment'\nimport { SCHEDULER_ENV, SCHEDULER_STATE } from './infrastructure/scheduler/scheduler.constants'\n\n@Injectable()\nexport class AppService {\n private static readonly logger = new Logger(AppService.name)\n static schedulerPID: number\n\n static clusterize(bootstrap: () => void) {\n if (cluster.isPrimary) {\n if (configuration.websocket.adapter === 'cluster') {\n // setup connections between the workers\n setupPrimary()\n }\n AppService.logger.log(`
|
|
1
|
+
{"version":3,"sources":["../../backend/src/app.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 { Injectable, Logger } from '@nestjs/common'\nimport { setupPrimary } from '@socket.io/cluster-adapter'\nimport cluster, { Worker } from 'node:cluster'\nimport { cpus } from 'node:os'\nimport process from 'node:process'\nimport { configuration } from './configuration/config.environment'\nimport { SCHEDULER_ENV, SCHEDULER_STATE } from './infrastructure/scheduler/scheduler.constants'\n\n@Injectable()\nexport class AppService {\n private static readonly logger = new Logger(AppService.name)\n static schedulerPID: number\n\n static clusterize(bootstrap: () => void) {\n if (cluster.isPrimary) {\n if (configuration.websocket.adapter === 'cluster') {\n // setup connections between the workers\n setupPrimary()\n }\n AppService.logger.log(`Workers: ${configuration.server.workers} / CPU cores: ${cpus().length}`)\n AppService.logger.log(`[Master:${process.pid}] started`)\n for (let i = 0; i < configuration.server.workers; i++) {\n AppService.forkProcess(i === configuration.server.workers - 1)\n }\n cluster.on('exit', (worker: Worker, code: number, signal: string) => {\n AppService.logger.log(`[Worker:${worker.process.pid}] (code: ${code}, signal: ${signal}) died.`)\n if (configuration.server.restartOnFailure) {\n const isScheduler = worker.process.pid === AppService.schedulerPID\n AppService.logger.log(`[Worker:${worker.process.pid}] restarting ${isScheduler ? `(with Scheduler)` : ''}...`)\n AppService.forkProcess(isScheduler)\n }\n })\n } else {\n AppService.logger.log(`[Worker:${process.pid}] started`)\n bootstrap()\n }\n }\n\n static forkProcess(isScheduler: boolean) {\n const w: Worker = cluster.fork({ [SCHEDULER_ENV]: isScheduler ? SCHEDULER_STATE.ENABLED : SCHEDULER_STATE.DISABLED })\n if (isScheduler) {\n AppService.schedulerPID = w.process.pid\n AppService.logger.log(`[Worker:${w.process.pid}] Scheduler role enabled`)\n }\n }\n}\n"],"names":["AppService","clusterize","bootstrap","cluster","isPrimary","configuration","websocket","adapter","setupPrimary","logger","log","server","workers","cpus","length","process","pid","i","forkProcess","on","worker","code","signal","restartOnFailure","isScheduler","schedulerPID","w","fork","SCHEDULER_ENV","SCHEDULER_STATE","ENABLED","DISABLED","Logger","name"],"mappings":"AAAA;;;;CAIC;;;;+BAWYA;;;eAAAA;;;wBATsB;gCACN;oEACG;wBACX;oEACD;mCACU;oCACiB;;;;;;;;;;;;AAGxC,IAAA,AAAMA,aAAN,MAAMA;IAIX,OAAOC,WAAWC,SAAqB,EAAE;QACvC,IAAIC,oBAAO,CAACC,SAAS,EAAE;YACrB,IAAIC,gCAAa,CAACC,SAAS,CAACC,OAAO,KAAK,WAAW;gBACjD,wCAAwC;gBACxCC,IAAAA,4BAAY;YACd;YACAR,WAAWS,MAAM,CAACC,GAAG,CAAC,CAAC,SAAS,EAAEL,gCAAa,CAACM,MAAM,CAACC,OAAO,CAAC,cAAc,EAAEC,IAAAA,YAAI,IAAGC,MAAM,EAAE;YAC9Fd,WAAWS,MAAM,CAACC,GAAG,CAAC,CAAC,QAAQ,EAAEK,oBAAO,CAACC,GAAG,CAAC,SAAS,CAAC;YACvD,IAAK,IAAIC,IAAI,GAAGA,IAAIZ,gCAAa,CAACM,MAAM,CAACC,OAAO,EAAEK,IAAK;gBACrDjB,WAAWkB,WAAW,CAACD,MAAMZ,gCAAa,CAACM,MAAM,CAACC,OAAO,GAAG;YAC9D;YACAT,oBAAO,CAACgB,EAAE,CAAC,QAAQ,CAACC,QAAgBC,MAAcC;gBAChDtB,WAAWS,MAAM,CAACC,GAAG,CAAC,CAAC,QAAQ,EAAEU,OAAOL,OAAO,CAACC,GAAG,CAAC,SAAS,EAAEK,KAAK,UAAU,EAAEC,OAAO,OAAO,CAAC;gBAC/F,IAAIjB,gCAAa,CAACM,MAAM,CAACY,gBAAgB,EAAE;oBACzC,MAAMC,cAAcJ,OAAOL,OAAO,CAACC,GAAG,KAAKhB,WAAWyB,YAAY;oBAClEzB,WAAWS,MAAM,CAACC,GAAG,CAAC,CAAC,QAAQ,EAAEU,OAAOL,OAAO,CAACC,GAAG,CAAC,aAAa,EAAEQ,cAAc,CAAC,gBAAgB,CAAC,GAAG,GAAG,GAAG,CAAC;oBAC7GxB,WAAWkB,WAAW,CAACM;gBACzB;YACF;QACF,OAAO;YACLxB,WAAWS,MAAM,CAACC,GAAG,CAAC,CAAC,QAAQ,EAAEK,oBAAO,CAACC,GAAG,CAAC,SAAS,CAAC;YACvDd;QACF;IACF;IAEA,OAAOgB,YAAYM,WAAoB,EAAE;QACvC,MAAME,IAAYvB,oBAAO,CAACwB,IAAI,CAAC;YAAE,CAACC,iCAAa,CAAC,EAAEJ,cAAcK,mCAAe,CAACC,OAAO,GAAGD,mCAAe,CAACE,QAAQ;QAAC;QACnH,IAAIP,aAAa;YACfxB,WAAWyB,YAAY,GAAGC,EAAEX,OAAO,CAACC,GAAG;YACvChB,WAAWS,MAAM,CAACC,GAAG,CAAC,CAAC,QAAQ,EAAEgB,EAAEX,OAAO,CAACC,GAAG,CAAC,wBAAwB,CAAC;QAC1E;IACF;AACF;AApCahB,WACaS,SAAS,IAAIuB,cAAM,CAAChC,WAAWiC,IAAI"}
|
|
@@ -338,6 +338,10 @@ const ONLY_OFFICE_EXTENSIONS = {
|
|
|
338
338
|
]),
|
|
339
339
|
EDITABLE: new Map([
|
|
340
340
|
// WORD
|
|
341
|
+
[
|
|
342
|
+
'doc',
|
|
343
|
+
'word'
|
|
344
|
+
],
|
|
341
345
|
[
|
|
342
346
|
'docm',
|
|
343
347
|
'word'
|
|
@@ -395,6 +399,10 @@ const ONLY_OFFICE_EXTENSIONS = {
|
|
|
395
399
|
'xlsm',
|
|
396
400
|
'cell'
|
|
397
401
|
],
|
|
402
|
+
[
|
|
403
|
+
'xls',
|
|
404
|
+
'cell'
|
|
405
|
+
],
|
|
398
406
|
[
|
|
399
407
|
'xlsx',
|
|
400
408
|
'cell'
|
|
@@ -440,6 +448,10 @@ const ONLY_OFFICE_EXTENSIONS = {
|
|
|
440
448
|
'pptm',
|
|
441
449
|
'slide'
|
|
442
450
|
],
|
|
451
|
+
[
|
|
452
|
+
'ppt',
|
|
453
|
+
'slide'
|
|
454
|
+
],
|
|
443
455
|
[
|
|
444
456
|
'pptx',
|
|
445
457
|
'slide'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/files/constants/only-office.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const ONLY_OFFICE_INTERNAL_URI = '/onlyoffice' // used by nginx as proxy\nexport const ONLY_OFFICE_CONTEXT = 'OnlyOfficeEnvironment'\nexport const ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME = 'token' as const\n\nexport const ONLY_OFFICE_EXTENSIONS = {\n VIEWABLE: new Map([\n // WORD\n ['doc', 'word'],\n ['docm', 'word'],\n ['docx', 'word'],\n ['dot', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['fodt', 'word'],\n ['gdoc', 'word'],\n ['htm', 'word'],\n ['html', 'word'],\n ['hwp', 'word'],\n ['hwpx', 'word'],\n ['md', 'word'],\n ['mht', 'word'],\n ['mhtml', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['pages', 'word'],\n ['rtf', 'word'],\n ['stw', 'word'],\n ['sxw', 'word'],\n ['txt', 'word'],\n ['wps', 'word'],\n ['wpt', 'word'],\n ['xml', 'word'],\n ['md', 'word'],\n\n // CELL\n ['csv', 'cell'],\n ['et', 'cell'],\n ['ett', 'cell'],\n ['fods', 'cell'],\n ['gsheet', 'cell'],\n ['numbers', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n ['sxc', 'cell'],\n ['xls', 'cell'],\n ['xlsm', 'cell'],\n ['xlsx', 'cell'],\n ['xlt', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n\n // SLIDE\n ['dps', 'slide'],\n ['dpt', 'slide'],\n ['fodp', 'slide'],\n ['gslide', 'slide'],\n ['key', 'slide'],\n ['odg', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n ['pot', 'slide'],\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['pps', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['ppt', 'slide'],\n ['pptm', 'slide'],\n ['pptx', 'slide'],\n ['sxi', 'slide'],\n\n // PDF\n ['djvu', 'pdf'],\n ['docxf', 'pdf'],\n ['oform', 'pdf'],\n ['oxps', 'pdf'],\n ['pdf', 'pdf'],\n ['xps', 'pdf'],\n\n // DIAGRAM\n ['vsdm', 'diagram'],\n ['vsdx', 'diagram'],\n ['vssm', 'diagram'],\n ['vssx', 'diagram'],\n ['vstm', 'diagram'],\n ['vstx', 'diagram']\n ]),\n\n EDITABLE: new Map([\n // WORD\n ['docm', 'word'],\n ['docx', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['html', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['rtf', 'word'],\n ['txt', 'word'],\n ['md', 'word'],\n\n // CELL\n ['xlsb', 'cell'],\n ['xlsm', 'cell'],\n ['xlsx', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n ['csv', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n\n // SLIDE\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['pptm', 'slide'],\n ['pptx', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n\n // PDF\n ['pdf', 'pdf']\n ])\n}\n\nexport const ONLY_OFFICE_CONVERT_EXTENSIONS = {\n ALLOW_AUTO: new Set(['doc', 'xls', 'ppt']),\n FROM: new Set([\n 'doc',\n 'docm',\n 'docx',\n 'docxf',\n 'dotx',\n 'epub',\n 'fb2',\n 'html',\n 'mhtml',\n 'odt',\n 'ott',\n 'pdf',\n 'rtf',\n 'stw',\n 'sxw',\n 'txt',\n 'wps',\n 'wpt',\n 'xps'\n ]),\n TO: new Set(['docx', 'docxf', 'dotx', 'epub', 'fb2', 'html', 'jpg', 'odt', 'ott', 'pdf', 'png', 'rtf', 'txt'])\n}\n\nexport const ONLY_OFFICE_CONVERT_ERROR = new Map([\n [-9, 'error conversion output format'],\n [-8, 'error document VKey'],\n [-7, 'error document request'],\n [-6, 'error database'],\n [-5, 'incorrect password'],\n [-4, 'download error'],\n [-3, 'convert error'],\n [-2, 'convert error timeout'],\n [-1, 'convert unknown']\n])\n"],"names":["ONLY_OFFICE_CONTEXT","ONLY_OFFICE_CONVERT_ERROR","ONLY_OFFICE_CONVERT_EXTENSIONS","ONLY_OFFICE_EXTENSIONS","ONLY_OFFICE_INTERNAL_URI","ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME","VIEWABLE","Map","EDITABLE","ALLOW_AUTO","Set","FROM","TO"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAGYA;eAAAA;;
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/files/constants/only-office.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const ONLY_OFFICE_INTERNAL_URI = '/onlyoffice' // used by nginx as proxy\nexport const ONLY_OFFICE_CONTEXT = 'OnlyOfficeEnvironment'\nexport const ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME = 'token' as const\n\nexport const ONLY_OFFICE_EXTENSIONS = {\n VIEWABLE: new Map([\n // WORD\n ['doc', 'word'],\n ['docm', 'word'],\n ['docx', 'word'],\n ['dot', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['fodt', 'word'],\n ['gdoc', 'word'],\n ['htm', 'word'],\n ['html', 'word'],\n ['hwp', 'word'],\n ['hwpx', 'word'],\n ['md', 'word'],\n ['mht', 'word'],\n ['mhtml', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['pages', 'word'],\n ['rtf', 'word'],\n ['stw', 'word'],\n ['sxw', 'word'],\n ['txt', 'word'],\n ['wps', 'word'],\n ['wpt', 'word'],\n ['xml', 'word'],\n ['md', 'word'],\n\n // CELL\n ['csv', 'cell'],\n ['et', 'cell'],\n ['ett', 'cell'],\n ['fods', 'cell'],\n ['gsheet', 'cell'],\n ['numbers', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n ['sxc', 'cell'],\n ['xls', 'cell'],\n ['xlsm', 'cell'],\n ['xlsx', 'cell'],\n ['xlt', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n\n // SLIDE\n ['dps', 'slide'],\n ['dpt', 'slide'],\n ['fodp', 'slide'],\n ['gslide', 'slide'],\n ['key', 'slide'],\n ['odg', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n ['pot', 'slide'],\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['pps', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['ppt', 'slide'],\n ['pptm', 'slide'],\n ['pptx', 'slide'],\n ['sxi', 'slide'],\n\n // PDF\n ['djvu', 'pdf'],\n ['docxf', 'pdf'],\n ['oform', 'pdf'],\n ['oxps', 'pdf'],\n ['pdf', 'pdf'],\n ['xps', 'pdf'],\n\n // DIAGRAM\n ['vsdm', 'diagram'],\n ['vsdx', 'diagram'],\n ['vssm', 'diagram'],\n ['vssx', 'diagram'],\n ['vstm', 'diagram'],\n ['vstx', 'diagram']\n ]),\n\n EDITABLE: new Map([\n // WORD\n ['doc', 'word'],\n ['docm', 'word'],\n ['docx', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['html', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['rtf', 'word'],\n ['txt', 'word'],\n ['md', 'word'],\n\n // CELL\n ['xlsb', 'cell'],\n ['xlsm', 'cell'],\n ['xls', 'cell'],\n ['xlsx', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n ['csv', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n\n // SLIDE\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['pptm', 'slide'],\n ['ppt', 'slide'],\n ['pptx', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n\n // PDF\n ['pdf', 'pdf']\n ])\n}\n\nexport const ONLY_OFFICE_CONVERT_EXTENSIONS = {\n ALLOW_AUTO: new Set(['doc', 'xls', 'ppt']),\n FROM: new Set([\n 'doc',\n 'docm',\n 'docx',\n 'docxf',\n 'dotx',\n 'epub',\n 'fb2',\n 'html',\n 'mhtml',\n 'odt',\n 'ott',\n 'pdf',\n 'rtf',\n 'stw',\n 'sxw',\n 'txt',\n 'wps',\n 'wpt',\n 'xps'\n ]),\n TO: new Set(['docx', 'docxf', 'dotx', 'epub', 'fb2', 'html', 'jpg', 'odt', 'ott', 'pdf', 'png', 'rtf', 'txt'])\n}\n\nexport const ONLY_OFFICE_CONVERT_ERROR = new Map([\n [-9, 'error conversion output format'],\n [-8, 'error document VKey'],\n [-7, 'error document request'],\n [-6, 'error database'],\n [-5, 'incorrect password'],\n [-4, 'download error'],\n [-3, 'convert error'],\n [-2, 'convert error timeout'],\n [-1, 'convert unknown']\n])\n"],"names":["ONLY_OFFICE_CONTEXT","ONLY_OFFICE_CONVERT_ERROR","ONLY_OFFICE_CONVERT_EXTENSIONS","ONLY_OFFICE_EXTENSIONS","ONLY_OFFICE_INTERNAL_URI","ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME","VIEWABLE","Map","EDITABLE","ALLOW_AUTO","Set","FROM","TO"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAGYA;eAAAA;;QA8JAC;eAAAA;;QA1BAC;eAAAA;;QAjIAC;eAAAA;;QAJAC;eAAAA;;QAEAC;eAAAA;;;AAFN,MAAMD,2BAA2B,cAAc,yBAAyB;;AACxE,MAAMJ,sBAAsB;AAC5B,MAAMK,qCAAqC;AAE3C,MAAMF,yBAAyB;IACpCG,UAAU,IAAIC,IAAI;QAChB,OAAO;QACP;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAM;SAAO;QACd;YAAC;YAAO;SAAO;QACf;YAAC;YAAS;SAAO;QACjB;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAS;SAAO;QACjB;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAM;SAAO;QAEd,OAAO;QACP;YAAC;YAAO;SAAO;QACf;YAAC;YAAM;SAAO;QACd;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAU;SAAO;QAClB;YAAC;YAAW;SAAO;QACnB;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAEhB,QAAQ;QACR;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAU;SAAQ;QACnB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAO;SAAQ;QAEhB,MAAM;QACN;YAAC;YAAQ;SAAM;QACf;YAAC;YAAS;SAAM;QAChB;YAAC;YAAS;SAAM;QAChB;YAAC;YAAQ;SAAM;QACf;YAAC;YAAO;SAAM;QACd;YAAC;YAAO;SAAM;QAEd,UAAU;QACV;YAAC;YAAQ;SAAU;QACnB;YAAC;YAAQ;SAAU;QACnB;YAAC;YAAQ;SAAU;QACnB;YAAC;YAAQ;SAAU;QACnB;YAAC;YAAQ;SAAU;QACnB;YAAC;YAAQ;SAAU;KACpB;IAEDC,UAAU,IAAID,IAAI;QAChB,OAAO;QACP;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAM;SAAO;QAEd,OAAO;QACP;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAQ;SAAO;QAChB;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QACf;YAAC;YAAO;SAAO;QAEf,QAAQ;QACR;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAQ;SAAQ;QACjB;YAAC;YAAO;SAAQ;QAChB;YAAC;YAAO;SAAQ;QAEhB,MAAM;QACN;YAAC;YAAO;SAAM;KACf;AACH;AAEO,MAAML,iCAAiC;IAC5CO,YAAY,IAAIC,IAAI;QAAC;QAAO;QAAO;KAAM;IACzCC,MAAM,IAAID,IAAI;QACZ;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;KACD;IACDE,IAAI,IAAIF,IAAI;QAAC;QAAQ;QAAS;QAAQ;QAAQ;QAAO;QAAQ;QAAO;QAAO;QAAO;QAAO;QAAO;QAAO;KAAM;AAC/G;AAEO,MAAMT,4BAA4B,IAAIM,IAAI;IAC/C;QAAC,CAAC;QAAG;KAAiC;IACtC;QAAC,CAAC;QAAG;KAAsB;IAC3B;QAAC,CAAC;QAAG;KAAyB;IAC9B;QAAC,CAAC;QAAG;KAAiB;IACtB;QAAC,CAAC;QAAG;KAAqB;IAC1B;QAAC,CAAC;QAAG;KAAiB;IACtB;QAAC,CAAC;QAAG;KAAgB;IACrB;QAAC,CAAC;QAAG;KAAwB;IAC7B;QAAC,CAAC;QAAG;KAAkB;CACxB"}
|
|
@@ -59,6 +59,7 @@ _ts_decorate([
|
|
|
59
59
|
let FilesConfig = class FilesConfig {
|
|
60
60
|
constructor(){
|
|
61
61
|
this.maxUploadSize = 5368709120; // 5 GB
|
|
62
|
+
this.contentIndexing = true;
|
|
62
63
|
this.showHiddenFiles = false;
|
|
63
64
|
this.onlyoffice = new FilesOnlyOfficeConfig();
|
|
64
65
|
}
|
|
@@ -87,6 +88,10 @@ _ts_decorate([
|
|
|
87
88
|
(0, _classvalidator.IsInt)(),
|
|
88
89
|
_ts_metadata("design:type", Number)
|
|
89
90
|
], FilesConfig.prototype, "maxUploadSize", void 0);
|
|
91
|
+
_ts_decorate([
|
|
92
|
+
(0, _classvalidator.IsBoolean)(),
|
|
93
|
+
_ts_metadata("design:type", Boolean)
|
|
94
|
+
], FilesConfig.prototype, "contentIndexing", void 0);
|
|
90
95
|
_ts_decorate([
|
|
91
96
|
(0, _classvalidator.IsBoolean)(),
|
|
92
97
|
_ts_metadata("design:type", Boolean)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/files/files.config.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 { Type } from 'class-transformer'\nimport { IsBoolean, IsInt, IsNotEmpty, IsNotEmptyObject, IsOptional, IsString, ValidateIf, ValidateNested } from 'class-validator'\n\nexport class FilesOnlyOfficeConfig {\n @IsBoolean()\n enabled = false\n\n @IsOptional()\n @IsString()\n externalServer: string = null\n\n @ValidateIf((o: FilesOnlyOfficeConfig) => o.enabled)\n @IsString()\n @IsNotEmpty()\n secret: string\n\n @IsBoolean()\n verifySSL: boolean = false\n}\n\nexport class FilesConfig {\n @IsNotEmpty()\n @IsString()\n dataPath: string\n\n @IsNotEmpty()\n @IsString()\n usersPath: string\n\n @IsNotEmpty()\n @IsString()\n spacesPath: string\n\n @IsNotEmpty()\n @IsString()\n tmpPath: string\n\n @IsInt()\n maxUploadSize: number = 5368709120 // 5 GB\n\n @IsBoolean()\n showHiddenFiles: boolean = false\n\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => FilesOnlyOfficeConfig)\n onlyoffice: FilesOnlyOfficeConfig = new FilesOnlyOfficeConfig()\n}\n"],"names":["FilesConfig","FilesOnlyOfficeConfig","enabled","externalServer","verifySSL","o","maxUploadSize","showHiddenFiles","onlyoffice"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAsBYA;eAAAA;;QAjBAC;eAAAA;;;kCAHQ;gCAC4F;;;;;;;;;;AAE1G,IAAA,AAAMA,wBAAN,MAAMA;;aAEXC,UAAU;aAIVC,iBAAyB;aAQzBC,YAAqB;;AACvB;;;;;;;;;;qCAPeC,IAA6BA,EAAEH,OAAO;;;;;;;;;AAS9C,IAAA,AAAMF,cAAN,MAAMA;;aAkBXM,gBAAwB,YAAW,OAAO;aAG1CC,kBAA2B;aAK3BC,aAAoC,
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/files/files.config.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 { Type } from 'class-transformer'\nimport { IsBoolean, IsInt, IsNotEmpty, IsNotEmptyObject, IsOptional, IsString, ValidateIf, ValidateNested } from 'class-validator'\n\nexport class FilesOnlyOfficeConfig {\n @IsBoolean()\n enabled = false\n\n @IsOptional()\n @IsString()\n externalServer: string = null\n\n @ValidateIf((o: FilesOnlyOfficeConfig) => o.enabled)\n @IsString()\n @IsNotEmpty()\n secret: string\n\n @IsBoolean()\n verifySSL: boolean = false\n}\n\nexport class FilesConfig {\n @IsNotEmpty()\n @IsString()\n dataPath: string\n\n @IsNotEmpty()\n @IsString()\n usersPath: string\n\n @IsNotEmpty()\n @IsString()\n spacesPath: string\n\n @IsNotEmpty()\n @IsString()\n tmpPath: string\n\n @IsInt()\n maxUploadSize: number = 5368709120 // 5 GB\n\n @IsBoolean()\n contentIndexing: boolean = true\n\n @IsBoolean()\n showHiddenFiles: boolean = false\n\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => FilesOnlyOfficeConfig)\n onlyoffice: FilesOnlyOfficeConfig = new FilesOnlyOfficeConfig()\n}\n"],"names":["FilesConfig","FilesOnlyOfficeConfig","enabled","externalServer","verifySSL","o","maxUploadSize","contentIndexing","showHiddenFiles","onlyoffice"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAsBYA;eAAAA;;QAjBAC;eAAAA;;;kCAHQ;gCAC4F;;;;;;;;;;AAE1G,IAAA,AAAMA,wBAAN,MAAMA;;aAEXC,UAAU;aAIVC,iBAAyB;aAQzBC,YAAqB;;AACvB;;;;;;;;;;qCAPeC,IAA6BA,EAAEH,OAAO;;;;;;;;;AAS9C,IAAA,AAAMF,cAAN,MAAMA;;aAkBXM,gBAAwB,YAAW,OAAO;aAG1CC,kBAA2B;aAG3BC,kBAA2B;aAK3BC,aAAoC,IAAIR;;AAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAFcA"}
|
|
@@ -56,7 +56,7 @@ let FilesContentManager = class FilesContentManager {
|
|
|
56
56
|
}
|
|
57
57
|
indexSuffixes.push(indexSuffix);
|
|
58
58
|
}
|
|
59
|
-
//
|
|
59
|
+
// clean up old tables
|
|
60
60
|
await this.filesIndexer.cleanIndexes(indexSuffixes);
|
|
61
61
|
}
|
|
62
62
|
async indexFiles(indexSuffix, paths) {
|
|
@@ -77,8 +77,8 @@ let FilesContentManager = class FilesContentManager {
|
|
|
77
77
|
context.regexBasePath = new RegExp(`^/?${p.realPath}/?`);
|
|
78
78
|
context.pathPrefix = p.pathPrefix || '';
|
|
79
79
|
if (!p.isDir) {
|
|
80
|
-
// space root file case
|
|
81
|
-
const rootFileContent = await this.analyzeFile(p.realPath, context);
|
|
80
|
+
// Handles the space root file or shared file case
|
|
81
|
+
const rootFileContent = await this.analyzeFile(p.realPath, context, true);
|
|
82
82
|
if (rootFileContent !== null) {
|
|
83
83
|
this.filesIndexer.insertRecord(indexName, rootFileContent).catch((e)=>{
|
|
84
84
|
errorRecords++;
|
|
@@ -134,10 +134,10 @@ let FilesContentManager = class FilesContentManager {
|
|
|
134
134
|
this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse : ${dir} : ${e}`);
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
-
async analyzeFile(realPath, context) {
|
|
137
|
+
async analyzeFile(realPath, context, isRootFile = false) {
|
|
138
138
|
const extension = _nodepath.default.extname(realPath).slice(1).toLowerCase();
|
|
139
139
|
if (!_indexing.indexableExtensions.has(extension)) return null;
|
|
140
|
-
const fileName = _nodepath.default.basename(realPath);
|
|
140
|
+
const fileName = isRootFile ? _nodepath.default.basename(context.pathPrefix) : _nodepath.default.basename(realPath);
|
|
141
141
|
// ignore temporary documents
|
|
142
142
|
if (fileName.startsWith('~$')) return null;
|
|
143
143
|
let stats;
|
|
@@ -150,7 +150,7 @@ let FilesContentManager = class FilesContentManager {
|
|
|
150
150
|
if (stats.size === 0 || stats.size > this.maxDocumentSize) {
|
|
151
151
|
return null;
|
|
152
152
|
}
|
|
153
|
-
const filePath = _nodepath.default.join(context.pathPrefix, _nodepath.default.dirname(realPath).replace(context.regexBasePath, '') || '.');
|
|
153
|
+
const filePath = isRootFile ? _nodepath.default.dirname(context.pathPrefix) || '.' : _nodepath.default.join(context.pathPrefix, _nodepath.default.dirname(realPath).replace(context.regexBasePath, '') || '.');
|
|
154
154
|
const f = context.db.get(stats.ino);
|
|
155
155
|
if (f && f.size === stats.size && f.path === filePath && f.name === fileName) {
|
|
156
156
|
// no changes, store inode id & skip it
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/files/services/files-content-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 { Injectable, Logger } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { indexableExtensions, shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { FileIndexContext, FileParseContext } from '../interfaces/file-parse-index'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { docTextify } from '../utils/doc-textify/doc-textify'\nimport { getMimeType } from '../utils/files'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesContentManager {\n private readonly maxDocumentSize = 150 * 1_000_000\n private readonly logger = new Logger(FilesContentManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser\n ) {}\n\n async parseAndIndexAllFiles(): Promise<void> {\n const indexSuffixes: string[] = []\n for await (const [id, type, paths] of this.filesParser.allPaths()) {\n let indexSuffix: string\n switch (type) {\n case 'user':\n indexSuffix = `${userIndexPrefix}${id}`\n break\n case 'space':\n indexSuffix = `${spaceIndexPrefix}${id}`\n break\n case 'share':\n indexSuffix = `${shareIndexPrefix}${id}`\n }\n try {\n await this.indexFiles(indexSuffix, paths)\n } catch (e) {\n this.logger.error(`${this.parseAndIndexAllFiles.name} : ${e}`)\n }\n indexSuffixes.push(indexSuffix)\n }\n // cleanup old tables\n await this.filesIndexer.cleanIndexes(indexSuffixes)\n }\n\n private async indexFiles(indexSuffix: string, paths: FileParseContext[]): Promise<void> {\n const indexName = this.filesIndexer.getIndexName(indexSuffix)\n if (!(await this.filesIndexer.createIndex(indexName))) {\n return\n }\n const context: FileIndexContext = {\n indexSuffix: indexSuffix,\n pathPrefix: '',\n regexBasePath: undefined,\n db: await this.filesIndexer.getRecordStats(indexName),\n fs: new Set()\n }\n let indexedRecords = 0\n let errorRecords = 0\n\n for (const p of paths) {\n context.regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n context.pathPrefix = p.pathPrefix || ''\n if (!p.isDir) {\n // space root file case\n const rootFileContent = await this.analyzeFile(p.realPath, context)\n if (rootFileContent !== null) {\n this.filesIndexer.insertRecord(indexName, rootFileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${rootFileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n continue\n }\n for await (const fileContent of this.parseFiles(p.realPath, context)) {\n this.filesIndexer.insertRecord(indexName, fileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${fileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n }\n\n if (context.db.size === 0 && indexedRecords === 0) {\n // case when no data\n this.filesIndexer\n .dropIndex(indexName)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to drop index : ${e}`))\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no data, index not stored`)\n } else {\n // clean up old records\n const recordsToDelete: number[] = [...context.db.keys()].filter((key) => !context.fs.has(key))\n if (recordsToDelete.length > 0) {\n this.filesIndexer\n .deleteRecords(indexName, recordsToDelete)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to delete records : ${e}`))\n }\n if (indexedRecords === 0 && errorRecords === 0 && recordsToDelete.length === 0) {\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no new data`)\n } else {\n this.logger.log(\n `${this.indexFiles.name} - ${indexSuffix} - indexed: ${indexedRecords - errorRecords}, errors: ${errorRecords}, deleted: ${recordsToDelete.length}`\n )\n }\n }\n }\n\n private async *parseFiles(dir: string, context: FileIndexContext): AsyncGenerator<FileContent> {\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()) {\n yield* this.parseFiles(realPath, context)\n continue\n }\n const fileContent = await this.analyzeFile(realPath, context)\n if (fileContent !== null) {\n yield fileContent\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse : ${dir} : ${e}`)\n }\n }\n\n private async analyzeFile(realPath: string, context: FileIndexContext): Promise<FileContent> {\n const extension = path.extname(realPath).slice(1).toLowerCase()\n if (!indexableExtensions.has(extension)) return null\n\n const fileName = path.basename(realPath)\n\n // ignore temporary documents\n if (fileName.startsWith('~$')) return null\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 stats ${realPath} : ${e}`)\n return null\n }\n if (stats.size === 0 || stats.size > this.maxDocumentSize) {\n return null\n }\n\n const filePath = path.join(context.pathPrefix, path.dirname(realPath).replace(context.regexBasePath, '') || '.')\n\n const f = context.db.get(stats.ino)\n if (f && f.size === stats.size && f.path === filePath && f.name === fileName) {\n // no changes, store inode id & skip it\n context.fs.add(stats.ino)\n return null\n }\n\n // store inode id\n context.fs.add(stats.ino)\n\n // store the content with null value to not parse it later\n return {\n id: stats.ino,\n path: filePath,\n name: fileName,\n mime: getMimeType(realPath, false),\n size: stats.size,\n mtime: stats.mtime.getTime(),\n content: await this.parseContent(realPath, extension)\n }\n }\n\n private async parseContent(rPath: string, extension: string): Promise<string> {\n try {\n const content = await docTextify(\n rPath,\n { newlineDelimiter: ' ', minCharsToExtract: 10 },\n {\n extension: extension,\n verified: true\n }\n )\n return content.length ? content : null\n } catch (e) {\n this.logger.warn(`${this.parseContent.name} - unable to index : ${rPath} : ${e}`)\n }\n return null\n }\n}\n"],"names":["FilesContentManager","parseAndIndexAllFiles","indexSuffixes","id","type","paths","filesParser","allPaths","indexSuffix","userIndexPrefix","spaceIndexPrefix","shareIndexPrefix","indexFiles","e","logger","error","name","push","filesIndexer","cleanIndexes","indexName","getIndexName","createIndex","context","pathPrefix","regexBasePath","undefined","db","getRecordStats","fs","Set","indexedRecords","errorRecords","p","RegExp","realPath","isDir","rootFileContent","analyzeFile","insertRecord","catch","fileContent","parseFiles","size","dropIndex","log","recordsToDelete","keys","filter","key","has","length","deleteRecords","dir","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","extension","extname","slice","toLowerCase","indexableExtensions","fileName","basename","startsWith","stats","stat","maxDocumentSize","filePath","dirname","replace","f","get","ino","add","mime","getMimeType","mtime","getTime","content","parseContent","rPath","docTextify","newlineDelimiter","minCharsToExtract","verified","Logger"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/files/services/files-content-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 { Injectable, Logger } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { indexableExtensions, shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { FileIndexContext, FileParseContext } from '../interfaces/file-parse-index'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { docTextify } from '../utils/doc-textify/doc-textify'\nimport { getMimeType } from '../utils/files'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesContentManager {\n private readonly maxDocumentSize = 150 * 1_000_000\n private readonly logger = new Logger(FilesContentManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser\n ) {}\n\n async parseAndIndexAllFiles(): Promise<void> {\n const indexSuffixes: string[] = []\n for await (const [id, type, paths] of this.filesParser.allPaths()) {\n let indexSuffix: string\n switch (type) {\n case 'user':\n indexSuffix = `${userIndexPrefix}${id}`\n break\n case 'space':\n indexSuffix = `${spaceIndexPrefix}${id}`\n break\n case 'share':\n indexSuffix = `${shareIndexPrefix}${id}`\n }\n try {\n await this.indexFiles(indexSuffix, paths)\n } catch (e) {\n this.logger.error(`${this.parseAndIndexAllFiles.name} : ${e}`)\n }\n indexSuffixes.push(indexSuffix)\n }\n // clean up old tables\n await this.filesIndexer.cleanIndexes(indexSuffixes)\n }\n\n private async indexFiles(indexSuffix: string, paths: FileParseContext[]): Promise<void> {\n const indexName = this.filesIndexer.getIndexName(indexSuffix)\n if (!(await this.filesIndexer.createIndex(indexName))) {\n return\n }\n const context: FileIndexContext = {\n indexSuffix: indexSuffix,\n pathPrefix: '',\n regexBasePath: undefined,\n db: await this.filesIndexer.getRecordStats(indexName),\n fs: new Set()\n }\n let indexedRecords = 0\n let errorRecords = 0\n\n for (const p of paths) {\n context.regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n context.pathPrefix = p.pathPrefix || ''\n if (!p.isDir) {\n // Handles the space root file or shared file case\n const rootFileContent = await this.analyzeFile(p.realPath, context, true)\n if (rootFileContent !== null) {\n this.filesIndexer.insertRecord(indexName, rootFileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${rootFileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n continue\n }\n for await (const fileContent of this.parseFiles(p.realPath, context)) {\n this.filesIndexer.insertRecord(indexName, fileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${fileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n }\n\n if (context.db.size === 0 && indexedRecords === 0) {\n // case when no data\n this.filesIndexer\n .dropIndex(indexName)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to drop index : ${e}`))\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no data, index not stored`)\n } else {\n // clean up old records\n const recordsToDelete: number[] = [...context.db.keys()].filter((key) => !context.fs.has(key))\n if (recordsToDelete.length > 0) {\n this.filesIndexer\n .deleteRecords(indexName, recordsToDelete)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to delete records : ${e}`))\n }\n if (indexedRecords === 0 && errorRecords === 0 && recordsToDelete.length === 0) {\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no new data`)\n } else {\n this.logger.log(\n `${this.indexFiles.name} - ${indexSuffix} - indexed: ${indexedRecords - errorRecords}, errors: ${errorRecords}, deleted: ${recordsToDelete.length}`\n )\n }\n }\n }\n\n private async *parseFiles(dir: string, context: FileIndexContext): AsyncGenerator<FileContent> {\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()) {\n yield* this.parseFiles(realPath, context)\n continue\n }\n const fileContent = await this.analyzeFile(realPath, context)\n if (fileContent !== null) {\n yield fileContent\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse : ${dir} : ${e}`)\n }\n }\n\n private async analyzeFile(realPath: string, context: FileIndexContext, isRootFile = false): Promise<FileContent> {\n const extension = path.extname(realPath).slice(1).toLowerCase()\n if (!indexableExtensions.has(extension)) return null\n\n const fileName = isRootFile ? path.basename(context.pathPrefix) : path.basename(realPath)\n\n // ignore temporary documents\n if (fileName.startsWith('~$')) return null\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 stats ${realPath} : ${e}`)\n return null\n }\n if (stats.size === 0 || stats.size > this.maxDocumentSize) {\n return null\n }\n\n const filePath = isRootFile\n ? path.dirname(context.pathPrefix) || '.'\n : path.join(context.pathPrefix, path.dirname(realPath).replace(context.regexBasePath, '') || '.')\n\n const f = context.db.get(stats.ino)\n if (f && f.size === stats.size && f.path === filePath && f.name === fileName) {\n // no changes, store inode id & skip it\n context.fs.add(stats.ino)\n return null\n }\n\n // store inode id\n context.fs.add(stats.ino)\n\n // store the content with null value to not parse it later\n return {\n id: stats.ino,\n path: filePath,\n name: fileName,\n mime: getMimeType(realPath, false),\n size: stats.size,\n mtime: stats.mtime.getTime(),\n content: await this.parseContent(realPath, extension)\n }\n }\n\n private async parseContent(rPath: string, extension: string): Promise<string> {\n try {\n const content = await docTextify(\n rPath,\n { newlineDelimiter: ' ', minCharsToExtract: 10 },\n {\n extension: extension,\n verified: true\n }\n )\n return content.length ? content : null\n } catch (e) {\n this.logger.warn(`${this.parseContent.name} - unable to index : ${rPath} : ${e}`)\n }\n return null\n }\n}\n"],"names":["FilesContentManager","parseAndIndexAllFiles","indexSuffixes","id","type","paths","filesParser","allPaths","indexSuffix","userIndexPrefix","spaceIndexPrefix","shareIndexPrefix","indexFiles","e","logger","error","name","push","filesIndexer","cleanIndexes","indexName","getIndexName","createIndex","context","pathPrefix","regexBasePath","undefined","db","getRecordStats","fs","Set","indexedRecords","errorRecords","p","RegExp","realPath","isDir","rootFileContent","analyzeFile","insertRecord","catch","fileContent","parseFiles","size","dropIndex","log","recordsToDelete","keys","filter","key","has","length","deleteRecords","dir","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","isRootFile","extension","extname","slice","toLowerCase","indexableExtensions","fileName","basename","startsWith","stats","stat","maxDocumentSize","filePath","dirname","replace","f","get","ino","add","mime","getMimeType","mtime","getTime","content","parseContent","rPath","docTextify","newlineDelimiter","minCharsToExtract","verified","Logger"],"mappings":"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"}
|
|
@@ -289,12 +289,12 @@ let FilesManager = class FilesManager {
|
|
|
289
289
|
/* Skip validation when moving to the same space; for copy operations, run all checks. */ if (!isMove || isMove && srcSpace.id !== dstSpace.id) {
|
|
290
290
|
const size = isDir ? (await (0, _files1.dirSize)(srcSpace.realPath))[0] : await (0, _files1.fileSize)(srcSpace.realPath);
|
|
291
291
|
if (dstSpace.willExceedQuota(size)) {
|
|
292
|
-
this.logger.warn(`${this.copyMove.name} - quota will be exceeded for *${dstSpace.alias}* (${dstSpace.id})`);
|
|
293
|
-
throw new _fileerror.FileError(_common.HttpStatus.INSUFFICIENT_STORAGE, '
|
|
292
|
+
this.logger.warn(`${this.copyMove.name} - storage quota will be exceeded for *${dstSpace.alias}* (${dstSpace.id})`);
|
|
293
|
+
throw new _fileerror.FileError(_common.HttpStatus.INSUFFICIENT_STORAGE, 'Storage quota will be exceeded');
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
|
-
// check lock conflicts on source
|
|
297
|
+
// check lock conflicts on source and destination
|
|
298
298
|
let recursive;
|
|
299
299
|
let depth;
|
|
300
300
|
if (dav?.depth) {
|
|
@@ -321,7 +321,7 @@ let FilesManager = class FilesManager {
|
|
|
321
321
|
// todo : versioning here
|
|
322
322
|
await this.delete(user, dstSpace);
|
|
323
323
|
}
|
|
324
|
-
// send to task watcher
|
|
324
|
+
// send it to task watcher
|
|
325
325
|
if (srcSpace.task?.cacheKey) {
|
|
326
326
|
if (!isDir) srcSpace.task.props.totalSize = await (0, _files1.fileSize)(srcSpace.realPath);
|
|
327
327
|
_filetaskevent.FileTaskEvent.emit('startWatch', srcSpace, isMove ? _operations.FILE_OPERATION.MOVE : _operations.FILE_OPERATION.COPY, dstSpace.realPath);
|