@internxt/cli 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +89 -27
  2. package/dist/commands/add-cert.js +2 -2
  3. package/dist/commands/create-folder.d.ts +3 -3
  4. package/dist/commands/delete-permanently-file.d.ts +2 -2
  5. package/dist/commands/delete-permanently-folder.d.ts +2 -2
  6. package/dist/commands/download-file.d.ts +4 -5
  7. package/dist/commands/download-file.js +22 -37
  8. package/dist/commands/list.d.ts +4 -4
  9. package/dist/commands/login-legacy.d.ts +5 -5
  10. package/dist/commands/login.d.ts +2 -2
  11. package/dist/commands/logs.js +3 -3
  12. package/dist/commands/move-file.d.ts +4 -4
  13. package/dist/commands/move-folder.d.ts +3 -3
  14. package/dist/commands/rename-file.d.ts +3 -3
  15. package/dist/commands/rename-folder.d.ts +3 -3
  16. package/dist/commands/trash-clear.d.ts +2 -2
  17. package/dist/commands/trash-file.d.ts +2 -2
  18. package/dist/commands/trash-folder.d.ts +2 -2
  19. package/dist/commands/trash-list.d.ts +2 -2
  20. package/dist/commands/trash-restore-file.d.ts +4 -4
  21. package/dist/commands/trash-restore-folder.d.ts +3 -3
  22. package/dist/commands/upload-file.d.ts +6 -7
  23. package/dist/commands/upload-file.js +61 -80
  24. package/dist/commands/upload-folder.d.ts +16 -0
  25. package/dist/commands/upload-folder.js +87 -0
  26. package/dist/commands/webdav-config.d.ts +6 -6
  27. package/dist/commands/webdav.d.ts +1 -1
  28. package/dist/constants/configs.d.ts +12 -0
  29. package/dist/constants/configs.js +20 -0
  30. package/dist/services/auth.service.js +11 -6
  31. package/dist/services/config.service.d.ts +0 -12
  32. package/dist/services/config.service.js +33 -38
  33. package/dist/services/drive/drive-folder.service.d.ts +1 -1
  34. package/dist/services/drive/trash.service.d.ts +1 -1
  35. package/dist/services/local-filesystem/local-filesystem.service.d.ts +6 -0
  36. package/dist/services/local-filesystem/local-filesystem.service.js +57 -0
  37. package/dist/services/local-filesystem/local-filesystem.types.d.ts +13 -0
  38. package/dist/services/local-filesystem/local-filesystem.types.js +2 -0
  39. package/dist/services/network/upload/upload-facade.service.d.ts +9 -0
  40. package/dist/services/network/upload/upload-facade.service.js +53 -0
  41. package/dist/services/network/upload/upload-file.service.d.ts +8 -0
  42. package/dist/services/network/upload/upload-file.service.js +134 -0
  43. package/dist/services/network/upload/upload-folder.service.d.ts +6 -0
  44. package/dist/services/network/upload/upload-folder.service.js +62 -0
  45. package/dist/services/network/upload/upload.types.d.ts +53 -0
  46. package/dist/services/network/upload/upload.types.js +6 -0
  47. package/dist/services/sdk-manager.service.d.ts +2 -2
  48. package/dist/services/sdk-manager.service.js +2 -2
  49. package/dist/services/thumbnail.service.js +1 -34
  50. package/dist/services/validation.service.d.ts +5 -0
  51. package/dist/services/validation.service.js +22 -18
  52. package/dist/types/command.types.d.ts +3 -0
  53. package/dist/types/command.types.js +8 -1
  54. package/dist/types/fast-xml-parser.types.d.ts +59 -0
  55. package/dist/types/fast-xml-parser.types.js +2 -0
  56. package/dist/utils/cli.utils.d.ts +16 -2
  57. package/dist/utils/cli.utils.js +84 -3
  58. package/dist/utils/errors.utils.d.ts +2 -0
  59. package/dist/utils/errors.utils.js +13 -2
  60. package/dist/utils/logger.utils.js +5 -5
  61. package/dist/utils/network.utils.d.ts +2 -2
  62. package/dist/utils/network.utils.js +24 -23
  63. package/dist/utils/thumbnail.utils.d.ts +17 -0
  64. package/dist/utils/thumbnail.utils.js +36 -8
  65. package/dist/utils/xml.utils.d.ts +2 -2
  66. package/dist/utils/xml.utils.js +1 -1
  67. package/dist/webdav/handlers/GET.handler.js +37 -26
  68. package/dist/webdav/handlers/PUT.handler.js +56 -41
  69. package/dist/webdav/middewares/errors.middleware.js +1 -1
  70. package/dist/webdav/webdav-server.js +4 -4
  71. package/oclif.manifest.json +62 -1
  72. package/package.json +24 -24
