@internxt/cli 1.5.7 → 1.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +37 -31
  2. package/dist/commands/add-cert.js +0 -1
  3. package/dist/commands/config.js +0 -1
  4. package/dist/commands/create-folder.js +0 -1
  5. package/dist/commands/delete-permanently-file.js +0 -1
  6. package/dist/commands/delete-permanently-folder.js +0 -1
  7. package/dist/commands/download-file.js +0 -1
  8. package/dist/commands/list.js +0 -1
  9. package/dist/commands/login.js +0 -1
  10. package/dist/commands/logout.js +0 -1
  11. package/dist/commands/logs.js +0 -1
  12. package/dist/commands/move-file.js +0 -1
  13. package/dist/commands/move-folder.js +0 -1
  14. package/dist/commands/rename-file.js +0 -1
  15. package/dist/commands/rename-folder.js +0 -1
  16. package/dist/commands/trash-clear.js +0 -1
  17. package/dist/commands/trash-file.js +0 -1
  18. package/dist/commands/trash-folder.js +0 -1
  19. package/dist/commands/trash-list.js +0 -1
  20. package/dist/commands/trash-restore-file.js +0 -1
  21. package/dist/commands/trash-restore-folder.js +0 -1
  22. package/dist/commands/upload-file.js +1 -2
  23. package/dist/commands/webdav-config.d.ts +1 -0
  24. package/dist/commands/webdav-config.js +10 -7
  25. package/dist/commands/webdav.js +0 -1
  26. package/dist/commands/whoami.js +0 -1
  27. package/dist/hooks/prerun/auth_check.js +0 -1
  28. package/dist/services/config.service.d.ts +1 -0
  29. package/dist/services/config.service.js +3 -0
  30. package/dist/types/command.types.d.ts +1 -0
  31. package/dist/types/drive.types.d.ts +1 -0
  32. package/dist/utils/cli.utils.d.ts +1 -2
  33. package/dist/utils/cli.utils.js +2 -2
  34. package/dist/utils/drive.utils.d.ts +2 -1
  35. package/dist/utils/drive.utils.js +14 -0
  36. package/dist/utils/errors.utils.d.ts +2 -1
  37. package/dist/utils/errors.utils.js +10 -4
  38. package/dist/utils/logger.utils.js +0 -10
  39. package/dist/utils/webdav.utils.d.ts +17 -5
  40. package/dist/utils/webdav.utils.js +15 -6
  41. package/dist/webdav/handlers/MKCOL.handler.d.ts +2 -0
  42. package/dist/webdav/handlers/MKCOL.handler.js +6 -16
  43. package/dist/webdav/handlers/MOVE.handler.d.ts +2 -0
  44. package/dist/webdav/handlers/MOVE.handler.js +3 -10
  45. package/dist/webdav/handlers/PUT.handler.d.ts +2 -2
  46. package/dist/webdav/handlers/PUT.handler.js +13 -18
  47. package/dist/webdav/middewares/auth.middleware.js +8 -2
  48. package/dist/webdav/middewares/errors.middleware.js +9 -2
  49. package/dist/webdav/services/webdav-folder.service.d.ts +17 -0
  50. package/dist/webdav/services/webdav-folder.service.js +51 -0
  51. package/dist/webdav/webdav-server.js +8 -1
  52. package/oclif.manifest.json +9 -1
  53. package/package.json +1 -1
