@internxt/cli 0.1.20 → 1.0.5

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 (40) hide show
  1. package/.env +3 -1
  2. package/README.md +42 -19
  3. package/dist/commands/create-folder.d.ts +13 -0
  4. package/dist/commands/create-folder.js +52 -0
  5. package/dist/commands/login.js +2 -0
  6. package/dist/commands/webdav.js +2 -0
  7. package/dist/hooks/prerun/auth_check.js +2 -1
  8. package/dist/services/analytics.service.d.ts +16 -0
  9. package/dist/services/analytics.service.js +47 -0
  10. package/dist/services/database/drive-database-manager.service.d.ts +2 -0
  11. package/dist/services/database/drive-database-manager.service.js +6 -0
  12. package/dist/services/database/drive-file/drive-file.repository.d.ts +1 -1
  13. package/dist/services/database/drive-file/drive-file.repository.js +2 -2
  14. package/dist/services/database/drive-folder/drive-folder.attributes.d.ts +1 -0
  15. package/dist/services/database/drive-folder/drive-folder.domain.d.ts +2 -1
  16. package/dist/services/database/drive-folder/drive-folder.domain.js +4 -1
  17. package/dist/services/database/drive-folder/drive-folder.model.d.ts +1 -0
  18. package/dist/services/database/drive-folder/drive-folder.model.js +4 -0
  19. package/dist/services/database/drive-folder/drive-folder.repository.d.ts +1 -1
  20. package/dist/services/database/drive-folder/drive-folder.repository.js +2 -2
  21. package/dist/services/drive/drive-folder.service.d.ts +5 -0
  22. package/dist/services/drive/drive-folder.service.js +7 -0
  23. package/dist/types/config.types.d.ts +2 -0
  24. package/dist/types/drive.types.d.ts +1 -0
  25. package/dist/utils/async.utils.d.ts +3 -0
  26. package/dist/utils/async.utils.js +9 -0
  27. package/dist/utils/drive.utils.js +1 -0
  28. package/dist/utils/webdav.utils.d.ts +1 -0
  29. package/dist/utils/webdav.utils.js +3 -0
  30. package/dist/webdav/handlers/DELETE.handler.d.ts +9 -1
  31. package/dist/webdav/handlers/DELETE.handler.js +24 -2
  32. package/dist/webdav/handlers/MKCOL.handler.d.ts +9 -1
  33. package/dist/webdav/handlers/MKCOL.handler.js +40 -2
  34. package/dist/webdav/handlers/PROPFIND.handler.js +3 -0
  35. package/dist/webdav/index.js +2 -1
  36. package/dist/webdav/middewares/request-logger.middleware.js +2 -0
  37. package/dist/webdav/webdav-server.d.ts +3 -1
  38. package/dist/webdav/webdav-server.js +11 -3
  39. package/oclif.manifest.json +41 -1
  40. package/package.json +4 -2
package/.env CHANGED
@@ -8,4 +8,6 @@ APP_CRYPTO_SECRET2=8Q8VMUE3BJZV87GT
8
8
  APP_MAGIC_IV=d139cb9a2cd17092e79e1861cf9d7023
9
9
  APP_MAGIC_SALT=38dce0391b49efba88dbc8c39ebf868f0267eb110bb0012ab27dc52a528d61b1d1ed9d76f400ff58e3240028442b1eab9bb84e111d9dadd997982dbde9dbd25e
10
10
  NETWORK_URL=https://api.internxt.com
