@internxt/cli 1.6.1 → 1.6.2

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 (35) hide show
  1. package/README.md +27 -27
  2. package/dist/commands/add-cert.js +2 -2
  3. package/dist/commands/logs.js +3 -3
  4. package/dist/commands/upload-file.d.ts +1 -1
  5. package/dist/commands/upload-file.js +55 -41
  6. package/dist/constants/configs.d.ts +12 -0
  7. package/dist/constants/configs.js +20 -0
  8. package/dist/services/auth.service.js +11 -6
  9. package/dist/services/config.service.d.ts +0 -12
  10. package/dist/services/config.service.js +33 -38
  11. package/dist/services/network/upload/upload-facade.service.js +1 -1
  12. package/dist/services/network/upload/upload-file.service.d.ts +5 -4
  13. package/dist/services/network/upload/upload-file.service.js +51 -29
  14. package/dist/services/network/upload/upload.types.d.ts +2 -2
  15. package/dist/services/network/upload/upload.types.js +1 -1
  16. package/dist/services/sdk-manager.service.d.ts +2 -2
  17. package/dist/services/sdk-manager.service.js +2 -2
  18. package/dist/services/validation.service.d.ts +5 -0
  19. package/dist/services/validation.service.js +22 -18
  20. package/dist/utils/cli.utils.d.ts +3 -0
  21. package/dist/utils/cli.utils.js +37 -3
  22. package/dist/utils/errors.utils.d.ts +1 -0
  23. package/dist/utils/errors.utils.js +8 -2
  24. package/dist/utils/logger.utils.js +5 -5
  25. package/dist/utils/network.utils.js +17 -18
  26. package/dist/utils/thumbnail.utils.d.ts +1 -1
  27. package/dist/utils/thumbnail.utils.js +8 -8
  28. package/dist/utils/xml.utils.d.ts +1 -1
  29. package/dist/utils/xml.utils.js +1 -1
  30. package/dist/webdav/handlers/GET.handler.js +0 -2
  31. package/dist/webdav/handlers/PUT.handler.js +56 -41
  32. package/dist/webdav/middewares/errors.middleware.js +1 -1
  33. package/dist/webdav/webdav-server.js +4 -4
  34. package/oclif.manifest.json +1 -1
  35. package/package.json +10 -10
@@ -4,23 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ConfigService = void 0;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const os_1 = __importDefault(require("os"));
9
7
  const promises_1 = __importDefault(require("node:fs/promises"));
10
8
  const crypto_service_1 = require("./crypto.service");