package/README.md CHANGED
@@ -10,6 +10,7 @@ A CLI tool to interact with your Internxt encrypted files
10
10
  * [Project Maintenance](#project-maintenance)
11
11
  * [Installation](#installation)
12
12
  * [Usage](#usage)
13
+ * [Docker](#docker)
13
14
  * [Commands](#commands)
14
15
  * [Current Limitations](#current-limitations)
15
16
  <!-- tocstop -->
@@ -51,7 +52,7 @@ $ npm install -g @internxt/cli
51
52
  $ internxt COMMAND
52
53
  running command...
53
54
  $ internxt (--version)
54
- @internxt/cli/1.5.7 linux-x64 node-v22.20.0
55
+ @internxt/cli/1.5.8 linux-x64 node-v22.21.1
55
56
  $ internxt --help [COMMAND]
56
57
  USAGE
57
58
  $ internxt COMMAND
@@ -59,6 +60,10 @@ USAGE
59
60
  ```
60
61
  <!-- usagestop -->
61
62
 
63
+ # Docker
64
+
65
+ [`Internxt WebDAV (Docker Integration)`](docker/README.md)
66
+
62
67
  # Commands
63
68
 
64
69
  <!-- commands -->
@@ -120,7 +125,7 @@ EXAMPLES
120
125
  $ internxt add-cert
121
126
  ```
122
127
 
123
- _See code: [src/commands/add-cert.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/add-cert.ts)_
128
+ _See code: [src/commands/add-cert.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/add-cert.ts)_
124
129
 
125
130
  ## `internxt autocomplete [SHELL]`
126
131
 
@@ -171,7 +176,7 @@ EXAMPLES
171
176
  $ internxt config
172
177
  ```
173
178
 
174
- _See code: [src/commands/config.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/config.ts)_
179
+ _See code: [src/commands/config.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/config.ts)_
175
180
 
176
181
  ## `internxt create-folder`
177
182
 
@@ -200,7 +205,7 @@ EXAMPLES
200
205
  $ internxt create-folder
201
206
  ```
202
207
 
203
- _See code: [src/commands/create-folder.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/create-folder.ts)_
208
+ _See code: [src/commands/create-folder.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/create-folder.ts)_
204
209
 
205
210
  ## `internxt delete-permanently-file`
206
211
 
@@ -230,7 +235,7 @@ EXAMPLES
230
235
  $ internxt delete-permanently-file
231
236
  ```
232
237
 
233
- _See code: [src/commands/delete-permanently-file.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/delete-permanently-file.ts)_
238
+ _See code: [src/commands/delete-permanently-file.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/delete-permanently-file.ts)_
234
239
 
235
240
  ## `internxt delete-permanently-folder`
236
241
 
@@ -260,7 +265,7 @@ EXAMPLES
260
265
  $ internxt delete-permanently-folder
261
266
  ```
262
267
 
263
- _See code: [src/commands/delete-permanently-folder.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/delete-permanently-folder.ts)_
268
+ _See code: [src/commands/delete-permanently-folder.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/delete-permanently-folder.ts)_
264
269
 
265
270
  ## `internxt delete permanently file`
266
271
 
@@ -349,7 +354,7 @@ EXAMPLES
349
354
  $ internxt download-file
350
355
  ```
351
356
 
352
- _See code: [src/commands/download-file.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/download-file.ts)_
357
+ _See code: [src/commands/download-file.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/download-file.ts)_
353
358
 
354
359
  ## `internxt download file`
355
360
 
@@ -408,7 +413,7 @@ EXAMPLES
408
413
  $ internxt list
409
414
  ```
410
415
 
411
- _See code: [src/commands/list.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/list.ts)_
416
+ _See code: [src/commands/list.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/list.ts)_
412
417
 
413
418
  ## `internxt login`
414
419
 
@@ -439,7 +444,7 @@ EXAMPLES
439
444
  $ internxt login
440
445
  ```
441
446
 
442
- _See code: [src/commands/login.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/login.ts)_
447
+ _See code: [src/commands/login.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/login.ts)_
443
448
 
444
449
  ## `internxt logout`
445
450
 
@@ -459,7 +464,7 @@ EXAMPLES
459
464
  $ internxt logout
460
465
  ```
461
466
 
462
- _See code: [src/commands/logout.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/logout.ts)_
467
+ _See code: [src/commands/logout.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/logout.ts)_
463
468
 
464
469
  ## `internxt logs`
465
470
 
@@ -479,7 +484,7 @@ EXAMPLES
479
484
  $ internxt logs
480
485
  ```
481
486
 
482
- _See code: [src/commands/logs.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/logs.ts)_
487
+ _See code: [src/commands/logs.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/logs.ts)_
483
488
 
484
489
  ## `internxt move-file`
485
490
 
@@ -511,7 +516,7 @@ EXAMPLES
511
516
  $ internxt move-file
512
517
  ```
513
518
 
514
- _See code: [src/commands/move-file.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/move-file.ts)_
519
+ _See code: [src/commands/move-file.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/move-file.ts)_
515
520
 
516
521
  ## `internxt move-folder`
517
522
 
@@ -543,7 +548,7 @@ EXAMPLES
543
548
  $ internxt move-folder
544
549
  ```
545
550
 
546
- _See code: [src/commands/move-folder.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/move-folder.ts)_
551
+ _See code: [src/commands/move-folder.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/move-folder.ts)_
547
552
 
548
553
  ## `internxt move file`
549
554
 
@@ -634,7 +639,7 @@ EXAMPLES
634
639
  $ internxt rename-file
635
640
  ```
636
641
 
637
- _See code: [src/commands/rename-file.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/rename-file.ts)_
642
+ _See code: [src/commands/rename-file.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/rename-file.ts)_
638
643
 
639
644
  ## `internxt rename-folder`
640
645
 
@@ -665,7 +670,7 @@ EXAMPLES
665
670
  $ internxt rename-folder
666
671
  ```
667
672
 
668
- _See code: [src/commands/rename-folder.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/rename-folder.ts)_
673
+ _See code: [src/commands/rename-folder.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/rename-folder.ts)_
669
674
 
670
675
  ## `internxt rename file`
671
676
 
@@ -753,7 +758,7 @@ EXAMPLES
753
758
  $ internxt trash-clear
754
759
  ```
755
760
 
756
- _See code: [src/commands/trash-clear.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/trash-clear.ts)_
761
+ _See code: [src/commands/trash-clear.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/trash-clear.ts)_
757
762
 
758
763
  ## `internxt trash-file`
759
764
 
@@ -783,7 +788,7 @@ EXAMPLES
783
788
  $ internxt trash-file
784
789
  ```
785
790
 
786
- _See code: [src/commands/trash-file.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/trash-file.ts)_
791
+ _See code: [src/commands/trash-file.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/trash-file.ts)_
787
792
 
788
793
  ## `internxt trash-folder`
789
794
 
@@ -813,7 +818,7 @@ EXAMPLES
813
818
  $ internxt trash-folder
814
819
  ```
815
820
 
816
- _See code: [src/commands/trash-folder.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/trash-folder.ts)_
821
+ _See code: [src/commands/trash-folder.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/trash-folder.ts)_
817
822
 
818
823
  ## `internxt trash-list`
819
824
 
@@ -839,7 +844,7 @@ EXAMPLES
839
844
  $ internxt trash-list
840
845
  ```
841
846
 
842
- _See code: [src/commands/trash-list.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/trash-list.ts)_
847
+ _See code: [src/commands/trash-list.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/trash-list.ts)_
843
848
 
844
849
  ## `internxt trash-restore-file`
845
850
 
@@ -870,7 +875,7 @@ EXAMPLES
870
875
  $ internxt trash-restore-file
871
876
  ```
872
877
 
873
- _See code: [src/commands/trash-restore-file.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/trash-restore-file.ts)_
878
+ _See code: [src/commands/trash-restore-file.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/trash-restore-file.ts)_
874
879
 
875
880
  ## `internxt trash-restore-folder`
876
881
 
@@ -901,7 +906,7 @@ EXAMPLES
901
906
  $ internxt trash-restore-folder
902
907
  ```
903
908
 
904
- _See code: [src/commands/trash-restore-folder.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/trash-restore-folder.ts)_
909
+ _See code: [src/commands/trash-restore-folder.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/trash-restore-folder.ts)_
905
910
 
906
911
  ## `internxt trash clear`
907
912
 
@@ -1098,7 +1103,7 @@ EXAMPLES
1098
1103
  $ internxt upload-file
1099
1104
  ```
1100
1105
 
1101
- _See code: [src/commands/upload-file.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/upload-file.ts)_
1106
+ _See code: [src/commands/upload-file.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/upload-file.ts)_
1102
1107
 
1103
1108
  ## `internxt upload file`
1104
1109
 
@@ -1153,7 +1158,7 @@ EXAMPLES
1153
1158
  $ internxt webdav status
1154
1159
  ```
1155
1160
 
1156
- _See code: [src/commands/webdav.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/webdav.ts)_
1161
+ _See code: [src/commands/webdav.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/webdav.ts)_
1157
1162
 
1158
1163
  ## `internxt webdav-config`
1159
1164
 
@@ -1161,14 +1166,15 @@ Edit the configuration of the Internxt CLI WebDav server as the port or the prot
1161
1166
 
1162
1167
  ```
1163
1168
  USAGE
1164
- $ internxt webdav-config [--json] [-l <value>] [-p <value>] [-s | -h] [-t <value>]
1169
+ $ internxt webdav-config [--json] [-l <value>] [-p <value>] [-s | -h] [-t <value>] [-c]
1165
1170
 
1166
1171
  FLAGS
1167
- -h, --http Configures the WebDAV server to use insecure plain HTTP.
1168
- -l, --host=<value> The listening host for the WebDAV server.
1169
- -p, --port=<value> The new port for the WebDAV server.
1170
- -s, --https Configures the WebDAV server to use HTTPS with self-signed certificates.
1171
- -t, --timeout=<value> Configures the WebDAV server to use this timeout in minutes.
1172
+ -c, --[no-]createFullPath Auto-create missing parent directories during file uploads.
1173
+ -h, --http Configures the WebDAV server to use insecure plain HTTP.
1174
+ -l, --host=<value> The listening host for the WebDAV server.
1175
+ -p, --port=<value> The new port for the WebDAV server.
1176
+ -s, --https Configures the WebDAV server to use HTTPS with self-signed certificates.
1177
+ -t, --timeout=<value> Configures the WebDAV server to use this timeout in minutes.
1172
1178
 
1173
1179
  GLOBAL FLAGS
1174
1180
  --json Format output as json.
@@ -1180,7 +1186,7 @@ EXAMPLES
1180
1186
  $ internxt webdav-config
1181
1187
  ```
1182
1188
 
1183
- _See code: [src/commands/webdav-config.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/webdav-config.ts)_
1189
+ _See code: [src/commands/webdav-config.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/webdav-config.ts)_
1184
1190
 
1185
1191
  ## `internxt whoami`
1186
1192
 
@@ -1200,7 +1206,7 @@ EXAMPLES
1200
1206
  $ internxt whoami
1201
1207
  ```
1202
1208
 
1203
- _See code: [src/commands/whoami.ts](https://github.com/internxt/cli/blob/v1.5.7/src/commands/whoami.ts)_
1209
+ _See code: [src/commands/whoami.ts](https://github.com/internxt/cli/blob/v1.5.8/src/commands/whoami.ts)_
1204
1210
  <!-- commandsstop -->
1205
1211
 
1206
1212
  # Current Limitations
@@ -41,7 +41,6 @@ class AddCert extends core_1.Command {
41
41
  error,
42
42
  command: this.id,
43
43
  logReporter: this.log.bind(this),
44
- errorReporter: this.error.bind(this),
45
44
  jsonFlag: flags['json'],
46
45
  });
47
46
  this.exit(1);
@@ -42,7 +42,6 @@ class Config extends core_1.Command {
42
42
  error,
43
43
  command: this.id,
44
44
  logReporter: this.log.bind(this),
45
- errorReporter: this.error.bind(this),
46
45
  jsonFlag: flags['json'],
47
46
  });
48
47
  this.exit(1);
@@ -60,7 +60,6 @@ class CreateFolder extends core_1.Command {
60
60
  error,
61
61
  command: this.id,
62
62
  logReporter: this.log.bind(this),
63
- errorReporter: this.error.bind(this),
64
63
  jsonFlag: flags['json'],
65
64
  });
66
65
  this.exit(1);
@@ -43,7 +43,6 @@ class DeletePermanentlyFile extends core_1.Command {
43
43
  error,
44
44
  command: this.id,
45
45
  logReporter: this.log.bind(this),
46
- errorReporter: this.error.bind(this),
47
46
  jsonFlag: flags['json'],
48
47
  });
49
48
  this.exit(1);
@@ -43,7 +43,6 @@ class DeletePermanentlyFolder extends core_1.Command {
43
43
  error,
44
44
  command: this.id,
45
45
  logReporter: this.log.bind(this),
46
- errorReporter: this.error.bind(this),
47
46
  jsonFlag: flags['json'],
48
47
  });
49
48
  this.exit(1);
@@ -92,7 +92,6 @@ class DownloadFile extends core_1.Command {
92
92
  error,
93
93
  command: this.id,
94
94
  logReporter: this.log.bind(this),
95
- errorReporter: this.error.bind(this),
96
95
  jsonFlag: flags['json'],
97
96
  });
98
97
  this.exit(1);
@@ -75,7 +75,6 @@ class List extends core_1.Command {
75
75
  error,
76
76
  command: this.id,
77
77
  logReporter: this.log.bind(this),
78
- errorReporter: this.error.bind(this),
79
78
  jsonFlag: flags['json'],
80
79
  });
81
80
  this.exit(1);
@@ -118,7 +118,6 @@ class Login extends core_1.Command {
118
118
  error,
119
119
  command: this.id,
120
120
  logReporter: this.log.bind(this),
121
- errorReporter: this.error.bind(this),
122
121
  jsonFlag: flags['json'],
123
122
  });
