From 63f1c76862dfbceacb2c508dff2acbbad3904e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Thu, 5 Mar 2026 12:52:23 +0100 Subject: [PATCH 1/6] Add abort signal to upload --- package.json | 2 +- src/network/index.ts | 58 ++++++++----------------- src/network/upload.ts | 28 +++--------- src/shared/http/client.ts | 4 +- test/network/network.test.ts | 82 +++++++++--------------------------- test/network/upload.test.ts | 77 ++++++++++++++++----------------- 6 files changed, 83 insertions(+), 168 deletions(-) diff --git a/package.json b/package.json index 00bfee31..2d8bad95 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@internxt/sdk", "author": "Internxt ", - "version": "1.15.1", + "version": "1.15.2", "description": "An sdk for interacting with Internxt's services", "repository": { "type": "git", diff --git a/src/network/index.ts b/src/network/index.ts index b8ae8112..b9e4661a 100644 --- a/src/network/index.ts +++ b/src/network/index.ts @@ -19,14 +19,6 @@ const uuidValidate = (str: string): boolean => UUID_REGEX.test(str); export * from './types'; -export class DuplicatedIndexesError extends Error { - constructor() { - super('Duplicated indexes found'); - - Object.setPrototypeOf(this, DuplicatedIndexesError.prototype); - } -} - export class InvalidFileIndexError extends Error { constructor() { super('Invalid file index'); @@ -35,14 +27,6 @@ export class InvalidFileIndexError extends Error { } } -export class InvalidUploadIndexError extends Error { - constructor() { - super('Invalid upload index'); - - Object.setPrototypeOf(this, InvalidUploadIndexError.prototype); - } -} - export class InvalidUploadSizeError extends Error { constructor() { super('Invalid size'); @@ -89,21 +73,13 @@ export class Network { return this.auth; } - startUpload(bucketId: string, payload: StartUploadPayload, parts = 1): Promise { - let totalSize = 0; - - for (const { index, size } of payload.uploads) { - if (index < 0) { - throw new InvalidUploadIndexError(); - } - if (size < 0) { - throw new InvalidUploadSizeError(); - } - totalSize += size; + startUpload(bucketId: string, fileSize: number, signal: AbortSignal, parts = 1): Promise { + if (fileSize < 0) { + throw new InvalidUploadSizeError(); } const MB100 = 100 * 1024 * 1024; - if (totalSize < MB100 && parts > 1) { + if (fileSize < MB100 && parts > 1) { throw new FileTooSmallForMultipartError(); } @@ -111,15 +87,10 @@ export class Network { throw new InvalidMultipartValueError(); } - const uploadIndexesWithoutDuplicates = new Set(payload.uploads.map((upload) => upload.index)); - - if (uploadIndexesWithoutDuplicates.size < payload.uploads.length) { - throw new DuplicatedIndexesError(); - } - return Network.startUpload( bucketId, - payload, + { uploads: [{ index: 0, size: fileSize }] }, + signal, { client: this.client, appDetails: this.appDetails, @@ -129,7 +100,7 @@ export class Network { ); } - finishUpload(bucketId: string, payload: FinishUploadPayload): Promise { + finishUpload(bucketId: string, payload: FinishUploadPayload, signal: AbortSignal): Promise { const { index, shards } = payload; if (!isHexString(index) || index.length !== 64) { throw new InvalidFileIndexError(); @@ -141,14 +112,18 @@ export class Network { } } - return Network.finishUpload(bucketId, payload, { + return Network.finishUpload(bucketId, payload, signal, { client: this.client, appDetails: this.appDetails, auth: this.auth, }); } - finishMultipartUpload(bucketId: string, payload: FinishMultipartUploadPayload): Promise { + finishMultipartUpload( + bucketId: string, + payload: FinishMultipartUploadPayload, + signal: AbortSignal, + ): Promise { const { index, shards } = payload; if (!isHexString(index) || index.length !== 64) { throw new InvalidFileIndexError(); @@ -167,7 +142,7 @@ export class Network { } } - return Network.finishUpload(bucketId, payload, { + return Network.finishUpload(bucketId, payload, signal, { client: this.client, appDetails: this.appDetails, auth: this.auth, @@ -203,6 +178,7 @@ export class Network { static startUpload( bucketId: string, payload: StartUploadPayload, + signal: AbortSignal, { client, appDetails, auth }: NetworkRequestConfig, parts = 1, ) { @@ -211,6 +187,7 @@ export class Network { `/v2/buckets/${bucketId}/files/start?multiparts=${parts}`, payload, headers, + signal, ); } @@ -223,10 +200,11 @@ export class Network { private static finishUpload( bucketId: string, payload: FinishUploadPayload | FinishMultipartUploadPayload, + signal: AbortSignal, { client, appDetails, auth }: NetworkRequestConfig, ) { const headers = Network.headersWithBasicAuth(appDetails, auth); - return client.post(`/v2/buckets/${bucketId}/files/finish`, payload, headers); + return client.post(`/v2/buckets/${bucketId}/files/finish`, payload, headers, signal); } /** diff --git a/src/network/upload.ts b/src/network/upload.ts index 41d8a9fb..47846fee 100644 --- a/src/network/upload.ts +++ b/src/network/upload.ts @@ -15,6 +15,7 @@ export async function uploadFile( bucketId: string, mnemonic: string, fileSize: number, + signal: AbortSignal, encryptFile: EncryptFileFunction, uploadFile: UploadFileFunction, ): Promise { @@ -33,14 +34,7 @@ export async function uploadFile( iv = index.slice(0, 16); key = await crypto.generateFileKey(mnemonic, bucketId, index); - const { uploads } = await network.startUpload(bucketId, { - uploads: [ - { - index: 0, - size: fileSize, - }, - ], - }); + const { uploads } = await network.startUpload(bucketId, fileSize, signal); const [{ url, uuid }] = uploads; @@ -56,7 +50,7 @@ export async function uploadFile( shards: [{ hash, uuid }], }; - const finishUploadResponse = await network.finishUpload(bucketId, finishUploadPayload); + const finishUploadResponse = await network.finishUpload(bucketId, finishUploadPayload, signal); return finishUploadResponse.id; } catch (err) { @@ -84,6 +78,7 @@ export async function uploadMultipartFile( bucketId: string, mnemonic: string, fileSize: number, + signal: AbortSignal, encryptFile: EncryptFileFunction, uploadMultiparts: UploadFileMultipartFunction, parts = 1, @@ -98,18 +93,7 @@ export async function uploadMultipartFile( const iv = index.slice(0, 16); const key = await crypto.generateFileKey(mnemonic, bucketId, index); - const { uploads } = await network.startUpload( - bucketId, - { - uploads: [ - { - index: 0, - size: fileSize, - }, - ], - }, - parts, - ); + const { uploads } = await network.startUpload(bucketId, fileSize, signal, parts); const [{ urls, uuid, UploadId }] = uploads; @@ -128,7 +112,7 @@ export async function uploadMultipartFile( shards: [{ hash, uuid, UploadId, parts: uploadedPartsReference }], }; - const finishUploadResponse = await network.finishUpload(bucketId, finishUploadPayload); + const finishUploadResponse = await network.finishUpload(bucketId, finishUploadPayload, signal); return finishUploadResponse.id; } diff --git a/src/shared/http/client.ts b/src/shared/http/client.ts index 1d6605ad..9f361e1f 100644 --- a/src/shared/http/client.ts +++ b/src/shared/http/client.ts @@ -129,8 +129,8 @@ export class HttpClient { * @param params * @param headers */ - public post(url: URL, params: Parameters, headers: Headers): Promise { - return this.execute(() => this.axios.post(url, params, { headers })); + public post(url: URL, params: Parameters, headers: Headers, signal?: AbortSignal): Promise { + return this.execute(() => this.axios.post(url, params, { headers, signal })); } /** diff --git a/test/network/network.test.ts b/test/network/network.test.ts index 535c9c43..2c671027 100644 --- a/test/network/network.test.ts +++ b/test/network/network.test.ts @@ -2,13 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { HttpClient } from '../../src/shared/http/client'; import { AppDetails } from '../../src/shared'; -import { - DuplicatedIndexesError, - InvalidFileIndexError, - InvalidUploadIndexError, - InvalidUploadSizeError, - Network, -} from '../../src/network/index'; +import { InvalidFileIndexError, Network, InvalidUploadSizeError } from '../../src/network/index'; import { headersWithBasicAuth } from '../../src/shared/headers/index'; import { StartUploadPayload, @@ -23,12 +17,11 @@ const validHex = '2e1884c34f174110ca6e324e7b745754b3d6356b53ef9f594b960fd5340500 const url = 'http://internxt.com'; -const invalidIndex = -1; -const validIndex = 0; - const invalidSize = -33; const validSize = 1; +const abortSignal = new AbortController().signal; + describe('network ', () => { beforeEach(() => { vi.restoreAllMocks(); @@ -40,66 +33,24 @@ describe('network ', () => { const idBucket = 'id-bucket'; try { - await client.startUpload(idBucket, { - uploads: [{ index: validIndex, size: invalidSize }], - }); + await client.startUpload(idBucket, invalidSize, abortSignal); fail('Expected function to throw an error, but it did not.'); } catch (err) { expect(err).toBeInstanceOf(InvalidUploadSizeError); } }); - it('Should throw if an invalid index is provided', async () => { - const { client } = clientAndHeadersWithBasicAuth(); - const idBucket = 'id-bucket'; - - try { - await client.startUpload(idBucket, { - uploads: [{ index: invalidIndex, size: validSize }], - }); - fail('Expected function to throw an error, but it did not.'); - } catch (err) { - expect(err).toBeInstanceOf(InvalidUploadIndexError); - } - }); - - it('Should throw if an index is duplicated', async () => { - const { client } = clientAndHeadersWithBasicAuth(); - const idBucket = 'id-bucket'; - - try { - await client.startUpload(idBucket, { - uploads: [ - { index: validIndex, size: validSize }, - { index: validIndex, size: validSize }, - ], - }); - fail('Expected function to throw an error, but it did not.'); - } catch (err) { - expect(err).toBeInstanceOf(DuplicatedIndexesError); - } - }); - it('Should work properly if the input is valid', async () => { const { client } = clientAndHeadersWithBasicAuth(); const idBucket = 'id-bucket'; - const uploads = [ - { index: validIndex, size: validSize }, - { index: validIndex + 1, size: validSize }, - ]; const expected = { - uploads: uploads.map((u) => ({ - index: u.index, - uuid: validUUID, - url, - urls: null, - })), + uploads: [{ index: 0, uuid: validUUID, url, urls: null }], }; vi.spyOn(Network, 'startUpload').mockResolvedValue(expected); - const received = await client.startUpload(idBucket, { uploads }); + const received = await client.startUpload(idBucket, validSize, abortSignal); expect(received).toStrictEqual(expected); }); @@ -120,7 +71,7 @@ describe('network ', () => { }; try { - const promise = await client.finishUpload(idBucket, invalidIndexPayload); + const promise = await client.finishUpload(idBucket, invalidIndexPayload, abortSignal); expect(promise).toBeUndefined(); } catch (err) { expect(err).toBeInstanceOf(InvalidFileIndexError); @@ -139,7 +90,7 @@ describe('network ', () => { // Act try { - const promise = await client.finishUpload(idBucket, invalidUUIDPayload); + const promise = await client.finishUpload(idBucket, invalidUUIDPayload, abortSignal); expect(promise).toBeUndefined(); } catch (err) { // Assert @@ -152,17 +103,18 @@ describe('network ', () => { // Arrange const { client, headers } = clientAndHeadersWithBasicAuth(); const idBucket = 'id-bucket'; + const size = 40; const validStartUploadPayload: StartUploadPayload = { - uploads: [{ index: 0, size: 40 }], + uploads: [{ index: 0, size }], }; const resolvesTo: StartUploadResponse = { - uploads: [{ index: validIndex, uuid: validUUID, url: '', urls: null }], + uploads: [{ index: 0, uuid: validUUID, url: '', urls: null }], }; const callStub = vi.spyOn(HttpClient.prototype, 'post').mockResolvedValue(resolvesTo); const staticStartUpload = vi.spyOn(Network.prototype, 'startUpload'); // Act - const response = await client.startUpload(idBucket, validStartUploadPayload); + const response = await client.startUpload(idBucket, size, abortSignal); // Assert expect(response).toEqual(resolvesTo); @@ -171,6 +123,7 @@ describe('network ', () => { `/v2/buckets/${idBucket}/files/start?multiparts=1`, validStartUploadPayload, headers, + abortSignal, ); }); @@ -201,12 +154,17 @@ describe('network ', () => { const staticFinishUpload = vi.spyOn(Network.prototype, 'finishUpload'); // Act - const response = await client.finishUpload(idBucket, validFinishUploadPayload); + const response = await client.finishUpload(idBucket, validFinishUploadPayload, abortSignal); // Assert expect(response).toEqual(resolvesTo); expect(staticFinishUpload).toHaveBeenCalled(); - expect(callStub).toHaveBeenCalledWith(`/v2/buckets/${idBucket}/files/finish`, validFinishUploadPayload, headers); + expect(callStub).toHaveBeenCalledWith( + `/v2/buckets/${idBucket}/files/finish`, + validFinishUploadPayload, + headers, + abortSignal, + ); }); it('should call static getDownloadLinks with correct parameters', async () => { diff --git a/test/network/upload.test.ts b/test/network/upload.test.ts index 4f9368bf..318fb062 100644 --- a/test/network/upload.test.ts +++ b/test/network/upload.test.ts @@ -10,6 +10,7 @@ const fakeFileId = 'aaaaaa'; const fakeBucketId = 'fake-bucket-id'; const fakeHash = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; const fakeMnemonic = 'test test test test test test test test'; +const abortSignal = new AbortController().signal; const crypto: Crypto = { validateMnemonic: () => { return false; @@ -77,44 +78,39 @@ describe('network/upload', () => { const encryptFileMock = vi.fn(); const uploadFileMock = vi.fn().mockReturnValue(fakeHash); - try { - const receivedFileId = await uploadFile( - network, - crypto, - bucketId, - mnemonic, - fileSize, - encryptFileMock, - uploadFileMock, - ); - - expect(validateMnemonicStub).toHaveBeenCalledOnce(); - expect(validateMnemonicStub).toHaveBeenCalledWith(mnemonic); - - expect(randomBytesStub).toHaveBeenCalledOnce(); - expect(randomBytesStub).toHaveBeenCalledWith(ALGORITHMS.AES256CTR.ivSize); - - expect(generateFileKeyStub).toHaveBeenCalledOnce(); - expect(generateFileKeyStub).toHaveBeenCalledWith(mnemonic, bucketId, bufferizedIndex); - - expect(startUploadStub).toHaveBeenCalledOnce(); - expect(startUploadStub).toHaveBeenCalledWith(bucketId, { - uploads: [ - { - index: 0, - size: fileSize, - }, - ], - }); + const receivedFileId = await uploadFile( + network, + crypto, + bucketId, + mnemonic, + fileSize, + abortSignal, + encryptFileMock, + uploadFileMock, + ); + + expect(validateMnemonicStub).toHaveBeenCalledOnce(); + expect(validateMnemonicStub).toHaveBeenCalledWith(mnemonic); - expect(encryptFileMock).toHaveBeenCalledTimes(1); - expect(encryptFileMock).toHaveBeenCalledWith(ALGORITHMS.AES256CTR.type, key, bufferizedIndex.slice(0, 16)); + expect(randomBytesStub).toHaveBeenCalledOnce(); + expect(randomBytesStub).toHaveBeenCalledWith(ALGORITHMS.AES256CTR.ivSize); - expect(uploadFileMock).toHaveBeenCalledTimes(1); - expect(uploadFileMock).toHaveBeenCalledWith(fakeUrl); + expect(generateFileKeyStub).toHaveBeenCalledOnce(); + expect(generateFileKeyStub).toHaveBeenCalledWith(mnemonic, bucketId, bufferizedIndex); - expect(finishUploadStub).toHaveBeenCalledOnce(); - expect(finishUploadStub).toHaveBeenCalledWith(bucketId, { + expect(startUploadStub).toHaveBeenCalledOnce(); + expect(startUploadStub).toHaveBeenCalledWith(bucketId, fileSize, abortSignal); + + expect(encryptFileMock).toHaveBeenCalledTimes(1); + expect(encryptFileMock).toHaveBeenCalledWith(ALGORITHMS.AES256CTR.type, key, bufferizedIndex.slice(0, 16)); + + expect(uploadFileMock).toHaveBeenCalledTimes(1); + expect(uploadFileMock).toHaveBeenCalledWith(fakeUrl); + + expect(finishUploadStub).toHaveBeenCalledOnce(); + expect(finishUploadStub).toHaveBeenCalledWith( + bucketId, + { index, shards: [ { @@ -122,12 +118,11 @@ describe('network/upload', () => { uuid: fakeUuid, }, ], - }); + }, + abortSignal, + ); - expect(receivedFileId).toEqual(fileId); - } catch { - fail('Expected function to not throw an error, but it did.'); - } + expect(receivedFileId).toEqual(fileId); }); it('Should throw if the mnemonic is invalid', async () => { @@ -139,7 +134,7 @@ describe('network/upload', () => { const randomBytes = vi.spyOn(crypto, 'randomBytes').mockReturnValue(Buffer.from('')); try { - await uploadFile(network, crypto, bucketId, mnemonic, fileSize, vi.fn(), vi.fn()); + await uploadFile(network, crypto, bucketId, mnemonic, fileSize, abortSignal, vi.fn(), vi.fn()); fail('Expected function to throw an error, but it did not.'); } catch (err) { From 0e618d4afd96a3312b8f8d5e3ff8cfca4ea8f93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Thu, 5 Mar 2026 16:59:42 +0100 Subject: [PATCH 2/6] Wrap into async and await --- src/network/index.ts | 40 +++++++++++++++++++++++---------------- src/shared/http/client.ts | 32 +++++++++++++++---------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/network/index.ts b/src/network/index.ts index b9e4661a..b3bbb2b1 100644 --- a/src/network/index.ts +++ b/src/network/index.ts @@ -73,7 +73,7 @@ export class Network { return this.auth; } - startUpload(bucketId: string, fileSize: number, signal: AbortSignal, parts = 1): Promise { + async startUpload(bucketId: string, fileSize: number, signal: AbortSignal, parts = 1): Promise { if (fileSize < 0) { throw new InvalidUploadSizeError(); } @@ -87,7 +87,7 @@ export class Network { throw new InvalidMultipartValueError(); } - return Network.startUpload( + return await Network.startUpload( bucketId, { uploads: [{ index: 0, size: fileSize }] }, signal, @@ -100,7 +100,11 @@ export class Network { ); } - finishUpload(bucketId: string, payload: FinishUploadPayload, signal: AbortSignal): Promise { + async finishUpload( + bucketId: string, + payload: FinishUploadPayload, + signal: AbortSignal, + ): Promise { const { index, shards } = payload; if (!isHexString(index) || index.length !== 64) { throw new InvalidFileIndexError(); @@ -112,14 +116,14 @@ export class Network { } } - return Network.finishUpload(bucketId, payload, signal, { + return await Network.finishUpload(bucketId, payload, signal, { client: this.client, appDetails: this.appDetails, auth: this.auth, }); } - finishMultipartUpload( + async finishMultipartUpload( bucketId: string, payload: FinishMultipartUploadPayload, signal: AbortSignal, @@ -142,15 +146,15 @@ export class Network { } } - return Network.finishUpload(bucketId, payload, signal, { + return await Network.finishUpload(bucketId, payload, signal, { client: this.client, appDetails: this.appDetails, auth: this.auth, }); } - getDownloadLinks(bucketId: string, fileId: string, token?: string): Promise { - return Network.getDownloadLinks( + async getDownloadLinks(bucketId: string, fileId: string, token?: string): Promise { + return await Network.getDownloadLinks( bucketId, fileId, { @@ -175,7 +179,7 @@ export class Network { * @param bucketId * @param uploads */ - static startUpload( + static async startUpload( bucketId: string, payload: StartUploadPayload, signal: AbortSignal, @@ -183,7 +187,7 @@ export class Network { parts = 1, ) { const headers = Network.headersWithBasicAuth(appDetails, auth); - return client.post( + return await client.post( `/v2/buckets/${bucketId}/files/start?multiparts=${parts}`, payload, headers, @@ -197,14 +201,14 @@ export class Network { * @param index * @param shards */ - private static finishUpload( + private static async finishUpload( bucketId: string, payload: FinishUploadPayload | FinishMultipartUploadPayload, signal: AbortSignal, { client, appDetails, auth }: NetworkRequestConfig, ) { const headers = Network.headersWithBasicAuth(appDetails, auth); - return client.post(`/v2/buckets/${bucketId}/files/finish`, payload, headers, signal); + return await client.post(`/v2/buckets/${bucketId}/files/finish`, payload, headers, signal); } /** @@ -212,7 +216,7 @@ export class Network { * @param bucketId * @param file */ - private static getDownloadLinks( + private static async getDownloadLinks( bucketId: string, fileId: string, { client, appDetails, auth }: NetworkRequestConfig, @@ -223,7 +227,7 @@ export class Network { ? Network.headersWithAuthToken(appDetails, token) : Network.headersWithBasicAuth(appDetails, auth); - return client.get(`/buckets/${bucketId}/files/${fileId}/info`, { + return await client.get(`/buckets/${bucketId}/files/${fileId}/info`, { ...headers, 'x-api-version': '2', }); @@ -234,9 +238,13 @@ export class Network { * @param bucketId * @param file */ - private static deleteFile(bucketId: string, fileId: string, { client, appDetails, auth }: NetworkRequestConfig) { + private static async deleteFile( + bucketId: string, + fileId: string, + { client, appDetails, auth }: NetworkRequestConfig, + ) { const headers = Network.headersWithBasicAuth(appDetails, auth); - return client.delete(`/v2/buckets/${bucketId}/files/${fileId}`, headers); + return await client.delete(`/v2/buckets/${bucketId}/files/${fileId}`, headers); } /** diff --git a/src/shared/http/client.ts b/src/shared/http/client.ts index 9f361e1f..de070ee6 100644 --- a/src/shared/http/client.ts +++ b/src/shared/http/client.ts @@ -85,8 +85,8 @@ export class HttpClient { * @param url * @param headers */ - public get(url: URL, headers: Headers): Promise { - return this.execute(() => this.axios.get(url, { headers })); + public async get(url: URL, headers: Headers): Promise { + return await this.execute(() => this.axios.get(url, { headers })); } /** @@ -95,8 +95,8 @@ export class HttpClient { * @param params * @param headers */ - public getWithParams(url: URL, params: Parameters, headers: Headers): Promise { - return this.execute(() => this.axios.get(url, { params, headers })); + public async getWithParams(url: URL, params: Parameters, headers: Headers): Promise { + return await this.execute(() => this.axios.get(url, { params, headers })); } /** @@ -129,8 +129,8 @@ export class HttpClient { * @param params * @param headers */ - public post(url: URL, params: Parameters, headers: Headers, signal?: AbortSignal): Promise { - return this.execute(() => this.axios.post(url, params, { headers, signal })); + public async post(url: URL, params: Parameters, headers: Headers, signal?: AbortSignal): Promise { + return await this.execute(() => this.axios.post(url, params, { headers, signal })); } /** @@ -139,8 +139,8 @@ export class HttpClient { * @param params * @param headers */ - public postForm(url: URL, params: Parameters, headers: Headers): Promise { - return this.execute(() => this.axios.postForm(url, params, { headers })); + public async postForm(url: URL, params: Parameters, headers: Headers): Promise { + return await this.execute(() => this.axios.postForm(url, params, { headers })); } /** @@ -175,8 +175,8 @@ export class HttpClient { * @param params * @param headers */ - public patch(url: URL, params: Parameters, headers: Headers): Promise { - return this.execute(() => this.axios.patch(url, params, { headers })); + public async patch(url: URL, params: Parameters, headers: Headers): Promise { + return await this.execute(() => this.axios.patch(url, params, { headers })); } /** @@ -185,8 +185,8 @@ export class HttpClient { * @param params * @param headers */ - public put(url: URL, params: Parameters, headers: Headers): Promise { - return this.execute(() => this.axios.put(url, params, { headers })); + public async put(url: URL, params: Parameters, headers: Headers): Promise { + return await this.execute(() => this.axios.put(url, params, { headers })); } /** @@ -195,8 +195,8 @@ export class HttpClient { * @param params * @param headers */ - public putForm(url: URL, params: Parameters, headers: Headers): Promise { - return this.execute(() => this.axios.putForm(url, params, { headers })); + public async putForm(url: URL, params: Parameters, headers: Headers): Promise { + return await this.execute(() => this.axios.putForm(url, params, { headers })); } /** @@ -205,8 +205,8 @@ export class HttpClient { * @param headers * @param params */ - public delete(url: URL, headers: Headers, params?: Parameters): Promise { - return this.execute(() => this.axios.delete(url, { headers, data: params })); + public async delete(url: URL, headers: Headers, params?: Parameters): Promise { + return await this.execute(() => this.axios.delete(url, { headers, data: params })); } /** From 06f8a19870300e0b547da2b5200c6cfff9f2ece2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Fri, 6 Mar 2026 09:05:03 +0100 Subject: [PATCH 3/6] Make signal optional --- src/network/index.ts | 44 +++++++++++++++++++++++-------------- src/network/upload.ts | 4 ++-- test/network/upload.test.ts | 2 +- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/network/index.ts b/src/network/index.ts index b3bbb2b1..2b62af17 100644 --- a/src/network/index.ts +++ b/src/network/index.ts @@ -73,8 +73,8 @@ export class Network { return this.auth; } - async startUpload(bucketId: string, fileSize: number, signal: AbortSignal, parts = 1): Promise { - if (fileSize < 0) { + async startUpload(bucketId: string, fileSize: number, signal?: AbortSignal, parts = 1): Promise { + if (fileSize <= 0) { throw new InvalidUploadSizeError(); } @@ -90,12 +90,12 @@ export class Network { return await Network.startUpload( bucketId, { uploads: [{ index: 0, size: fileSize }] }, - signal, { client: this.client, appDetails: this.appDetails, auth: this.auth, }, + signal, parts, ); } @@ -103,7 +103,7 @@ export class Network { async finishUpload( bucketId: string, payload: FinishUploadPayload, - signal: AbortSignal, + signal?: AbortSignal, ): Promise { const { index, shards } = payload; if (!isHexString(index) || index.length !== 64) { @@ -116,17 +116,22 @@ export class Network { } } - return await Network.finishUpload(bucketId, payload, signal, { - client: this.client, - appDetails: this.appDetails, - auth: this.auth, - }); + return await Network.finishUpload( + bucketId, + payload, + { + client: this.client, + appDetails: this.appDetails, + auth: this.auth, + }, + signal, + ); } async finishMultipartUpload( bucketId: string, payload: FinishMultipartUploadPayload, - signal: AbortSignal, + signal?: AbortSignal, ): Promise { const { index, shards } = payload; if (!isHexString(index) || index.length !== 64) { @@ -146,11 +151,16 @@ export class Network { } } - return await Network.finishUpload(bucketId, payload, signal, { - client: this.client, - appDetails: this.appDetails, - auth: this.auth, - }); + return await Network.finishUpload( + bucketId, + payload, + { + client: this.client, + appDetails: this.appDetails, + auth: this.auth, + }, + signal, + ); } async getDownloadLinks(bucketId: string, fileId: string, token?: string): Promise { @@ -182,8 +192,8 @@ export class Network { static async startUpload( bucketId: string, payload: StartUploadPayload, - signal: AbortSignal, { client, appDetails, auth }: NetworkRequestConfig, + signal?: AbortSignal, parts = 1, ) { const headers = Network.headersWithBasicAuth(appDetails, auth); @@ -204,8 +214,8 @@ export class Network { private static async finishUpload( bucketId: string, payload: FinishUploadPayload | FinishMultipartUploadPayload, - signal: AbortSignal, { client, appDetails, auth }: NetworkRequestConfig, + signal?: AbortSignal, ) { const headers = Network.headersWithBasicAuth(appDetails, auth); return await client.post(`/v2/buckets/${bucketId}/files/finish`, payload, headers, signal); diff --git a/src/network/upload.ts b/src/network/upload.ts index 47846fee..69348e1d 100644 --- a/src/network/upload.ts +++ b/src/network/upload.ts @@ -15,9 +15,9 @@ export async function uploadFile( bucketId: string, mnemonic: string, fileSize: number, - signal: AbortSignal, encryptFile: EncryptFileFunction, uploadFile: UploadFileFunction, + signal?: AbortSignal, ): Promise { let index: BinaryData; let iv: BinaryData; @@ -78,9 +78,9 @@ export async function uploadMultipartFile( bucketId: string, mnemonic: string, fileSize: number, - signal: AbortSignal, encryptFile: EncryptFileFunction, uploadMultiparts: UploadFileMultipartFunction, + signal?: AbortSignal, parts = 1, ): Promise { const mnemonicIsValid = crypto.validateMnemonic(mnemonic); diff --git a/test/network/upload.test.ts b/test/network/upload.test.ts index 318fb062..a08015ba 100644 --- a/test/network/upload.test.ts +++ b/test/network/upload.test.ts @@ -84,9 +84,9 @@ describe('network/upload', () => { bucketId, mnemonic, fileSize, - abortSignal, encryptFileMock, uploadFileMock, + abortSignal, ); expect(validateMnemonicStub).toHaveBeenCalledOnce(); From 84b7d49a46db7ca3b2ee37d1d59fdc420e4cf6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Fri, 6 Mar 2026 09:06:30 +0100 Subject: [PATCH 4/6] Update upload.test.ts --- test/network/upload.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/network/upload.test.ts b/test/network/upload.test.ts index a08015ba..a00fb760 100644 --- a/test/network/upload.test.ts +++ b/test/network/upload.test.ts @@ -134,7 +134,7 @@ describe('network/upload', () => { const randomBytes = vi.spyOn(crypto, 'randomBytes').mockReturnValue(Buffer.from('')); try { - await uploadFile(network, crypto, bucketId, mnemonic, fileSize, abortSignal, vi.fn(), vi.fn()); + await uploadFile(network, crypto, bucketId, mnemonic, fileSize, vi.fn(), vi.fn(), abortSignal); fail('Expected function to throw an error, but it did not.'); } catch (err) { From 4f5af1e0a13df337cab7a4b3426c3bb8e81c55e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Fri, 6 Mar 2026 09:11:16 +0100 Subject: [PATCH 5/6] Update index.ts --- src/network/index.ts | 58 +++++++++++--------------------------------- 1 file changed, 14 insertions(+), 44 deletions(-) diff --git a/src/network/index.ts b/src/network/index.ts index 2b62af17..1a39d937 100644 --- a/src/network/index.ts +++ b/src/network/index.ts @@ -87,17 +87,7 @@ export class Network { throw new InvalidMultipartValueError(); } - return await Network.startUpload( - bucketId, - { uploads: [{ index: 0, size: fileSize }] }, - { - client: this.client, - appDetails: this.appDetails, - auth: this.auth, - }, - signal, - parts, - ); + return await this.startUploadRequest(bucketId, { uploads: [{ index: 0, size: fileSize }] }, signal, parts); } async finishUpload( @@ -116,16 +106,7 @@ export class Network { } } - return await Network.finishUpload( - bucketId, - payload, - { - client: this.client, - appDetails: this.appDetails, - auth: this.auth, - }, - signal, - ); + return await this.finishUploadRequest(bucketId, payload, signal); } async finishMultipartUpload( @@ -151,16 +132,7 @@ export class Network { } } - return await Network.finishUpload( - bucketId, - payload, - { - client: this.client, - appDetails: this.appDetails, - auth: this.auth, - }, - signal, - ); + return await this.finishUploadRequest(bucketId, payload, signal); } async getDownloadLinks(bucketId: string, fileId: string, token?: string): Promise { @@ -189,15 +161,9 @@ export class Network { * @param bucketId * @param uploads */ - static async startUpload( - bucketId: string, - payload: StartUploadPayload, - { client, appDetails, auth }: NetworkRequestConfig, - signal?: AbortSignal, - parts = 1, - ) { - const headers = Network.headersWithBasicAuth(appDetails, auth); - return await client.post( + async startUploadRequest(bucketId: string, payload: StartUploadPayload, signal?: AbortSignal, parts = 1) { + const headers = Network.headersWithBasicAuth(this.appDetails, this.auth); + return await this.client.post( `/v2/buckets/${bucketId}/files/start?multiparts=${parts}`, payload, headers, @@ -211,14 +177,18 @@ export class Network { * @param index * @param shards */ - private static async finishUpload( + private async finishUploadRequest( bucketId: string, payload: FinishUploadPayload | FinishMultipartUploadPayload, - { client, appDetails, auth }: NetworkRequestConfig, signal?: AbortSignal, ) { - const headers = Network.headersWithBasicAuth(appDetails, auth); - return await client.post(`/v2/buckets/${bucketId}/files/finish`, payload, headers, signal); + const headers = Network.headersWithBasicAuth(this.appDetails, this.auth); + return await this.client.post( + `/v2/buckets/${bucketId}/files/finish`, + payload, + headers, + signal, + ); } /** From c2d1fec60caa0bb01b1e98a585dac4844c502586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Fri, 6 Mar 2026 09:13:21 +0100 Subject: [PATCH 6/6] Update network.test.ts --- test/network/network.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/network/network.test.ts b/test/network/network.test.ts index 2c671027..f0f811e0 100644 --- a/test/network/network.test.ts +++ b/test/network/network.test.ts @@ -48,7 +48,7 @@ describe('network ', () => { uploads: [{ index: 0, uuid: validUUID, url, urls: null }], }; - vi.spyOn(Network, 'startUpload').mockResolvedValue(expected); + vi.spyOn(client, 'startUploadRequest').mockResolvedValue(expected); const received = await client.startUpload(idBucket, validSize, abortSignal);