From 20b0bbd7c1727c7a5acb5599ee27a5e009c3184b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Thu, 14 May 2026 09:50:24 +0200 Subject: [PATCH] Fix types --- src/cli/Commands.ts | 37 +++------ src/cli/index.ts | 2 - src/cli/upload-file-multipart.ts | 44 ----------- src/cli/upload-file.ts | 33 +++----- src/cli/upload-folder-zip.ts | 125 ------------------------------- tests/services/api.test.ts | 6 +- 6 files changed, 25 insertions(+), 222 deletions(-) delete mode 100644 src/cli/upload-file-multipart.ts delete mode 100644 src/cli/upload-folder-zip.ts diff --git a/src/cli/Commands.ts b/src/cli/Commands.ts index 1210923..2da0789 100644 --- a/src/cli/Commands.ts +++ b/src/cli/Commands.ts @@ -1,3 +1,4 @@ +import { Command } from 'commander'; import { logger } from '../lib/utils/logger'; import { buildCommand } from './CommandInterface'; import { createBucket } from './create-bucket'; @@ -7,8 +8,6 @@ import { getDownloadLinks } from './get-download-links'; import { getFileInfo } from './get-filo-info'; import { renameFile } from './rename-file'; import { uploadFile } from './upload-file'; -import { uploadFileMultipart } from './upload-file-multipart'; -import { uploadFolder } from './upload-folder-zip'; function notifyProgramFinished(programName: string) { return () => { @@ -16,7 +15,7 @@ function notifyProgramFinished(programName: string) { }; } -export const uploadFileCommand = buildCommand({ +export const uploadFileCommand: Command = buildCommand({ version: '0.0.1', command: 'upload-file ', description: 'Upload a file', @@ -25,25 +24,7 @@ export const uploadFileCommand = buildCommand({ return uploadFile(path); }); -export const uploadFileMultipartCommand = buildCommand({ - version: '0.0.1', - command: 'upload-file-multipart ', - description: 'Upload a file using multipart', - options: [], -}).action((path) => { - return uploadFileMultipart(path); -}); - -export const uploadFolderZipCommand = buildCommand({ - version: '0.0.1', - command: 'upload-folder-zip ', - description: 'Upload a folder zipped', - options: [], -}).action((path: string) => { - uploadFolder(path).finally(notifyProgramFinished('upload-folder-zip')); -}); - -export const downloadFileCommand = buildCommand({ +export const downloadFileCommand: Command = buildCommand({ version: '0.0.1', command: 'download-file ', description: 'Download a file', @@ -52,7 +33,7 @@ export const downloadFileCommand = buildCommand({ downloadFile(fileId, path, 1).finally(notifyProgramFinished('download-file')); }); -export const downloadFileCommandParallel = buildCommand({ +export const downloadFileCommandParallel: Command = buildCommand({ version: '0.0.1', command: 'download-file-parallel ', description: 'Download a file', @@ -61,7 +42,7 @@ export const downloadFileCommandParallel = buildCommand({ downloadFile(fileId, path, 10).finally(notifyProgramFinished('download-file-parallel')); }); -export const renameFileCommand = buildCommand({ +export const renameFileCommand: Command = buildCommand({ version: '0.0.1', command: 'rename-file ', description: 'Renames a file in the network', @@ -70,7 +51,7 @@ export const renameFileCommand = buildCommand({ renameFile(fileId, newName).finally(notifyProgramFinished('rename-file')); }); -export const getFileInfoCommand = buildCommand({ +export const getFileInfoCommand: Command = buildCommand({ version: '0.0.1', command: 'get-file-info ', description: 'Gets file info', @@ -79,7 +60,7 @@ export const getFileInfoCommand = buildCommand({ getFileInfo(fileId).finally(notifyProgramFinished('get-file-info')); }); -export const createBucketCommand = buildCommand({ +export const createBucketCommand: Command = buildCommand({ version: '0.0.1', command: 'create-bucket ', description: 'Creates a bucket with the given name', @@ -88,7 +69,7 @@ export const createBucketCommand = buildCommand({ createBucket(bucketName).finally(notifyProgramFinished('create-bucket')); }); -export const deleteBucketCommand = buildCommand({ +export const deleteBucketCommand: Command = buildCommand({ version: '0.0.1', command: 'delete-bucket ', description: 'Deletes a bucket given its id', @@ -97,7 +78,7 @@ export const deleteBucketCommand = buildCommand({ deleteBucket(bucketId).finally(notifyProgramFinished('delete-bucket')); }); -export const getDownloadLinksCommand = buildCommand({ +export const getDownloadLinksCommand: Command = buildCommand({ version: '0.0.1', command: 'get-download-links ', description: 'Gets download links of file ids', diff --git a/src/cli/index.ts b/src/cli/index.ts index 015c3a6..1799285 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -7,8 +7,6 @@ import * as commands from './Commands'; const program = new Command(); program.addCommand(commands.uploadFileCommand); -program.addCommand(commands.uploadFileMultipartCommand); -program.addCommand(commands.uploadFolderZipCommand); program.addCommand(commands.downloadFileCommand); program.addCommand(commands.downloadFileCommandParallel); program.addCommand(commands.renameFileCommand); diff --git a/src/cli/upload-file-multipart.ts b/src/cli/upload-file-multipart.ts deleted file mode 100644 index 427c09e..0000000 --- a/src/cli/upload-file-multipart.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { createReadStream, existsSync, statSync } from 'fs'; - -import { logger } from '../lib/utils/logger'; -import { getEnvironment } from './CommandInterface'; -import { EnvService } from './EnvService'; - -export async function uploadFileMultipart(filepath: string) { - if (!existsSync(filepath)) { - logger.error('File "%s" does not exist', filepath); - return process.exit(-1); - } - try { - const network = getEnvironment(); - - const bucketId = EnvService.instance.get('BUCKET_ID'); - - const fileId = await new Promise((resolve: (fileId: string) => void, reject) => { - const state = network.uploadMultipartFile(bucketId, { - progressCallback: (progress: number) => { - logger.info('Progress %s%', (progress * 100).toFixed(2)); - }, - finishedCallback: (err: Error | null, res: string | null) => { - if (err) { - return reject(err); - } - - resolve(res as string); - }, - fileSize: statSync(filepath).size, - source: createReadStream(filepath), - }); - - process.on('SIGINT', () => { - logger.info('Aborting upload'); - network.uploadCancel(state); - }); - }); - - console.log('File %s uploaded', fileId); - } catch (err) { - logger.error('Error uploading file: %s. %s', (err as Error).message ?? '', (err as Error).stack ?? ''); - process.exit(-1); - } -} diff --git a/src/cli/upload-file.ts b/src/cli/upload-file.ts index 2d1f973..cd66fc2 100644 --- a/src/cli/upload-file.ts +++ b/src/cli/upload-file.ts @@ -12,30 +12,21 @@ export async function uploadFile(filepath: string) { try { const network = getEnvironment(); - const bucketId = EnvService.instance.get('BUCKET_ID'); + const abortController = new AbortController(); - const fileId = await new Promise((resolve: (fileId: string) => void, reject) => { - const state = network.upload(bucketId, { - progressCallback: (progress: number) => { - logger.info('Progress %s%', (progress * 100).toFixed(2)); - }, - finishedCallback: (err: Error | null, res: string | null) => { - if (err) { - return reject(err); - } else if (!res) { - return reject('No response received from Network download'); - } - resolve(res); - }, - fileSize: statSync(filepath).size, - source: createReadStream(filepath), - }); + process.on('SIGINT', () => { + logger.info('Aborting upload'); + abortController.abort(); + }); - process.on('SIGINT', () => { - logger.info('Aborting upload'); - network.uploadCancel(state); - }); + const fileId = await network.upload(bucketId, { + progressCallback: (progress: number) => { + logger.info('Progress %s%', (progress * 100).toFixed(2)); + }, + fileSize: statSync(filepath).size, + source: createReadStream(filepath), + abortSignal: abortController.signal, }); console.log('File %s uploaded', fileId); diff --git a/src/cli/upload-folder-zip.ts b/src/cli/upload-folder-zip.ts deleted file mode 100644 index 3051d21..0000000 --- a/src/cli/upload-folder-zip.ts +++ /dev/null @@ -1,125 +0,0 @@ -import archiver from 'archiver'; -import { Cipher, createCipheriv, randomBytes } from 'crypto'; -import { pipeline } from 'stream'; -import { promisify } from 'util'; -import { v4 } from 'uuid'; - -import { Environment } from '..'; -import { EnvironmentConfig } from '../api'; -import { GenerateFileKey } from '../lib/utils/crypto'; -import { HashStream, BytesCounter } from '../lib/utils/streams'; -import { logger } from '../lib/utils/logger'; -import { UploadOptions } from '../lib/core'; -import { EnvService } from './EnvService'; - -const pipelineAsync = promisify(pipeline); -const archive = archiver('zip', { zlib: { level: 9 } }); - -function getEnvironment(fileEncryptionKey?: Buffer, index?: Buffer): Environment { - const envConfig: EnvironmentConfig = { - bridgePass: EnvService.instance.get('BRIDGE_PASS'), - bridgeUser: EnvService.instance.get('BRIDGE_USER'), - encryptionKey: EnvService.instance.get('MNEMONIC'), - bridgeUrl: EnvService.instance.get('BRIDGE_URL'), - appDetails: { - clientName: 'inxt-js', - clientVersion: '1.0', - }, - inject: {}, - }; - - if (envConfig.inject && fileEncryptionKey) { - envConfig.inject.fileEncryptionKey = fileEncryptionKey; - } - - if (envConfig.inject && index) { - envConfig.inject.index = index; - } - - return new Environment(envConfig); -} - -function getEncryptedFolderMeta(folderPath: string, cipher: Cipher): Promise<{ hash: string; size: number }> { - const hasher = new HashStream(); - const counter = new BytesCounter(); - - setTimeout(archive.finalize.bind(archive), 100); - - hasher.on('data', () => null); - - return pipelineAsync(archive.directory(folderPath + '/', false), cipher, counter, hasher).then(() => { - return { - hash: hasher.getHash().toString('hex'), - size: counter.count, - }; - }); -} - -export async function uploadFolder(path: string) { - const encryptionKey = EnvService.instance.get('MNEMONIC'); - const bucketId = EnvService.instance.get('BUCKET_ID'); - const index = randomBytes(32); - const iv = index.slice(0, 16); - const fileEncryptionKey = await GenerateFileKey(encryptionKey, bucketId, index); - - const network = getEnvironment(fileEncryptionKey, index); - - logger.info('Uploading folder "%s"', path); - logger.debug( - 'Provided params { bucketId: %s, bridgeApi: %s, bridgeUser: %s, directoryPath: %s }', - bucketId, - network.config.bridgeUrl, - network.config.bridgeUser, - path, - ); - - const cipher = createCipheriv('aes-256-ctr', fileEncryptionKey, iv); - const { hash, size } = await getEncryptedFolderMeta(path, cipher); - const networkFilename = v4(); - - const archiverSetup = archiver('zip', { zlib: { level: 9 } }); - const directoryStream = archiverSetup.directory(path + '/', false); - archiverSetup.finalize(); - - logger.debug('directory hash zipped is %s', hash); - logger.debug('directory ziped size is %s', size); - logger.info('Network name is %s', networkFilename); - - type ResolveFunction = (res: null) => void; - type RejectFunction = (err: Error) => void; - - const finishCbGenerator = (resolve: ResolveFunction, reject: RejectFunction) => { - return (err: Error | null) => { - if (err) { - reject(err); - } else { - resolve(null); - } - }; - }; - - const uploadOptionsGenerator = (resolve: ResolveFunction, reject: RejectFunction): UploadOptions => ({ - source: directoryStream, - fileSize: size, - progressCallback: (progress: number) => { - logger.debug('Progress %s%', (progress * 100).toFixed(2)); - }, - finishedCallback: finishCbGenerator(resolve, reject), - }); - - await new Promise((resolve, reject) => { - const state = network.upload(bucketId, uploadOptionsGenerator(resolve, reject)); - - process.on('SIGINT', () => network.uploadCancel(state)); - }) - .then((fileId) => { - logger.info('File upload finished. File id: %s', fileId); - - process.exit(0); - }) - .catch((err) => { - logger.error('Error uploading file: %s', err.message); - - process.exit(-1); - }); -} diff --git a/tests/services/api.test.ts b/tests/services/api.test.ts index d1f07a1..086f085 100644 --- a/tests/services/api.test.ts +++ b/tests/services/api.test.ts @@ -3,18 +3,20 @@ import { expect } from 'chai'; import { generateShardMeta } from '../mocks'; import { Bridge } from '../../src/services/api'; import { Methods } from '../../src/lib'; +import { AppDetails } from '@internxt/sdk/dist/shared'; const bridgeUrl = 'https://api.internxt.com'; const bridgePass = 'bridgePass'; const bridgeUser = 'fake@user.com'; -const bridge = new Bridge({ bridgePass, bridgeUser, bridgeUrl }); +const appDetails: AppDetails = { clientName: 'clientName', clientVersion: '1.0.0' }; +const bridge = new Bridge({ bridgePass, bridgeUser, bridgeUrl, appDetails }); describe('services/api.ts', () => { describe('Bridge', () => { describe('# constructor()', () => { it('Should throw if bridge url is empty', () => { expect(() => { - new Bridge({ bridgeUser: 'fake@user.com', bridgePass: 'fakePass', bridgeUrl: '' }); + new Bridge({ bridgeUser: 'fake@user.com', bridgePass: 'fakePass', bridgeUrl: '', appDetails }); }).to.throw('Empty bridge url'); }); });