124
123
  this.exit(1);
@@ -32,7 +32,6 @@ class Logout extends core_1.Command {
32
32
  error,
33
33
  command: this.id,
34
34
  logReporter: this.log.bind(this),
35
- errorReporter: this.error.bind(this),
36
35
  jsonFlag: flags['json'],
37
36
  });
38
37
  this.exit(1);
@@ -21,7 +21,6 @@ class Logs extends core_1.Command {
21
21
  error,
22
22
  command: this.id,
23
23
  logReporter: this.log.bind(this),
24
- errorReporter: this.error.bind(this),
25
24
  jsonFlag: flags['json'],
26
25
  });
27
26
  this.exit(1);
@@ -48,7 +48,6 @@ class MoveFile extends core_1.Command {
48
48
  error,
49
49
  command: this.id,
50
50
  logReporter: this.log.bind(this),
51
- errorReporter: this.error.bind(this),
52
51
  jsonFlag: flags['json'],
53
52
  });
54
53
  this.exit(1);
@@ -50,7 +50,6 @@ class MoveFolder extends core_1.Command {
50
50
  error,
51
51
  command: this.id,
52
52
  logReporter: this.log.bind(this),
53
- errorReporter: this.error.bind(this),
54
53
  jsonFlag: flags['json'],
55
54
  });
56
55
  this.exit(1);
@@ -51,7 +51,6 @@ class RenameFile extends core_1.Command {
51
51
  error,
52
52
  command: this.id,
53
53
  logReporter: this.log.bind(this),
54
- errorReporter: this.error.bind(this),
55
54
  jsonFlag: flags['json'],
56
55
  });
57
56
  this.exit(1);
@@ -44,7 +44,6 @@ class RenameFolder extends core_1.Command {
44
44
  error,
45
45
  command: this.id,
46
46
  logReporter: this.log.bind(this),
47
- errorReporter: this.error.bind(this),
48
47
  jsonFlag: flags['json'],
49
48
  });
50
49
  this.exit(1);
@@ -49,7 +49,6 @@ class TrashClear extends core_1.Command {
49
49
  error,
50
50
  command: this.id,
51
51
  logReporter: this.log.bind(this),
52
- errorReporter: this.error.bind(this),
53
52
  jsonFlag: flags['json'],
54
53
  });
55
54
  this.exit(1);
@@ -38,7 +38,6 @@ class TrashFile extends core_1.Command {
38
38
  error,
39
39
  command: this.id,
40
40
  logReporter: this.log.bind(this),
41
- errorReporter: this.error.bind(this),
42
41
  jsonFlag: flags['json'],
43
42
  });
44
43
  this.exit(1);
@@ -38,7 +38,6 @@ class TrashFolder extends core_1.Command {
38
38
  error,
39
39
  command: this.id,
40
40
  logReporter: this.log.bind(this),
41
- errorReporter: this.error.bind(this),
42
41
  jsonFlag: flags['json'],
43
42
  });
44
43
  this.exit(1);
@@ -62,7 +62,6 @@ class TrashList extends core_1.Command {
62
62
  error,
63
63
  command: this.id,
64
64
  logReporter: this.log.bind(this),
65
- errorReporter: this.error.bind(this),
66
65
  jsonFlag: flags['json'],
67
66
  });
68
67
  this.exit(1);
@@ -48,7 +48,6 @@ class TrashRestoreFile extends core_1.Command {
48
48
  error,
49
49
  command: this.id,
50
50
  logReporter: this.log.bind(this),
51
- errorReporter: this.error.bind(this),
52
51
  jsonFlag: flags['json'],
53
52
  });
54
53
  this.exit(1);
@@ -50,7 +50,6 @@ class TrashRestoreFolder extends core_1.Command {
50
50
  error,
51
51
  command: this.id,
52
52
  logReporter: this.log.bind(this),
53
- errorReporter: this.error.bind(this),
54
53
  jsonFlag: flags['json'],
55
54
  });
56
55
  this.exit(1);
@@ -121,7 +121,7 @@ class UploadFile extends core_1.Command {
121
121
  }
122
122
  }
123
123
  catch (error) {
124
- errors_utils_1.ErrorUtils.report(this.error.bind(this), error, { command: this.id });
124
+ errors_utils_1.ErrorUtils.report(error, { command: this.id });
125
125
  }
126
126
  progressBar?.update(100);
127
127
  progressBar?.stop();
@@ -144,7 +144,6 @@ class UploadFile extends core_1.Command {
144
144
  error,
145
145
  command: this.id,
146
146
  logReporter: this.log.bind(this),
147
- errorReporter: this.error.bind(this),
148
147
  jsonFlag: flags['json'],
149
148
  });
150
149
  this.exit(1);
@@ -10,6 +10,7 @@ export default class WebDAVConfig extends Command {
10
10
  https: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
11
  http: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
12
  timeout: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ createFullPath: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
14
  };
14
15
  static readonly enableJsonFlag = true;
