diff --git a/README.md b/README.md index 09917a6a..1c9b2157 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ $ npm install -g @internxt/cli $ internxt COMMAND running command... $ internxt (--version) -@internxt/cli/1.6.2 win32-x64 node-v24.3.0 +@internxt/cli/1.6.3 win32-x64 node-v24.3.0 $ internxt --help [COMMAND] USAGE $ internxt COMMAND @@ -68,9 +68,11 @@ USAGE * [`internxt add-cert`](#internxt-add-cert) +* [`internxt add cert`](#internxt-add-cert) * [`internxt autocomplete [SHELL]`](#internxt-autocomplete-shell) * [`internxt config`](#internxt-config) * [`internxt create-folder`](#internxt-create-folder) +* [`internxt create folder`](#internxt-create-folder) * [`internxt delete-permanently-file`](#internxt-delete-permanently-file) * [`internxt delete-permanently-folder`](#internxt-delete-permanently-folder) * [`internxt delete permanently file`](#internxt-delete-permanently-file) @@ -109,6 +111,12 @@ USAGE * [`internxt webdav ACTION`](#internxt-webdav-action) * [`internxt webdav-config`](#internxt-webdav-config) * [`internxt whoami`](#internxt-whoami) +* [`internxt workspaces-list`](#internxt-workspaces-list) +* [`internxt workspaces-unset`](#internxt-workspaces-unset) +* [`internxt workspaces-use`](#internxt-workspaces-use) +* [`internxt workspaces list`](#internxt-workspaces-list) +* [`internxt workspaces unset`](#internxt-workspaces-unset) +* [`internxt workspaces use`](#internxt-workspaces-use) ## `internxt add-cert` @@ -124,11 +132,35 @@ GLOBAL FLAGS DESCRIPTION Add a self-signed certificate to the trusted store for macOS, Linux, and Windows. +ALIASES + $ internxt add cert + EXAMPLES $ internxt add-cert ``` -_See code: [src/commands/add-cert.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/add-cert.ts)_ +_See code: [src/commands/add-cert.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/add-cert.ts)_ + +## `internxt add cert` + +Add a self-signed certificate to the trusted store for macOS, Linux, and Windows. + +``` +USAGE + $ internxt add cert [--json] + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Add a self-signed certificate to the trusted store for macOS, Linux, and Windows. + +ALIASES + $ internxt add cert + +EXAMPLES + $ internxt add cert +``` ## `internxt autocomplete [SHELL]` @@ -159,7 +191,7 @@ EXAMPLES $ internxt autocomplete --refresh-cache ``` -_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.39/src/commands/autocomplete/index.ts)_ +_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.40/src/commands/autocomplete/index.ts)_ ## `internxt config` @@ -167,7 +199,16 @@ Display useful information from the user logged into the Internxt CLI. ``` USAGE - $ internxt config [--json] + $ internxt config [--json] [-x] [--debug] [-e] + +FLAGS + -e, --extended Displays additional information in the list. + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -179,7 +220,7 @@ EXAMPLES $ internxt config ``` -_See code: [src/commands/config.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/config.ts)_ +_See code: [src/commands/config.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/config.ts)_ ## `internxt create-folder` @@ -187,7 +228,7 @@ Create a folder in your Internxt Drive ``` USAGE - $ internxt create-folder [--json] [-x] [-n ] [-i ] + $ internxt create-folder [--json] [-x] [--debug] [-n ] [-i ] FLAGS -i, --id= The ID of the folder where the new folder will be created. Defaults to your root folder if not @@ -197,6 +238,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -204,11 +247,46 @@ GLOBAL FLAGS DESCRIPTION Create a folder in your Internxt Drive +ALIASES + $ internxt create folder + EXAMPLES $ internxt create-folder ``` -_See code: [src/commands/create-folder.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/create-folder.ts)_ +_See code: [src/commands/create-folder.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/create-folder.ts)_ + +## `internxt create folder` + +Create a folder in your Internxt Drive + +``` +USAGE + $ internxt create folder [--json] [-x] [--debug] [-n ] [-i ] + +FLAGS + -i, --id= The ID of the folder where the new folder will be created. Defaults to your root folder if not + specified. + -n, --name= The new name for the folder + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Create a folder in your Internxt Drive + +ALIASES + $ internxt create folder + +EXAMPLES + $ internxt create folder +``` ## `internxt delete-permanently-file` @@ -216,7 +294,7 @@ Deletes permanently a file. This action cannot be undone. ``` USAGE - $ internxt delete-permanently-file [--json] [-x] [-i ] + $ internxt delete-permanently-file [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The file id to be permanently deleted. @@ -224,6 +302,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -238,7 +318,7 @@ EXAMPLES $ internxt delete-permanently-file ``` -_See code: [src/commands/delete-permanently-file.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/delete-permanently-file.ts)_ +_See code: [src/commands/delete-permanently-file.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/delete-permanently-file.ts)_ ## `internxt delete-permanently-folder` @@ -246,7 +326,7 @@ Deletes permanently a folder. This action cannot be undone. ``` USAGE - $ internxt delete-permanently-folder [--json] [-x] [-i ] + $ internxt delete-permanently-folder [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The folder id to be permanently deleted. @@ -254,6 +334,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -268,7 +350,7 @@ EXAMPLES $ internxt delete-permanently-folder ``` -_See code: [src/commands/delete-permanently-folder.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/delete-permanently-folder.ts)_ +_See code: [src/commands/delete-permanently-folder.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/delete-permanently-folder.ts)_ ## `internxt delete permanently file` @@ -276,7 +358,7 @@ Deletes permanently a file. This action cannot be undone. ``` USAGE - $ internxt delete permanently file [--json] [-x] [-i ] + $ internxt delete permanently file [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The file id to be permanently deleted. @@ -284,6 +366,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -304,7 +388,7 @@ Deletes permanently a folder. This action cannot be undone. ``` USAGE - $ internxt delete permanently folder [--json] [-x] [-i ] + $ internxt delete permanently folder [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The folder id to be permanently deleted. @@ -312,6 +396,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -332,7 +418,7 @@ Download and decrypts a file from Internxt Drive to a directory. The file name w ``` USAGE - $ internxt download-file [--json] [-x] [-i ] [-d ] [-o] + $ internxt download-file [--json] [-x] [--debug] [-i ] [-d ] [-o] FLAGS -d, --directory= The directory to download the file to. Leave empty for the current folder. @@ -342,6 +428,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -357,7 +445,7 @@ EXAMPLES $ internxt download-file ``` -_See code: [src/commands/download-file.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/download-file.ts)_ +_See code: [src/commands/download-file.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/download-file.ts)_ ## `internxt download file` @@ -365,7 +453,7 @@ Download and decrypts a file from Internxt Drive to a directory. The file name w ``` USAGE - $ internxt download file [--json] [-x] [-i ] [-d ] [-o] + $ internxt download file [--json] [-x] [--debug] [-i ] [-d ] [-o] FLAGS -d, --directory= The directory to download the file to. Leave empty for the current folder. @@ -375,6 +463,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -396,7 +486,7 @@ Lists the content of a folder id. ``` USAGE - $ internxt list [--json] [-x] [-i ] [-e] + $ internxt list [--json] [-x] [--debug] [-i ] [-e] FLAGS -e, --extended Displays additional information in the list. @@ -405,6 +495,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -416,7 +508,7 @@ EXAMPLES $ internxt list ``` -_See code: [src/commands/list.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/list.ts)_ +_See code: [src/commands/list.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/list.ts)_ ## `internxt login` @@ -444,7 +536,7 @@ EXAMPLES $ internxt login ``` -_See code: [src/commands/login.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/login.ts)_ +_See code: [src/commands/login.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/login.ts)_ ## `internxt login-legacy` @@ -452,7 +544,7 @@ _See code: [src/commands/login.ts](https://github.com/internxt/cli/blob/v1.6.2/s ``` USAGE - $ internxt login-legacy [--json] [-x] [-e ] [-p ] [-w 123456] [-t token] + $ internxt login-legacy [--json] [-x] [--debug] [-e ] [-p ] [-w 123456] [-t token] FLAGS -e, --email= [env: INXT_USER] The email to log in @@ -464,6 +556,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -476,7 +570,7 @@ EXAMPLES $ internxt login-legacy ``` -_See code: [src/commands/login-legacy.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/login-legacy.ts)_ +_See code: [src/commands/login-legacy.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/login-legacy.ts)_ ## `internxt logout` @@ -496,7 +590,7 @@ EXAMPLES $ internxt logout ``` -_See code: [src/commands/logout.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/logout.ts)_ +_See code: [src/commands/logout.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/logout.ts)_ ## `internxt logs` @@ -516,7 +610,7 @@ EXAMPLES $ internxt logs ``` -_See code: [src/commands/logs.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/logs.ts)_ +_See code: [src/commands/logs.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/logs.ts)_ ## `internxt move-file` @@ -524,7 +618,7 @@ Move a file into a destination folder. ``` USAGE - $ internxt move-file [--json] [-x] [-i ] [-d ] + $ internxt move-file [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The destination folder id where the file is going to be moved. Leave empty for the root @@ -534,6 +628,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -548,7 +644,7 @@ EXAMPLES $ internxt move-file ``` -_See code: [src/commands/move-file.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/move-file.ts)_ +_See code: [src/commands/move-file.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/move-file.ts)_ ## `internxt move-folder` @@ -556,7 +652,7 @@ Move a folder into a destination folder. ``` USAGE - $ internxt move-folder [--json] [-x] [-i ] [-d ] + $ internxt move-folder [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The destination folder id where the folder is going to be moved. Leave empty for the root @@ -566,6 +662,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -580,7 +678,7 @@ EXAMPLES $ internxt move-folder ``` -_See code: [src/commands/move-folder.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/move-folder.ts)_ +_See code: [src/commands/move-folder.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/move-folder.ts)_ ## `internxt move file` @@ -588,7 +686,7 @@ Move a file into a destination folder. ``` USAGE - $ internxt move file [--json] [-x] [-i ] [-d ] + $ internxt move file [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The destination folder id where the file is going to be moved. Leave empty for the root @@ -598,6 +696,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -618,7 +718,7 @@ Move a folder into a destination folder. ``` USAGE - $ internxt move folder [--json] [-x] [-i ] [-d ] + $ internxt move folder [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The destination folder id where the folder is going to be moved. Leave empty for the root @@ -628,6 +728,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -648,7 +750,7 @@ Rename a file. ``` USAGE - $ internxt rename-file [--json] [-x] [-i ] [-n ] + $ internxt rename-file [--json] [-x] [--debug] [-i ] [-n ] FLAGS -i, --id= The ID of the file to be renamed. @@ -657,6 +759,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -671,7 +775,7 @@ EXAMPLES $ internxt rename-file ``` -_See code: [src/commands/rename-file.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/rename-file.ts)_ +_See code: [src/commands/rename-file.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/rename-file.ts)_ ## `internxt rename-folder` @@ -679,7 +783,7 @@ Rename a folder. ``` USAGE - $ internxt rename-folder [--json] [-x] [-i ] [-n ] + $ internxt rename-folder [--json] [-x] [--debug] [-i ] [-n ] FLAGS -i, --id= The ID of the folder to be renamed. @@ -688,6 +792,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -702,7 +808,7 @@ EXAMPLES $ internxt rename-folder ``` -_See code: [src/commands/rename-folder.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/rename-folder.ts)_ +_See code: [src/commands/rename-folder.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/rename-folder.ts)_ ## `internxt rename file` @@ -710,7 +816,7 @@ Rename a file. ``` USAGE - $ internxt rename file [--json] [-x] [-i ] [-n ] + $ internxt rename file [--json] [-x] [--debug] [-i ] [-n ] FLAGS -i, --id= The ID of the file to be renamed. @@ -719,6 +825,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -739,7 +847,7 @@ Rename a folder. ``` USAGE - $ internxt rename folder [--json] [-x] [-i ] [-n ] + $ internxt rename folder [--json] [-x] [--debug] [-i ] [-n ] FLAGS -i, --id= The ID of the folder to be renamed. @@ -748,6 +856,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -768,7 +878,7 @@ Deletes permanently all the content of the trash. This action cannot be undone. ``` USAGE - $ internxt trash-clear [--json] [-x] [-f] + $ internxt trash-clear [--json] [-x] [--debug] [-f] FLAGS -f, --force It forces the trash to be emptied without confirmation. @@ -776,6 +886,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -790,7 +902,7 @@ EXAMPLES $ internxt trash-clear ``` -_See code: [src/commands/trash-clear.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/trash-clear.ts)_ +_See code: [src/commands/trash-clear.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/trash-clear.ts)_ ## `internxt trash-file` @@ -798,7 +910,7 @@ Moves a given file to the trash. ``` USAGE - $ internxt trash-file [--json] [-x] [-i ] + $ internxt trash-file [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The file id to be trashed. @@ -806,6 +918,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -820,7 +934,7 @@ EXAMPLES $ internxt trash-file ``` -_See code: [src/commands/trash-file.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/trash-file.ts)_ +_See code: [src/commands/trash-file.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/trash-file.ts)_ ## `internxt trash-folder` @@ -828,7 +942,7 @@ Moves a given folder to the trash. ``` USAGE - $ internxt trash-folder [--json] [-x] [-i ] + $ internxt trash-folder [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The folder id to be trashed. @@ -836,6 +950,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -850,7 +966,7 @@ EXAMPLES $ internxt trash-folder ``` -_See code: [src/commands/trash-folder.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/trash-folder.ts)_ +_See code: [src/commands/trash-folder.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/trash-folder.ts)_ ## `internxt trash-list` @@ -876,7 +992,7 @@ EXAMPLES $ internxt trash-list ``` -_See code: [src/commands/trash-list.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/trash-list.ts)_ +_See code: [src/commands/trash-list.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/trash-list.ts)_ ## `internxt trash-restore-file` @@ -884,7 +1000,7 @@ Restore a trashed file into a destination folder. ``` USAGE - $ internxt trash-restore-file [--json] [-x] [-i ] [-d ] + $ internxt trash-restore-file [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The folder id where the file is going to be restored. Leave empty for the root folder. @@ -893,6 +1009,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -907,7 +1025,7 @@ EXAMPLES $ internxt trash-restore-file ``` -_See code: [src/commands/trash-restore-file.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/trash-restore-file.ts)_ +_See code: [src/commands/trash-restore-file.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/trash-restore-file.ts)_ ## `internxt trash-restore-folder` @@ -915,7 +1033,7 @@ Restore a trashed folder into a destination folder. ``` USAGE - $ internxt trash-restore-folder [--json] [-x] [-i ] [-d ] + $ internxt trash-restore-folder [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The folder id where the folder is going to be restored. Leave empty for the root folder. @@ -924,6 +1042,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -938,7 +1058,7 @@ EXAMPLES $ internxt trash-restore-folder ``` -_See code: [src/commands/trash-restore-folder.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/trash-restore-folder.ts)_ +_See code: [src/commands/trash-restore-folder.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/trash-restore-folder.ts)_ ## `internxt trash clear` @@ -946,7 +1066,7 @@ Deletes permanently all the content of the trash. This action cannot be undone. ``` USAGE - $ internxt trash clear [--json] [-x] [-f] + $ internxt trash clear [--json] [-x] [--debug] [-f] FLAGS -f, --force It forces the trash to be emptied without confirmation. @@ -954,6 +1074,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -974,7 +1096,7 @@ Moves a given file to the trash. ``` USAGE - $ internxt trash file [--json] [-x] [-i ] + $ internxt trash file [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The file id to be trashed. @@ -982,6 +1104,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1002,7 +1126,7 @@ Moves a given folder to the trash. ``` USAGE - $ internxt trash folder [--json] [-x] [-i ] + $ internxt trash folder [--json] [-x] [--debug] [-i ] FLAGS -i, --id= The folder id to be trashed. @@ -1010,6 +1134,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1054,7 +1180,7 @@ Restore a trashed file into a destination folder. ``` USAGE - $ internxt trash restore file [--json] [-x] [-i ] [-d ] + $ internxt trash restore file [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The folder id where the file is going to be restored. Leave empty for the root folder. @@ -1063,6 +1189,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1083,7 +1211,7 @@ Restore a trashed folder into a destination folder. ``` USAGE - $ internxt trash restore folder [--json] [-x] [-i ] [-d ] + $ internxt trash restore folder [--json] [-x] [--debug] [-i ] [-d ] FLAGS -d, --destination= The folder id where the folder is going to be restored. Leave empty for the root folder. @@ -1092,6 +1220,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1112,7 +1242,7 @@ Upload a file to Internxt Drive ``` USAGE - $ internxt upload-file [--json] [-x] [-f ] [-i ] + $ internxt upload-file [--json] [-x] [--debug] [-f ] [-i ] FLAGS -f, --file= The path to the file on your system. @@ -1121,6 +1251,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1135,7 +1267,7 @@ EXAMPLES $ internxt upload-file ``` -_See code: [src/commands/upload-file.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/upload-file.ts)_ +_See code: [src/commands/upload-file.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/upload-file.ts)_ ## `internxt upload-folder` @@ -1143,7 +1275,7 @@ Upload a folder to Internxt Drive ``` USAGE - $ internxt upload-folder [--json] [-x] [-f ] [-i ] + $ internxt upload-folder [--json] [-x] [--debug] [-f ] [-i ] FLAGS -f, --folder= The path to the folder on your system. @@ -1152,6 +1284,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1166,7 +1300,7 @@ EXAMPLES $ internxt upload-folder ``` -_See code: [src/commands/upload-folder.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/upload-folder.ts)_ +_See code: [src/commands/upload-folder.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/upload-folder.ts)_ ## `internxt upload file` @@ -1174,7 +1308,7 @@ Upload a file to Internxt Drive ``` USAGE - $ internxt upload file [--json] [-x] [-f ] [-i ] + $ internxt upload file [--json] [-x] [--debug] [-f ] [-i ] FLAGS -f, --file= The path to the file on your system. @@ -1183,6 +1317,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1203,7 +1339,7 @@ Upload a folder to Internxt Drive ``` USAGE - $ internxt upload folder [--json] [-x] [-f ] [-i ] + $ internxt upload folder [--json] [-x] [--debug] [-f ] [-i ] FLAGS -f, --folder= The path to the folder on your system. @@ -1212,6 +1348,8 @@ FLAGS HELPER FLAGS -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. GLOBAL FLAGS --json Format output as json. @@ -1228,7 +1366,7 @@ EXAMPLES ## `internxt webdav ACTION` -Enable, disable, restart or get the status of the Internxt CLI WebDav server +Start, stop, restart or get the status of the Internxt CLI WebDAV server ``` USAGE @@ -1238,19 +1376,19 @@ GLOBAL FLAGS --json Format output as json. DESCRIPTION - Enable, disable, restart or get the status of the Internxt CLI WebDav server + Start, stop, restart or get the status of the Internxt CLI WebDAV server EXAMPLES - $ internxt webdav enable + $ internxt webdav enable | start - $ internxt webdav disable + $ internxt webdav disable | stop $ internxt webdav restart $ internxt webdav status ``` -_See code: [src/commands/webdav.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/webdav.ts)_ +_See code: [src/commands/webdav.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/webdav.ts)_ ## `internxt webdav-config` @@ -1278,7 +1416,7 @@ EXAMPLES $ internxt webdav-config ``` -_See code: [src/commands/webdav-config.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/webdav-config.ts)_ +_See code: [src/commands/webdav-config.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/webdav-config.ts)_ ## `internxt whoami` @@ -1298,7 +1436,197 @@ EXAMPLES $ internxt whoami ``` -_See code: [src/commands/whoami.ts](https://github.com/internxt/cli/blob/v1.6.2/src/commands/whoami.ts)_ +_See code: [src/commands/whoami.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/whoami.ts)_ + +## `internxt workspaces-list` + +Get the list of workspaces. + +``` +USAGE + $ internxt workspaces-list [--json] [-x] [--debug] [-e] + +FLAGS + -e, --extended Displays additional information in the list. + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Get the list of workspaces. + +ALIASES + $ internxt workspaces list + +EXAMPLES + $ internxt workspaces-list +``` + +_See code: [src/commands/workspaces-list.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/workspaces-list.ts)_ + +## `internxt workspaces-unset` + +Unset the active workspace context for the current user session. Once a workspace is unset, WebDAV and all of the subsequent CLI commands will operate within the personal drive space until it is changed or set again. + +``` +USAGE + $ internxt workspaces-unset [--json] [-x] [--debug] + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Unset the active workspace context for the current user session. Once a workspace is unset, WebDAV and all of the + subsequent CLI commands will operate within the personal drive space until it is changed or set again. + +ALIASES + $ internxt workspaces unset + +EXAMPLES + $ internxt workspaces-unset +``` + +_See code: [src/commands/workspaces-unset.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/workspaces-unset.ts)_ + +## `internxt workspaces-use` + +Set the active workspace context for the current user session. Once a workspace is selected, WebDAV and all of the subsequent CLI commands will operate within that workspace until it is changed or unset. + +``` +USAGE + $ internxt workspaces-use [--json] [-x] [--debug] [-i | -p] + +FLAGS + -i, --id= The id of the workspace to activate. Use internxt workspaces list to view your available workspace + ids. + -p, --personal Change to the personal drive space. It unsets the active workspace context for the current user + session. + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Set the active workspace context for the current user session. Once a workspace is selected, WebDAV and all of the + subsequent CLI commands will operate within that workspace until it is changed or unset. + +ALIASES + $ internxt workspaces use + +EXAMPLES + $ internxt workspaces-use +``` + +_See code: [src/commands/workspaces-use.ts](https://github.com/internxt/cli/blob/v1.6.3/src/commands/workspaces-use.ts)_ + +## `internxt workspaces list` + +Get the list of workspaces. + +``` +USAGE + $ internxt workspaces list [--json] [-x] [--debug] [-e] + +FLAGS + -e, --extended Displays additional information in the list. + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Get the list of workspaces. + +ALIASES + $ internxt workspaces list + +EXAMPLES + $ internxt workspaces list +``` + +## `internxt workspaces unset` + +Unset the active workspace context for the current user session. Once a workspace is unset, WebDAV and all of the subsequent CLI commands will operate within the personal drive space until it is changed or set again. + +``` +USAGE + $ internxt workspaces unset [--json] [-x] [--debug] + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Unset the active workspace context for the current user session. Once a workspace is unset, WebDAV and all of the + subsequent CLI commands will operate within the personal drive space until it is changed or set again. + +ALIASES + $ internxt workspaces unset + +EXAMPLES + $ internxt workspaces unset +``` + +## `internxt workspaces use` + +Set the active workspace context for the current user session. Once a workspace is selected, WebDAV and all of the subsequent CLI commands will operate within that workspace until it is changed or unset. + +``` +USAGE + $ internxt workspaces use [--json] [-x] [--debug] [-i | -p] + +FLAGS + -i, --id= The id of the workspace to activate. Use internxt workspaces list to view your available workspace + ids. + -p, --personal Change to the personal drive space. It unsets the active workspace context for the current user + session. + +HELPER FLAGS + -x, --non-interactive [env: INXT_NONINTERACTIVE] Prevents the CLI from being interactive. When enabled, the CLI will + not request input through the console and will throw errors directly. + --debug [env: INXT_DEBUG] Enables debug mode. When enabled, the CLI will print debug messages to the + console. + +GLOBAL FLAGS + --json Format output as json. + +DESCRIPTION + Set the active workspace context for the current user session. Once a workspace is selected, WebDAV and all of the + subsequent CLI commands will operate within that workspace until it is changed or unset. + +ALIASES + $ internxt workspaces use + +EXAMPLES + $ internxt workspaces use +``` # Current Limitations diff --git a/package.json b/package.json index d5c80bd6..afff293b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "author": "Internxt ", - "version": "1.6.2", + "version": "1.6.3", "description": "Internxt CLI to manage your encrypted storage", "scripts": { "build": "yarn clean && tsc", diff --git a/src/commands/create-folder.ts b/src/commands/create-folder.ts index f32b9ab3..1a0dee0c 100644 --- a/src/commands/create-folder.ts +++ b/src/commands/create-folder.ts @@ -5,6 +5,7 @@ import { ConfigService } from '../services/config.service'; import { ValidationService } from '../services/validation.service'; import { EmptyFolderNameError, MissingCredentialsError, NotValidFolderUuidError } from '../types/command.types'; import { AsyncUtils } from '../utils/async.utils'; +import { AuthService } from '../services/auth.service'; export default class CreateFolder extends Command { static readonly args = {}; @@ -56,8 +57,14 @@ export default class CreateFolder extends Command { await AsyncUtils.sleep(500); CLIUtils.done(flags['json']); - // eslint-disable-next-line max-len - const message = `Folder ${newFolder.plainName} created successfully, view it at ${ConfigService.instance.get('DRIVE_WEB_URL')}/folder/${newFolder.uuid}`; + + const workspace = await AuthService.instance.getCurrentWorkspace(); + const workspaceId = workspace?.workspaceData.workspace.id; + + const message = + `Folder ${newFolder.plainName} created successfully, view it at ` + + `${ConfigService.instance.get('DRIVE_WEB_URL')}/folder/${newFolder.uuid}` + + `${workspaceId ? `?workspaceid=${workspaceId}` : ''}`; CLIUtils.success(this.log.bind(this), message); return { success: true, message, folder: newFolder }; }; diff --git a/src/commands/upload-file.ts b/src/commands/upload-file.ts index 441eeb5d..7567cc7c 100644 --- a/src/commands/upload-file.ts +++ b/src/commands/upload-file.ts @@ -12,6 +12,7 @@ import { BufferStream } from '../utils/stream.utils'; import { Readable } from 'node:stream'; import { ThumbnailUtils } from '../utils/thumbnail.utils'; import { ThumbnailService } from '../services/thumbnail.service'; +import { AuthService } from '../services/auth.service'; export default class UploadFile extends Command { static readonly args = {}; @@ -49,11 +50,13 @@ export default class UploadFile extends Command { const fileInfo = path.parse(filePath); const fileType = fileInfo.ext.replaceAll('.', ''); + const reporter = this.log.bind(this); + const destinationFolderUuidFromFlag = await CLIUtils.getDestinationFolderUuid({ destinationFolderUuidFlag: flags['destination'], destinationFlagName: UploadFile.flags['destination'].name, nonInteractive, - reporter: this.log.bind(this), + reporter, }); const destinationFolderUuid = await CLIUtils.fallbackToRootFolderIdIfEmpty(destinationFolderUuidFromFlag); @@ -141,6 +144,7 @@ export default class UploadFile extends Command { bucket, fileUuid: createdDriveFile.uuid, networkFacade, + size: fileSize, }); } timings.thumbnailUpload = thumbnailTimer.stop(); @@ -151,18 +155,23 @@ export default class UploadFile extends Command { const totalTime = Object.values(timings).reduce((sum, time) => sum + time, 0); const throughputMBps = CLIUtils.calculateThroughputMBps(stats.size, timings.networkUpload); - this.log('\n'); - this.log( - '[PUT] Timing breakdown:\n' + - `Network upload: ${CLIUtils.formatDuration(timings.networkUpload)} (${throughputMBps.toFixed(2)} MB/s)\n` + - `Drive upload: ${CLIUtils.formatDuration(timings.driveUpload)}\n` + - `Thumbnail: ${CLIUtils.formatDuration(timings.thumbnailUpload)}\n`, - ); - this.log('\n'); + if (flags['debug']) { + CLIUtils.log( + reporter, + '[PUT] Timing breakdown:\n' + + `Network upload: ${CLIUtils.formatDuration(timings.networkUpload)} (${throughputMBps.toFixed(2)} MB/s)\n` + + `Drive upload: ${CLIUtils.formatDuration(timings.driveUpload)}\n` + + `Thumbnail: ${CLIUtils.formatDuration(timings.thumbnailUpload)}\n`, + ); + } + const workspace = await AuthService.instance.getCurrentWorkspace(); + const workspaceId = workspace?.workspaceData.workspace.id; + const message = `File uploaded successfully in ${CLIUtils.formatDuration(totalTime)}, view it at ` + - `${ConfigService.instance.get('DRIVE_WEB_URL')}/file/${createdDriveFile.uuid}`; - CLIUtils.success(this.log.bind(this), message); + `${ConfigService.instance.get('DRIVE_WEB_URL')}/file/${createdDriveFile.uuid}` + + `${workspaceId ? `?workspaceid=${workspaceId}` : ''}`; + CLIUtils.success(reporter, message); return { success: true, message, diff --git a/src/commands/upload-folder.ts b/src/commands/upload-folder.ts index de1ef530..fea1e4af 100644 --- a/src/commands/upload-folder.ts +++ b/src/commands/upload-folder.ts @@ -34,11 +34,13 @@ export default class UploadFolder extends Command { const localPath = await this.getFolderPath(flags['folder'], flags['non-interactive']); + const reporter = this.log.bind(this); + const destinationFolderUuidFromFlag = await CLIUtils.getDestinationFolderUuid({ destinationFolderUuidFlag: flags['destination'], destinationFlagName: UploadFolder.flags['destination'].name, nonInteractive: flags['non-interactive'], - reporter: this.log.bind(this), + reporter, }); const destinationFolderUuid = await CLIUtils.fallbackToRootFolderIdIfEmpty(destinationFolderUuidFromFlag); @@ -58,6 +60,8 @@ export default class UploadFolder extends Command { onProgress: (progress) => { progressBar?.update(progress.percentage); }, + debugMode: flags['debug'], + reporter, }); progressBar?.update(100); diff --git a/src/commands/workspaces-unset.ts b/src/commands/workspaces-unset.ts index 468383f4..fa4139a2 100644 --- a/src/commands/workspaces-unset.ts +++ b/src/commands/workspaces-unset.ts @@ -1,8 +1,9 @@ import { Command } from '@oclif/core'; import { ConfigService } from '../services/config.service'; -import { CLIUtils } from '../utils/cli.utils'; +import { CLIUtils, LogReporter } from '../utils/cli.utils'; import { LoginCredentials, MissingCredentialsError } from '../types/command.types'; import { SdkManager } from '../services/sdk-manager.service'; +import { DatabaseService } from '../services/database/database.service'; export default class WorkspacesUnset extends Command { static readonly args = {}; @@ -37,9 +38,10 @@ export default class WorkspacesUnset extends Command { this.exit(1); }; - static readonly unsetWorkspace = async (userCredentials: LoginCredentials, reporter: (message: string) => void) => { + static readonly unsetWorkspace = async (userCredentials: LoginCredentials, reporter: LogReporter) => { SdkManager.init({ token: userCredentials.token }); await ConfigService.instance.saveUser({ ...userCredentials, workspace: undefined }); + void DatabaseService.instance.clear(); CLIUtils.success(reporter, 'Personal drive space selected successfully.'); return { success: true, message: 'Personal drive space selected successfully.' }; }; diff --git a/src/commands/workspaces-use.ts b/src/commands/workspaces-use.ts index 66de3091..b019a9d2 100644 --- a/src/commands/workspaces-use.ts +++ b/src/commands/workspaces-use.ts @@ -7,6 +7,7 @@ import { FormatUtils } from '../utils/format.utils'; import { ValidationService } from '../services/validation.service'; import { SdkManager } from '../services/sdk-manager.service'; import WorkspacesUnset from './workspaces-unset'; +import { DatabaseService } from '../services/database/database.service'; export default class WorkspacesUse extends Command { static readonly args = {}; @@ -74,6 +75,8 @@ export default class WorkspacesUse extends Command { }, }); + void DatabaseService.instance.clear(); + const message = `Workspace ${workspaceUuid} selected successfully. Now WebDAV and all of the CLI commands ` + 'will operate within this workspace until it is changed or unset.'; diff --git a/src/services/network/upload/upload-facade.service.ts b/src/services/network/upload/upload-facade.service.ts index 37ef3973..c40e1e00 100644 --- a/src/services/network/upload/upload-facade.service.ts +++ b/src/services/network/upload/upload-facade.service.ts @@ -1,6 +1,5 @@ import { basename } from 'node:path'; import { CLIUtils } from '../../../utils/cli.utils'; -import { logger } from '../../../utils/logger.utils'; import { LocalFilesystemService } from '../../local-filesystem/local-filesystem.service'; import { UploadFolderParams } from './upload.types'; import { UploadFolderService } from './upload-folder.service'; @@ -15,16 +14,21 @@ export class UploadFacade { destinationFolderUuid, loginUserDetails, jsonFlag, + debugMode, onProgress, + reporter, }: UploadFolderParams) => { const timer = CLIUtils.timer(); CLIUtils.doing('Preparing Network', jsonFlag); const { networkFacade, bucket } = await CLIUtils.prepareNetwork(loginUserDetails); CLIUtils.done(jsonFlag); const scanResult = await LocalFilesystemService.instance.scanLocalDirectory(localPath); - logger.info( - `Scanned folder ${localPath}: found ${scanResult.totalItems} items, total size ${scanResult.totalBytes} bytes.`, - ); + if (debugMode) { + CLIUtils.success( + reporter, + `Scanned folder ${localPath}: found ${scanResult.totalItems} items, total size ${scanResult.totalBytes} bytes.`, + ); + } const currentProgress = { itemsUploaded: 0, bytesUploaded: 0 }; const emitProgress = () => { @@ -39,6 +43,8 @@ export class UploadFacade { destinationFolderUuid, currentProgress, emitProgress, + reporter, + debugMode, }); if (folderMap.size === 0) { @@ -55,6 +61,8 @@ export class UploadFacade { destinationFolderUuid, currentProgress, emitProgress, + debugMode, + reporter, }); const rootFolderName = basename(localPath); diff --git a/src/services/network/upload/upload-file.service.ts b/src/services/network/upload/upload-file.service.ts index d33f4321..2e187345 100644 --- a/src/services/network/upload/upload-file.service.ts +++ b/src/services/network/upload/upload-file.service.ts @@ -27,6 +27,8 @@ export class UploadFileService { destinationFolderUuid, currentProgress, emitProgress, + debugMode, + reporter, }: UploadFilesConcurrentlyParams): Promise => { let bytesUploaded = 0; @@ -40,7 +42,9 @@ export class UploadFileService { parentPath === '.' || parentPath === '' ? destinationFolderUuid : folderMap.get(parentPath); if (!parentFolderUuid) { - logger.warn(`Parent folder not found for ${file.relativePath}, skipping...`); + if (debugMode) { + CLIUtils.warning(reporter, `Parent folder not found for ${file.relativePath}, skipping...`); + } return null; } const createdFileUuid = await this.uploadFileWithRetry({ @@ -48,6 +52,8 @@ export class UploadFileService { network, bucket, parentFolderUuid, + debugMode, + reporter, }); if (createdFileUuid) { bytesUploaded += file.size; @@ -66,6 +72,8 @@ export class UploadFileService { network, bucket, parentFolderUuid, + debugMode, + reporter, }: UploadFileWithRetryParams): Promise => { for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) { try { @@ -131,20 +139,25 @@ export class UploadFileService { bucket, fileUuid: createdDriveFile.uuid, networkFacade: network, + size: fileSize, }); } timings.thumbnailUpload = thumbnailTimer.stop(); - const totalTime = Object.values(timings).reduce((sum, time) => sum + time, 0); - const throughputMBps = CLIUtils.calculateThroughputMBps(stats.size, timings.networkUpload); - logger.info(`Uploaded '${file.name}' (${CLIUtils.formatBytesToString(stats.size)})`); - logger.info( - 'Timing breakdown:\n' + - `Network upload: ${CLIUtils.formatDuration(timings.networkUpload)} (${throughputMBps.toFixed(2)} MB/s)\n` + - `Drive upload: ${CLIUtils.formatDuration(timings.driveUpload)}\n` + - `Thumbnail: ${CLIUtils.formatDuration(timings.thumbnailUpload)}\n` + - `Total: ${CLIUtils.formatDuration(totalTime)}\n`, - ); + if (debugMode) { + const totalTime = Object.values(timings).reduce((sum, time) => sum + time, 0); + const throughputMBps = CLIUtils.calculateThroughputMBps(stats.size, timings.networkUpload); + CLIUtils.success(reporter, `Uploaded '${file.name}' (${CLIUtils.formatBytesToString(stats.size)})`); + CLIUtils.log( + reporter, + 'Timing breakdown:\n' + + `Network upload: ${CLIUtils.formatDuration(timings.networkUpload)}` + + ` (${throughputMBps.toFixed(2)} MB/s)\n` + + `Drive upload: ${CLIUtils.formatDuration(timings.driveUpload)}\n` + + `Thumbnail: ${CLIUtils.formatDuration(timings.thumbnailUpload)}\n` + + `Total: ${CLIUtils.formatDuration(totalTime)}\n`, + ); + } return createdDriveFile; } catch (error: unknown) { @@ -156,11 +169,13 @@ export class UploadFileService { if (attempt < MAX_RETRIES) { const delay = DELAYS_MS[attempt]; - const retryMsg = `Failed to upload file ${file.name}, retrying in ${delay}ms...`; - logger.warn(`${retryMsg} (attempt ${attempt + 1}/${MAX_RETRIES + 1})`); + if (debugMode) { + const retryMsg = `Failed to upload file ${file.name}, retrying in ${delay}ms...`; + CLIUtils.warning(reporter, `${retryMsg} (attempt ${attempt + 1}/${MAX_RETRIES + 1})`); + } await new Promise((resolve) => setTimeout(resolve, delay)); } else { - logger.error(`Failed to upload file ${file.name} after ${MAX_RETRIES + 1} attempts`); + CLIUtils.error(reporter, `Failed to upload file '${file.name}' after ${MAX_RETRIES + 1} attempts`); return null; } } diff --git a/src/services/network/upload/upload-folder.service.ts b/src/services/network/upload/upload-folder.service.ts index 78b8efe7..0f0a65b6 100644 --- a/src/services/network/upload/upload-folder.service.ts +++ b/src/services/network/upload/upload-folder.service.ts @@ -3,6 +3,7 @@ import { ErrorUtils } from '../../../utils/errors.utils'; import { logger } from '../../../utils/logger.utils'; import { DriveFolderService } from '../../drive/drive-folder.service'; import { CreateFoldersParams, CreateFolderWithRetryParams, DELAYS_MS, MAX_RETRIES } from './upload.types'; +import { CLIUtils } from '../../../utils/cli.utils'; export class UploadFolderService { static readonly instance = new UploadFolderService(); @@ -12,6 +13,8 @@ export class UploadFolderService { destinationFolderUuid, currentProgress, emitProgress, + debugMode, + reporter, }: CreateFoldersParams): Promise> => { const folderMap = new Map(); for (const folder of foldersToCreate) { @@ -26,6 +29,8 @@ export class UploadFolderService { const createdFolderUuid = await this.createFolderWithRetry({ folderName: folder.name, parentFolderUuid: parentUuid, + debugMode, + reporter, }); if (createdFolderUuid) { @@ -40,6 +45,8 @@ export class UploadFolderService { public createFolderWithRetry = async ({ folderName, parentFolderUuid, + debugMode, + reporter, }: CreateFolderWithRetryParams): Promise => { for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) { try { @@ -52,18 +59,22 @@ export class UploadFolderService { return createdFolder.uuid; } catch (error: unknown) { if (ErrorUtils.isAlreadyExistsError(error)) { - logger.info(`Folder ${folderName} already exists, skipping...`); + logger.warn(`Folder ${folderName} already exists, skipping...`); return null; } + if (attempt < MAX_RETRIES) { const delay = DELAYS_MS[attempt]; - logger.warn( - `Failed to create folder ${folderName}, - retrying in ${delay}ms... (attempt ${attempt + 1}/${MAX_RETRIES + 1})`, - ); + if (debugMode) { + CLIUtils.warning( + reporter, + `Failed to create folder '${folderName}', retrying in ${delay}ms... ` + + `(attempt ${attempt + 1}/${MAX_RETRIES + 1})`, + ); + } await new Promise((resolve) => setTimeout(resolve, delay)); } else { - logger.error(`Failed to create folder ${folderName} after ${MAX_RETRIES + 1} attempts`); + CLIUtils.error(reporter, `Failed to create folder '${folderName}' after ${MAX_RETRIES + 1} attempts`); throw error; } } diff --git a/src/services/network/upload/upload.types.ts b/src/services/network/upload/upload.types.ts index 60d7c86f..e55ac4da 100644 --- a/src/services/network/upload/upload.types.ts +++ b/src/services/network/upload/upload.types.ts @@ -1,4 +1,5 @@ import { LoginUserDetails } from '../../../types/command.types'; +import { LogReporter } from '../../../utils/cli.utils'; import { FileSystemNode } from '../../local-filesystem/local-filesystem.types'; import { NetworkFacade } from '../network-facade.service'; @@ -14,6 +15,8 @@ export interface UploadFolderParams { loginUserDetails: LoginUserDetails; jsonFlag?: boolean; onProgress: (progress: UploadProgress) => void; + debugMode: boolean; + reporter: LogReporter; } export interface UploadProgress { @@ -26,11 +29,15 @@ export interface CreateFoldersParams { destinationFolderUuid: string; currentProgress: { itemsUploaded: number; bytesUploaded: number }; emitProgress: () => void; + debugMode: boolean; + reporter: LogReporter; } export interface CreateFolderWithRetryParams { folderName: string; parentFolderUuid: string; + debugMode: boolean; + reporter: LogReporter; } export interface UploadFilesConcurrentlyParams { @@ -41,6 +48,8 @@ export interface UploadFilesConcurrentlyParams { destinationFolderUuid: string; currentProgress: { itemsUploaded: number; bytesUploaded: number }; emitProgress: () => void; + debugMode: boolean; + reporter: LogReporter; } export interface UploadFileWithRetryParams { @@ -48,7 +57,10 @@ export interface UploadFileWithRetryParams { network: NetworkFacade; bucket: string; parentFolderUuid: string; + debugMode: boolean; + reporter: LogReporter; } + export const MAX_CONCURRENT_UPLOADS = 10; export const DELAYS_MS = [500, 1000, 2000]; export const MAX_RETRIES = 2; diff --git a/src/services/thumbnail.service.ts b/src/services/thumbnail.service.ts index 9505a775..54efb57c 100644 --- a/src/services/thumbnail.service.ts +++ b/src/services/thumbnail.service.ts @@ -22,6 +22,7 @@ const getSharp = async () => { export class ThumbnailService { public static readonly instance: ThumbnailService = new ThumbnailService(); + private static readonly MAX_THUMBNAIL_TIMEOUT = 30000; public uploadThumbnail = async ( fileContent: Buffer, @@ -29,9 +30,10 @@ export class ThumbnailService { userBucket: string, file_id: string, networkFacade: NetworkFacade, + fileSize: number, ): Promise => { let thumbnailBuffer: Buffer | undefined; - if (ThumbnailUtils.isImageThumbnailable(fileType)) { + if (ThumbnailUtils.isImageThumbnailable(fileType, fileSize)) { thumbnailBuffer = await this.getThumbnailFromImageBuffer(fileContent); } if (thumbnailBuffer) { @@ -88,17 +90,31 @@ export class ThumbnailService { bucket, fileUuid, networkFacade, + size, }: { bufferStream?: BufferStream; fileType: string; bucket: string; fileUuid: string; networkFacade: NetworkFacade; + size: number; }) => { try { const thumbnailBuffer = bufferStream?.getBuffer(); if (thumbnailBuffer) { - await ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, bucket, fileUuid, networkFacade); + let timeoutId: NodeJS.Timeout; + const timeoutPromise = new Promise((_, reject) => { + timeoutId = setTimeout(() => { + reject(new Error('Thumbnail upload timeout')); + }, ThumbnailService.MAX_THUMBNAIL_TIMEOUT); + }); + + await Promise.race([ + ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, bucket, fileUuid, networkFacade, size), + timeoutPromise, + ]).finally(() => { + clearTimeout(timeoutId); + }); } } catch (error) { ErrorUtils.report(error); diff --git a/src/services/universal-link.service.ts b/src/services/universal-link.service.ts index ab2d8028..ffc38094 100644 --- a/src/services/universal-link.service.ts +++ b/src/services/universal-link.service.ts @@ -4,7 +4,7 @@ import { AddressInfo } from 'node:net'; import { LoginCredentials } from '../types/command.types'; import { ConfigService } from './config.service'; import { AuthService } from './auth.service'; -import { CLIUtils } from '../utils/cli.utils'; +import { CLIUtils, LogReporter } from '../utils/cli.utils'; export class UniversalLinkService { public static readonly instance: UniversalLinkService = new UniversalLinkService(); @@ -33,7 +33,7 @@ export class UniversalLinkService { public loginSSO = async ( jsonFlag: boolean, - reporter: (message: string) => void, + reporter: LogReporter, hostIp = '127.0.0.1', forcedPort = 0, ): Promise => { diff --git a/src/utils/cli.utils.ts b/src/utils/cli.utils.ts index 13659370..7975da25 100644 --- a/src/utils/cli.utils.ts +++ b/src/utils/cli.utils.ts @@ -12,6 +12,8 @@ import { NetworkFacade } from '../services/network/network-facade.service'; import { AuthService } from '../services/auth.service'; import { NetworkCredentials, NetworkOptions } from '../types/network.types'; +export type LogReporter = (message: string) => void; + export class CLIUtils { static readonly clearPreviousLine = (jsonFlag?: boolean) => { if (!jsonFlag) { @@ -20,19 +22,19 @@ export class CLIUtils { } }; - static readonly warning = (reporter: (message: string) => void, message: string) => { + static readonly warning = (reporter: LogReporter, message: string) => { reporter(ux.colorize('#a67805', `⚠ Warning: ${message}`)); }; - static readonly error = (reporter: (message: string) => void, message: string) => { + static readonly error = (reporter: LogReporter, message: string) => { reporter(ux.colorize('red', `⚠ Error: ${message}`)); }; - static readonly success = (reporter: (message: string) => void, message: string) => { + static readonly success = (reporter: LogReporter, message: string) => { reporter(ux.colorize('green', `✓ ${message}`)); }; - static readonly log = (reporter: (message: string) => void, message: string) => { + static readonly log = (reporter: LogReporter, message: string) => { reporter(`${message}`); }; @@ -68,7 +70,7 @@ export class CLIUtils { } }; - static readonly table = (reporter: (message: string) => void, header: Header[], rows: object[]) => { + static readonly table = (reporter: LogReporter, header: Header[], rows: object[]) => { const table = Table(header, rows); reporter(table.render()); }; @@ -90,6 +92,12 @@ export class CLIUtils { 'Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly.', required: false, }), + debug: Flags.boolean({ + env: 'INXT_DEBUG', + helpGroup: 'helper', + description: 'Enables debug mode. When enabled, the CLI will print debug messages to the console.', + required: false, + }), }; static readonly getValueFromFlag = async ( @@ -107,7 +115,7 @@ export class CLIUtils { error: Error; canBeEmpty?: boolean; }, - reporter: (message: string) => void, + reporter: LogReporter, ): Promise => { // It returns the value passed from the flag if it is valid. If it is not valid, it will throw an error when nonInteractive mode is active and a warning otherwise // It throws an error if nonInteractive mode is active and no flag value is aquired @@ -141,7 +149,7 @@ export class CLIUtils { destinationFolderUuidFlag: string | undefined; destinationFlagName: string; nonInteractive: boolean; - reporter: (message: string) => void; + reporter: LogReporter; }): Promise => { const destinationFolderUuid = await this.getValueFromFlag( { @@ -173,7 +181,7 @@ export class CLIUtils { error: Error; canBeEmpty?: boolean; }, - reporter: (message: string) => void, + reporter: LogReporter, ): Promise => { let isValid = false; let currentAttempts = 0; @@ -257,7 +265,7 @@ export class CLIUtils { }: { error: Error; command?: string; - logReporter: (message: string) => void; + logReporter: LogReporter; jsonFlag?: boolean; }) => { let message; diff --git a/src/utils/thumbnail.utils.ts b/src/utils/thumbnail.utils.ts index 480a631e..baeeed7c 100644 --- a/src/utils/thumbnail.utils.ts +++ b/src/utils/thumbnail.utils.ts @@ -31,6 +31,8 @@ const thumbnailablePdfExtension: Set = new Set(pdfExtensions['pdf']); const thumbnailableExtension: Set = new Set(thumbnailableImageExtension); export class ThumbnailUtils { + static readonly MAX_IMAGE_THUMBNAILABLE_SIZE_IN_MB = 500 * 1024 * 1024; + static readonly isFileThumbnailable = (fileType: string) => { return fileType.trim().length > 0 && thumbnailableExtension.has(fileType.trim().toLowerCase()); }; @@ -39,7 +41,8 @@ export class ThumbnailUtils { return fileType.trim().length > 0 && thumbnailablePdfExtension.has(fileType.trim().toLowerCase()); }; - static readonly isImageThumbnailable = (fileType: string) => { + static readonly isImageThumbnailable = (fileType: string, size: number) => { + if (size > ThumbnailUtils.MAX_IMAGE_THUMBNAILABLE_SIZE_IN_MB) return false; return fileType.trim().length > 0 && thumbnailableImageExtension.has(fileType.trim().toLowerCase()); }; } diff --git a/src/webdav/handlers/PUT.handler.ts b/src/webdav/handlers/PUT.handler.ts index 6f8dda34..2a4c7cab 100644 --- a/src/webdav/handlers/PUT.handler.ts +++ b/src/webdav/handlers/PUT.handler.ts @@ -131,6 +131,7 @@ export class PUTRequestHandler implements WebDavMethodHandler { fileType, bucket, networkFacade, + size: contentLength, }); } timings.thumbnailUpload = thumbnailTimer.stop(); diff --git a/test/services/network/upload/upload-facade.service.test.ts b/test/services/network/upload/upload-facade.service.test.ts index 020e61b8..ca36d77f 100644 --- a/test/services/network/upload/upload-facade.service.test.ts +++ b/test/services/network/upload/upload-facade.service.test.ts @@ -67,6 +67,8 @@ describe('UploadFacade', () => { loginUserDetails: mockLoginUserDetails, jsonFlag: false, onProgress, + debugMode: false, + reporter: vi.fn(), }), ).rejects.toThrow('Failed to create folders, cannot upload files'); @@ -75,12 +77,15 @@ describe('UploadFacade', () => { }); it('should properly handle the upload of folder and the creation of file and return proper result', async () => { + const reporter = vi.fn(); const result = await sut.uploadFolder({ localPath, destinationFolderUuid, loginUserDetails: mockLoginUserDetails, jsonFlag: false, onProgress, + debugMode: true, + reporter, }); expect(result).toBeDefined(); @@ -89,7 +94,9 @@ describe('UploadFacade', () => { expect(result.uploadTimeMs).toBe(1000); expect(UploadFolderService.instance.createFolders).toHaveBeenCalled(); expect(UploadFileService.instance.uploadFilesConcurrently).toHaveBeenCalled(); - expect(logger.info).toHaveBeenCalledWith(`Scanned folder ${localPath}: found 2 items, total size 500 bytes.`); + expect(reporter).toHaveBeenCalledWith( + expect.stringContaining(`Scanned folder ${localPath}: found 2 items, total size 500 bytes.`), + ); }); it('should report progress correctly during upload', async () => { @@ -118,6 +125,8 @@ describe('UploadFacade', () => { loginUserDetails: mockLoginUserDetails, jsonFlag: false, onProgress, + debugMode: false, + reporter: vi.fn(), }); expect(onProgress).toHaveBeenCalledTimes(2); @@ -137,6 +146,8 @@ describe('UploadFacade', () => { loginUserDetails: mockLoginUserDetails, jsonFlag: false, onProgress, + debugMode: false, + reporter: vi.fn(), }); await vi.advanceTimersByTimeAsync(500); diff --git a/test/services/network/upload/upload-file.service.test.ts b/test/services/network/upload/upload-file.service.test.ts index 5828e312..b78f6c12 100644 --- a/test/services/network/upload/upload-file.service.test.ts +++ b/test/services/network/upload/upload-file.service.test.ts @@ -72,6 +72,8 @@ describe('UploadFileService', () => { destinationFolderUuid, currentProgress, emitProgress, + debugMode: false, + reporter: vi.fn(), }); expect(result).toBe(600); @@ -102,6 +104,8 @@ describe('UploadFileService', () => { destinationFolderUuid, currentProgress, emitProgress, + debugMode: false, + reporter: vi.fn(), }); expect(uploadFileWithRetrySpy).toHaveBeenCalledTimes(12); @@ -132,6 +136,8 @@ describe('UploadFileService', () => { destinationFolderUuid, currentProgress, emitProgress, + debugMode: false, + reporter: vi.fn(), }); expect(currentProgress.itemsUploaded).toBe(2); @@ -156,6 +162,8 @@ describe('UploadFileService', () => { const uploadFileWithRetrySpy = vi.spyOn(sut, 'uploadFileWithRetry'); + const reporter = vi.fn(); + const result = await sut.uploadFilesConcurrently({ network: mockNetworkFacade, filesToUpload: files, @@ -164,10 +172,14 @@ describe('UploadFileService', () => { destinationFolderUuid, currentProgress, emitProgress, + debugMode: true, + reporter, }); expect(result).toBe(0); - expect(logger.warn).toHaveBeenCalledWith('Parent folder not found for subfolder/nested.txt, skipping...'); + expect(reporter).toHaveBeenLastCalledWith( + expect.stringContaining('Parent folder not found for subfolder/nested.txt, skipping...'), + ); expect(uploadFileWithRetrySpy).not.toHaveBeenCalled(); uploadFileWithRetrySpy.mockRestore(); @@ -192,6 +204,8 @@ describe('UploadFileService', () => { network: mockNetworkFacade, bucket, parentFolderUuid: destinationFolderUuid, + debugMode: false, + reporter: vi.fn(), }); expect(result).toBe(mockFile); @@ -240,11 +254,15 @@ describe('UploadFileService', () => { return { stop: vi.fn() } as unknown as ReturnType; }); + const reporter = vi.fn(); + const resultPromise = sut.uploadFileWithRetry({ file, network: mockNetworkFacade, bucket, parentFolderUuid: destinationFolderUuid, + debugMode: true, + reporter, }); await vi.runAllTimersAsync(); @@ -253,7 +271,7 @@ describe('UploadFileService', () => { expect(result).toBe(mockFile); expect(mockNetworkFacade.uploadFile).toHaveBeenCalledTimes(3); - expect(logger.warn).toHaveBeenCalledTimes(2); + expect(reporter).toHaveBeenCalledTimes(4); vi.useRealTimers(); }); @@ -274,6 +292,8 @@ describe('UploadFileService', () => { network: mockNetworkFacade, bucket, parentFolderUuid: destinationFolderUuid, + debugMode: false, + reporter: vi.fn(), }); expect(result).toBe(mockFile); @@ -313,6 +333,8 @@ describe('UploadFileService', () => { network: mockNetworkFacade, bucket, parentFolderUuid: destinationFolderUuid, + debugMode: false, + reporter: vi.fn(), }); expect(ThumbnailService.instance.tryUploadThumbnail).toHaveBeenCalledWith({ @@ -321,6 +343,7 @@ describe('UploadFileService', () => { bucket, fileUuid: mockFile.uuid, networkFacade: mockNetworkFacade, + size: file.size, }); }); @@ -343,6 +366,8 @@ describe('UploadFileService', () => { network: mockNetworkFacade, bucket, parentFolderUuid: destinationFolderUuid, + debugMode: false, + reporter: vi.fn(), }); expect(result).toBeNull(); @@ -364,11 +389,15 @@ describe('UploadFileService', () => { return { stop: vi.fn() } as unknown as ReturnType; }); + const reporter = vi.fn(); + const resultPromise = sut.uploadFileWithRetry({ file, network: mockNetworkFacade, bucket, parentFolderUuid: destinationFolderUuid, + debugMode: true, + reporter, }); await vi.runAllTimersAsync(); @@ -376,7 +405,10 @@ describe('UploadFileService', () => { const result = await resultPromise; expect(result).toBeNull(); - expect(logger.error).toHaveBeenCalledWith('Failed to upload file fail.txt after 3 attempts'); + expect(reporter).toHaveBeenCalledTimes(3); + expect(reporter).toHaveBeenLastCalledWith( + expect.stringContaining(`Error: Failed to upload file '${file.name}' after 3 attempts`), + ); expect(mockNetworkFacade.uploadFile).toHaveBeenCalledTimes(3); vi.useRealTimers(); diff --git a/test/services/network/upload/upload-folder.service.test.ts b/test/services/network/upload/upload-folder.service.test.ts index 6f91b85b..42a9ea70 100644 --- a/test/services/network/upload/upload-folder.service.test.ts +++ b/test/services/network/upload/upload-folder.service.test.ts @@ -38,6 +38,8 @@ describe('UploadFolderService', () => { destinationFolderUuid, currentProgress, emitProgress, + reporter: vi.fn(), + debugMode: true, }); expect(result.size).toBe(2); @@ -55,6 +57,8 @@ describe('UploadFolderService', () => { destinationFolderUuid, currentProgress, emitProgress, + reporter: vi.fn(), + debugMode: true, }); expect(result.size).toBe(0); @@ -70,6 +74,8 @@ describe('UploadFolderService', () => { destinationFolderUuid, currentProgress, emitProgress, + reporter: vi.fn(), + debugMode: true, }); expect(DriveFolderService.instance.createFolder).toHaveBeenCalledWith({ @@ -86,12 +92,15 @@ describe('UploadFolderService', () => { destinationFolderUuid, currentProgress, emitProgress, + reporter: vi.fn(), + debugMode: true, }); expect(currentProgress.itemsUploaded).toBe(1); expect(emitProgress).toHaveBeenCalledTimes(1); }); }); + describe('createFolderWithRetry', () => { const folderName = 'test-folder'; const parentFolderUuid = 'parent-uuid'; @@ -101,7 +110,12 @@ describe('UploadFolderService', () => { Promise.resolve({ uuid: 'created-folder-uuid' }), ] as unknown as ReturnType); - const result = await sut.createFolderWithRetry({ folderName, parentFolderUuid }); + const result = await sut.createFolderWithRetry({ + folderName, + parentFolderUuid, + reporter: vi.fn(), + debugMode: true, + }); expect(result).toBe('created-folder-uuid'); expect(DriveFolderService.instance.createFolder).toHaveBeenCalledWith({ @@ -113,14 +127,17 @@ describe('UploadFolderService', () => { it('should properly return null if the folder already exists', async () => { const alreadyExistsError = new Error('Folder already exists'); vi.spyOn(ErrorUtils, 'isAlreadyExistsError').mockReturnValue(true); - vi.spyOn(DriveFolderService.instance, 'createFolder').mockReturnValueOnce([ - Promise.reject(alreadyExistsError), - ] as unknown as ReturnType); + vi.spyOn(DriveFolderService.instance, 'createFolder').mockRejectedValue(alreadyExistsError); - const result = await sut.createFolderWithRetry({ folderName, parentFolderUuid }); + const result = await sut.createFolderWithRetry({ + folderName, + parentFolderUuid, + reporter: vi.fn(), + debugMode: true, + }); expect(result).toBeNull(); - expect(logger.info).toHaveBeenCalledWith(`Folder ${folderName} already exists, skipping...`); + expect(logger.warn).toHaveBeenCalledWith(`Folder ${folderName} already exists, skipping...`); }); it('should properly retry up to 3 times when error caught', async () => { @@ -138,7 +155,14 @@ describe('UploadFolderService', () => { typeof DriveFolderService.instance.createFolder >); - const resultPromise = sut.createFolderWithRetry({ folderName, parentFolderUuid }); + const reporter = vi.fn(); + + const resultPromise = sut.createFolderWithRetry({ + folderName, + parentFolderUuid, + reporter, + debugMode: true, + }); await vi.advanceTimersByTimeAsync(DELAYS_MS[0]); await vi.advanceTimersByTimeAsync(DELAYS_MS[1]); @@ -147,7 +171,7 @@ describe('UploadFolderService', () => { expect(result).toBe('success-uuid'); expect(DriveFolderService.instance.createFolder).toHaveBeenCalledTimes(3); - expect(logger.warn).toHaveBeenCalledTimes(2); + expect(reporter).toHaveBeenCalledTimes(2); vi.useRealTimers(); }); @@ -164,14 +188,22 @@ describe('UploadFolderService', () => { typeof DriveFolderService.instance.createFolder >; }); + const reporter = vi.fn(); - const resultPromise = sut.createFolderWithRetry({ folderName, parentFolderUuid }); + const resultPromise = sut.createFolderWithRetry({ + folderName, + parentFolderUuid, + reporter, + debugMode: true, + }); await vi.advanceTimersByTimeAsync(DELAYS_MS[0]); await vi.advanceTimersByTimeAsync(DELAYS_MS[1]); await expect(resultPromise).rejects.toThrow('Persistent network error'); expect(DriveFolderService.instance.createFolder).toHaveBeenCalledTimes(3); - expect(logger.warn).toHaveBeenCalledTimes(2); - expect(logger.error).toHaveBeenCalledWith(`Failed to create folder ${folderName} after 3 attempts`); + expect(reporter).toHaveBeenCalledTimes(3); + expect(reporter).toHaveBeenLastCalledWith( + expect.stringContaining(`Error: Failed to create folder '${folderName}' after 3 attempts`), + ); vi.useRealTimers(); }); diff --git a/test/utils/cli.utils.test.ts b/test/utils/cli.utils.test.ts index 705a60ad..3e1e82cb 100644 --- a/test/utils/cli.utils.test.ts +++ b/test/utils/cli.utils.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach, MockInstance } from 'vitest'; import { ux } from '@oclif/core'; -import { CLIUtils } from '../../src/utils/cli.utils'; +import { CLIUtils, LogReporter } from '../../src/utils/cli.utils'; import { Direction } from 'node:readline'; import { Options } from '@oclif/core/lib/ux/action/types'; import { LoginUserDetails } from '../../src/types/command.types'; @@ -37,7 +37,7 @@ describe('CliUtils', () => { (str: Uint8Array | string, encoding?: BufferEncoding, cb?: (err?: Error) => void): boolean; }>; let stdoutClear: MockInstance<(dir: Direction, callback?: () => void) => boolean>; - const reporter: (message: string) => void = vi.fn(); + const reporter: LogReporter = vi.fn(); const BRIDGE_URL = 'https://test.com'; const mockNetworkFacade: NetworkFacade = {} as NetworkFacade;