11
- WEBDAV_SERVER_PORT=3005
11
+ WEBDAV_SERVER_PORT=3005
12
+ RUDDERSTACK_WRITE_KEY=2g8ct5UZBpPdG4K1VuH1PoT4gHV
13
+ RUDDERSTACK_DATAPLANE_URL=https://cdp.internxt.com
package/README.md CHANGED
@@ -10,22 +10,19 @@ A CLI tool to interact with yout Internxt encrypted files
10
10
  * [Installation](#installation)
11
11
  * [Usage](#usage)
12
12
  * [Commands](#commands)
13
+ * [Current Limitations](#current-limitations)
13
14
  <!-- tocstop -->
14
15
 
15
16
  # Installation
16
17
 
17
- Binaries and specific installers are available in the latest release:
18
-
19
- [View Internxt CLI latest release here](https://github.com/internxt/cli/releases/latest)
20
-
21
- You can install the Internxt CLI in different ways:
22
-
23
- ### NPM
18
+ You can install the Internxt CLI by using NPM:
24
19
 
25
20
  Requires Node >= 20.0.0
26
21
 
27
22
  `npm i -g @internxt/cli`
28
23
 
24
+ [View Internxt CLI latest release here](https://www.npmjs.com/package/@internxt/cli)
25
+
29
26
  # Usage
30
27
 
31
28
  <!-- usage -->
@@ -34,7 +31,7 @@ $ npm install -g @internxt/cli
34
31
  $ internxt COMMAND
35
32
  running command...
36
33
  $ internxt (--version)
37
- @internxt/cli/0.1.20 darwin-arm64 node-v20.10.0
34
+ @internxt/cli/1.0.5 darwin-arm64 node-v20.10.0
38
35
  $ internxt --help [COMMAND]
39
36
  USAGE
40
37
  $ internxt COMMAND
@@ -46,6 +43,7 @@ USAGE
46
43
 
47
44
  <!-- commands -->
48
45
  * [`internxt config`](#internxt-config)
46
+ * [`internxt create-folder`](#internxt-create-folder)
49
47
  * [`internxt download`](#internxt-download)
50
48
  * [`internxt list`](#internxt-list)
51
49
  * [`internxt login`](#internxt-login)
@@ -84,7 +82,28 @@ EXAMPLES
84
82
  $ internxt config
85
83
  ```
86
84
 
87
- _See code: [src/commands/config.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/config.ts)_
85
+ _See code: [src/commands/config.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/config.ts)_
86
+
87
+ ## `internxt create-folder`
88
+
89
+ Create a folder in your Internxt Drive
90
+
91
+ ```
92
+ USAGE
93
+ $ internxt create-folder --name <value> [--id <value>]
94
+
95
+ FLAGS
96
+ --id=<value> The folder id to create the folder in, defaults to your root folder
97
+ --name=<value> (required) The new folder name
98
+
99
+ DESCRIPTION
100
+ Create a folder in your Internxt Drive
101
+
102
+ EXAMPLES
103
+ $ internxt create-folder
104
+ ```
105
+
106
+ _See code: [src/commands/create-folder.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/create-folder.ts)_
88
107
 
89
108
  ## `internxt download`
90
109
 
@@ -107,7 +126,7 @@ EXAMPLES
107
126
  $ internxt download
108
127
  ```
109
128
 
110
- _See code: [src/commands/download.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/download.ts)_
129
+ _See code: [src/commands/download.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/download.ts)_
111
130
 
112
131
  ## `internxt list`
113
132
 
@@ -141,7 +160,7 @@ EXAMPLES
141
160
  $ internxt list
142
161
  ```
143
162
 
144
- _See code: [src/commands/list.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/list.ts)_
163
+ _See code: [src/commands/list.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/list.ts)_
145
164
 
146
165
  ## `internxt login`
147
166
 
@@ -167,7 +186,7 @@ EXAMPLES
167
186
  $ internxt login
168
187
  ```
169
188
 
170
- _See code: [src/commands/login.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/login.ts)_
189
+ _See code: [src/commands/login.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/login.ts)_
171
190
 
172
191
  ## `internxt logout`
173
192
 
@@ -184,7 +203,7 @@ EXAMPLES
184
203
  $ internxt logout
185
204
  ```
186
205
 
187
- _See code: [src/commands/logout.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/logout.ts)_
206
+ _See code: [src/commands/logout.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/logout.ts)_
188
207
 
189
208
  ## `internxt logs`
190
209
 
@@ -201,7 +220,7 @@ EXAMPLES
201
220
  $ internxt logs
202
221
  ```
203
222
 
204
- _See code: [src/commands/logs.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/logs.ts)_
223
+ _See code: [src/commands/logs.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/logs.ts)_
205
224
 
206
225
  ## `internxt move`
207
226
 
@@ -226,7 +245,7 @@ EXAMPLES
226
245
  $ internxt move
227
246
  ```
228
247
 
229
- _See code: [src/commands/move.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/move.ts)_
248
+ _See code: [src/commands/move.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/move.ts)_
230
249
 
231
250
  ## `internxt trash`
232
251
 
@@ -250,7 +269,7 @@ EXAMPLES
250
269
  $ internxt trash
251
270
  ```
252
271
 
253
- _See code: [src/commands/trash.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/trash.ts)_
272
+ _See code: [src/commands/trash.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/trash.ts)_
254
273
 
255
274
  ## `internxt upload`
256
275
 
@@ -274,7 +293,7 @@ EXAMPLES
274
293
  $ internxt upload
275
294
  ```
276
295
 
277
- _See code: [src/commands/upload.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/upload.ts)_
296
+ _See code: [src/commands/upload.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/upload.ts)_
278
297
 
279
298
  ## `internxt webdav ACTION`
280
299
 
@@ -291,7 +310,7 @@ EXAMPLES
291
310
  $ internxt webdav
292
311
  ```
293
312
 
294
- _See code: [src/commands/webdav.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/webdav.ts)_
313
+ _See code: [src/commands/webdav.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/webdav.ts)_
295
314
 
296
315
  ## `internxt whoami`
297
316
 
@@ -308,5 +327,9 @@ EXAMPLES
308
327
  $ internxt whoami
309
328
  ```
310
329
 
311
- _See code: [src/commands/whoami.ts](https://github.com/internxt/cli/blob/v0.1.20/src/commands/whoami.ts)_
330
+ _See code: [src/commands/whoami.ts](https://github.com/internxt/cli/blob/v1.0.5/src/commands/whoami.ts)_
312
331
  <!-- commandsstop -->
332
+
333
+ # Current Limitations
334
+
335
+ - We currently have a 5GB size upload limitation per file for both, CLI and WebDAV
@@ -0,0 +1,13 @@
1
+ import { Command } from '@oclif/core';
2
+ import { DriveFolderItem } from '../types/drive.types';
3
+ export default class CreateFolder extends Command {
4
+ static description: string;
5
+ static examples: string[];
6
+ static flags: {
7
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ id: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ catch(error: Error): Promise<void>;
11
+ getParentFolder(uuid: string): Promise<DriveFolderItem>;
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const auth_service_1 = require("../services/auth.service");
5
+ const errors_utils_1 = require("../utils/errors.utils");
6
+ const cli_utils_1 = require("../utils/cli.utils");
7
+ const drive_folder_service_1 = require("../services/drive/drive-folder.service");
8
+ const config_service_1 = require("../services/config.service");
9
+ class CreateFolder extends core_1.Command {
10
+ static description = 'Create a folder in your Internxt Drive';
11
+ static examples = ['<%= config.bin %> <%= command.id %>'];
12
+ static flags = {
13
+ name: core_1.Flags.string({ description: 'The new folder name', required: true }),
14
+ id: core_1.Flags.string({
15
+ description: 'The folder id to create the folder in, defaults to your root folder',
16
+ required: false,
17
+ }),
18
+ };
19
+ async catch(error) {
20
+ errors_utils_1.ErrorUtils.report(error, { command: this.id });
21
+ cli_utils_1.CLIUtils.error(error.message);
22
+ this.exit(1);
23
+ }
24
+ getParentFolder(uuid) {
25
+ return drive_folder_service_1.DriveFolderService.instance.getFolderMetaByUuid(uuid);
26
+ }
27
+ async run() {
28
+ const { flags } = await this.parse(CreateFolder);
29
+ const folderName = flags.name;
30
+ const user = await auth_service_1.AuthService.instance.getUser();
31
+ let parentFolder;
32
+ if (flags.id) {
33
+ parentFolder = await this.getParentFolder(flags.id);
34
+ if (!parentFolder) {
35
+ throw new Error(`Folder with id ${flags.id} not found`);
36
+ }
37
+ }
38
+ cli_utils_1.CLIUtils.doing('Creating folder...');
39
+ const [createNewFolder, requestCanceler] = drive_folder_service_1.DriveFolderService.instance.createFolder({
40
+ folderName,
41
+ parentFolderId: parentFolder ? parentFolder.id : user.root_folder_id,
42
+ });
43
+ process.on('SIGINT', () => {
44
+ requestCanceler.cancel('SIGINT received');
45
+ process.exit(1);
46
+ });
47
+ const newFolder = await createNewFolder;
48
+ cli_utils_1.CLIUtils.done();
49
+ cli_utils_1.CLIUtils.success(`Folder ${newFolder.plain_name} created successfully, view it at view it at ${config_service_1.ConfigService.instance.get('DRIVE_URL')}/folder/${newFolder.uuid}`);
50
+ }
51
+ }
52
+ exports.default = CreateFolder;
@@ -10,6 +10,7 @@ const errors_utils_1 = require("../utils/errors.utils");
10
10
  const drive_folder_service_1 = require("../services/drive/drive-folder.service");
11
11
  const sdk_manager_service_1 = require("../services/sdk-manager.service");
12
12
  const drive_database_manager_service_1 = require("../services/database/drive-database-manager.service");
13
+ const analytics_service_1 = require("../services/analytics.service");
13
14
  class Login extends core_1.Command {
14
15
  static args = {};
15
16
  static description = 'Logs into an Internxt account. If the account is two-factor protected, then an extra code will be required.';
@@ -58,6 +59,7 @@ class Login extends core_1.Command {
58
59
  await config_service_1.ConfigService.instance.saveUser(Object.assign(loginCredentials, { root_folder_uuid: rootMeta.uuid }));
59
60
  await drive_database_manager_service_1.DriveDatabaseManager.init();
60
61
  await drive_database_manager_service_1.DriveDatabaseManager.clean();
62
+ analytics_service_1.AnalyticsService.instance.track('CLILogin', { app: 'internxt-cli' });
61
63
  cli_utils_1.CLIUtils.success(`Succesfully logged in to: ${loginCredentials.user.email} `);
62
64
  }
63
65
  async catch(error) {
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const pm2_utils_1 = require("../utils/pm2.utils");
5
5
  const cli_utils_1 = require("../utils/cli.utils");
6
6
  const config_service_1 = require("../services/config.service");
7
+ const analytics_service_1 = require("../services/analytics.service");
7
8
  class Webdav extends core_1.Command {
8
9
  static description = 'Enable or disable the Internxt CLI WebDav server';
9
10
  static examples = ['<%= config.bin %> <%= command.id %>'];
@@ -24,6 +25,7 @@ class Webdav extends core_1.Command {
24
25
  if (status === 'online') {
25
26
  core_1.ux.log(`\nWebDav server status: ${core_1.ux.colorize('green', 'online')}\n`);
26
27
  cli_utils_1.CLIUtils.success(`Internxt WebDav server started successfully on https://${config_service_1.ConfigService.WEBDAV_LOCAL_URL}:${process.env.WEBDAV_SERVER_PORT}`);
28
+ await analytics_service_1.AnalyticsService.instance.track('WebDAVEnabled', { app: 'internxt-cli' });
27
29
  }
28
30
  else {
29
31
  core_1.ux.log(`WebDav server status: ${core_1.ux.colorize('red', status)}`);
@@ -6,11 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const whoami_1 = __importDefault(require("../../commands/whoami"));
7
7
  const login_1 = __importDefault(require("../../commands/login"));
8
8
  const logout_1 = __importDefault(require("../../commands/logout"));
9
+ const logs_1 = __importDefault(require("../../commands/logs"));
9
10
  const cli_utils_1 = require("../../utils/cli.utils");
10
11
  const sdk_manager_service_1 = require("../../services/sdk-manager.service");
11
12
  const auth_service_1 = require("../../services/auth.service");
12
13
  const command_types_1 = require("../../types/command.types");
13
- const CommandsToSkip = [whoami_1.default, login_1.default, logout_1.default];
14
+ const CommandsToSkip = [whoami_1.default, login_1.default, logout_1.default, logs_1.default];
14
15
  const hook = async function (opts) {
15
16
  if (!CommandsToSkip.map((command) => command.name).includes(opts.Command.name)) {
16
17
  cli_utils_1.CLIUtils.doing('Checking credentials');
@@ -0,0 +1,16 @@
1
+ import { ConfigService } from './config.service';
2
+ export declare const AnalyticsEvents: {
3
+ CLILogin: string;
4
+ WebDAVEnabled: string;
5
+ WebDAVRequest: string;
6
+ };
7
+ export declare class AnalyticsService {
8
+ private config;
9
+ static readonly instance: AnalyticsService;
10
+ constructor(config: ConfigService);
11
+ private getRudderstack;
12
+ track(eventKey: keyof typeof AnalyticsEvents, options: {
13
+ app: 'internxt-cli' | 'internxt-webdav';
14
+ userId?: string;
15
+ }, params?: object): Promise<void>;
16
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AnalyticsService = exports.AnalyticsEvents = void 0;
7
+ const rudder_sdk_node_1 = __importDefault(require("@rudderstack/rudder-sdk-node"));
8
+ const config_service_1 = require("./config.service");
9
+ const package_json_1 = __importDefault(require("../../package.json"));
10
+ const crypto_1 = require("crypto");
11
+ exports.AnalyticsEvents = {
12
+ CLILogin: 'CLI Login',
13
+ WebDAVEnabled: 'WebDAV Enabled',
14
+ WebDAVRequest: 'WebDAV Request',
15
+ };
16
+ class AnalyticsService {
17
+ config;
18
+ static instance = new AnalyticsService(config_service_1.ConfigService.instance);
19
+ constructor(config) {
20
+ this.config = config;
21
+ }
22
+ getRudderstack() {
23
+ return new rudder_sdk_node_1.default(this.config.get('RUDDERSTACK_WRITE_KEY'), {
24
+ dataPlaneUrl: this.config.get('RUDDERSTACK_DATAPLANE_URL'),
25
+ });
26
+ }
27
+ track(eventKey, options, params = {}) {
28
+ return new Promise((resolve) => {
29
+ const rudderstack = this.getRudderstack();
30
+ rudderstack.track({
31
+ event: exports.AnalyticsEvents[eventKey],
32
+ userId: options.userId,
33
+ anonymousId: options.userId ? undefined : (0, crypto_1.randomUUID)(),
34
+ properties: {
35
+ app: {
36
+ name: options.app,
37
+ version: package_json_1.default.version,
38
+ },
39
+ ...params,
40
+ },
41
+ }, () => {
42
+ resolve();
43
+ });
44
+ });
45
+ }
46
+ }
47
+ exports.AnalyticsService = AnalyticsService;
@@ -15,4 +15,6 @@ export declare class DriveDatabaseManager {
15
15
  createFile: (driveFile: DriveFileItem) => Promise<DriveFile>;
16
16
  buildRelativePathForFile: (fileName: string, parentId: number | null) => Promise<string>;
17
17
  buildRelativePathForFolder: (folderName: string, parentId: number | null) => Promise<string>;
18
+ deleteFile: (id: number) => Promise<void>;
19
+ deleteFolder: (id: number) => Promise<void>;
18
20
  }
@@ -73,5 +73,11 @@ class DriveDatabaseManager {
73
73
  const parentPath = await this.buildRelativePathForFolder(parentFolder.name, parentFolder.parentId);
74
74
  return webdav_utils_1.WebDavUtils.joinURL(parentPath, folderName, '/');
75
75
  };
76
+ deleteFile = (id) => {
77
+ return this.driveFileRepository.deleteById(id);
78
+ };
79
+ deleteFolder = (id) => {
80
+ return this.driveFolderRepository.deleteById(id);
81
+ };
76
82
  }
77
83
  exports.DriveDatabaseManager = DriveDatabaseManager;
@@ -4,7 +4,7 @@ import { DriveFile } from './drive-file.domain';
4
4
  export declare class DriveFileRepository {
5
5
  findByRelativePath: (relativePath: DriveFile['relativePath']) => Promise<DriveFile | null>;
6
6
  findById: (id: DriveFile['id']) => Promise<DriveFile | null>;
7
- deleteById: (id: DriveFile['id']) => Promise<number>;
7
+ deleteById: (id: DriveFile['id']) => Promise<void>;
8
8
  createFile: (driveFileItem: DriveFileItem, relativePath: string) => Promise<DriveFile>;
9
9
  toDomain: (model: DriveFileModel) => DriveFile;
10
10
  static readonly clean: () => Promise<void>;
@@ -16,8 +16,8 @@ class DriveFileRepository {
16
16
  const file = await drive_file_model_1.DriveFileModel.findByPk(id);
17
17
  return file ? this.toDomain(file) : null;
18
18
  };
19
- deleteById = (id) => {
20
- return drive_file_model_1.DriveFileModel.destroy({ where: { id } });
19
+ deleteById = async (id) => {
20
+ await drive_file_model_1.DriveFileModel.destroy({ where: { id } });
21
21
  };
22
22
  createFile = async (driveFileItem, relativePath) => {
23
23
  const driveFile = drive_file_domain_1.DriveFile.build({
@@ -2,6 +2,7 @@ export interface DriveFolderAttributes {
2
2
  id: number;
3
3
  name: string;
4
4
  uuid: string;
5
+ status: 'EXISTS' | 'TRASHED';
5
6
  relativePath: string;
6
7
  parentId: number | null;
7
8
  createdAt: Date;
@@ -7,7 +7,8 @@ export declare class DriveFolder implements DriveFolderAttributes {
7
7
  parentId: number | null;
8
8
  createdAt: Date;
9
9
  updatedAt: Date;
10
- constructor({ id, name, uuid, relativePath, parentId, createdAt, updatedAt }: DriveFolderAttributes);
10
+ status: DriveFolderAttributes['status'];
11
+ constructor({ id, name, uuid, relativePath, parentId, createdAt, updatedAt, status }: DriveFolderAttributes);
11
12
  static build(folder: DriveFolderAttributes): DriveFolder;
12
13
  toJSON(): DriveFolderAttributes;
13
14
  }
@@ -9,7 +9,8 @@ class DriveFolder {
9
9
  parentId;
10
10
  createdAt;
11
11
  updatedAt;
12
- constructor({ id, name, uuid, relativePath, parentId, createdAt, updatedAt }) {
12
+ status;
13
+ constructor({ id, name, uuid, relativePath, parentId, createdAt, updatedAt, status }) {
13
14
  this.id = id;
14
15
  this.name = name;
15
16
  this.uuid = uuid;
@@ -17,6 +18,7 @@ class DriveFolder {
17
18
  this.parentId = parentId;
18
19
  this.createdAt = createdAt;
19
20
  this.updatedAt = updatedAt;
21
+ this.status = status;
20
22
  }
21
23
  static build(folder) {
22
24
  return new DriveFolder(folder);
@@ -26,6 +28,7 @@ class DriveFolder {
26
28
  id: this.id,
27
29
  name: this.name,
28
30
  uuid: this.uuid,
31
+ status: this.status,
29
32
  relativePath: this.relativePath,
30
33
  parentId: this.parentId,
31
34
  createdAt: this.createdAt,
@@ -3,6 +3,7 @@ import { DriveFolderAttributes } from './drive-folder.attributes';
3
3
  export declare class DriveFolderModel extends Model implements DriveFolderAttributes {
4
4
  id: number;
5
5
  name: string;
6
+ status: 'EXISTS' | 'TRASHED';
6
7
  uuid: string;
7
8
  relativePath: string;
8
9
  parentId: number | null;
@@ -25,6 +25,10 @@ __decorate([
25
25
  (0, sequelize_typescript_1.Column)(sequelize_typescript_1.DataType.STRING),
26
26
  __metadata("design:type", String)
27
27
  ], DriveFolderModel.prototype, "name", void 0);
28
+ __decorate([
29
+ (0, sequelize_typescript_1.Column)(sequelize_typescript_1.DataType.STRING),
30
+ __metadata("design:type", String)
31
+ ], DriveFolderModel.prototype, "status", void 0);
28
32
  __decorate([
29
33
  sequelize_typescript_1.Unique,
30
34
  (0, sequelize_typescript_1.Column)(sequelize_typescript_1.DataType.UUIDV4),
@@ -4,7 +4,7 @@ import { DriveFolderModel } from './drive-folder.model';
4
4
  export declare class DriveFolderRepository {
5
5
  findByRelativePath: (relativePath: DriveFolder['relativePath']) => Promise<DriveFolder | null>;
6
6
  findById: (id: DriveFolder['id']) => Promise<DriveFolder | null>;
7
- deleteById: (id: DriveFolder['id']) => Promise<number>;
7
+ deleteById: (id: DriveFolder['id']) => Promise<void>;
8
8
  createFolder: (driveFolderItem: DriveFolderItem, relativePath: string) => Promise<DriveFolder>;
9
9
  toDomain: (model: DriveFolderModel) => DriveFolder;
10
10
  static readonly clean: () => Promise<void>;
@@ -16,8 +16,8 @@ class DriveFolderRepository {
16
16
  const folder = await drive_folder_model_1.DriveFolderModel.findByPk(id);
17
17
  return folder ? this.toDomain(folder) : null;
18
18
  };
19
- deleteById = (id) => {
20
- return drive_folder_model_1.DriveFolderModel.destroy({ where: { id } });
19
+ deleteById = async (id) => {
20
+ await drive_folder_model_1.DriveFolderModel.destroy({ where: { id } });
21
21
  };
22
22
  createFolder = async (driveFolderItem, relativePath) => {
23
23
  const driveFolder = drive_folder_domain_1.DriveFolder.build({
@@ -1,6 +1,7 @@
1
1
  import { FetchPaginatedFile, FetchPaginatedFolder } from '@internxt/sdk/dist/drive/storage/types';
2
2
  import { StorageTypes } from '@internxt/sdk/dist/drive';
3
3
  import { DriveFolderItem } from '../../types/drive.types';
4
+ import { RequestCanceler } from '@internxt/sdk/dist/shared/http/types';
4
5
  export declare class DriveFolderService {
5
6
  static readonly instance: DriveFolderService;
6
7
  getFolderMetaByUuid: (uuid: string) => Promise<DriveFolderItem>;
@@ -12,4 +13,8 @@ export declare class DriveFolderService {
12
13
  private getAllSubfolders;
13
14
  private getAllSubfiles;
14
15
  moveFolder: (payload: StorageTypes.MoveFolderUuidPayload) => Promise<StorageTypes.FolderMeta>;
16
+ createFolder(payload: {
17
+ folderName: string;
18
+ parentFolderId: number;
19
+ }): [Promise<StorageTypes.CreateFolderResponse>, RequestCanceler];
15
20
  }
@@ -45,5 +45,12 @@ class DriveFolderService {
45
45
  const storageClient = sdk_manager_service_1.SdkManager.instance.getStorage(true);
46
46
  return storageClient.moveFolderByUuid(payload);
47
47
  };
48
+ createFolder(payload) {
49
+ const storageClient = sdk_manager_service_1.SdkManager.instance.getStorage();
50
+ return storageClient.createFolder({
51
+ folderName: payload.folderName,
52
+ parentFolderId: payload.parentFolderId,
53
+ });
54
+ }
48
55
  }
49
56
  exports.DriveFolderService = DriveFolderService;
@@ -10,4 +10,6 @@ export interface ConfigKeys {
10
10
  readonly APP_MAGIC_SALT: string;
11
11
  readonly NETWORK_URL: string;
12
12
  readonly WEBDAV_SERVER_PORT: string;
13
+ readonly RUDDERSTACK_WRITE_KEY: string;
14
+ readonly RUDDERSTACK_DATAPLANE_URL: string;
13
15
  }
@@ -11,4 +11,5 @@ export type DriveFolderItem = Pick<DriveFolderData, 'name' | 'bucket' | 'id' | '
11
11
  uuid: string;
12
12
  createdAt: Date;
13
13
  updatedAt: Date;
14
+ status: 'EXISTS' | 'TRASHED';
14
15
  };
@@ -0,0 +1,3 @@
1
+ export declare class AsyncUtils {
2
+ static sleep(ms: number): Promise<void>;
3
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AsyncUtils = void 0;
4
+ class AsyncUtils {
5
+ static sleep(ms) {
6
+ return new Promise((resolve) => setTimeout(resolve, ms));
7
+ }
8
+ }
9
+ exports.AsyncUtils = AsyncUtils;
@@ -23,6 +23,7 @@ class DriveUtils {
23
23
  uuid: folderMeta.uuid,
24
24
  id: folderMeta.id,
25
25
  bucket: folderMeta.bucket,
26
+ status: folderMeta.deleted || folderMeta.removed ? 'TRASHED' : 'EXISTS',
26
27
  name: folderMeta.plainName ?? folderMeta.name,
27
28
  encryptedName: folderMeta.name,
28
29
  parentId: folderMeta.parentId,
@@ -3,5 +3,6 @@ import { WebDavRequestedResource } from '../types/webdav.types';
3
3
  import { DriveDatabaseManager } from '../services/database/drive-database-manager.service';
4
4
  export declare class WebDavUtils {
5
5
  static joinURL(...pathComponents: string[]): string;
6
+ static getParentPath(fromPath: string): string;
6
7
  static getRequestedResource(req: Request, driveDatabaseManager: DriveDatabaseManager): Promise<WebDavRequestedResource>;
7
8
  }
@@ -11,6 +11,9 @@ class WebDavUtils {
11
11
  static joinURL(...pathComponents) {
12
12
  return path_1.default.posix.join(...pathComponents);
13
13
  }
14
+ static getParentPath(fromPath) {
15
+ return path_1.default.dirname(fromPath);
16
+ }
14
17
  static async getRequestedResource(req, driveDatabaseManager) {
15
18
  const decodedUrl = decodeURI(req.url);
16
19
  const parsedPath = path_1.default.parse(decodedUrl);
@@ -1,4 +1,12 @@
1
+ import { Request, Response } from 'express';
1
2
  import { WebDavMethodHandler } from '../../types/webdav.types';
3
+ import { DriveDatabaseManager } from '../../services/database/drive-database-manager.service';
4
+ import { TrashService } from '../../services/drive/trash.service';
2
5
  export declare class DELETERequestHandler implements WebDavMethodHandler {
3
- handle(): Promise<void>;
6
+ private dependencies;
7
+ constructor(dependencies: {
8
+ driveDatabaseManager: DriveDatabaseManager;
9
+ trashService: TrashService;
10
+ });
11
+ handle: (req: Request, res: Response) => Promise<void>;
4
12
  }
@@ -2,9 +2,31 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DELETERequestHandler = void 0;
4
4
  const errors_utils_1 = require("../../utils/errors.utils");
5
+ const webdav_utils_1 = require("../../utils/webdav.utils");
6
+ const logger_utils_1 = require("../../utils/logger.utils");
5
7
  class DELETERequestHandler {
6
- async handle() {
7
- throw new errors_utils_1.NotImplementedError('DELETE is not implemented yet.');
8
+ dependencies;
9
+ constructor(dependencies) {
10
+ this.dependencies = dependencies;
8
11
  }
12
+ handle = async (req, res) => {
13
+ logger_utils_1.webdavLogger.info('DELETE request received');
14
+ const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req, this.dependencies.driveDatabaseManager);
15
+ logger_utils_1.webdavLogger.info('Resource found for DELETE request', { resource });
16
+ const databaseItem = await this.dependencies.driveDatabaseManager.findByRelativePath(resource.url);
17
+ if (!databaseItem)
18
+ throw new errors_utils_1.NotFoundError('Resource not found');
19
+ logger_utils_1.webdavLogger.info(`Trashing ${resource.type} with UUID ${databaseItem.uuid}...`);
20
+ await this.dependencies.trashService.trashItems({
21
+ items: [{ type: resource.type, uuid: databaseItem.uuid }],
22
+ });
23
+ if (resource.type === 'folder') {
24
+ await this.dependencies.driveDatabaseManager.deleteFolder(databaseItem.id);
25
+ }
26
+ if (resource.type === 'file') {
27
+ await this.dependencies.driveDatabaseManager.deleteFile(databaseItem.id);
28
+ }
29
+ res.status(204).send();
30
+ };
9
31
  }
10
32
  exports.DELETERequestHandler = DELETERequestHandler;
@@ -1,4 +1,12 @@
1
+ import { DriveDatabaseManager } from '../../services/database/drive-database-manager.service';
1
2
  import { WebDavMethodHandler } from '../../types/webdav.types';
3
+ import { Request, Response } from 'express';
4
+ import { DriveFolderService } from '../../services/drive/drive-folder.service';
2
5
  export declare class MKCOLRequestHandler implements WebDavMethodHandler {
3
- handle(): Promise<void>;
6
+ private dependencies;
7
+ constructor(dependencies: {
8
+ driveDatabaseManager: DriveDatabaseManager;
9
+ driveFolderService: DriveFolderService;
10
+ });
11
+ handle: (req: Request, res: Response) => Promise<void>;
4
12
  }
@@ -1,10 +1,48 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.MKCOLRequestHandler = void 0;
7
+ const webdav_utils_1 = require("../../utils/webdav.utils");
4
8
  const errors_utils_1 = require("../../utils/errors.utils");
9
+ const logger_utils_1 = require("../../utils/logger.utils");
10
+ const path_1 = __importDefault(require("path"));
11
+ const xml_utils_1 = require("../../utils/xml.utils");
12
+ const async_utils_1 = require("../../utils/async.utils");
5
13
  class MKCOLRequestHandler {
6
- async handle() {
7
- throw new errors_utils_1.NotImplementedError('MKCOL is not implemented yet.');
14
+ dependencies;
15
+ constructor(dependencies) {
16
+ this.dependencies = dependencies;
8
17
  }
18
+ handle = async (req, res) => {
19
+ const { driveDatabaseManager, driveFolderService } = this.dependencies;
20
+ const resourceParsedPath = path_1.default.parse(decodeURI(req.url));
21
+ const parentPath = webdav_utils_1.WebDavUtils.getParentPath(req.url);
22
+ const parentResource = await driveDatabaseManager.findByRelativePath(parentPath);
23
+ if (!parentResource)
24
+ throw new errors_utils_1.NotFoundError(`Parent resource not found for parent path ${parentPath}`);
25
+ logger_utils_1.webdavLogger.info(`MKCOL request received for folder at ${req.url}`);
26
+ logger_utils_1.webdavLogger.info(`Parent path: ${parentResource.id}`);
27
+ const [createFolder] = driveFolderService.createFolder({
28
+ folderName: resourceParsedPath.name,
29
+ parentFolderId: parentResource.id,
30
+ });
31
+ const newFolder = await createFolder;
32
+ logger_utils_1.webdavLogger.info(`✅ Folder created with UUID ${newFolder.uuid}`);
33
+ await driveDatabaseManager.createFolder({
34
+ name: newFolder.plain_name,
35
+ status: 'EXISTS',
36
+ encryptedName: newFolder.name,
37
+ bucket: newFolder.bucket,
38
+ id: newFolder.id,
39
+ parentId: newFolder.parentId,
40
+ uuid: newFolder.uuid,
41
+ createdAt: new Date(newFolder.createdAt),
42
+ updatedAt: new Date(newFolder.updatedAt),
43
+ });
44
+ await async_utils_1.AsyncUtils.sleep(500);
45
+ res.status(201).send(xml_utils_1.XMLUtils.toWebDavXML({}, {}));
46
+ };
9
47
  }
10
48
  exports.MKCOLRequestHandler = MKCOLRequestHandler;
@@ -30,6 +30,7 @@ class PROPFINDRequestHandler {
30
30
  const rootFolder = await this.dependencies.driveFolderService.getFolderMetaById(req.user.rootFolderId);
31
31
  await this.dependencies.driveDatabaseManager.createFolder({
32
32
  name: '',
33
+ status: 'EXISTS',
33
34
  encryptedName: rootFolder.name,
34
35
  bucket: rootFolder.bucket,
35
36
  id: rootFolder.id,
@@ -112,6 +113,7 @@ class PROPFINDRequestHandler {
112
113
  return this.driveFolderItemToXMLNode({
113
114
  name: folder.plainName,
114
115
  bucket: folder.bucket,
116
+ status: folder.deleted || folder.removed ? 'TRASHED' : 'EXISTS',
115
117
  createdAt: new Date(folder.createdAt),
116
118
  updatedAt: new Date(folder.updatedAt),
117
119
  id: folder.id,
@@ -125,6 +127,7 @@ class PROPFINDRequestHandler {
125
127
  ...folder,
126
128
  name: folder.plainName,
127
129
  encryptedName: folder.name,
130
+ status: folder.deleted || folder.removed ? 'TRASHED' : 'EXISTS',
128
131
  });
129
132
  });
130
133
  const filesXML = folderContent.files.map((file) => {
@@ -16,13 +16,14 @@ const upload_service_1 = require("../services/network/upload.service");
16
16
  const download_service_1 = require("../services/network/download.service");
17
17
  const auth_service_1 = require("../services/auth.service");
18
18
  const crypto_service_1 = require("../services/crypto.service");
19
+ const trash_service_1 = require("../services/drive/trash.service");
19
20
  dotenv_1.default.config();
20
21
  const init = async () => {
21
22
  await config_service_1.ConfigService.instance.ensureInternxtCliDataDirExists();
22
23
  await config_service_1.ConfigService.instance.ensureWebdavCertsDirExists();
23
24
  await config_service_1.ConfigService.instance.ensureInternxtLogsDirExists();
24
25
  await drive_database_manager_service_1.DriveDatabaseManager.init();
25
- new webdav_server_1.WebDavServer((0, express_1.default)(), config_service_1.ConfigService.instance, drive_file_service_1.DriveFileService.instance, drive_folder_service_1.DriveFolderService.instance, new drive_database_manager_service_1.DriveDatabaseManager(new drive_file_repository_1.DriveFileRepository(), new drive_folder_repository_1.DriveFolderRepository()), upload_service_1.UploadService.instance, download_service_1.DownloadService.instance, auth_service_1.AuthService.instance, crypto_service_1.CryptoService.instance)
26
+ new webdav_server_1.WebDavServer((0, express_1.default)(), config_service_1.ConfigService.instance, drive_file_service_1.DriveFileService.instance, drive_folder_service_1.DriveFolderService.instance, new drive_database_manager_service_1.DriveDatabaseManager(new drive_file_repository_1.DriveFileRepository(), new drive_folder_repository_1.DriveFolderRepository()), upload_service_1.UploadService.instance, download_service_1.DownloadService.instance, auth_service_1.AuthService.instance, crypto_service_1.CryptoService.instance, trash_service_1.TrashService.instance)
26
27
  .start()
27
28
  .then()
28
29
  .catch(console.error);
@@ -2,8 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RequestLoggerMiddleware = void 0;
4
4
  const logger_utils_1 = require("../../utils/logger.utils");
5
+ const analytics_service_1 = require("../../services/analytics.service");
5
6
  const RequestLoggerMiddleware = (config) => {
6
7
  return (req, _, next) => {
8
+ analytics_service_1.AnalyticsService.instance.track('WebDAVRequest', { app: 'internxt-webdav' }, { method: req.method.toUpperCase() });
7
9
  if (!config.enable)
8
10
  return next();
9
11
  if (config.methods && !config.methods.includes(req.method))
@@ -7,6 +7,7 @@ import { UploadService } from '../services/network/upload.service';
7
7
  import { DownloadService } from '../services/network/download.service';
8
8
  import { AuthService } from '../services/auth.service';
9
9
  import { CryptoService } from '../services/crypto.service';
10
+ import { TrashService } from '../services/drive/trash.service';
10
11
  export declare class WebDavServer {
11
12
  private app;
12
13
  private configService;
@@ -17,7 +18,8 @@ export declare class WebDavServer {
17
18
  private downloadService;
18
19
  private authService;
19
20
  private cryptoService;
20
- constructor(app: Express, configService: ConfigService, driveFileService: DriveFileService, driveFolderService: DriveFolderService, driveDatabaseManager: DriveDatabaseManager, uploadService: UploadService, downloadService: DownloadService, authService: AuthService, cryptoService: CryptoService);
21
+ private trashService;
22
+ constructor(app: Express, configService: ConfigService, driveFileService: DriveFileService, driveFolderService: DriveFolderService, driveDatabaseManager: DriveDatabaseManager, uploadService: UploadService, downloadService: DownloadService, authService: AuthService, cryptoService: CryptoService, trashService: TrashService);
21
23
  private getNetwork;
22
24
  private registerMiddlewares;
23
25
  private registerHandlers;
@@ -35,7 +35,8 @@ class WebDavServer {
35
35
  downloadService;
36
36
  authService;
37
37
  cryptoService;
38
- constructor(app, configService, driveFileService, driveFolderService, driveDatabaseManager, uploadService, downloadService, authService, cryptoService) {
38
+ trashService;
39
+ constructor(app, configService, driveFileService, driveFolderService, driveDatabaseManager, uploadService, downloadService, authService, cryptoService, trashService) {
39
40
  this.app = app;
40
41
  this.configService = configService;
41
42
  this.driveFileService = driveFileService;
@@ -45,6 +46,7 @@ class WebDavServer {
45
46
  this.downloadService = downloadService;
46
47
  this.authService = authService;
47
48
  this.cryptoService = cryptoService;
49
+ this.trashService = trashService;
48
50
  }
49
51
  async getNetwork() {
50
52
  const credentials = await this.configService.readUser();
@@ -89,8 +91,14 @@ class WebDavServer {
89
91
  authService: this.authService,
90
92
  networkFacade: await this.getNetwork(),
91
93
  }).handle));
92
- this.app.mkcol('*', (0, express_async_handler_1.default)(new MKCOL_handler_1.MKCOLRequestHandler().handle));
93
- this.app.delete('*', (0, express_async_handler_1.default)(new DELETE_handler_1.DELETERequestHandler().handle));
94
+ this.app.mkcol('*', (0, express_async_handler_1.default)(new MKCOL_handler_1.MKCOLRequestHandler({
95
+ driveDatabaseManager: this.driveDatabaseManager,
96
+ driveFolderService: this.driveFolderService,
97
+ }).handle));
98
+ this.app.delete('*', (0, express_async_handler_1.default)(new DELETE_handler_1.DELETERequestHandler({
99
+ driveDatabaseManager: this.driveDatabaseManager,
100
+ trashService: this.trashService,
101
+ }).handle));
94
102
  this.app.proppatch('*', (0, express_async_handler_1.default)(new PROPPATCH_handler_1.PROPPATCHRequestHandler().handle));
95
103
  this.app.move('*', (0, express_async_handler_1.default)(new MOVE_handler_1.MOVERequestHandler().handle));
96
104
  this.app.copy('*', (0, express_async_handler_1.default)(new COPY_handler_1.COPYRequestHandler().handle));
@@ -101,6 +101,46 @@
101
101
  "config.js"
102
102
  ]
103
103
  },
104
+ "create-folder": {
105
+ "aliases": [],
106
+ "args": {},
107
+ "description": "Create a folder in your Internxt Drive",
108
+ "examples": [
109
+ "<%= config.bin %> <%= command.id %>"
110
+ ],
111
+ "flags": {
112
+ "name": {
113
+ "description": "The new folder name",
114
+ "name": "name",
115
+ "required": true,
116
+ "hasDynamicHelp": false,
117
+ "multiple": false,
118
+ "type": "option"
119
+ },
120
+ "id": {
121
+ "description": "The folder id to create the folder in, defaults to your root folder",
122
+ "name": "id",
123
+ "required": false,
124
+ "hasDynamicHelp": false,
125
+ "multiple": false,
126
+ "type": "option"
127
+ }
128
+ },
129
+ "hasDynamicHelp": false,
130
+ "hiddenAliases": [],
131
+ "id": "create-folder",
132
+ "pluginAlias": "@internxt/cli",
133
+ "pluginName": "@internxt/cli",
134
+ "pluginType": "core",
135
+ "strict": true,
136
+ "enableJsonFlag": false,
137
+ "isESM": false,
138
+ "relativePath": [
139
+ "dist",
140
+ "commands",
141
+ "create-folder.js"
142
+ ]
143
+ },
104
144
  "download": {
105
145
  "aliases": [],
106
146
  "args": {},
@@ -589,5 +629,5 @@
589
629
  ]
590
630
  }
591
631
  },
592
- "version": "0.1.20"
632
+ "version": "1.0.5"
593
633
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "author": "PixoDev",
3
- "version": "0.1.20",
3
+ "version": "1.0.5",
4
4
  "description": "Internxt CLI to manage your encrypted storage",
5
5
  "scripts": {
6
6
  "build": "tsc",
@@ -12,6 +12,7 @@
12
12
  "test:unit": "nyc --reporter=lcov --reporter=text mocha \"test/**/*.test.ts\" --exit",
13
13
  "dev:webdav": "nodemon -e ts --exec ts-node src/webdav/index.ts",
14
14
  "version": "oclif readme && git add README.md",
15
+ "pack:win": "oclif pack win",
15
16
  "migrate": "sequelize db:migrate",
16
17
  "migrate:undo": "sequelize db:migrate:undo",
17
18
  "publish:npm": "npm run build && npm publish --scope=@internxt --registry=https://registry.npmjs.org/ --access public",
@@ -37,8 +38,9 @@
37
38
  "dependencies": {
38
39
  "@internxt/inxt-js": "^2.0.11",
39
40
  "@internxt/lib": "^1.2.1",
40
- "@internxt/sdk": "^1.4.76",
41
+ "@internxt/sdk": "^1.4.79",
41
42
  "@oclif/core": "^3",
43
+ "@rudderstack/rudder-sdk-node": "^2.0.7",
42
44
  "axios": "^1.6.7",
43
45
  "bip39": "^3.1.0",
44
46
  "body-parser": "^1.20.2",