15
16
  run: () => Promise<{
@@ -39,16 +39,20 @@ class WebDAVConfig extends core_1.Command {
39
39
  required: false,
40
40
  min: 0,
41
41
  }),
42
+ createFullPath: core_1.Flags.boolean({
43
+ char: 'c',
44
+ description: 'Auto-create missing parent directories during file uploads.',
45
+ required: false,
46
+ allowNo: true,
47
+ }),
42
48
  };
43
49
  static enableJsonFlag = true;
44
50
  run = async () => {
45
- const { flags } = await this.parse(WebDAVConfig);
51
+ const { flags: { host, port, http, https, timeout, createFullPath }, } = await this.parse(WebDAVConfig);
46
52
  const webdavConfig = await config_service_1.ConfigService.instance.readWebdavConfig();
47
- const host = flags['host'];
48
53
  if (host) {
49
54
  webdavConfig['host'] = host;
50
55
  }
51
- const port = flags['port'];
52
56
  if (port) {
53
57
  if (validation_service_1.ValidationService.instance.validateTCPIntegerPort(port)) {
54
58
  webdavConfig['port'] = port;
@@ -57,18 +61,18 @@ class WebDAVConfig extends core_1.Command {
57
61
  throw new command_types_1.NotValidPortError();
58
62
  }
59
63
  }
60
- const http = flags['http'];
61
64
  if (http) {
62
65
  webdavConfig['protocol'] = 'http';
63
66
  }
64
- const https = flags['https'];
65
67
  if (https) {
66
68
  webdavConfig['protocol'] = 'https';
67
69
  }
68
- const timeout = flags['timeout'];
69
70
  if (timeout !== undefined) {
70
71
  webdavConfig['timeoutMinutes'] = timeout;
71
72
  }
73
+ if (createFullPath !== undefined) {
74
+ webdavConfig['createFullPath'] = createFullPath;
75
+ }
72
76
  await config_service_1.ConfigService.instance.saveWebdavConfig(webdavConfig);
73
77
  const message = `On the next start, the WebDAV server will use the next config: ${JSON.stringify(webdavConfig)}`;
74
78
  cli_utils_1.CLIUtils.success(this.log.bind(this), message);
@@ -80,7 +84,6 @@ class WebDAVConfig extends core_1.Command {
80
84
  error,
81
85
  command: this.id,
82
86
  logReporter: this.log.bind(this),
83
- errorReporter: this.error.bind(this),
84
87
  jsonFlag: flags['json'],
85
88
  });
86
89
  this.exit(1);
@@ -62,7 +62,6 @@ class Webdav extends core_1.Command {
62
62
  error,
63
63
  command: this.id,
64
64
  logReporter: this.log.bind(this),
65
- errorReporter: this.error.bind(this),
66
65
  jsonFlag: flags['json'],
67
66
  });
68
67
  this.exit(1);
@@ -47,7 +47,6 @@ class Whoami extends core_1.Command {
47
47
  error,
48
48
  command: this.id,
49
49
  logReporter: this.log.bind(this),
50
- errorReporter: this.error.bind(this),
51
50
  jsonFlag: flags['json'],
52
51
  });
53
52
  this.exit(1);
@@ -30,7 +30,6 @@ const hook = async function (opts) {
30
30
  error: err,
31
31
  command: Command.id,
32
32
  logReporter: this.log.bind(this),
33
- errorReporter: this.error.bind(this),
34
33
  jsonFlag,
35
34
  });
36
35
  opts.context.exit(1);