@@ -5,6 +5,7 @@ const webdav_utils_1 = require("../../utils/webdav.utils");
5
5
  const errors_utils_1 = require("../../utils/errors.utils");
6
6
  const logger_utils_1 = require("../../utils/logger.utils");
7
7
  const network_utils_1 = require("../../utils/network.utils");
8
+ const command_types_1 = require("../../types/command.types");
8
9
  class GETRequestHandler {
9
10
  dependencies;
10
11
  constructor(dependencies) {
@@ -13,8 +14,6 @@ class GETRequestHandler {
13
14
  handle = async (req, res) => {
14
15
  const { driveFileService, authService, networkFacade } = this.dependencies;
15
16
  const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
16
- if (resource.name.startsWith('._'))
17
- throw new errors_utils_1.NotFoundError('File not found');
18
17
  logger_utils_1.webdavLogger.info(`[GET] Request received item at ${resource.url}`);
19
18
  const driveFile = await webdav_utils_1.WebDavUtils.getDriveFileFromResource({
20
19
  url: resource.url,
@@ -26,31 +25,43 @@ class GETRequestHandler {
26
25
  logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Found Drive File`);
27
26
  const { user } = await authService.getAuthDetails();
28
27
  logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Network ready for download`);
29
- const range = req.headers['range'];
30
- const rangeOptions = network_utils_1.NetworkUtils.parseRangeHeader({
31
- range,
32
- totalFileSize: driveFile.size,
33
- });
34
- let contentLength = driveFile.size;
35
- if (rangeOptions) {
36
- logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Range request received:`, { rangeOptions });
37
- contentLength = rangeOptions.rangeSize;
38
- }
39
28
  res.header('Content-Type', 'application/octet-stream');
40
- res.header('Content-length', contentLength.toString());
41
- const writable = new WritableStream({
42
- write(chunk) {
43
- res.write(chunk);
44
- },
45
- close() {
46
- res.end();
47
- },
48
- });
49
- const [executeDownload] = await networkFacade.downloadToStream(driveFile.bucket, user.mnemonic, driveFile.fileId, contentLength, writable, rangeOptions);
50
- logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Download prepared, executing...`);
51
- res.status(200);
52
- await executeDownload;
53
- logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Download ready, replying to client`);
29
+ const fileSize = driveFile.size ?? 0;
30
+ if (fileSize > 0) {
31
+ const range = req.headers['range'];
32
+ const rangeOptions = network_utils_1.NetworkUtils.parseRangeHeader({
33
+ range,
34
+ totalFileSize: fileSize,
35
+ });
36
+ let contentLength = fileSize;
37
+ if (rangeOptions) {
38
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Range request received:`, { rangeOptions });
39
+ contentLength = rangeOptions.rangeSize;
40
+ }
41
+ res.header('Content-length', contentLength.toString());
42
+ const writable = new WritableStream({
43
+ write(chunk) {
44
+ res.write(chunk);
45
+ },
46
+ close() {
47
+ res.end();
48
+ },
49
+ });
50
+ if (!driveFile.fileId) {
51
+ throw new command_types_1.NotValidFileIdError();
52
+ }
53
+ const [executeDownload] = await networkFacade.downloadToStream(driveFile.bucket, user.mnemonic, driveFile.fileId, contentLength, writable, rangeOptions);
54
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Download prepared, executing...`);
55
+ res.status(200);
56
+ await executeDownload;
57
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] ✅ Download ready, replying to client`);
58
+ }
59
+ else {
60
+ logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] File is empty, replying to client with no content`);
61
+ res.header('Content-length', '0');
62
+ res.status(200);
63
+ res.end();
64
+ }
54
65
  };
55
66
  }
56
67
  exports.GETRequestHandler = GETRequestHandler;
@@ -9,7 +9,6 @@ const types_1 = require("@internxt/sdk/dist/drive/storage/types");
9
9
  const cli_utils_1 = require("../../utils/cli.utils");
10
10
  const stream_utils_1 = require("../../utils/stream.utils");
11
11
  const thumbnail_utils_1 = require("../../utils/thumbnail.utils");
12
- const thumbnail_service_1 = require("../../services/thumbnail.service");
13
12
  const async_utils_1 = require("../../utils/async.utils");
14
13
  class PUTRequestHandler {
15
14
  dependencies;
@@ -17,9 +16,9 @@ class PUTRequestHandler {
17
16
  this.dependencies = dependencies;
18
17
  }
19
18
  handle = async (req, res) => {
20
- const contentLength = Number(req.headers['content-length']);
21
- if (!contentLength || isNaN(contentLength) || contentLength <= 0) {
22
- throw new errors_utils_1.UnsupportedMediaTypeError('Empty files are not supported');
19
+ let contentLength = Number(req.headers['content-length']);
20
+ if (!contentLength || Number.isNaN(contentLength) || contentLength <= 0) {
21
+ contentLength = 0;
23
22
  }
24
23
  const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
25
24
  const driveFileItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
@@ -31,7 +30,12 @@ class PUTRequestHandler {
31
30
  throw new errors_utils_1.NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.');
32
31
  }
33
32
  logger_utils_1.webdavLogger.info(`[PUT] Request received for file at ${resource.url}`);
34
- logger_utils_1.webdavLogger.info(`[PUT] Uploading '${resource.name}' to '${resource.parentPath}'`);
33
+ logger_utils_1.webdavLogger.info(`[PUT] Uploading '${resource.name}' (${cli_utils_1.CLIUtils.formatBytesToString(contentLength)}) to '${resource.parentPath}'`);
34
+ const timings = {
35
+ networkUpload: 0,
36
+ driveUpload: 0,
37
+ thumbnailUpload: 0,
38
+ };
35
39
  const parentDriveFolderItem = (await this.dependencies.webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
36
40
  (await this.dependencies.webDavFolderService.createParentPathOrThrow(resource.parentPath));
37
41
  try {
@@ -46,7 +50,6 @@ class PUTRequestHandler {
46
50
  }
47
51
  const { user } = await this.dependencies.authService.getAuthDetails();
48
52
  const fileType = resource.path.ext.replace('.', '');
49
- const timer = cli_utils_1.CLIUtils.timer();
50
53
  let bufferStream;
51
54
  let fileStream = req;
52
55
  const isThumbnailable = (0, thumbnail_utils_1.isFileThumbnailable)(fileType);
@@ -54,30 +57,36 @@ class PUTRequestHandler {
54
57
  bufferStream = new stream_utils_1.BufferStream();
55
58
  fileStream = req.pipe(bufferStream);
56
59
  }
57
- let uploaded = false, aborted = false;
58
- const progressCallback = (progress) => {
59
- if (!uploaded && !aborted) {
60
- logger_utils_1.webdavLogger.info(`[PUT] Upload progress for file ${resource.name}: ${(progress * 100).toFixed(2)}%`);
61
- }
62
- };
63
- const fileId = await new Promise((resolve, reject) => {
64
- const state = this.dependencies.networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
65
- if (err) {
66
- aborted = true;
67
- return reject(err);
68
- }
69
- resolve(res);
70
- }, progressCallback);
71
- res.on('close', async () => {
72
- aborted = true;
73
- if (!uploaded) {
74
- logger_utils_1.webdavLogger.info('[PUT] ❌ HTTP Client has been disconnected, res has been closed.');
75
- state.stop();
60
+ let fileId;
61
+ if (contentLength > 0) {
62
+ let uploaded = false, aborted = false;
63
+ const progressCallback = (progress) => {
64
+ if (!uploaded && !aborted) {
65
+ logger_utils_1.webdavLogger.info(`[PUT] Upload progress for file ${resource.name}: ${(progress * 100).toFixed(2)}%`);
76
66
  }
67
+ };
68
+ const networkUploadTimer = cli_utils_1.CLIUtils.timer();
69
+ fileId = await new Promise((resolve, reject) => {
70
+ const state = this.dependencies.networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
71
+ if (err) {
72
+ aborted = true;
73
+ return reject(err);
74
+ }
75
+ resolve(res);
76
+ }, progressCallback);
77
+ res.on('close', async () => {
78
+ aborted = true;
79
+ if (!uploaded) {
80
+ logger_utils_1.webdavLogger.info('[PUT] ❌ HTTP Client has been disconnected, res has been closed.');
81
+ state.stop();
82
+ }
83
+ });
77
84
  });
78
- });
79
- uploaded = true;
80
- logger_utils_1.webdavLogger.info('[PUT] ✅ File uploaded to network');
85
+ uploaded = true;
86
+ timings.networkUpload = networkUploadTimer.stop();
87
+ logger_utils_1.webdavLogger.info('[PUT] ✅ File uploaded to network');
88
+ }
89
+ const driveTimer = cli_utils_1.CLIUtils.timer();
81
90
  const file = await drive_file_service_1.DriveFileService.instance.createFile({
82
91
  plainName: resource.path.name,
83
92
  type: fileType,
@@ -87,21 +96,27 @@ class PUTRequestHandler {
87
96
  bucket: user.bucket,
88
97
  encryptVersion: types_1.EncryptionVersion.Aes03,
89
98
  });
90
- try {
91
- if (isThumbnailable && bufferStream) {
92
- const thumbnailBuffer = bufferStream.getBuffer();
93
- if (thumbnailBuffer) {
94
- await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, user.bucket, file.uuid, this.dependencies.networkFacade);
95
- }
96
- }
97
- }
98
- catch (error) {
99
- logger_utils_1.webdavLogger.info(`[PUT] ❌ File thumbnail upload failed ${error.message}`);
99
+ timings.driveUpload = driveTimer.stop();
100
+ const thumbnailTimer = cli_utils_1.CLIUtils.timer();
101
+ if (contentLength > 0 && isThumbnailable && bufferStream) {
102
+ void (0, thumbnail_utils_1.tryUploadThumbnail)({
103
+ bufferStream,
104
+ fileType,
105
+ userBucket: user.bucket,
106
+ fileUuid: file.uuid,
107
+ networkFacade: this.dependencies.networkFacade,
108
+ });
100
109
  }
101
- const uploadTime = timer.stop();
102
- logger_utils_1.webdavLogger.info(`[PUT] File uploaded in ${uploadTime}ms to Internxt Drive`);
110
+ timings.thumbnailUpload = thumbnailTimer.stop();
111
+ const totalTime = Object.values(timings).reduce((sum, time) => sum + time, 0);
112
+ const throughputMBps = cli_utils_1.CLIUtils.calculateThroughputMBps(contentLength, timings.networkUpload);
113
+ logger_utils_1.webdavLogger.info(`[PUT] ✅ File uploaded in ${cli_utils_1.CLIUtils.formatDuration(totalTime)} to Internxt Drive`);
114
+ logger_utils_1.webdavLogger.info(`[PUT] Timing breakdown:\n
115
+ Network upload: ${cli_utils_1.CLIUtils.formatDuration(timings.networkUpload)} (${throughputMBps.toFixed(2)} MB/s)\n
116
+ Drive upload: ${cli_utils_1.CLIUtils.formatDuration(timings.driveUpload)}\n
117
+ Thumbnail: ${cli_utils_1.CLIUtils.formatDuration(timings.thumbnailUpload)}\n`);
103
118
  await async_utils_1.AsyncUtils.sleep(500);
104
- logger_utils_1.webdavLogger.info(`[PUT] [RESPONSE-201] ${resource.url} - Returning 201 Created after ${uploadTime}ms (+ 500ms propagation delay)`);
119
+ logger_utils_1.webdavLogger.info(`[PUT] [RESPONSE-201] ${resource.url} - Returning 201 Created after ${cli_utils_1.CLIUtils.formatDuration(totalTime)}`);
105
120
  res.status(201).send();
106
121
  };
107
122
  }
@@ -16,7 +16,7 @@ const ErrorHandlingMiddleware = (err, req, res, _) => {
16
16
  [xml_utils_1.XMLUtils.addDefaultNamespace('responsedescription')]: message,
17
17
  }, {}, 'error');
18
18
  let statusCode = 500;
19
- if ('statusCode' in err && !isNaN(err.statusCode)) {
19
+ if ('statusCode' in err && !Number.isNaN(err.statusCode)) {
20
20
  statusCode = err.statusCode;
21
21
  }
22
22
  res.status(statusCode).send(errorBodyXML);
@@ -4,8 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.WebDavServer = void 0;
7
- const https_1 = __importDefault(require("https"));
8
- const http_1 = __importDefault(require("http"));
7
+ const node_https_1 = __importDefault(require("node:https"));
8
+ const node_http_1 = __importDefault(require("node:http"));
9
9
  const config_service_1 = require("../services/config.service");
10
10
  const OPTIONS_handler_1 = require("./handlers/OPTIONS.handler");
11
11
  const PROPFIND_handler_1 = require("./handlers/PROPFIND.handler");
@@ -136,11 +136,11 @@ class WebDavServer {
136
136
  const plainHttp = configs.protocol === 'http';
137
137
  let server;
138
138
  if (plainHttp) {
139
- server = http_1.default.createServer(this.app);
139
+ server = node_http_1.default.createServer(this.app);
140
140
  }
141
141
  else {
142
142
  const httpsCerts = await network_utils_1.NetworkUtils.getWebdavSSLCerts(configs);
143
- server = https_1.default.createServer(httpsCerts, this.app);
143
+ server = node_https_1.default.createServer(httpsCerts, this.app);
144
144
  }
145
145
  server.requestTimeout = configs.timeoutMinutes * 60 * 1000;
146
146
  server.listen(Number(configs.port), configs.host, undefined, () => {
@@ -1190,6 +1190,67 @@
1190
1190
  "upload-file.js"
1191
1191
  ]
1192
1192
  },
1193
+ "upload-folder": {
1194
+ "aliases": [
1195
+ "upload:folder"
1196
+ ],
1197
+ "args": {},
1198
+ "description": "Upload a folder to Internxt Drive",
1199
+ "examples": [
1200
+ "<%= config.bin %> <%= command.id %>"
1201
+ ],
1202
+ "flags": {
1203
+ "json": {
1204
+ "description": "Format output as json.",
1205
+ "helpGroup": "GLOBAL",
1206
+ "name": "json",
1207
+ "allowNo": false,
1208
+ "type": "boolean"
1209
+ },
1210
+ "non-interactive": {
1211
+ "char": "x",
1212
+ "description": "Prevents the CLI from being interactive. When enabled, the CLI will not request input through the console and will throw errors directly.",
1213
+ "env": "INXT_NONINTERACTIVE",
1214
+ "helpGroup": "helper",
1215
+ "name": "non-interactive",
1216
+ "required": false,
1217
+ "allowNo": false,
1218
+ "type": "boolean"
1219
+ },
1220
+ "folder": {
1221
+ "char": "f",
1222
+ "description": "The path to the folder on your system.",
1223
+ "name": "folder",
1224
+ "required": false,
1225
+ "hasDynamicHelp": false,
1226
+ "multiple": false,
1227
+ "type": "option"
1228
+ },
1229
+ "destination": {
1230
+ "char": "i",
1231
+ "description": "The folder id where the folder is going to be uploaded to. Leave empty for the root folder.",
1232
+ "name": "destination",
1233
+ "required": false,
1234
+ "hasDynamicHelp": false,
1235
+ "multiple": false,
1236
+ "type": "option"
1237
+ }
1238
+ },
1239
+ "hasDynamicHelp": false,
1240
+ "hiddenAliases": [],
1241
+ "id": "upload-folder",
1242
+ "pluginAlias": "@internxt/cli",
1243
+ "pluginName": "@internxt/cli",
1244
+ "pluginType": "core",
1245
+ "strict": true,
1246
+ "enableJsonFlag": true,
1247
+ "isESM": false,
1248
+ "relativePath": [
1249
+ "dist",
1250
+ "commands",
1251
+ "upload-folder.js"
1252
+ ]
1253
+ },
1193
1254
  "webdav-config": {
1194
1255
  "aliases": [],
1195
1256
  "args": {},
@@ -1355,5 +1416,5 @@
1355
1416
  ]
1356
1417
  }
1357
1418
  },
1358
- "version": "1.6.0"
1419
+ "version": "1.6.2"
1359
1420
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "author": "Internxt <hello@internxt.com>",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Internxt CLI to manage your encrypted storage",
5
5
  "scripts": {
6
6
  "build": "yarn clean && tsc",
@@ -36,59 +36,59 @@
36
36
  "/oclif.manifest.json"
37
37
  ],
38
38
  "dependencies": {
39
- "@inquirer/prompts": "7.10.1",
39
+ "@inquirer/prompts": "8.2.0",
40
40
  "@internxt/inxt-js": "2.2.9",
41
41
  "@internxt/lib": "1.4.1",
42
- "@internxt/sdk": "1.11.15",
42
+ "@internxt/sdk": "1.12.0",
43
43
  "@oclif/core": "4.8.0",
44
44
  "@oclif/plugin-autocomplete": "3.2.39",
45
45
  "axios": "1.13.2",
46
46
  "bip39": "3.1.0",
47
- "body-parser": "2.2.0",
47
+ "body-parser": "2.2.2",
48
48
  "cli-progress": "3.12.0",
49
49
  "dayjs": "1.11.19",
50
50
  "dotenv": "17.2.3",
51
- "express": "5.1.0",
51
+ "express": "5.2.1",
52
52
  "express-async-handler": "1.2.0",
53
- "fast-xml-parser": "5.3.2",
54
- "mime-types": "3.0.1",
53
+ "fast-xml-parser": "5.3.3",
54
+ "mime-types": "3.0.2",
55
55
  "open": "11.0.0",
56
- "openpgp": "6.2.2",
56
+ "openpgp": "6.3.0",
57
57
  "otpauth": "9.4.1",
58
- "pm2": "6.0.13",
58
+ "pm2": "6.0.14",
59
59
  "range-parser": "1.2.1",
60
- "selfsigned": "4.0.0",
60
+ "selfsigned": "5.5.0",
61
61
  "tty-table": "5.0.0",
62
- "winston": "3.18.3"
62
+ "winston": "3.19.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@internxt/eslint-config-internxt": "2.0.1",
66
66
  "@internxt/prettier-config": "internxt/prettier-config#v1.0.2",
67
- "@openpgp/web-stream-tools": "0.1.3",
67
+ "@openpgp/web-stream-tools": "0.3.0",
68
68
  "@types/cli-progress": "3.11.6",
69
- "@types/express": "5.0.5",
69
+ "@types/express": "5.0.6",
70
70
  "@types/mime-types": "3.0.1",
71
- "@types/node": "22.18.12",
71
+ "@types/node": "25.0.7",
72
72
  "@types/range-parser": "1.2.7",
73
- "@vitest/coverage-istanbul": "4.0.10",
74
- "@vitest/spy": "4.0.10",
75
- "eslint": "9.39.1",
73
+ "@vitest/coverage-istanbul": "4.0.17",
74
+ "@vitest/spy": "4.0.17",
75
+ "eslint": "9.39.2",
76
76
  "husky": "9.1.7",
77
- "lint-staged": "16.2.6",
77
+ "lint-staged": "16.2.7",
78
78
  "nodemon": "3.1.11",
79
- "oclif": "4.22.47",
80
- "prettier": "3.6.2",
81
- "rimraf": "6.1.0",
79
+ "oclif": "4.22.65",
80
+ "prettier": "3.7.4",
81
+ "rimraf": "6.1.2",
82
82
  "ts-node": "10.9.2",
83
83
  "typescript": "5.9.3",
84
- "vitest": "4.0.10",
84
+ "vitest": "4.0.17",
85
85
  "vitest-mock-express": "2.2.0"
86
86
  },
87
87
  "optionalDependencies": {
88
- "sharp": "0.34.4"
88
+ "sharp": "0.34.5"
89
89
  },
90
90
  "engines": {
91
- "node": ">=22.12.0"
91
+ "node": ">=22.13.0"
92
92
  },
93
93
  "bin": {
94
94
  "internxt": "./bin/run.js"