@internxt/cli 1.5.8 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +187 -95
  2. package/dist/commands/create-folder.d.ts +3 -3
  3. package/dist/commands/delete-permanently-file.d.ts +2 -2
  4. package/dist/commands/delete-permanently-folder.d.ts +2 -2
  5. package/dist/commands/download-file.d.ts +4 -5
  6. package/dist/commands/download-file.js +22 -37
  7. package/dist/commands/list.d.ts +4 -4
  8. package/dist/commands/login-legacy.d.ts +24 -0
  9. package/dist/commands/login-legacy.js +175 -0
  10. package/dist/commands/login.d.ts +3 -9
  11. package/dist/commands/login.js +18 -132
  12. package/dist/commands/move-file.d.ts +4 -4
  13. package/dist/commands/move-folder.d.ts +3 -3
  14. package/dist/commands/rename-file.d.ts +3 -3
  15. package/dist/commands/rename-folder.d.ts +3 -3
  16. package/dist/commands/trash-clear.d.ts +2 -2
  17. package/dist/commands/trash-file.d.ts +2 -2
  18. package/dist/commands/trash-file.js +1 -1
  19. package/dist/commands/trash-folder.d.ts +2 -2
  20. package/dist/commands/trash-folder.js +1 -1
  21. package/dist/commands/trash-list.d.ts +2 -2
  22. package/dist/commands/trash-restore-file.d.ts +4 -4
  23. package/dist/commands/trash-restore-folder.d.ts +3 -3
  24. package/dist/commands/upload-file.d.ts +8 -8
  25. package/dist/commands/upload-file.js +7 -40
  26. package/dist/commands/upload-folder.d.ts +16 -0
  27. package/dist/commands/upload-folder.js +87 -0
  28. package/dist/commands/webdav-config.d.ts +6 -6
  29. package/dist/commands/webdav.d.ts +1 -1
  30. package/dist/commands/whoami.js +1 -1
  31. package/dist/hooks/prerun/auth_check.js +2 -1
  32. package/dist/services/auth.service.d.ts +1 -2
  33. package/dist/services/auth.service.js +11 -26
  34. package/dist/services/crypto.service.js +1 -1
  35. package/dist/services/database/drive-file/drive-file.domain.js +1 -0
  36. package/dist/services/database/drive-folder/drive-folder.domain.js +1 -0
  37. package/dist/services/drive/drive-file.service.js +1 -0
  38. package/dist/services/drive/drive-folder.service.d.ts +1 -1
  39. package/dist/services/drive/trash.service.d.ts +1 -1
  40. package/dist/services/local-filesystem/local-filesystem.service.d.ts +6 -0
  41. package/dist/services/local-filesystem/local-filesystem.service.js +57 -0
  42. package/dist/services/local-filesystem/local-filesystem.types.d.ts +13 -0
  43. package/dist/services/local-filesystem/local-filesystem.types.js +2 -0
  44. package/dist/services/network/upload/upload-facade.service.d.ts +9 -0
  45. package/dist/services/network/upload/upload-facade.service.js +53 -0
  46. package/dist/services/network/upload/upload-file.service.d.ts +7 -0
  47. package/dist/services/network/upload/upload-file.service.js +112 -0
  48. package/dist/services/network/upload/upload-folder.service.d.ts +6 -0
  49. package/dist/services/network/upload/upload-folder.service.js +62 -0
  50. package/dist/services/network/upload/upload.types.d.ts +53 -0
  51. package/dist/services/network/upload/upload.types.js +6 -0
  52. package/dist/services/thumbnail.service.js +1 -34
  53. package/dist/services/universal-link.service.d.ts +10 -0
  54. package/dist/services/universal-link.service.js +85 -0
  55. package/dist/types/command.types.d.ts +3 -2
  56. package/dist/types/command.types.js +8 -1
  57. package/dist/types/drive.types.d.ts +2 -0
  58. package/dist/types/fast-xml-parser.types.d.ts +59 -0
  59. package/dist/types/fast-xml-parser.types.js +2 -0
  60. package/dist/types/webdav.types.d.ts +0 -1
  61. package/dist/utils/cli.utils.d.ts +13 -2
  62. package/dist/utils/cli.utils.js +47 -0
  63. package/dist/utils/drive.utils.js +3 -0
  64. package/dist/utils/errors.utils.d.ts +1 -0
  65. package/dist/utils/errors.utils.js +5 -0
  66. package/dist/utils/logger.utils.js +10 -0
  67. package/dist/utils/network.utils.d.ts +2 -2
  68. package/dist/utils/network.utils.js +7 -5
  69. package/dist/utils/thumbnail.utils.d.ts +17 -0
  70. package/dist/utils/thumbnail.utils.js +29 -1
  71. package/dist/utils/webdav.utils.d.ts +12 -10
  72. package/dist/utils/webdav.utils.js +39 -29
  73. package/dist/utils/xml.utils.d.ts +1 -1
  74. package/dist/webdav/handlers/DELETE.handler.js +5 -5
  75. package/dist/webdav/handlers/GET.handler.js +43 -33
  76. package/dist/webdav/handlers/HEAD.handler.js +5 -10
  77. package/dist/webdav/handlers/MKCOL.handler.js +4 -4
  78. package/dist/webdav/handlers/MOVE.handler.js +19 -17
  79. package/dist/webdav/handlers/OPTIONS.handler.js +3 -3
  80. package/dist/webdav/handlers/PROPFIND.handler.js +7 -31
  81. package/dist/webdav/handlers/PUT.handler.d.ts +2 -0
  82. package/dist/webdav/handlers/PUT.handler.js +10 -8
  83. package/dist/webdav/services/webdav-folder.service.js +5 -4
  84. package/dist/webdav/webdav-server.js +1 -0
  85. package/oclif.manifest.json +121 -3
  86. package/package.json +33 -32