9
+ const errors_utils_1 = require("../utils/errors.utils");
10
+ const configs_1 = require("../constants/configs");
11
11
  class ConfigService {
12
- static INTERNXT_CLI_DATA_DIR = node_path_1.default.join(os_1.default.homedir(), '.internxt-cli');
13
- static INTERNXT_CLI_LOGS_DIR = node_path_1.default.join(this.INTERNXT_CLI_DATA_DIR, 'logs');
14
- static INTERNXT_TMP_DIR = os_1.default.tmpdir();
15
- static CREDENTIALS_FILE = node_path_1.default.join(this.INTERNXT_CLI_DATA_DIR, '.inxtcli');
16
- static DRIVE_SQLITE_FILE = node_path_1.default.join(this.INTERNXT_CLI_DATA_DIR, 'internxt-cli-drive.sqlite');
17
- static WEBDAV_SSL_CERTS_DIR = node_path_1.default.join(this.INTERNXT_CLI_DATA_DIR, 'certs');
18
- static WEBDAV_CONFIGS_FILE = node_path_1.default.join(this.INTERNXT_CLI_DATA_DIR, 'config.webdav.inxt');
19
- static WEBDAV_DEFAULT_HOST = '127.0.0.1';
20
- static WEBDAV_DEFAULT_PORT = '3005';
21
- static WEBDAV_DEFAULT_PROTOCOL = 'https';
22
- static WEBDAV_DEFAULT_TIMEOUT = 0;
23
- static WEBDAV_DEFAULT_CREATE_FULL_PATH = true;
24
12
  static instance = new ConfigService();
25
13
  get = (key) => {
26
14
  const value = process.env[key];
@@ -32,17 +20,24 @@ class ConfigService {
32
20
  await this.ensureInternxtCliDataDirExists();
33
21
  const credentialsString = JSON.stringify(loginCredentials);
34
22
  const encryptedCredentials = crypto_service_1.CryptoService.instance.encryptText(credentialsString);
35
- await promises_1.default.writeFile(ConfigService.CREDENTIALS_FILE, encryptedCredentials, 'utf8');
23
+ await promises_1.default.writeFile(configs_1.CREDENTIALS_FILE, encryptedCredentials, 'utf8');
36
24
  };
37
25
  clearUser = async () => {
38
- const stat = await promises_1.default.stat(ConfigService.CREDENTIALS_FILE);
39
- if (stat.size === 0)
40
- throw new Error('Credentials file is already empty');
41
- return promises_1.default.writeFile(ConfigService.CREDENTIALS_FILE, '', 'utf8');
26
+ try {
27
+ const stat = await promises_1.default.stat(configs_1.CREDENTIALS_FILE);
28
+ if (stat.size === 0)
29
+ return;
30
+ await promises_1.default.writeFile(configs_1.CREDENTIALS_FILE, '', 'utf8');
31
+ }
32
+ catch (error) {
33
+ if (!(0, errors_utils_1.isFileNotFoundError)(error)) {
34
+ throw error;
35
+ }
36
+ }
42
37
  };
43
38
  readUser = async () => {
44
39
  try {
45
- const encryptedCredentials = await promises_1.default.readFile(ConfigService.CREDENTIALS_FILE, 'utf8');
40
+ const encryptedCredentials = await promises_1.default.readFile(configs_1.CREDENTIALS_FILE, 'utf8');
46
41
  const credentialsString = crypto_service_1.CryptoService.instance.decryptText(encryptedCredentials);
47
42
  const loginCredentials = JSON.parse(credentialsString);
48
43
  return loginCredentials;
@@ -54,52 +49,52 @@ class ConfigService {
54
49
  saveWebdavConfig = async (webdavConfig) => {
55
50
  await this.ensureInternxtCliDataDirExists();
56
51
  const configs = JSON.stringify(webdavConfig);
57
- await promises_1.default.writeFile(ConfigService.WEBDAV_CONFIGS_FILE, configs, 'utf8');
52
+ await promises_1.default.writeFile(configs_1.WEBDAV_CONFIGS_FILE, configs, 'utf8');
58
53
  };
59
54
  readWebdavConfig = async () => {
60
55
  try {
61
- const configsData = await promises_1.default.readFile(ConfigService.WEBDAV_CONFIGS_FILE, 'utf8');
56
+ const configsData = await promises_1.default.readFile(configs_1.WEBDAV_CONFIGS_FILE, 'utf8');
62
57
  const configs = JSON.parse(configsData);
63
58
  return {
64
- host: configs?.host ?? ConfigService.WEBDAV_DEFAULT_HOST,
65
- port: configs?.port ?? ConfigService.WEBDAV_DEFAULT_PORT,
66
- protocol: configs?.protocol ?? ConfigService.WEBDAV_DEFAULT_PROTOCOL,
67
- timeoutMinutes: configs?.timeoutMinutes ?? ConfigService.WEBDAV_DEFAULT_TIMEOUT,
68
- createFullPath: configs?.createFullPath ?? ConfigService.WEBDAV_DEFAULT_CREATE_FULL_PATH,
59
+ host: configs?.host ?? configs_1.WEBDAV_DEFAULT_HOST,
60
+ port: configs?.port ?? configs_1.WEBDAV_DEFAULT_PORT,
61
+ protocol: configs?.protocol ?? configs_1.WEBDAV_DEFAULT_PROTOCOL,
62
+ timeoutMinutes: configs?.timeoutMinutes ?? configs_1.WEBDAV_DEFAULT_TIMEOUT,
63
+ createFullPath: configs?.createFullPath ?? configs_1.WEBDAV_DEFAULT_CREATE_FULL_PATH,
69
64
  };
70
65
  }
71
66
  catch {
72
67
  return {
73
- host: ConfigService.WEBDAV_DEFAULT_HOST,
74
- port: ConfigService.WEBDAV_DEFAULT_PORT,
75
- protocol: ConfigService.WEBDAV_DEFAULT_PROTOCOL,
76
- timeoutMinutes: ConfigService.WEBDAV_DEFAULT_TIMEOUT,
77
- createFullPath: ConfigService.WEBDAV_DEFAULT_CREATE_FULL_PATH,
68
+ host: configs_1.WEBDAV_DEFAULT_HOST,
69
+ port: configs_1.WEBDAV_DEFAULT_PORT,
70
+ protocol: configs_1.WEBDAV_DEFAULT_PROTOCOL,
71
+ timeoutMinutes: configs_1.WEBDAV_DEFAULT_TIMEOUT,
72
+ createFullPath: configs_1.WEBDAV_DEFAULT_CREATE_FULL_PATH,
78
73
  };
79
74
  }
80
75
  };
81
76
  ensureInternxtCliDataDirExists = async () => {
82
77
  try {
83
- await promises_1.default.access(ConfigService.INTERNXT_CLI_DATA_DIR);
78
+ await promises_1.default.access(configs_1.INTERNXT_CLI_DATA_DIR);
84
79
  }
85
80
  catch {
86
- await promises_1.default.mkdir(ConfigService.INTERNXT_CLI_DATA_DIR);
81
+ await promises_1.default.mkdir(configs_1.INTERNXT_CLI_DATA_DIR);
87
82
  }
88
83
  };
89
84
  ensureWebdavCertsDirExists = async () => {
90
85
  try {
91
- await promises_1.default.access(ConfigService.WEBDAV_SSL_CERTS_DIR);
86
+ await promises_1.default.access(configs_1.WEBDAV_SSL_CERTS_DIR);
92
87
  }
93
88
  catch {
94
- await promises_1.default.mkdir(ConfigService.WEBDAV_SSL_CERTS_DIR);
89
+ await promises_1.default.mkdir(configs_1.WEBDAV_SSL_CERTS_DIR);
95
90
  }
96
91
  };
97
92
  ensureInternxtLogsDirExists = async () => {
98
93
  try {
99
- await promises_1.default.access(ConfigService.INTERNXT_CLI_LOGS_DIR);
94
+ await promises_1.default.access(configs_1.INTERNXT_CLI_LOGS_DIR);
100
95
  }
101
96
  catch {
102
- await promises_1.default.mkdir(ConfigService.INTERNXT_CLI_LOGS_DIR);
97
+ await promises_1.default.mkdir(configs_1.INTERNXT_CLI_LOGS_DIR);
103
98
  }
104
99
  };
105
100
  }
@@ -32,7 +32,7 @@ class UploadFacade {
32
32
  throw new Error('Failed to create folders, cannot upload files');
33
33
  }
34
34
  await async_utils_1.AsyncUtils.sleep(500);
35
- const totalBytes = await upload_file_service_1.UploadFileService.instance.uploadFilesInChunks({
35
+ const totalBytes = await upload_file_service_1.UploadFileService.instance.uploadFilesConcurrently({
36
36
  network,
37
37
  filesToUpload: scanResult.files,
38
38
  folderMap,
@@ -1,7 +1,8 @@
1
- import { UploadFilesInBatchesParams, UploadFileWithRetryParams } from './upload.types';
1
+ import { UploadFilesConcurrentlyParams, UploadFileWithRetryParams } from './upload.types';
2
+ import { DriveFileItem } from '../../../types/drive.types';
2
3
  export declare class UploadFileService {
3
4
  static readonly instance: UploadFileService;
4
- uploadFilesInChunks({ network, filesToUpload, folderMap, bucket, destinationFolderUuid, currentProgress, emitProgress, }: UploadFilesInBatchesParams): Promise<number>;
5
- uploadFileWithRetry({ file, network, bucket, parentFolderUuid, }: UploadFileWithRetryParams): Promise<string | null>;
6
- private chunkArray;
5
+ uploadFilesConcurrently({ network, filesToUpload, folderMap, bucket, destinationFolderUuid, currentProgress, emitProgress, }: UploadFilesConcurrentlyParams): Promise<number>;
6
+ uploadFileWithRetry({ file, network, bucket, parentFolderUuid, }: UploadFileWithRetryParams): Promise<DriveFileItem | null>;
7
+ private concurrencyArray;
7
8
  }
@@ -9,13 +9,14 @@ const errors_utils_1 = require("../../../utils/errors.utils");
9
9
  const promises_1 = require("node:fs/promises");
10
10
  const types_1 = require("@internxt/sdk/dist/drive/storage/types");
11
11
  const thumbnail_utils_1 = require("../../../utils/thumbnail.utils");
12
+ const cli_utils_1 = require("../../../utils/cli.utils");
12
13
  class UploadFileService {
13
14
  static instance = new UploadFileService();
14
- async uploadFilesInChunks({ network, filesToUpload, folderMap, bucket, destinationFolderUuid, currentProgress, emitProgress, }) {
15
+ async uploadFilesConcurrently({ network, filesToUpload, folderMap, bucket, destinationFolderUuid, currentProgress, emitProgress, }) {
15
16
  let bytesUploaded = 0;
16
- const chunks = this.chunkArray(filesToUpload, upload_types_1.MAX_CONCURRENT_UPLOADS);
17
- for (const chunk of chunks) {
18
- await Promise.allSettled(chunk.map(async (file) => {
17
+ const concurrentFiles = this.concurrencyArray(filesToUpload, upload_types_1.MAX_CONCURRENT_UPLOADS);
18
+ for (const fileArray of concurrentFiles) {
19
+ await Promise.allSettled(fileArray.map(async (file) => {
19
20
  const parentPath = (0, node_path_1.dirname)(file.relativePath);
20
21
  const parentFolderUuid = parentPath === '.' || parentPath === '' ? destinationFolderUuid : folderMap.get(parentPath);
21
22
  if (!parentFolderUuid) {
@@ -42,27 +43,37 @@ class UploadFileService {
42
43
  for (let attempt = 0; attempt <= upload_types_1.MAX_RETRIES; attempt++) {
43
44
  try {
44
45
  const stats = await (0, promises_1.stat)(file.absolutePath);
45
- if (!stats.size) {
46
- logger_utils_1.logger.warn(`Skipping empty file: ${file.relativePath}`);
47
- return null;
48
- }
46
+ const fileSize = stats.size ?? 0;
49
47
  const fileType = (0, node_path_1.extname)(file.absolutePath).replaceAll('.', '');
50
- const { fileStream, bufferStream } = (0, thumbnail_utils_1.createFileStreamWithBuffer)({
51
- path: file.absolutePath,
52
- fileType,
53
- });
54
- const fileId = await new Promise((resolve, reject) => {
55
- network.uploadFile(fileStream, stats.size, bucket, (err, res) => {
56
- if (err) {
57
- return reject(err);
58
- }
59
- resolve(res);
60
- }, () => { });
61
- });
48
+ let fileId;
49
+ let thumbnailStream;
50
+ const timings = {
51
+ networkUpload: 0,
52
+ driveUpload: 0,
53
+ thumbnailUpload: 0,
54
+ };
55
+ if (fileSize > 0) {
56
+ const { fileStream, bufferStream } = (0, thumbnail_utils_1.createFileStreamWithBuffer)({
57
+ path: file.absolutePath,
58
+ fileType,
59
+ });
60
+ const uploadTimer = cli_utils_1.CLIUtils.timer();
61
+ thumbnailStream = bufferStream;
62
+ fileId = await new Promise((resolve, reject) => {
63
+ network.uploadFile(fileStream, fileSize, bucket, (err, res) => {
64
+ if (err) {
65
+ return reject(err);
66
+ }
67
+ resolve(res);
68
+ }, () => { });
69
+ });
70
+ timings.networkUpload = uploadTimer.stop();
71
+ }
72
+ const driveTimer = cli_utils_1.CLIUtils.timer();
62
73
  const createdDriveFile = await drive_file_service_1.DriveFileService.instance.createFile({
63
74
  plainName: file.name,
64
75
  type: fileType,
65
- size: stats.size,
76
+ size: fileSize,
66
77
  folderUuid: parentFolderUuid,
67
78
  fileId,
68
79
  bucket,
@@ -70,16 +81,27 @@ class UploadFileService {
70
81
  creationTime: stats.birthtime?.toISOString(),
71
82
  modificationTime: stats.mtime?.toISOString(),
72
83
  });
73
- if (bufferStream) {
84
+ timings.driveUpload = driveTimer.stop();
85
+ const thumbnailTimer = cli_utils_1.CLIUtils.timer();
86
+ if (thumbnailStream && fileSize > 0) {
74
87
  void (0, thumbnail_utils_1.tryUploadThumbnail)({
75
- bufferStream,
88
+ bufferStream: thumbnailStream,
76
89
  fileType,
77
90
  userBucket: bucket,
78
91
  fileUuid: createdDriveFile.uuid,
79
92
  networkFacade: network,
80
93
  });
81
94
  }
82
- return createdDriveFile.fileId;
95
+ timings.thumbnailUpload = thumbnailTimer.stop();
96
+ const totalTime = Object.values(timings).reduce((sum, time) => sum + time, 0);
97
+ const throughputMBps = cli_utils_1.CLIUtils.calculateThroughputMBps(stats.size, timings.networkUpload);
98
+ logger_utils_1.logger.info(`Uploaded '${file.name}' (${cli_utils_1.CLIUtils.formatBytesToString(stats.size)})`);
99
+ logger_utils_1.logger.info(`Timing breakdown:\n
100
+ Network upload: ${cli_utils_1.CLIUtils.formatDuration(timings.networkUpload)} (${throughputMBps.toFixed(2)} MB/s)\n
101
+ Drive upload: ${cli_utils_1.CLIUtils.formatDuration(timings.driveUpload)}\n
102
+ Thumbnail: ${cli_utils_1.CLIUtils.formatDuration(timings.thumbnailUpload)}\n
103
+ Total: ${cli_utils_1.CLIUtils.formatDuration(totalTime)}\n`);
104
+ return createdDriveFile;
83
105
  }
84
106
  catch (error) {
85
107
  if ((0, errors_utils_1.isAlreadyExistsError)(error)) {
@@ -101,12 +123,12 @@ class UploadFileService {
101
123
  }
102
124
  return null;
103
125
  }
104
- chunkArray(array, chunkSize) {
105
- const chunks = [];
106
- for (let i = 0; i < array.length; i += chunkSize) {
107
- chunks.push(array.slice(i, i + chunkSize));
126
+ concurrencyArray(array, arraySize) {
127
+ const arrays = [];
128
+ for (let i = 0; i < array.length; i += arraySize) {
129
+ arrays.push(array.slice(i, i + arraySize));
108
130
  }
109
- return chunks;
131
+ return arrays;
110
132
  }
111
133
  }
112
134
  exports.UploadFileService = UploadFileService;
@@ -30,7 +30,7 @@ export interface CreateFolderWithRetryParams {
30
30
  folderName: string;
31
31
  parentFolderUuid: string;
32
32
  }
33
- export interface UploadFilesInBatchesParams {
33
+ export interface UploadFilesConcurrentlyParams {
34
34
  network: NetworkFacade;
35
35
  filesToUpload: FileSystemNode[];
36
36
  folderMap: Map<string, string>;
@@ -48,6 +48,6 @@ export interface UploadFileWithRetryParams {
48
48
  bucket: string;
49
49
  parentFolderUuid: string;
50
50
  }
51
- export declare const MAX_CONCURRENT_UPLOADS = 5;
51
+ export declare const MAX_CONCURRENT_UPLOADS = 10;
52
52
  export declare const DELAYS_MS: number[];
53
53
  export declare const MAX_RETRIES = 2;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MAX_RETRIES = exports.DELAYS_MS = exports.MAX_CONCURRENT_UPLOADS = void 0;
4
- exports.MAX_CONCURRENT_UPLOADS = 5;
4
+ exports.MAX_CONCURRENT_UPLOADS = 10;
5
5
  exports.DELAYS_MS = [500, 1000, 2000];
6
6
  exports.MAX_RETRIES = 2;
@@ -6,8 +6,8 @@ export declare class SdkManager {
6
6
  private static apiSecurity?;
7
7
  static readonly init: (apiSecurity: SdkManagerApiSecurity) => void;
8
8
  static readonly clean: () => void;
9
- static readonly getApiSecurity: (config?: {
10
- throwErrorOnMissingCredentials: boolean;
9
+ static readonly getApiSecurity: ({ throwErrorOnMissingCredentials }?: {
10
+ throwErrorOnMissingCredentials?: boolean | undefined;
11
11
  }) => SdkManagerApiSecurity;
12
12
  static readonly getAppDetails: () => AppDetails;
13
13
  getAuth(): Auth;
@@ -18,8 +18,8 @@ class SdkManager {
18
18
  static clean = () => {
19
19
  SdkManager.apiSecurity = undefined;
20
20
  };
21
- static getApiSecurity = (config = { throwErrorOnMissingCredentials: true }) => {
22
- if (!SdkManager.apiSecurity && config.throwErrorOnMissingCredentials)
21
+ static getApiSecurity = ({ throwErrorOnMissingCredentials = true } = {}) => {
22
+ if (!SdkManager.apiSecurity && throwErrorOnMissingCredentials)
23
23
  throw new Error('Api security properties not found in SdkManager');
24
24
  return SdkManager.apiSecurity;
25
25
  };
@@ -9,6 +9,11 @@ export declare class ValidationService {
9
9
  validateStringIsNotEmpty: (str: string) => boolean;
10
10
  validateDirectoryExists: (path: string) => Promise<boolean>;
11
11
  validateFileExists: (path: string) => Promise<boolean>;
12
+ validateJwtAndCheckExpiration: (token?: string) => number | null;
13
+ checkTokenExpiration: (expirationTimestamp: number) => {
14
+ expired: boolean;
15
+ refreshRequired: boolean;
16
+ };
12
17
  validateTokenAndCheckExpiration: (token?: string) => {
13
18
  isValid: boolean;
14
19
  expiration: {
@@ -38,29 +38,33 @@ class ValidationService {
38
38
  const fileStat = await promises_1.default.stat(path);
39
39
  return fileStat.isFile();
40
40
  };
41
- validateTokenAndCheckExpiration = (token) => {
42
- if (!token || typeof token !== 'string') {
43
- return { isValid: false, expiration: { expired: true, refreshRequired: false } };
44
- }
45
- const parts = token.split('.');
46
- if (parts.length !== 3) {
47
- return { isValid: false, expiration: { expired: true, refreshRequired: false } };
41
+ validateJwtAndCheckExpiration = (token) => {
42
+ if (!token || typeof token !== 'string' || token.split('.').length !== 3) {
43
+ return null;
48
44
  }
49
45
  try {
50
- const payload = JSON.parse(atob(parts[1]));
51
- if (typeof payload.exp !== 'number') {
52
- return { isValid: false, expiration: { expired: true, refreshRequired: false } };
53
- }
54
- const currentTime = Math.floor(Date.now() / 1000);
55
- const twoDaysInSeconds = 2 * 24 * 60 * 60;
56
- const remainingSeconds = payload.exp - currentTime;
57
- const expired = remainingSeconds <= 0;
58
- const refreshRequired = remainingSeconds > 0 && remainingSeconds <= twoDaysInSeconds;
59
- return { isValid: true, expiration: { expired, refreshRequired } };
46
+ const payload = JSON.parse(atob(token.split('.')[1]));
47
+ return typeof payload.exp === 'number' ? payload.exp : null;
60
48
  }
61
49
  catch {
62
- return { isValid: false, expiration: { expired: true, refreshRequired: false } };
50
+ return null;
63
51
  }
64
52
  };
53
+ checkTokenExpiration = (expirationTimestamp) => {
54
+ const TWO_DAYS_IN_SECONDS = 2 * 24 * 60 * 60;
55
+ const currentTime = Math.floor(Date.now() / 1000);
56
+ const remainingSeconds = expirationTimestamp - currentTime;
57
+ return {
58
+ expired: remainingSeconds <= 0,
59
+ refreshRequired: remainingSeconds > 0 && remainingSeconds <= TWO_DAYS_IN_SECONDS,
60
+ };
61
+ };
62
+ validateTokenAndCheckExpiration = (token) => {
63
+ const expiration = this.validateJwtAndCheckExpiration(token);
64
+ return {
65
+ isValid: expiration !== null,
66
+ expiration: expiration ? this.checkTokenExpiration(expiration) : { expired: true, refreshRequired: false },
67
+ };
68
+ };
65
69
  }
66
70
  exports.ValidationService = ValidationService;
@@ -43,6 +43,9 @@ export declare class CLIUtils {
43
43
  static readonly timer: () => {
44
44
  stop: () => number;
45
45
  };
46
+ static readonly formatDuration: (milliseconds: number) => string;
47
+ static readonly formatBytesToString: (bytes: number) => string;
48
+ static readonly calculateThroughputMBps: (bytes: number, milliseconds: number) => number;
46
49
  static readonly catchError: ({ error, logReporter, command, jsonFlag, }: {
47
50
  error: Error;
48
51
  command?: string;
@@ -143,11 +143,11 @@ class CLIUtils {
143
143
  }
144
144
  }
145
145
  } while (!isValid && currentAttempts < maxAttempts);
146
- if (!isValid) {
147
- throw validation.error;
146
+ if (isValid) {
147
+ return promptValue;
148
148
  }
149
149
  else {
150
- return promptValue;
150
+ throw validation.error;
151
151
  }
152
152
  };
153
153
  static timer = () => {
@@ -160,6 +160,40 @@ class CLIUtils {
160
160
  },
161
161
  };
162
162
  };
163
+ static formatDuration = (milliseconds) => {
164
+ if (milliseconds <= 0) {
165
+ return '00:00:00.000';
166
+ }
167
+ const totalSeconds = Math.floor(milliseconds / 1000);
168
+ const hours = Math.floor(totalSeconds / 3600);
169
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
170
+ const seconds = totalSeconds % 60;
171
+ const ms = Math.floor(milliseconds % 1000);
172
+ const hoursFormated = hours.toString().padStart(2, '0');
173
+ const minutesFormated = minutes.toString().padStart(2, '0');
174
+ const secondsFormated = seconds.toString().padStart(2, '0');
175
+ const msFormated = ms.toString().padStart(3, '0');
176
+ return `${hoursFormated}:${minutesFormated}:${secondsFormated}.${msFormated}`;
177
+ };
178
+ static formatBytesToString = (bytes) => {
179
+ if (bytes <= 0) {
180
+ return '0.00 KB';
181
+ }
182
+ const kb = bytes / 1024;
183
+ if (kb < 1024) {
184
+ return `${kb.toFixed(2)} KB`;
185
+ }
186
+ const mb = kb / 1024;
187
+ return `${mb.toFixed(2)} MB`;
188
+ };
189
+ static calculateThroughputMBps = (bytes, milliseconds) => {
190
+ if (bytes <= 0 || milliseconds <= 0) {
191
+ return 0;
192
+ }
193
+ const megabytes = bytes / 1024 / 1024;
194
+ const seconds = milliseconds / 1000;
195
+ return megabytes / seconds;
196
+ };
163
197
  static catchError = ({ error, logReporter, command, jsonFlag, }) => {
164
198
  let message;
165
199
  if ('message' in error && error.message.trim().length > 0) {
@@ -1,5 +1,6 @@
1
1
  export declare function isError(error: unknown): error is Error;
2
2
  export declare function isAlreadyExistsError(error: unknown): error is Error;
3
+ export declare function isFileNotFoundError(error: unknown): error is NodeJS.ErrnoException;
3
4
  export declare class ErrorUtils {
4
5
  static report(error: unknown, props?: Record<string, unknown>): void;
5
6
  }
@@ -3,15 +3,21 @@ 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
5
  exports.isAlreadyExistsError = isAlreadyExistsError;
6
+ exports.isFileNotFoundError = isFileNotFoundError;
6
7
  const logger_utils_1 = require("./logger.utils");
7
- const node_util_1 = require("node:util");
8
8
  function isError(error) {
9
- return node_util_1.types.isNativeError(error);
9
+ return typeof Error.isError === 'function'
10
+ ? Error.isError(error)
11
+ : error instanceof Error ||
12
+ (typeof error === 'object' && error !== null && 'message' in error && ('stack' in error || 'name' in error));
10
13
  }
11
14
  function isAlreadyExistsError(error) {
12
15
  return ((isError(error) && error.message.includes('already exists')) ||
13
16
  (typeof error === 'object' && error !== null && 'status' in error && error.status === 409));
14
17
  }
18
+ function isFileNotFoundError(error) {
19
+ return isError(error) && 'code' in error && error.code === 'ENOENT';
20
+ }
15
21
  class ErrorUtils {
16
22
  static report(error, props = {}) {
17
23
  if (isError(error)) {
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.webdavLogger = exports.logger = void 0;
7
7
  const winston_1 = __importDefault(require("winston"));
8
- const config_service_1 = require("../services/config.service");
8
+ const configs_1 = require("../constants/configs");
9
9
  const maxLogSize = 40 * 1024 * 1024;
10
10
  const maxLogsFiles = 5;
11
11
  exports.logger = winston_1.default.createLogger({
@@ -16,14 +16,14 @@ exports.logger = winston_1.default.createLogger({
16
16
  new winston_1.default.transports.File({
17
17
  filename: 'internxt-cli-error.log',
18
18
  level: 'error',
19
- dirname: config_service_1.ConfigService.INTERNXT_CLI_LOGS_DIR,
19
+ dirname: configs_1.INTERNXT_CLI_LOGS_DIR,
20
20
  maxsize: maxLogSize,
21
21
  maxFiles: maxLogsFiles,
22
22
  tailable: true,
23
23
  }),
24
24
  new winston_1.default.transports.File({
25
25
  filename: 'internxt-cli-combined.log',
26
- dirname: config_service_1.ConfigService.INTERNXT_CLI_LOGS_DIR,
26
+ dirname: configs_1.INTERNXT_CLI_LOGS_DIR,
27
27
  maxsize: maxLogSize,
28
28
  maxFiles: maxLogsFiles,
29
29
  tailable: true,
@@ -38,14 +38,14 @@ exports.webdavLogger = winston_1.default.createLogger({
38
38
  new winston_1.default.transports.File({
39
39
  filename: 'internxt-webdav-error.log',
40
40
  level: 'error',
41
- dirname: config_service_1.ConfigService.INTERNXT_CLI_LOGS_DIR,
41
+ dirname: configs_1.INTERNXT_CLI_LOGS_DIR,
42
42
  maxsize: maxLogSize,
43
43
  maxFiles: maxLogsFiles,
44
44
  tailable: true,
45
45
  }),
46
46
  new winston_1.default.transports.File({
47
47
  filename: 'internxt-webdav-combined.log',
48
- dirname: config_service_1.ConfigService.INTERNXT_CLI_LOGS_DIR,
48
+ dirname: configs_1.INTERNXT_CLI_LOGS_DIR,
49
49
  maxsize: maxLogSize,
50
50
  maxFiles: maxLogsFiles,
51
51
  tailable: true,
@@ -9,7 +9,7 @@ const promises_1 = require("node:fs/promises");
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const selfsigned_1 = __importDefault(require("selfsigned"));
11
11
  const range_parser_1 = __importDefault(require("range-parser"));
12
- const config_service_1 = require("../services/config.service");
12
+ const configs_1 = require("../constants/configs");
13
13
  class NetworkUtils {
14
14
  static getAuthFromCredentials(creds) {
15
15
  return {
@@ -18,8 +18,8 @@ class NetworkUtils {
18
18
  };
19
19
  }
20
20
  static WEBDAV_SSL_CERTS_PATH = {
21
- cert: node_path_1.default.join(config_service_1.ConfigService.WEBDAV_SSL_CERTS_DIR, 'cert.crt'),
22
- privateKey: node_path_1.default.join(config_service_1.ConfigService.WEBDAV_SSL_CERTS_DIR, 'priv.key'),
21
+ cert: node_path_1.default.join(configs_1.WEBDAV_SSL_CERTS_DIR, 'cert.crt'),
22
+ privateKey: node_path_1.default.join(configs_1.WEBDAV_SSL_CERTS_DIR, 'priv.key'),
23
23
  };
24
24
  static async generateNewSelfsignedCerts(configs) {
25
25
  const newCerts = await this.generateSelfSignedSSLCerts(configs);
@@ -59,17 +59,16 @@ class NetworkUtils {
59
59
  }
60
60
  static async generateSelfSignedSSLCerts(configs) {
61
61
  const attrs = [{ name: 'commonName', value: configs.host }];
62
- const extensions = [
63
- {
64
- name: 'subjectAltName',
65
- altNames: [
66
- {
67
- type: 2,
68
- value: configs.host,
69
- },
70
- ],
71
- },
72
- ];
62
+ const extension = {
63
+ name: 'subjectAltName',
64
+ altNames: [
65
+ {
66
+ type: 2,
67
+ value: configs.host,
68
+ },
69
+ ],
70
+ };
71
+ const extensions = [extension];
73
72
  const notAfterDate = new Date();
74
73
  notAfterDate.setDate(notAfterDate.getDate() + 365);
75
74
  const pems = await selfsigned_1.default.generate(attrs, { notAfterDate, algorithm: 'sha256', keySize: 2048, extensions });
@@ -87,10 +86,7 @@ class NetworkUtils {
87
86
  else if (parsed.length <= 0) {
88
87
  throw new Error(`Empty Range-Request. ${JSON.stringify(rangeOptions)}`);
89
88
  }
90
- else if (parsed.type !== 'bytes') {
91
- throw new Error(`Unkwnown Range-Request type "${parsed.type}". ${JSON.stringify(rangeOptions)}`);
92
- }
93
- else {
89
+ if (parsed.type === 'bytes') {
94
90
  const rangeSize = parsed[0].end - parsed[0].start + 1;
95
91
  return {
96
92
  range: rangeOptions.range,
@@ -99,6 +95,9 @@ class NetworkUtils {
99
95
  parsed: parsed[0],
100
96
  };
101
97
  }
98
+ else {
99
+ throw new Error(`Unkwnown Range-Request type "${parsed.type}". ${JSON.stringify(rangeOptions)}`);
100
+ }
102
101
  }
103
102
  else if (parsed === -1) {
104
103
  throw new Error(`Malformed Range-Request. ${JSON.stringify(rangeOptions)}`);
@@ -11,7 +11,7 @@ export declare const isFileThumbnailable: (fileType: string) => boolean;
11
11
  export declare const isPDFThumbnailable: (fileType: string) => boolean;
12
12
  export declare const isImageThumbnailable: (fileType: string) => boolean;
13
13
  export declare const tryUploadThumbnail: ({ bufferStream, fileType, userBucket, fileUuid, networkFacade, }: {
14
- bufferStream: BufferStream;
14
+ bufferStream?: BufferStream;
15
15
  fileType: string;
16
16
  userBucket: string;
17
17
  fileUuid: string;