@@ -12,6 +12,7 @@ export declare class ConfigService {
12
12
  static readonly WEBDAV_DEFAULT_PORT = "3005";
13
13
  static readonly WEBDAV_DEFAULT_PROTOCOL = "https";
14
14
  static readonly WEBDAV_DEFAULT_TIMEOUT = 0;
15
+ static readonly WEBDAV_DEFAULT_CREATE_FULL_PATH = true;
15
16
  static readonly instance: ConfigService;
16
17
  get: (key: keyof ConfigKeys) => string;
17
18
  saveUser: (loginCredentials: LoginCredentials) => Promise<void>;
@@ -20,6 +20,7 @@ class ConfigService {
20
20
  static WEBDAV_DEFAULT_PORT = '3005';
21
21
  static WEBDAV_DEFAULT_PROTOCOL = 'https';
22
22
  static WEBDAV_DEFAULT_TIMEOUT = 0;
23
+ static WEBDAV_DEFAULT_CREATE_FULL_PATH = true;
23
24
  static instance = new ConfigService();
24
25
  get = (key) => {
25
26
  const value = process.env[key];
@@ -64,6 +65,7 @@ class ConfigService {
64
65
  port: configs?.port ?? ConfigService.WEBDAV_DEFAULT_PORT,
65
66
  protocol: configs?.protocol ?? ConfigService.WEBDAV_DEFAULT_PROTOCOL,
66
67
  timeoutMinutes: configs?.timeoutMinutes ?? ConfigService.WEBDAV_DEFAULT_TIMEOUT,
68
+ createFullPath: configs?.createFullPath ?? ConfigService.WEBDAV_DEFAULT_CREATE_FULL_PATH,
67
69
  };
68
70
  }
69
71
  catch {
@@ -72,6 +74,7 @@ class ConfigService {
72
74
  port: ConfigService.WEBDAV_DEFAULT_PORT,
73
75
  protocol: ConfigService.WEBDAV_DEFAULT_PROTOCOL,
74
76
  timeoutMinutes: ConfigService.WEBDAV_DEFAULT_TIMEOUT,
77
+ createFullPath: ConfigService.WEBDAV_DEFAULT_CREATE_FULL_PATH,
75
78
  };
76
79
  }
77
80
  };
@@ -34,6 +34,7 @@ export interface WebdavConfig {
34
34
  port: string;
35
35
  protocol: 'http' | 'https';
36
36
  timeoutMinutes: number;
37
+ createFullPath: boolean;
37
38
  }
38
39
  export declare class NotValidEmailError extends Error {
39
40
  constructor();
@@ -15,3 +15,4 @@ export type DriveFolderItem = Pick<DriveFolderData, 'name' | 'bucket' | 'id' | '
15
15
  status: 'EXISTS' | 'TRASHED';
16
16
  parentUuid: string | null;
17
17
  };
18
+ export type DriveItem = DriveFileItem | DriveFolderItem;
@@ -36,11 +36,10 @@ export declare class CLIUtils {
36
36
  static readonly timer: () => {
37
37
  stop: () => number;
38
38
  };
39
- static readonly catchError: ({ error, logReporter, errorReporter, command, jsonFlag, }: {
39
+ static readonly catchError: ({ error, logReporter, command, jsonFlag, }: {
40
40
  error: Error;
41
41
  command?: string;
42
42
  logReporter: (message: string) => void;
43
- errorReporter: (message: string) => void;
44
43
  jsonFlag?: boolean;
45
44
  }) => void;
46
45
  static readonly parseEmpty: (input: string) => Promise<string>;
@@ -130,7 +130,7 @@ class CLIUtils {
130
130
  },
131
131
  };
132
132
  };
133
- static catchError = ({ error, logReporter, errorReporter, command, jsonFlag, }) => {
133
+ static catchError = ({ error, logReporter, command, jsonFlag, }) => {
134
134
  let message;
135
135
  if ('message' in error && error.message.trim().length > 0) {
136
136
  message = error.message;
@@ -143,7 +143,7 @@ class CLIUtils {
143
143
  CLIUtils.consoleLog(JSON.stringify({ success: false, message }));
144
144
  }
145
145
  else {
146
- errors_utils_1.ErrorUtils.report(errorReporter, error, { command });
146
+ errors_utils_1.ErrorUtils.report(error, { command });
147
147
  CLIUtils.error(logReporter, message);
148
148
  }
149
149
  };
@@ -1,6 +1,7 @@
1
- import { FileMeta, FolderMeta } from '@internxt/sdk/dist/drive/storage/types';
1
+ import { FileMeta, FolderMeta, CreateFolderResponse } from '@internxt/sdk/dist/drive/storage/types';
2
2
  import { DriveFileItem, DriveFolderItem } from '../types/drive.types';
3
3
  export declare class DriveUtils {
4
4
  static driveFileMetaToItem(fileMeta: FileMeta): DriveFileItem;
5
5
  static driveFolderMetaToItem(folderMeta: FolderMeta): DriveFolderItem;
6
+ static createFolderResponseToItem(folderResponse: CreateFolderResponse): DriveFolderItem;
6
7
  }
@@ -34,5 +34,19 @@ class DriveUtils {
34
34
  updatedAt: new Date(folderMeta.updatedAt),
35
35
  };
36
36
  }
37
+ static createFolderResponseToItem(folderResponse) {
38
+ return {
39
+ uuid: folderResponse.uuid,
40
+ id: folderResponse.id,
41
+ bucket: folderResponse.bucket,
42
+ status: folderResponse.deleted || folderResponse.removed ? 'TRASHED' : 'EXISTS',
43
+ name: folderResponse.plainName ?? folderResponse.name,
44
+ encryptedName: folderResponse.name,
45
+ parentId: folderResponse.parentId,
46
+ parentUuid: folderResponse.parentUuid,
47
+ createdAt: new Date(folderResponse.createdAt),
48
+ updatedAt: new Date(folderResponse.updatedAt),
49
+ };
50
+ }
37
51
  }
38
52
  exports.DriveUtils = DriveUtils;
@@ -1,5 +1,6 @@
1
+ export declare function isError(error: unknown): error is Error;
1
2
  export declare class ErrorUtils {
2
- static report(reporter: (error: string) => void, error: unknown, props?: Record<string, unknown>): void;
3
+ static report(error: unknown, props?: Record<string, unknown>): void;
3
4
  }
4
5
  export declare class ConflictError extends Error {
5
6
  statusCode: number;
@@ -1,13 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NotImplementedError = exports.MethodNotAllowed = exports.UnsupportedMediaTypeError = exports.BadRequestError = exports.NotFoundError = exports.ConflictError = exports.ErrorUtils = void 0;
4
+ exports.isError = isError;
5
+ const logger_utils_1 = require("./logger.utils");
6
+ const node_util_1 = require("node:util");
7
+ function isError(error) {
8
+ return node_util_1.types.isNativeError(error);
9
+ }
4
10
  class ErrorUtils {
5
- static report(reporter, error, props = {}) {
6
- if (error instanceof Error) {
7
- reporter(`[REPORTED_ERROR]: ${error.message}\nProperties => ${JSON.stringify(props, null, 2)}\nStack => ${error.stack}`);
11
+ static report(error, props = {}) {
12
+ if (isError(error)) {
13
+ logger_utils_1.logger.error(`[REPORTED_ERROR]: ${error.message}\nProperties => ${JSON.stringify(props, null, 2)}\nStack => ${error.stack}`);
8
14
  }
9
15
  else {
10
- reporter(`[REPORTED_ERROR]: ${JSON.stringify(error)}\nProperties => ${JSON.stringify(props, null, 2)}\n`);
16
+ logger_utils_1.logger.error(`[REPORTED_ERROR]: ${JSON.stringify(error)}\nProperties => ${JSON.stringify(props, null, 2)}\n`);
11
17
  }
12
18
  }
13
19
  }
@@ -52,13 +52,3 @@ exports.webdavLogger = winston_1.default.createLogger({
52
52
  }),
53
53
  ],
54
54
  });
55
- if (process.env.NODE_ENV !== 'production') {
56
- exports.webdavLogger.add(new winston_1.default.transports.Console({
57
- format: winston_1.default.format.simple(),
58
- }));
59
- }
60
- if (process.env.NODE_ENV !== 'production') {
61
- exports.logger.add(new winston_1.default.transports.Console({
62
- format: winston_1.default.format.simple(),
63
- }));
64
- }
@@ -2,14 +2,26 @@ import { Request } from 'express';
2
2
  import { WebDavRequestedResource } from '../types/webdav.types';
3
3
  import { DriveFolderService } from '../services/drive/drive-folder.service';
4
4
  import { DriveFileService } from '../services/drive/drive-file.service';
5
- import { DriveFileItem, DriveFolderItem } from '../types/drive.types';
5
+ import { DriveFileItem, DriveFolderItem, DriveItem } from '../types/drive.types';
6
6
  export declare class WebDavUtils {
7
7
  static joinURL(...pathComponents: string[]): string;
8
8
  static removeHostFromURL(completeURL: string): string;
9
+ static decodeUrl(requestUrl: string, decodeUri?: boolean): string;
10
+ static normalizeFolderPath(path: string): string;
9
11
  static getRequestedResource(urlObject: string | Request, decodeUri?: boolean): Promise<WebDavRequestedResource>;
10
- static getDriveItemFromResource({ resource, driveFolderService, driveFileService, }: {
12
+ static getDriveItemFromResource(params: {
11
13
  resource: WebDavRequestedResource;
12
- driveFolderService?: DriveFolderService;
13
- driveFileService?: DriveFileService;
14
- }): Promise<DriveFileItem | DriveFolderItem | undefined>;
14
+ driveFolderService: DriveFolderService;
15
+ driveFileService?: never;
16
+ }): Promise<DriveFolderItem | undefined>;
17
+ static getDriveItemFromResource(params: {
18
+ resource: WebDavRequestedResource;
19
+ driveFolderService?: never;
20
+ driveFileService: DriveFileService;
21
+ }): Promise<DriveFileItem | undefined>;
22
+ static getDriveItemFromResource(params: {
23
+ resource: WebDavRequestedResource;
24
+ driveFolderService: DriveFolderService;
25
+ driveFileService: DriveFileService;
26
+ }): Promise<DriveItem | undefined>;
15
27
  }
@@ -19,6 +19,19 @@ class WebDavUtils {
19
19
  url = '/'.concat(url);
20
20
  return url;
21
21
  }
22
+ static decodeUrl(requestUrl, decodeUri = true) {
23
+ return (decodeUri ? decodeURIComponent(requestUrl) : requestUrl).replaceAll('/./', '/');
24
+ }
25
+ static normalizeFolderPath(path) {
26
+ let normalizedPath = path;
27
+ if (!normalizedPath.startsWith('/')) {
28
+ normalizedPath = `/${normalizedPath}`;
29
+ }
30
+ if (!normalizedPath.endsWith('/')) {
31
+ normalizedPath = `${normalizedPath}/`;
32
+ }
33
+ return normalizedPath;
34
+ }
22
35
  static async getRequestedResource(urlObject, decodeUri = true) {
23
36
  let requestUrl;
24
37
  if (typeof urlObject === 'string') {
@@ -27,13 +40,9 @@ class WebDavUtils {
27
40
  else {
28
41
  requestUrl = urlObject.url;
29
42
  }
30
- const decodedUrl = (decodeUri ? decodeURIComponent(requestUrl) : requestUrl).replaceAll('/./', '/');
43
+ const decodedUrl = this.decodeUrl(requestUrl, decodeUri);
31
44
  const parsedPath = node_path_1.default.parse(decodedUrl);
32
- let parentPath = node_path_1.default.dirname(decodedUrl);
33
- if (!parentPath.startsWith('/'))
34
- parentPath = '/'.concat(parentPath);
35
- if (!parentPath.endsWith('/'))
36
- parentPath = parentPath.concat('/');
45
+ const parentPath = this.normalizeFolderPath(node_path_1.default.dirname(decodedUrl));
37
46
  const isFolder = requestUrl.endsWith('/');
38
47
  if (isFolder) {
39
48
  return {
@@ -1,10 +1,12 @@
1
1
  import { WebDavMethodHandler } from '../../types/webdav.types';
2
2
  import { Request, Response } from 'express';
3
3
  import { DriveFolderService } from '../../services/drive/drive-folder.service';
4
+ import { WebDavFolderService } from '../services/webdav-folder.service';
4
5
  export declare class MKCOLRequestHandler implements WebDavMethodHandler {
5
6
  private readonly dependencies;
6
7
  constructor(dependencies: {
7
8
  driveFolderService: DriveFolderService;
9
+ webDavFolderService: WebDavFolderService;
8
10
  });
9
11
  handle: (req: Request, res: Response) => Promise<void>;
10
12
  }
@@ -4,7 +4,6 @@ exports.MKCOLRequestHandler = void 0;
4
4
  const webdav_utils_1 = require("../../utils/webdav.utils");
5
5
  const logger_utils_1 = require("../../utils/logger.utils");
6
6
  const xml_utils_1 = require("../../utils/xml.utils");
7
- const async_utils_1 = require("../../utils/async.utils");
8
7
  const errors_utils_1 = require("../../utils/errors.utils");
9
8
  class MKCOLRequestHandler {
10
9
  dependencies;
@@ -12,18 +11,11 @@ class MKCOLRequestHandler {
12
11
  this.dependencies = dependencies;
13
12
  }
14
13
  handle = async (req, res) => {
15
- const { driveFolderService } = this.dependencies;
14
+ const { driveFolderService, webDavFolderService } = this.dependencies;
16
15
  const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
17
16
  logger_utils_1.webdavLogger.info(`[MKCOL] Request received for ${resource.type} at ${resource.url}`);
18
- const parentResource = await webdav_utils_1.WebDavUtils.getRequestedResource(resource.parentPath, false);
19
- const parentDriveItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
20
- resource: parentResource,
21
- driveFolderService,
22
- });
23
- if (!parentDriveItem) {
24
- throw new errors_utils_1.ConflictError(`Parent folders not found on Internxt Drive at ${resource.url}`);
25
- }
26
- const parentFolderItem = parentDriveItem;
17
+ const parentDriveFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
18
+ (await webDavFolderService.createParentPathOrThrow(resource.parentPath));
27
19
  const driveFolderItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
28
20
  resource,
29
21
  driveFolderService,
@@ -33,13 +25,11 @@ class MKCOLRequestHandler {
33
25
  logger_utils_1.webdavLogger.info(`[MKCOL] ❌ Folder '${resource.url}' already exists`);
34
26
  throw new errors_utils_1.MethodNotAllowed('Folder already exists');
35
27
  }
36
- const [createFolder] = driveFolderService.createFolder({
37
- plainName: resource.path.base,
38
- parentFolderUuid: parentFolderItem.uuid,
28
+ const newFolder = await webDavFolderService.createFolder({
29
+ folderName: resource.path.base,
30
+ parentFolderUuid: parentDriveFolderItem.uuid,
39
31
  });
40
- const newFolder = await createFolder;
41
32
  logger_utils_1.webdavLogger.info(`[MKCOL] ✅ Folder created with UUID ${newFolder.uuid}`);
42
- await async_utils_1.AsyncUtils.sleep(500);
43
33
  res.status(201).send(xml_utils_1.XMLUtils.toWebDavXML({}, {}));
44
34
  };
45
35
  }
@@ -2,11 +2,13 @@ import { Request, Response } from 'express';
2
2
  import { DriveFileService } from '../../services/drive/drive-file.service';
3
3
  import { DriveFolderService } from '../../services/drive/drive-folder.service';
4
4
  import { WebDavMethodHandler } from '../../types/webdav.types';
5
+ import { WebDavFolderService } from '../services/webdav-folder.service';
5
6
  export declare class MOVERequestHandler implements WebDavMethodHandler {
6
7
  private readonly dependencies;
7
8
  constructor(dependencies: {
8
9
  driveFolderService: DriveFolderService;
9
10
  driveFileService: DriveFileService;
11
+ webDavFolderService: WebDavFolderService;
10
12
  });
11
13
  handle: (req: Request, res: Response) => Promise<void>;
12
14
  }
@@ -10,7 +10,7 @@ class MOVERequestHandler {
10
10
  this.dependencies = dependencies;
11
11
  }
12
12
  handle = async (req, res) => {
13
- const { driveFolderService, driveFileService } = this.dependencies;
13
+ const { driveFolderService, driveFileService, webDavFolderService } = this.dependencies;
14
14
  const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
15
15
  logger_utils_1.webdavLogger.info(`[MOVE] Request received for ${resource.type} at ${resource.url}`);
16
16
  const destinationUrl = req.header('destination');
@@ -49,15 +49,8 @@ class MOVERequestHandler {
49
49
  }
50
50
  else {
51
51
  logger_utils_1.webdavLogger.info(`[MOVE] Moving ${resource.type} with UUID ${originalDriveItem.uuid} to ${destinationPath}`);
52
- const destinationFolderResource = await webdav_utils_1.WebDavUtils.getRequestedResource(destinationResource.parentPath);
53
- const destinationDriveFolderItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
54
- resource: destinationFolderResource,
55
- driveFolderService,
56
- });
57
- if (!destinationDriveFolderItem) {
58
- throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
59
- }
60
- const destinationFolderItem = destinationDriveFolderItem;
52
+ const destinationFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(destinationResource.parentPath)) ??
53
+ (await webDavFolderService.createParentPathOrThrow(destinationResource.parentPath));
61
54
  if (resource.type === 'folder') {
62
55
  const folder = originalDriveItem;
63
56
  await driveFolderService.moveFolder(folder.uuid, {
@@ -3,13 +3,13 @@ import { DriveFileService } from '../../services/drive/drive-file.service';
3
3
  import { NetworkFacade } from '../../services/network/network-facade.service';
4
4
  import { AuthService } from '../../services/auth.service';
5
5
  import { WebDavMethodHandler } from '../../types/webdav.types';
6
- import { DriveFolderService } from '../../services/drive/drive-folder.service';
7
6
  import { TrashService } from '../../services/drive/trash.service';
7
+ import { WebDavFolderService } from '../services/webdav-folder.service';
8
8
  export declare class PUTRequestHandler implements WebDavMethodHandler {
9
9
  private readonly dependencies;
10
10
  constructor(dependencies: {
11
11
  driveFileService: DriveFileService;
12
- driveFolderService: DriveFolderService;
12
+ webDavFolderService: WebDavFolderService;
13
13
  trashService: TrashService;
14
14
  authService: AuthService;
15
15
  networkFacade: NetworkFacade;
@@ -10,13 +10,13 @@ const cli_utils_1 = require("../../utils/cli.utils");
10
10
  const stream_utils_1 = require("../../utils/stream.utils");
11
11
  const thumbnail_utils_1 = require("../../utils/thumbnail.utils");
12
12
  const thumbnail_service_1 = require("../../services/thumbnail.service");
13
+ const async_utils_1 = require("../../utils/async.utils");
13
14
  class PUTRequestHandler {
14
15
  dependencies;
15
16
  constructor(dependencies) {
16
17
  this.dependencies = dependencies;
17
18
  }
18
19
  handle = async (req, res) => {
19
- const { authService, networkFacade, driveFileService, driveFolderService, trashService } = this.dependencies;
20
20
  const contentLength = Number(req.headers['content-length']);
21
21
  if (!contentLength || isNaN(contentLength) || contentLength <= 0) {
22
22
  throw new errors_utils_1.UnsupportedMediaTypeError('Empty files are not supported');
@@ -26,30 +26,23 @@ class PUTRequestHandler {
26
26
  throw new errors_utils_1.NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.');
27
27
  logger_utils_1.webdavLogger.info(`[PUT] Request received for ${resource.type} at ${resource.url}`);
28
28
  logger_utils_1.webdavLogger.info(`[PUT] Uploading '${resource.name}' to '${resource.parentPath}'`);
29
- const parentResource = await webdav_utils_1.WebDavUtils.getRequestedResource(resource.parentPath, false);
30
- const parentDriveFolderItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
31
- resource: parentResource,
32
- driveFolderService,
33
- });
34
- if (!parentDriveFolderItem) {
35
- throw new errors_utils_1.ConflictError(`Parent folders not found on Internxt Drive at ${resource.url}`);
36
- }
37
- const parentFolderItem = parentDriveFolderItem;
29
+ const parentDriveFolderItem = (await this.dependencies.webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
30
+ (await this.dependencies.webDavFolderService.createParentPathOrThrow(resource.parentPath));
38
31
  try {
39
- const driveFileItem = (await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
32
+ const driveFileItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
40
33
  resource: resource,
41
- driveFileService,
42
- }));
34
+ driveFileService: this.dependencies.driveFileService,
35
+ });
43
36
  if (driveFileItem && driveFileItem.status === 'EXISTS') {
44
37
  logger_utils_1.webdavLogger.info(`[PUT] File '${resource.name}' already exists in '${resource.path.dir}', trashing it...`);
45
- await trashService.trashItems({
38
+ await this.dependencies.trashService.trashItems({
46
39
  items: [{ type: resource.type, uuid: driveFileItem.uuid, id: null }],
47
40
  });
48
41
  }
49
42
  }
50
43
  catch {
51
44
  }
52
- const { user } = await authService.getAuthDetails();
45
+ const { user } = await this.dependencies.authService.getAuthDetails();
53
46
  const fileType = resource.path.ext.replace('.', '');
54
47
  const timer = cli_utils_1.CLIUtils.timer();
55
48
  let bufferStream;
@@ -66,7 +59,7 @@ class PUTRequestHandler {
66
59
  }
67
60
  };
68
61
  const fileId = await new Promise((resolve, reject) => {
69
- const state = networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
62
+ const state = this.dependencies.networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
70
63
  if (err) {
71
64
  aborted = true;
72
65
  return reject(err);
@@ -87,7 +80,7 @@ class PUTRequestHandler {
87
80
  plainName: resource.path.name,
88
81
  type: fileType,
89
82
  size: contentLength,
90
- folderUuid: parentFolderItem.uuid,
83
+ folderUuid: parentDriveFolderItem.uuid,
91
84
  fileId: fileId,
92
85
  bucket: user.bucket,
93
86
  encryptVersion: types_1.EncryptionVersion.Aes03,
@@ -96,7 +89,7 @@ class PUTRequestHandler {
96
89
  if (isThumbnailable && bufferStream) {
97
90
  const thumbnailBuffer = bufferStream.getBuffer();
98
91
  if (thumbnailBuffer) {
99
- await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, user.bucket, file.uuid, networkFacade);
92
+ await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, user.bucket, file.uuid, this.dependencies.networkFacade);
100
93
  }
101
94
  }
102
95
  }
@@ -105,6 +98,8 @@ class PUTRequestHandler {
105
98
  }
106
99
  const uploadTime = timer.stop();
107
100
  logger_utils_1.webdavLogger.info(`[PUT] ✅ File uploaded in ${uploadTime}ms to Internxt Drive`);
101
+ await async_utils_1.AsyncUtils.sleep(500);
102
+ logger_utils_1.webdavLogger.info(`[PUT] [RESPONSE-201] ${resource.url} - Returning 201 Created after ${uploadTime}ms (+ 500ms propagation delay)`);
108
103
  res.status(201).send();
109
104
  };
110
105
  }
@@ -4,6 +4,7 @@ exports.AuthMiddleware = void 0;
4
4
  const sdk_manager_service_1 = require("../../services/sdk-manager.service");
5
5
  const logger_utils_1 = require("../../utils/logger.utils");
6
6
  const xml_utils_1 = require("../../utils/xml.utils");
7
+ const errors_utils_1 = require("../../utils/errors.utils");
7
8
  const AuthMiddleware = (authService) => {
8
9
  return (_, res, next) => {
9
10
  (async () => {
@@ -14,10 +15,15 @@ const AuthMiddleware = (authService) => {
14
15
  }
15
16
  catch (error) {
16
17
  let message = 'Authentication required to access this resource.';
17
- if ('message' in error && error.message.trim().length > 0) {
18
+ if ((0, errors_utils_1.isError)(error)) {
18
19
  message = error.message;
20
+ if (error.stack) {
21
+ logger_utils_1.webdavLogger.error(`Error from AuthMiddleware: ${message}\nStack: ${error.stack}`);
22
+ }
23
+ else {
24
+ logger_utils_1.webdavLogger.error(`Error from AuthMiddleware: ${message}`);
25
+ }
19
26
  }
20
- logger_utils_1.webdavLogger.error('Error from AuthMiddleware: ' + message);
21
27
  const errorBodyXML = xml_utils_1.XMLUtils.toWebDavXML({
22
28
  [xml_utils_1.XMLUtils.addDefaultNamespace('responsedescription')]: message,
23
29
  }, {}, 'error');
@@ -3,10 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ErrorHandlingMiddleware = void 0;
4
4
  const logger_utils_1 = require("../../utils/logger.utils");
5
5
  const xml_utils_1 = require("../../utils/xml.utils");
6
+ const errors_utils_1 = require("../../utils/errors.utils");
6
7
  const ErrorHandlingMiddleware = (err, req, res, _) => {
7
- logger_utils_1.webdavLogger.error(`[ERROR MIDDLEWARE] [${req.method.toUpperCase()} - ${req.url}]`, err);
8
+ const message = (0, errors_utils_1.isError)(err) ? err.message : 'Something went wrong';
9
+ if ((0, errors_utils_1.isError)(err) && err.stack) {
10
+ logger_utils_1.webdavLogger.error(`[ERROR MIDDLEWARE] [${req.method.toUpperCase()} - ${req.url}] ${message}\nStack: ${err.stack}`);
11
+ }
12
+ else {
13
+ logger_utils_1.webdavLogger.error(`[ERROR MIDDLEWARE] [${req.method.toUpperCase()} - ${req.url}] ${message}`);
14
+ }
8
15
  const errorBodyXML = xml_utils_1.XMLUtils.toWebDavXML({
9
- [xml_utils_1.XMLUtils.addDefaultNamespace('responsedescription')]: 'message' in err ? err.message : 'Something went wrong',
16
+ [xml_utils_1.XMLUtils.addDefaultNamespace('responsedescription')]: message,
10
17
  }, {}, 'error');
11
18
  let statusCode = 500;
12
19
  if ('statusCode' in err && !isNaN(err.statusCode)) {
@@ -0,0 +1,17 @@
1
+ import { ConfigService } from '../../services/config.service';
2
+ import { DriveFolderService } from '../../services/drive/drive-folder.service';
3
+ import { DriveFolderItem } from '../../types/drive.types';
4
+ export declare class WebDavFolderService {
5
+ private readonly dependencies;
6
+ constructor(dependencies: {
7
+ driveFolderService: DriveFolderService;
8
+ configService: ConfigService;
9
+ });
10
+ getDriveFolderItemFromPath: (path: string) => Promise<DriveFolderItem | undefined>;
11
+ createFolder: ({ folderName, parentFolderUuid, }: {
12
+ folderName: string;
13
+ parentFolderUuid: string;
14
+ }) => Promise<DriveFolderItem>;
15
+ createParentPathOrThrow: (parentPath: string) => Promise<DriveFolderItem>;
16
+ private createFolderRecursively;
17
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebDavFolderService = void 0;
4
+ const errors_utils_1 = require("../../utils/errors.utils");
5
+ const webdav_utils_1 = require("../../utils/webdav.utils");
6
+ const async_utils_1 = require("../../utils/async.utils");
7
+ const auth_service_1 = require("../../services/auth.service");
8
+ const drive_utils_1 = require("../../utils/drive.utils");
9
+ class WebDavFolderService {
10
+ dependencies;
11
+ constructor(dependencies) {
12
+ this.dependencies = dependencies;
13
+ }
14
+ getDriveFolderItemFromPath = async (path) => {
15
+ const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(path, false);
16
+ return await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
17
+ resource,
18
+ driveFolderService: this.dependencies.driveFolderService,
19
+ });
20
+ };
21
+ createFolder = async ({ folderName, parentFolderUuid, }) => {
22
+ const [createFolderPromise] = this.dependencies.driveFolderService.createFolder({
23
+ plainName: folderName,
24
+ parentFolderUuid: parentFolderUuid,
25
+ });
26
+ const newFolder = await createFolderPromise;
27
+ await async_utils_1.AsyncUtils.sleep(500);
28
+ return drive_utils_1.DriveUtils.createFolderResponseToItem(newFolder);
29
+ };
30
+ createParentPathOrThrow = async (parentPath) => {
31
+ const { createFullPath } = await this.dependencies.configService.readWebdavConfig();
32
+ if (!createFullPath) {
33
+ throw new errors_utils_1.ConflictError(`Parent folders not found on Internxt Drive at ${webdav_utils_1.WebDavUtils.decodeUrl(parentPath, false)}`);
34
+ }
35
+ const folders = parentPath.split('/').filter((f) => f.length > 0);
36
+ const { user } = await auth_service_1.AuthService.instance.getAuthDetails();
37
+ return await this.createFolderRecursively(folders, user.rootFolderId);
38
+ };
39
+ async createFolderRecursively(remainingFolders, parentFolderUuid, accumulatedPath = '') {
40
+ const [currentFolderName, ...rest] = remainingFolders;
41
+ const newPath = webdav_utils_1.WebDavUtils.joinURL(accumulatedPath, currentFolderName);
42
+ const folderPath = webdav_utils_1.WebDavUtils.normalizeFolderPath(newPath);
43
+ const folder = (await this.getDriveFolderItemFromPath(folderPath)) ??
44
+ (await this.createFolder({ folderName: currentFolderName, parentFolderUuid }));
45
+ if (rest.length === 0) {
46
+ return folder;
47
+ }
48
+ return await this.createFolderRecursively(rest, folder.uuid, newPath);
49
+ }
50
+ }
51
+ exports.WebDavFolderService = WebDavFolderService;
@@ -31,6 +31,7 @@ const MOVE_handler_1 = require("./handlers/MOVE.handler");
31
31
  const COPY_handler_1 = require("./handlers/COPY.handler");
32
32
  const inxt_js_1 = require("@internxt/inxt-js");
33
33
  const mkcol_middleware_1 = require("./middewares/mkcol.middleware");
34
+ const webdav_folder_service_1 = require("./services/webdav-folder.service");
34
35
  class WebDavServer {
35
36
  app;
36
37
  configService;
@@ -82,6 +83,10 @@ class WebDavServer {
82
83
  registerHandlers = async () => {
83
84
  const serverListenPath = /(.*)/;
84
85
  const networkFacade = await this.getNetworkFacade();
86
+ const webDavFolderService = new webdav_folder_service_1.WebDavFolderService({
87
+ driveFolderService: this.driveFolderService,
88
+ configService: this.configService,
89
+ });
85
90
  this.app.head(serverListenPath, (0, express_async_handler_1.default)(new HEAD_handler_1.HEADRequestHandler({
86
91
  driveFileService: this.driveFileService,
87
92
  }).handle));
@@ -99,13 +104,14 @@ class WebDavServer {
99
104
  }).handle));
100
105
  this.app.put(serverListenPath, (0, express_async_handler_1.default)(new PUT_handler_1.PUTRequestHandler({
101
106
  driveFileService: this.driveFileService,
102
- driveFolderService: this.driveFolderService,
107
+ webDavFolderService: webDavFolderService,
103
108
  authService: this.authService,
104
109
  trashService: this.trashService,
105
110
  networkFacade: networkFacade,
106
111
  }).handle));
107
112
  this.app.mkcol(serverListenPath, (0, express_async_handler_1.default)(new MKCOL_handler_1.MKCOLRequestHandler({
108
113
  driveFolderService: this.driveFolderService,
114
+ webDavFolderService: webDavFolderService,
109
115
  }).handle));
110
116
  this.app.delete(serverListenPath, (0, express_async_handler_1.default)(new DELETE_handler_1.DELETERequestHandler({
111
117
  trashService: this.trashService,
@@ -116,6 +122,7 @@ class WebDavServer {
116
122
  this.app.move(serverListenPath, (0, express_async_handler_1.default)(new MOVE_handler_1.MOVERequestHandler({
117
123
  driveFolderService: this.driveFolderService,
118
124
  driveFileService: this.driveFileService,
125
+ webDavFolderService,
119
126
  }).handle));
120
127
  this.app.copy(serverListenPath, (0, express_async_handler_1.default)(new COPY_handler_1.COPYRequestHandler().handle));
121
128
  };
@@ -1196,6 +1196,14 @@
1196
1196
  "hasDynamicHelp": false,
1197
1197
  "multiple": false,
1198
1198
  "type": "option"
1199
+ },
1200
+ "createFullPath": {
1201
+ "char": "c",
1202
+ "description": "Auto-create missing parent directories during file uploads.",
1203
+ "name": "createFullPath",
1204
+ "required": false,
1205
+ "allowNo": true,
1206
+ "type": "boolean"
1199
1207
  }
1200
1208
  },
1201
1209
  "hasDynamicHelp": false,
@@ -1290,5 +1298,5 @@
1290
1298
  ]
1291
1299
  }
1292
1300
  },
1293
- "version": "1.5.7"
1301
+ "version": "1.5.8"
1294
1302
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "author": "Internxt <hello@internxt.com>",
3
- "version": "1.5.7",
3
+ "version": "1.5.8",
4
4
  "description": "Internxt CLI to manage your encrypted storage",
5
5
  "scripts": {
6
6
  "build": "yarn clean && tsc",