From 260720c43f18c9a2289a8b510829c82f193a7126 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Mon, 20 Jul 2026 16:20:37 +0200 Subject: [PATCH 1/5] simplify tus options --- packages/@uppy/tus/src/index.ts | 49 ++++++++++++++------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/packages/@uppy/tus/src/index.ts b/packages/@uppy/tus/src/index.ts index 65b4bb196..9cd9fd276 100644 --- a/packages/@uppy/tus/src/index.ts +++ b/packages/@uppy/tus/src/index.ts @@ -160,34 +160,21 @@ export default class Tus extends BasePlugin< this.uploaderEvents = Object.create(null) } + /** + * @param fileID + * @param terminate Terminate the upload on the server (sends a `DELETE` request). + */ + #abortUploader(fileID: string, terminate?: boolean) { + const uploader = this.uploaders[fileID] + uploader?.abort(terminate) + } + /** * Clean up all references for a file's upload: the tus.Upload instance, * any events related to the file, and the Companion WebSocket connection. */ - resetUploaderReferences( - fileID: string, - opts?: { - /** Terminate the upload on the server (sends a `DELETE` request). */ - abort?: boolean - /** - * Abort the underlying request. Defaults to `true`. Set to `false` when - * the request has already completed (e.g. in the error handler), so the - * underlying `xhr` — and thus the server response — is preserved instead - * of being reset by `abort()`. - */ - abortRequest?: boolean - }, - ): void { - const uploader = this.uploaders[fileID] - if (uploader) { - if (opts?.abortRequest !== false) { - uploader.abort() - - if (opts?.abort) { - uploader.abort(true) - } - } - + #resetUploaderReferences(fileID: string): void { + if (this.uploaders[fileID]) { this.uploaders[fileID] = null } if (this.uploaderEvents[fileID]) { @@ -232,7 +219,8 @@ export default class Tus extends BasePlugin< async #uploadLocalFile( file: LocalUppyFile, ): Promise { - this.resetUploaderReferences(file.id) + this.#abortUploader(file.id) + this.#resetUploaderReferences(file.id) // Captured in `onError` and forwarded to the `upload-error` event in the // `.catch` below, so consumers can read the failing server response. @@ -341,7 +329,7 @@ export default class Tus extends BasePlugin< // it would reset the underlying `xhr` (status `0`, empty body) and // discard the response we just captured. We still drop our references // and remove the event listeners. - this.resetUploaderReferences(file.id, { abortRequest: false }) + this.#resetUploaderReferences(file.id) queuedRequest?.abort() if (typeof opts.onError === 'function') { @@ -380,7 +368,8 @@ export default class Tus extends BasePlugin< this.uppy.emit('upload-success', this.uppy.getFile(file.id), uploadResp) - this.resetUploaderReferences(file.id) + this.#abortUploader(file.id) + this.#resetUploaderReferences(file.id) queuedRequest.done() if (upload.url) { @@ -523,7 +512,8 @@ export default class Tus extends BasePlugin< eventManager.onFileRemove(file.id, (targetFileID) => { queuedRequest.abort() - this.resetUploaderReferences(file.id, { abort: !!upload.url }) + this.#abortUploader(file.id, !!upload.url) + this.#resetUploaderReferences(file.id) resolve(`upload ${targetFileID} was removed`) }) @@ -546,7 +536,8 @@ export default class Tus extends BasePlugin< eventManager.onCancelAll(file.id, () => { queuedRequest.abort() - this.resetUploaderReferences(file.id, { abort: !!upload.url }) + this.#abortUploader(file.id, !!upload.url) + this.#resetUploaderReferences(file.id) resolve(`upload ${file.id} was canceled`) }) From 260720fcf0602dce3742e3d3f6d7382ccd46f86d Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Mon, 20 Jul 2026 22:49:30 +0200 Subject: [PATCH 2/5] fix comments --- packages/@uppy/tus/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@uppy/tus/src/index.ts b/packages/@uppy/tus/src/index.ts index 9cd9fd276..fb3c1397e 100644 --- a/packages/@uppy/tus/src/index.ts +++ b/packages/@uppy/tus/src/index.ts @@ -205,7 +205,7 @@ export default class Tus extends BasePlugin< * * When working on this function, keep in mind: * - When an upload is completed or cancelled for any reason, the tus.Upload and EventManager instances need to be cleaned - * up using this.resetUploaderReferences(). + * up using this.#resetUploaderReferences() and this.#abortUploader(). * - When an upload is cancelled or paused, for any reason, it needs to be removed from the `this.requests` queue using * `queuedRequest.abort()`. * - When an upload is completed for any reason, including errors, it needs to be marked as such using @@ -491,7 +491,7 @@ export default class Tus extends BasePlugin< upload.start() } // Don't do anything here, the caller will take care of cancelling the upload itself - // using resetUploaderReferences(). This is because resetUploaderReferences() has to be + // using #resetUploaderReferences(). This is because #resetUploaderReferences() has to be // called when this request is still in the queue, and has not been started yet, too. At // that point this cancellation function is not going to be called. // Also, we need to remove the request from the queue _without_ destroying everything From a1457210f4088c6380f349829e18eba0fd574363 Mon Sep 17 00:00:00 2001 From: prakash Date: Tue, 21 Jul 2026 11:58:25 +0530 Subject: [PATCH 3/5] add comments regarder uploader.abort() --- packages/@uppy/tus/src/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/@uppy/tus/src/index.ts b/packages/@uppy/tus/src/index.ts index fb3c1397e..547e1129c 100644 --- a/packages/@uppy/tus/src/index.ts +++ b/packages/@uppy/tus/src/index.ts @@ -161,8 +161,12 @@ export default class Tus extends BasePlugin< } /** + * `uploader.abort()` is provided by tus-js-client. With no argument (or + * `false`), it aborts only the local upload request. Passing `true` also + * terminates the Tus upload on the server by sending a `DELETE` request. + * * @param fileID - * @param terminate Terminate the upload on the server (sends a `DELETE` request). + * @param terminate Whether to terminate the upload on the server. */ #abortUploader(fileID: string, terminate?: boolean) { const uploader = this.uploaders[fileID] From f8fd5db7ccd4ae198030ceba85844c0db91537cd Mon Sep 17 00:00:00 2001 From: prakash Date: Tue, 21 Jul 2026 12:06:17 +0530 Subject: [PATCH 4/5] harden regression tests --- packages/@uppy/tus/src/index.test.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/@uppy/tus/src/index.test.ts b/packages/@uppy/tus/src/index.test.ts index 1a46170e4..12c69ae58 100644 --- a/packages/@uppy/tus/src/index.test.ts +++ b/packages/@uppy/tus/src/index.test.ts @@ -36,7 +36,12 @@ vi.mock('tus-js-client', async (importOriginal) => { setTimeout(() => this.options.onError(err), 0) } - abort() {} + abort() { + // Mirrors XMLHttpRequest.abort(): the response object is reset. This + // makes the test fail if Tus aborts the completed errored request. + fakeXhr.status = 0 + fakeXhr.responseText = '' + } // ponytail: tus calls this before start(); return empty so no resume logic runs findPreviousUploads() { @@ -115,13 +120,19 @@ describe('Tus', () => { }), event.then(([, , response]) => { expect(response?.status).toBe(403) + expect(response?.body?.xhr.status).toBe(403) expect(JSON.parse(response!.body!.xhr.responseText).message).toBe( 'File cannot be uploaded as the BIN content type is disallowed!', ) }), ]) - expect(core.getFile(id).response?.status).toBe(403) + const file = core.getFile(id) + expect(file.response?.status).toBe(403) + expect(file.response?.body?.xhr.status).toBe(403) + expect(JSON.parse(file.response!.body!.xhr.responseText).message).toBe( + 'File cannot be uploaded as the BIN content type is disallowed!', + ) }) }) }) From bbf041bd67c73335c343b149c69263763e86f690 Mon Sep 17 00:00:00 2001 From: Prakash Date: Sat, 25 Jul 2026 01:56:12 +0530 Subject: [PATCH 5/5] Update packages/@uppy/tus/src/index.ts Co-authored-by: Mikael Finstad --- packages/@uppy/tus/src/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@uppy/tus/src/index.ts b/packages/@uppy/tus/src/index.ts index 547e1129c..114c2d22f 100644 --- a/packages/@uppy/tus/src/index.ts +++ b/packages/@uppy/tus/src/index.ts @@ -161,9 +161,9 @@ export default class Tus extends BasePlugin< } /** - * `uploader.abort()` is provided by tus-js-client. With no argument (or - * `false`), it aborts only the local upload request. Passing `true` also - * terminates the Tus upload on the server by sending a `DELETE` request. + * Stop the upload in Tus. If `terminate` is `true`, it will also terminate the + * upload on the Tus server by sending a `DELETE` request. If not, it will just + * cancel any current upload request and leave the upload in a half-uploaded state. * * @param fileID * @param terminate Whether to terminate the upload on the server.