@@ -7,8 +7,16 @@ exports.NoFlagProvidedError = exports.CLIUtils = void 0;
7
7
  const core_1 = require("@oclif/core");
8
8
  const cli_progress_1 = __importDefault(require("cli-progress"));
9
9
  const tty_table_1 = __importDefault(require("tty-table"));
10
+ const command_types_1 = require("../types/command.types");
10
11
  const inquirer_utils_1 = require("./inquirer.utils");
11
12
  const errors_utils_1 = require("./errors.utils");
13
+ const validation_service_1 = require("../services/validation.service");
14
+ const sdk_manager_service_1 = require("../services/sdk-manager.service");
15
+ const inxt_js_1 = require("@internxt/inxt-js");
16
+ const config_service_1 = require("../services/config.service");
17
+ const network_facade_service_1 = require("../services/network/network-facade.service");
18
+ const download_service_1 = require("../services/network/download.service");
19
+ const crypto_service_1 = require("../services/crypto.service");
12
20
  class CLIUtils {
13
21
  static clearPreviousLine = (jsonFlag) => {
14
22
  if (!jsonFlag) {
@@ -94,6 +102,28 @@ class CLIUtils {
94
102
  return await CLIUtils.promptWithAttempts(command.prompt, maxAttempts, validation, reporter);
95
103
  }
96
104
  };
105
+ static getDestinationFolderUuid = async ({ destinationFolderUuidFlag, destinationFlagName, nonInteractive, reporter, }) => {
106
+ const destinationFolderUuid = await this.getValueFromFlag({
107
+ value: destinationFolderUuidFlag,
108
+ name: destinationFlagName,
109
+ }, {
110
+ nonInteractive,
111
+ prompt: {
112
+ message: 'What is the destination folder id? (leave empty for the root folder)',
113
+ options: { type: 'input' },
114
+ },
115
+ }, {
116
+ validate: validation_service_1.ValidationService.instance.validateUUIDv4,
117
+ error: new command_types_1.NotValidFolderUuidError(),
118
+ canBeEmpty: true,
119
+ }, reporter);
120
+ if (destinationFolderUuid.trim().length === 0) {
121
+ return undefined;
122
+ }
123
+ else {
124
+ return destinationFolderUuid;
125
+ }
126
+ };
97
127
  static promptWithAttempts = async (prompt, maxAttempts, validation, reporter) => {
98
128
  let isValid = false;
99
129
  let currentAttempts = 0;
@@ -148,6 +178,23 @@ class CLIUtils {
148
178
  }
149
179
  };
150
180
  static parseEmpty = async (input) => (input.trim().length === 0 ? ' ' : input);
181
+ static prepareNetwork = ({ jsonFlag, loginUserDetails, }) => {
182
+ CLIUtils.doing('Preparing Network', jsonFlag);
183
+ const networkModule = sdk_manager_service_1.SdkManager.instance.getNetwork({
184
+ user: loginUserDetails.bridgeUser,
185
+ pass: loginUserDetails.userId,
186
+ });
187
+ const environment = new inxt_js_1.Environment({
188
+ bridgeUser: loginUserDetails.bridgeUser,
189
+ bridgePass: loginUserDetails.userId,
190
+ bridgeUrl: config_service_1.ConfigService.instance.get('NETWORK_URL'),
191
+ encryptionKey: loginUserDetails.mnemonic,
192
+ appDetails: sdk_manager_service_1.SdkManager.getAppDetails(),
193
+ });
194
+ const networkFacade = new network_facade_service_1.NetworkFacade(networkModule, environment, download_service_1.DownloadService.instance, crypto_service_1.CryptoService.instance);
195
+ CLIUtils.done(jsonFlag);
196
+ return networkFacade;
197
+ };
151
198
  }
152
199
  exports.CLIUtils = CLIUtils;
153
200
  class NoFlagProvidedError extends Error {
@@ -4,6 +4,7 @@ exports.DriveUtils = void 0;
4
4
  class DriveUtils {
5
5
  static driveFileMetaToItem(fileMeta) {
6
6
  return {
7
+ itemType: 'file',
7
8
  uuid: fileMeta.uuid ?? '',
8
9
  status: fileMeta.status,
9
10
  folderId: fileMeta.folderId,
@@ -22,6 +23,7 @@ class DriveUtils {
22
23
  }
23
24
  static driveFolderMetaToItem(folderMeta) {
24
25
  return {
26
+ itemType: 'folder',
25
27
  uuid: folderMeta.uuid,
26
28
  id: folderMeta.id,
27
29
  bucket: folderMeta.bucket,
@@ -36,6 +38,7 @@ class DriveUtils {
36
38
  }
37
39
  static createFolderResponseToItem(folderResponse) {
38
40
  return {
41
+ itemType: 'folder',
39
42
  uuid: folderResponse.uuid,
40
43
  id: folderResponse.id,
41
44
  bucket: folderResponse.bucket,
@@ -1,4 +1,5 @@
1
1
  export declare function isError(error: unknown): error is Error;
2
+ export declare function isAlreadyExistsError(error: unknown): error is Error;
2
3
  export declare class ErrorUtils {
3
4
  static report(error: unknown, props?: Record<string, unknown>): void;
4
5
  }
@@ -2,11 +2,16 @@
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
4
  exports.isError = isError;
5
+ exports.isAlreadyExistsError = isAlreadyExistsError;
5
6
  const logger_utils_1 = require("./logger.utils");
6
7
  const node_util_1 = require("node:util");
7
8
  function isError(error) {
8
9
  return node_util_1.types.isNativeError(error);
9
10
  }
11
+ function isAlreadyExistsError(error) {
12
+ return ((isError(error) && error.message.includes('already exists')) ||
13
+ (typeof error === 'object' && error !== null && 'status' in error && error.status === 409));
14
+ }
10
15
  class ErrorUtils {
11
16
  static report(error, props = {}) {
12
17
  if (isError(error)) {
@@ -52,3 +52,13 @@ 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
+ }
@@ -11,10 +11,10 @@ export declare class NetworkUtils {
11
11
  cert: string;
12
12
  privateKey: string;
13
13
  };
14
- static generateNewSelfsignedCerts(configs: WebdavConfig): SelfsignedCert;
14
+ static generateNewSelfsignedCerts(configs: WebdavConfig): Promise<SelfsignedCert>;
15
15
  static getWebdavSSLCerts(configs: WebdavConfig): Promise<SelfsignedCert>;
16
16
  static saveWebdavSSLCerts(pems: selfsigned.GenerateResult): Promise<void>;
17
- static generateSelfSignedSSLCerts(configs: WebdavConfig): selfsigned.GenerateResult;
17
+ static generateSelfSignedSSLCerts(configs: WebdavConfig): Promise<selfsigned.GenerateResult>;
18
18
  static parseRangeHeader(rangeOptions: {
19
19
  range?: string;
20
20
  totalFileSize: number;
@@ -21,8 +21,8 @@ class NetworkUtils {
21
21
  cert: node_path_1.default.join(config_service_1.ConfigService.WEBDAV_SSL_CERTS_DIR, 'cert.crt'),
22
22
  privateKey: node_path_1.default.join(config_service_1.ConfigService.WEBDAV_SSL_CERTS_DIR, 'priv.key'),
23
23
  };
24
- static generateNewSelfsignedCerts(configs) {
25
- const newCerts = this.generateSelfSignedSSLCerts(configs);
24
+ static async generateNewSelfsignedCerts(configs) {
25
+ const newCerts = await this.generateSelfSignedSSLCerts(configs);
26
26
  this.saveWebdavSSLCerts(newCerts);
27
27
  return {
28
28
  cert: newCerts.cert,
@@ -44,7 +44,7 @@ class NetworkUtils {
44
44
  const dateToday = new Date();
45
45
  const dateValid = new Date(validTo);
46
46
  if (dateToday > dateValid) {
47
- const newCerts = this.generateNewSelfsignedCerts(configs);
47
+ const newCerts = await this.generateNewSelfsignedCerts(configs);
48
48
  selfsignedCert = {
49
49
  cert: newCerts.cert,
50
50
  key: newCerts.key,
@@ -57,7 +57,7 @@ class NetworkUtils {
57
57
  await (0, promises_1.writeFile)(this.WEBDAV_SSL_CERTS_PATH.cert, pems.cert, 'utf8');
58
58
  await (0, promises_1.writeFile)(this.WEBDAV_SSL_CERTS_PATH.privateKey, pems.private, 'utf8');
59
59
  }
60
- static generateSelfSignedSSLCerts(configs) {
60
+ static async generateSelfSignedSSLCerts(configs) {
61
61
  const attrs = [{ name: 'commonName', value: configs.host }];
62
62
  const extensions = [
63
63
  {
@@ -70,7 +70,9 @@ class NetworkUtils {
70
70
  ],
71
71
  },
72
72
  ];
73
- const pems = selfsigned_1.default.generate(attrs, { days: 365, algorithm: 'sha256', keySize: 2048, extensions });
73
+ const notAfterDate = new Date();
74
+ notAfterDate.setDate(notAfterDate.getDate() + 365);
75
+ const pems = await selfsigned_1.default.generate(attrs, { notAfterDate, algorithm: 'sha256', keySize: 2048, extensions });
74
76
  return pems;
75
77
  }
76
78
  static parseRangeHeader(rangeOptions) {
@@ -1,3 +1,6 @@
1
+ import { Readable } from 'node:stream';
2
+ import { NetworkFacade } from '../services/network/network-facade.service';
3
+ import { BufferStream } from './stream.utils';
1
4
  export declare const ThumbnailConfig: {
2
5
  readonly MaxWidth: 300;
3
6
  readonly MaxHeight: 300;
@@ -7,3 +10,17 @@ export declare const ThumbnailConfig: {
7
10
  export declare const isFileThumbnailable: (fileType: string) => boolean;
8
11
  export declare const isPDFThumbnailable: (fileType: string) => boolean;
9
12
  export declare const isImageThumbnailable: (fileType: string) => boolean;
13
+ export declare const tryUploadThumbnail: ({ bufferStream, fileType, userBucket, fileUuid, networkFacade, }: {
14
+ bufferStream: BufferStream;
15
+ fileType: string;
16
+ userBucket: string;
17
+ fileUuid: string;
18
+ networkFacade: NetworkFacade;
19
+ }) => Promise<void>;
20
+ export declare const createFileStreamWithBuffer: ({ path, fileType, }: {
21
+ path: string;
22
+ fileType: string;
23
+ }) => {
24
+ bufferStream?: BufferStream;
25
+ fileStream: Readable;
26
+ };
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isImageThumbnailable = exports.isPDFThumbnailable = exports.isFileThumbnailable = exports.ThumbnailConfig = void 0;
3
+ exports.createFileStreamWithBuffer = exports.tryUploadThumbnail = exports.isImageThumbnailable = exports.isPDFThumbnailable = exports.isFileThumbnailable = exports.ThumbnailConfig = void 0;
4
+ const thumbnail_service_1 = require("../services/thumbnail.service");
5
+ const errors_utils_1 = require("./errors.utils");
6
+ const stream_utils_1 = require("./stream.utils");
7
+ const node_fs_1 = require("node:fs");
4
8
  exports.ThumbnailConfig = {
5
9
  MaxWidth: 300,
6
10
  MaxHeight: 300,
@@ -42,3 +46,27 @@ const isImageThumbnailable = (fileType) => {
42
46
  return fileType.trim().length > 0 && thumbnailableImageExtension.includes(fileType.trim().toLowerCase());
43
47
  };
44
48
  exports.isImageThumbnailable = isImageThumbnailable;
49
+ const tryUploadThumbnail = async ({ bufferStream, fileType, userBucket, fileUuid, networkFacade, }) => {
50
+ try {
51
+ const thumbnailBuffer = bufferStream.getBuffer();
52
+ if (thumbnailBuffer) {
53
+ await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, userBucket, fileUuid, networkFacade);
54
+ }
55
+ }
56
+ catch (error) {
57
+ errors_utils_1.ErrorUtils.report(error);
58
+ }
59
+ };
60
+ exports.tryUploadThumbnail = tryUploadThumbnail;
61
+ const createFileStreamWithBuffer = ({ path, fileType, }) => {
62
+ const readable = (0, node_fs_1.createReadStream)(path);
63
+ if ((0, exports.isFileThumbnailable)(fileType)) {
64
+ const bufferStream = new stream_utils_1.BufferStream();
65
+ return {
66
+ bufferStream,
67
+ fileStream: readable.pipe(bufferStream),
68
+ };
69
+ }
70
+ return { fileStream: readable };
71
+ };
72
+ exports.createFileStreamWithBuffer = createFileStreamWithBuffer;
@@ -1,4 +1,3 @@
1
- import { Request } from 'express';
2
1
  import { WebDavRequestedResource } from '../types/webdav.types';
3
2
  import { DriveFolderService } from '../services/drive/drive-folder.service';
4
3
  import { DriveFileService } from '../services/drive/drive-file.service';
@@ -8,18 +7,21 @@ export declare class WebDavUtils {
8
7
  static removeHostFromURL(completeURL: string): string;
9
8
  static decodeUrl(requestUrl: string, decodeUri?: boolean): string;
10
9
  static normalizeFolderPath(path: string): string;
11
- static getRequestedResource(urlObject: string | Request, decodeUri?: boolean): Promise<WebDavRequestedResource>;
12
- static getDriveItemFromResource(params: {
13
- resource: WebDavRequestedResource;
10
+ static getRequestedResource(requestUrl: string, decodeUri?: boolean): Promise<WebDavRequestedResource>;
11
+ static tryGetFileOrFolderMetadata({ url, driveFileService, driveFolderService, }: {
12
+ url: string;
14
13
  driveFolderService: DriveFolderService;
15
- driveFileService?: never;
16
- }): Promise<DriveFolderItem | undefined>;
17
- static getDriveItemFromResource(params: {
18
- resource: WebDavRequestedResource;
19
- driveFolderService?: never;
14
+ driveFileService: DriveFileService;
15
+ }): Promise<DriveItem | undefined>;
16
+ static getDriveFileFromResource({ url, driveFileService, }: {
17
+ url: string;
20
18
  driveFileService: DriveFileService;
21
19
  }): Promise<DriveFileItem | undefined>;
22
- static getDriveItemFromResource(params: {
20
+ static getDriveFolderFromResource({ url, driveFolderService, }: {
21
+ url: string;
22
+ driveFolderService: DriveFolderService;
23
+ }): Promise<DriveFolderItem | undefined>;
24
+ static getDriveItemFromResource({ resource, driveFolderService, driveFileService, }: {
23
25
  resource: WebDavRequestedResource;
24
26
  driveFolderService: DriveFolderService;
25
27
  driveFileService: DriveFileService;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.WebDavUtils = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
+ const logger_utils_1 = require("./logger.utils");
8
9
  class WebDavUtils {
9
10
  static joinURL(...pathComponents) {
10
11
  return node_path_1.default.posix.join(...pathComponents);
@@ -32,45 +33,54 @@ class WebDavUtils {
32
33
  }
33
34
  return normalizedPath;
34
35
  }
35
- static async getRequestedResource(urlObject, decodeUri = true) {
36
- let requestUrl;
37
- if (typeof urlObject === 'string') {
38
- requestUrl = urlObject;
39
- }
40
- else {
41
- requestUrl = urlObject.url;
42
- }
36
+ static async getRequestedResource(requestUrl, decodeUri = true) {
43
37
  const decodedUrl = this.decodeUrl(requestUrl, decodeUri);
44
38
  const parsedPath = node_path_1.default.parse(decodedUrl);
45
39
  const parentPath = this.normalizeFolderPath(node_path_1.default.dirname(decodedUrl));
46
- const isFolder = requestUrl.endsWith('/');
47
- if (isFolder) {
48
- return {
49
- type: 'folder',
50
- url: decodedUrl,
51
- name: parsedPath.base,
52
- path: parsedPath,
53
- parentPath,
54
- };
40
+ return {
41
+ url: decodedUrl,
42
+ name: parsedPath.base,
43
+ path: parsedPath,
44
+ parentPath,
45
+ };
46
+ }
47
+ static async tryGetFileOrFolderMetadata({ url, driveFileService, driveFolderService, }) {
48
+ try {
49
+ return await driveFileService.getFileMetadataByPath(url);
50
+ }
51
+ catch {
52
+ return await driveFolderService.getFolderMetadataByPath(url);
53
+ }
54
+ }
55
+ static async getDriveFileFromResource({ url, driveFileService, }) {
56
+ try {
57
+ return await driveFileService.getFileMetadataByPath(url);
58
+ }
59
+ catch (err) {
60
+ logger_utils_1.webdavLogger.error('Exception while getting the file metadata by path', err);
61
+ }
62
+ }
63
+ static async getDriveFolderFromResource({ url, driveFolderService, }) {
64
+ try {
65
+ return await driveFolderService.getFolderMetadataByPath(url);
55
66
  }
56
- else {
57
- return {
58
- type: 'file',
59
- url: decodedUrl,
60
- name: parsedPath.name,
61
- path: parsedPath,
62
- parentPath,
63
- };
67
+ catch (err) {
68
+ logger_utils_1.webdavLogger.error('Exception while getting the folder metadata by path', err);
64
69
  }
65
70
  }
66
71
  static async getDriveItemFromResource({ resource, driveFolderService, driveFileService, }) {
67
72
  let item = undefined;
73
+ const isFolder = resource.url.endsWith('/');
68
74
  try {
69
- if (resource.type === 'folder') {
70
- item = await driveFolderService?.getFolderMetadataByPath(resource.url);
75
+ if (isFolder) {
76
+ item = await driveFolderService.getFolderMetadataByPath(resource.url);
71
77
  }
72
- if (resource.type === 'file') {
73
- item = await driveFileService?.getFileMetadataByPath(resource.url);
78
+ else {
79
+ item = await this.tryGetFileOrFolderMetadata({
80
+ url: resource.url,
81
+ driveFileService,
82
+ driveFolderService,
83
+ });
74
84
  }
75
85
  }
76
86
  catch {
@@ -1,4 +1,4 @@
1
- import { X2jOptions, XmlBuilderOptions } from 'fast-xml-parser';
1
+ import { X2jOptions, XmlBuilderOptions } from '../types/fast-xml-parser.types';
2
2
  export declare class XMLUtils {
3
3
  static readonly DEFAULT_NAMESPACE_LETTER = "D";
4
4
  static toJSON(xml: string, options?: X2jOptions): any;
@@ -11,8 +11,8 @@ class DELETERequestHandler {
11
11
  }
12
12
  handle = async (req, res) => {
13
13
  const { driveFileService, driveFolderService, trashService } = this.dependencies;
14
- const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
15
- logger_utils_1.webdavLogger.info(`[DELETE] Request received for ${resource.type} at ${resource.url}`);
14
+ const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
15
+ logger_utils_1.webdavLogger.info(`[DELETE] Request received for item at ${resource.url}`);
16
16
  const driveItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
17
17
  resource,
18
18
  driveFolderService,
@@ -21,12 +21,12 @@ class DELETERequestHandler {
21
21
  if (!driveItem) {
22
22
  throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
23
23
  }
24
- logger_utils_1.webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${resource.type}`);
24
+ logger_utils_1.webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${driveItem.itemType}`);
25
25
  await trashService.trashItems({
26
- items: [{ type: resource.type, uuid: driveItem.uuid, id: null }],
26
+ items: [{ type: driveItem.itemType, uuid: driveItem.uuid }],
27
27
  });
28
28
  res.status(204).send();
29
- const type = resource.type.charAt(0).toUpperCase() + resource.type.substring(1);
29
+ const type = driveItem.itemType.charAt(0).toUpperCase() + driveItem.itemType.substring(1);
30
30
  logger_utils_1.webdavLogger.info(`[DELETE] [${driveItem.uuid}] ${type} trashed successfully`);
31
31
  };
32
32
  }
@@ -5,6 +5,7 @@ const webdav_utils_1 = require("../../utils/webdav.utils");
5
5
  const errors_utils_1 = require("../../utils/errors.utils");
6
6
  const logger_utils_1 = require("../../utils/logger.utils");
7
7
  const network_utils_1 = require("../../utils/network.utils");
8
+ const command_types_1 = require("../../types/command.types");
8
9
  class GETRequestHandler {
9
10
  dependencies;
10
11
  constructor(dependencies) {
@@ -12,48 +13,57 @@ class GETRequestHandler {
12
13
  }
13
14
  handle = async (req, res) => {
14
15
  const { driveFileService, authService, networkFacade } = this.dependencies;
15
- const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
16
+ const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
16
17
  if (resource.name.startsWith('._'))
17
18
  throw new errors_utils_1.NotFoundError('File not found');
18
- if (resource.type === 'folder')
19
- throw new errors_utils_1.NotFoundError('Folders cannot be listed with GET. Use PROPFIND instead.');
20
- logger_utils_1.webdavLogger.info(`[GET] Request received for ${resource.type} at ${resource.url}`);
21
- const driveItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
22
- resource,
19
+ logger_utils_1.webdavLogger.info(`[GET] Request received item at ${resource.url}`);
20
+ const driveFile = await webdav_utils_1.WebDavUtils.getDriveFileFromResource({
21
+ url: resource.url,
23
22
  driveFileService,
24
23
  });
25
- if (!driveItem) {
26
- throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
24
+ if (!driveFile) {
25
+ throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}, if trying to access a folder use PROPFIND instead.`);
27
26
  }
28
- const driveFile = driveItem;
29
27
  logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Found Drive File`);
30
28
  const { user } = await authService.getAuthDetails();
31
29
  logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Network ready for download`);
32
- const range = req.headers['range'];
33
- const rangeOptions = network_utils_1.NetworkUtils.parseRangeHeader({
34
- range,
35
- totalFileSize: driveFile.size,
36
- });
37
- let contentLength = driveFile.size;
38
- if (rangeOptions) {
39
- logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Range request received:`, { rangeOptions });
40
- contentLength = rangeOptions.rangeSize;
41
- }
42
30
  res.header('Content-Type', 'application/octet-stream');
43
- res.header('Content-length', contentLength.toString());
44
- const writable = new WritableStream({
45
- write(chunk) {
46
- res.write(chunk);
47
- },
48
- close() {
49
- res.end();
50
- },
51
- });
52
- const [executeDownload] = await networkFacade.downloadToStream(driveFile.bucket, user.mnemonic, driveFile.fileId, contentLength, writable, rangeOptions);
53
- logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Download prepared, executing...`);
54
- res.status(200);
55
- await executeDownload;
56
- logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Download ready, replying to client`);
31
+ const fileSize = driveFile.size ?? 0;
32
+ if (fileSize > 0) {
33
+ const range = req.headers['range'];
34
+ const rangeOptions = network_utils_1.NetworkUtils.parseRangeHeader({
35
+ range,
36
+ totalFileSize: fileSize,
37
+ });
38
+ let contentLength = fileSize;
39
+ if (rangeOptions) {
40
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Range request received:`, { rangeOptions });
41
+ contentLength = rangeOptions.rangeSize;
42
+ }
43
+ res.header('Content-length', contentLength.toString());
44
+ const writable = new WritableStream({
45
+ write(chunk) {
46
+ res.write(chunk);
47
+ },
48
+ close() {
49
+ res.end();
50
+ },
51
+ });
52
+ if (!driveFile.fileId) {
53
+ throw new command_types_1.NotValidFileIdError();
54
+ }
55
+ const [executeDownload] = await networkFacade.downloadToStream(driveFile.bucket, user.mnemonic, driveFile.fileId, contentLength, writable, rangeOptions);
56
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Download prepared, executing...`);
57
+ res.status(200);
58
+ await executeDownload;
59
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] ✅ Download ready, replying to client`);
60
+ }
61
+ else {
62
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] File is empty, replying to client with no content`);
63
+ res.header('Content-length', '0');
64
+ res.status(200);
65
+ res.end();
66
+ }
57
67
  };
58
68
  }
59
69
  exports.GETRequestHandler = GETRequestHandler;
@@ -12,21 +12,16 @@ class HEADRequestHandler {
12
12
  }
13
13
  handle = async (req, res) => {
14
14
  const { driveFileService } = this.dependencies;
15
- const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
16
- if (resource.type === 'folder') {
17
- res.status(200).send();
18
- return;
19
- }
20
- logger_utils_1.webdavLogger.info(`[HEAD] Request received for ${resource.type} at ${resource.url}`);
15
+ const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
16
+ logger_utils_1.webdavLogger.info(`[HEAD] Request received for file at ${resource.url}`);
21
17
  try {
22
- const driveItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
23
- resource,
18
+ const driveFile = await webdav_utils_1.WebDavUtils.getDriveFileFromResource({
19
+ url: resource.url,
24
20
  driveFileService,
25
21
  });
26
- if (!driveItem) {
22
+ if (!driveFile) {
27
23
  throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
28
24
  }
29
- const driveFile = driveItem;
30
25
  logger_utils_1.webdavLogger.info(`[HEAD] [${driveFile.uuid}] Found Drive File`);
31
26
  const range = req.headers['range'];
32
27
  const rangeOptions = network_utils_1.NetworkUtils.parseRangeHeader({
@@ -12,12 +12,12 @@ class MKCOLRequestHandler {
12
12
  }
13
13
  handle = async (req, res) => {
14
14
  const { driveFolderService, webDavFolderService } = this.dependencies;
15
- const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
16
- logger_utils_1.webdavLogger.info(`[MKCOL] Request received for ${resource.type} at ${resource.url}`);
15
+ const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
16
+ logger_utils_1.webdavLogger.info(`[MKCOL] Request received for folder at ${resource.url}`);
17
17
  const parentDriveFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
18
18
  (await webDavFolderService.createParentPathOrThrow(resource.parentPath));
19
- const driveFolderItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
20
- resource,
19
+ const driveFolderItem = await webdav_utils_1.WebDavUtils.getDriveFolderFromResource({
20
+ url: resource.url,
21
21
  driveFolderService,
22
22
  });
23
23
  const folderAlreadyExists = !!driveFolderItem;
@@ -11,8 +11,8 @@ class MOVERequestHandler {
11
11
  }
12
12
  handle = async (req, res) => {
13
13
  const { driveFolderService, driveFileService, webDavFolderService } = this.dependencies;
14
- const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
15
- logger_utils_1.webdavLogger.info(`[MOVE] Request received for ${resource.type} at ${resource.url}`);
14
+ const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
15
+ logger_utils_1.webdavLogger.info(`[MOVE] Request received for item at ${resource.url}`);
16
16
  const destinationUrl = req.header('destination');
17
17
  if (!destinationUrl) {
18
18
  throw new errors_utils_1.NotFoundError('[MOVE] Destination folder not received');
@@ -28,43 +28,45 @@ class MOVERequestHandler {
28
28
  if (!originalDriveItem) {
29
29
  throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
30
30
  }
31
- const newName = destinationResource.name;
32
31
  if (destinationResource.path.dir === resource.path.dir) {
33
- logger_utils_1.webdavLogger.info(`[MOVE] Renaming ${resource.type} with UUID ${originalDriveItem.uuid} to ${destinationResource.name}`);
34
- if (resource.type === 'folder') {
32
+ logger_utils_1.webdavLogger.info(`[MOVE] Renaming ${originalDriveItem.itemType}
33
+ with UUID ${originalDriveItem.uuid} to ${destinationResource.name}`);
34
+ if (originalDriveItem.itemType === 'folder') {
35
35
  const folder = originalDriveItem;
36
36
  await driveFolderService.renameFolder({
37
37
  folderUuid: folder.uuid,
38
- name: newName,
38
+ name: destinationResource.name,
39
39
  });
40
40
  }
41
- else if (resource.type === 'file') {
42
- const newType = destinationResource.path.ext.replace('.', '');
41
+ else if (originalDriveItem.itemType === 'file') {
43
42
  const file = originalDriveItem;
43
+ const plainName = destinationResource.path.name;
44
+ const fileType = destinationResource.path.ext.replace('.', '');
44
45
  await driveFileService.renameFile(file.uuid, {
45
- plainName: newName,
46
- type: newType,
46
+ plainName: plainName,
47
+ type: fileType,
47
48
  });
48
49
  }
49
50
  }
50
51
  else {
51
- logger_utils_1.webdavLogger.info(`[MOVE] Moving ${resource.type} with UUID ${originalDriveItem.uuid} to ${destinationPath}`);
52
+ logger_utils_1.webdavLogger.info(`[MOVE] Moving ${originalDriveItem.itemType} with UUID ${originalDriveItem.uuid} to ${destinationPath}`);
52
53
  const destinationFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(destinationResource.parentPath)) ??
53
54
  (await webDavFolderService.createParentPathOrThrow(destinationResource.parentPath));
54
- if (resource.type === 'folder') {
55
+ if (originalDriveItem.itemType === 'folder') {
55
56
  const folder = originalDriveItem;
56
57
  await driveFolderService.moveFolder(folder.uuid, {
57
58
  destinationFolder: destinationFolderItem.uuid,
58
- name: newName,
59
+ name: destinationResource.name,
59
60
  });
60
61
  }
61
- else if (resource.type === 'file') {
62
+ else if (originalDriveItem.itemType === 'file') {
62
63
  const file = originalDriveItem;
63
- const newType = destinationResource.path.ext.replace('.', '');
64
+ const plainName = destinationResource.path.name;
65
+ const fileType = destinationResource.path.ext.replace('.', '');
64
66
  await driveFileService.moveFile(file.uuid, {
65
67
  destinationFolder: destinationFolderItem.uuid,
66
- name: newName,
67
- type: newType,
68
+ name: plainName,
69
+ type: fileType,
68
70
  });
69
71
  }
70
72
  }