tus is a protocol based on HTTP for resumable file uploads. Resumable here means that an interrupted upload can carry on without re-uploading already uploaded data again. An interruption may happen willingly, if the user wants to pause while switching to another workspace, or by accident in case of an network issue or server outage. When resumability is implemented with automatic retries (with this release now the default), the user does not need to notice there was an interruption. Since HTTP/1.1 such a resumability is available for file downloads already but not for file uploads as tus offers.

tus-js-client is the official client implementation for the tus protocol in JavaScript. Since it had been born five years ago, it has grown enormously in numbers of features and supported environments. While it was originally designed for web browsers, it can now also be used in:

  • Node.js,
  • React Native, and
  • Apache Cordova applications.

However, over time this growth came at the cost of some technical debt which can hinder further development. In this release we cleaned up the code base, removed some odd API decisions from early stages and add long awaited features, such as Automatic Retries and Parallel Chunked Uploads. We are pleased to introduce you to the all new tus-js-client v2.0.0, which packs all this, and more.

New features

Besides cleaning up old technical debt, this release also introduces new functionality:

  • Add support for Parallel Uploads
    tus-js-client now supports parallel upload requests using the Concatenation extension. When enabled, an input file will be split into multiple equally sized parts which are uploaded in parallel. After all requests are finished, the parts will be stitched together on the server-side to produce the original file. The motivation behind this feature is to allow better utilization of network connections and available bandwidth. See the parallelUploads documentation for more details.
  • Add Upload Storage API
    tus-js-client was always able to resume uploads which have been started in a previous browsing session. This is possible by storing the upload resource’s URL after it has been created and retrieving it from said storage based on file metadata later on. This allows users to pick up an upload where it had been left off even after the browser is (accidentally) closed. tus-js-client uses the Web Storage API to save this pointer inside the browsers but historically provided little access to retrieve or modify elements in this URL storage. To remove this limitation, we introduce the URL Storage interface: You are now able to supply your own URL storage using the urlStorage option, if you want to save URLs in a database, for example. Furthermore, you can now easily query the URL storage to retrieve a list of previously started uploads using the findPreviousUploads method and ask the end user which upload should be resumed. Please have a look at the corresponding example for more details on this approach.
  • Add HTTP abstraction layer
    tus-js-client has always contained an abstraction layer to smooth out the differences between the network APIs in browsers and inside Node.js. Users now also have the ability to supply a custom HTTP stack to further customize the used HTTP interface. See the httpStack documentation for more details.
  • Add File Reader abstraction layer
    Similar to the HTTP abstraction layer, tus-js-client also uses an abstraction to uniformly read data from the different input file types. If you want to add support for another input type, you can supply your own file reader implementation now. See the fileReader documentation for more details.
  • Add request IDs
    tus-js-client can now be configured to send unique request IDs using the X-Request-ID header. Since tus-js-client includes this ID in its error messages, it can be used to correlate client errors with server logs to make debugging easier. See the addRequestId documentation for more details.
  • Add request and response callbacks
    This release also adds the onBeforeRequest and onAfterResponse callbacks which will be invoked before a HTTP request is sent and directly after a HTTP response is received. This allows you to modify outgoing requests or retrieve additional information from incoming responses. See the documentation for more information and examples.

Breaking changes

The main behavior of tus-js-client and the vast majority of its API surface stay the same. However, the following breaking changes were necessary:

  • Drop support for Node.js 6 and 7
    Only Node.js 8 or newer are fully supported and tested for compatibility with tus-js-client from now own. Earlier versions may work but we don’t guarantee or support it. Please note that we still support the same browsers as before, with the exception of requiring a polyfill in some cases, explained further down.
  • Require support for Promises
    The internal code has been partially rewritten to use Promises instead of callbacks, which allowed us to clean up a lot of old spaghetti code. For library users this means that you need to use a Promise polyfill if your application runs in older browsers which do not support Promises. Have a look at caniuse.com for a list of those browsers and core-js for a polyfill.
  • Use Promises for abort/terminate functions
    The Upload#abort and Upload.terminate functions do not longer accept a callback but instead return a Promise now. We recommend adding a catch phrase to avoid errors about unhandled rejections. If you have code such as:
    upload.abort(true, (err) => {
      if (err) // Handle error
      else // Handle successful abort call
    })
    

    you should rewrite it to:

    upload.abort(true).then(() => {
      // Handle success
    }).catch((err) => {
      // Handle error
    })
    
  • Use Promises for the fingerprint option
    The function that is passed as the fingerprint option into the Upload-constructor is not callback-based anymore. Instead it must also return a Promise. If you supply a custom fingerprint function it must have a signature such as:
    function fingerprint (file, options) {
      const result = ....
      return Promise.resolve(result)
    })
    
  • Enable retries by default
    tus-js-client has supported automated retries of network-caused error for years using the retryDelays option. However, in order to avoid breaking changes, this feature had been disabled by default when it was introduced. With this release, the retrying mechanism will be enabled by default to make it easier for new users to take advantage of it. If you have custom retrying code implemented, you may want to check that it is compatible when tus-js-client also retries HTTP requests.
  • Remove resume option
    Historically, the resume option has controlled whether tus-js-client will check if it is possible to resume an upload from a previous browsing session (e.g. when the browser has accidentally been closed while the upload was still running). This was implemented by calculating the fingerprint for the given input file and comparing it to a list of previously created uploads which was stored in the browser’s localStorage. If such an upload exists, tus-js-client would attempt to resume it. However, this effectively gives the application no control over which upload is resumed. In previous versions, applications were not able to retrieve the list of previously created uploads or remove items from this list. Furthermore, if multiple matching uploads were found for a fingerprint, the applications could not decide which of those uploads should be resumed. In this release, the resume option has been removed and instead the Upload Storage API has been added. An introduction into the Upload Storage API can be found in the New Features section higher up. If you previously did not explicitly set resume: false, and hence relied on tus-js-client deciding to resume, you can get the previous behavior using following code snippet:
    upload = new tus.Upload(file, options)
    upload.findPreviousUploads().then((previousUploads) => {
      if (previousUploads.length > 0) {
        upload.resumeFromPreviousUpload(previousUploads[0])
      }
    
      upload.start()
    })
    

    or in async/await syntax:

    upload = new tus.Upload(file, options)
    const previousUploads = await upload.findPreviousUploads()
    if (previousUploads.length > 0) {
      upload.resumeFromPreviousUpload(previousUploads[0])
    }
    upload.start()
    
  • Remove withCredentials option
    This release introduces an HTTP abstraction layer to overcome differences between network APIs in browsers and inside Node.js. This makes internal code a lot cleaner but also means that the browser-only withCredentials option is not properly possible anymore. If you used this feature before, you can now explicitly set this flag using the request callbacks:
    upload = new tus.Upload(file, {
      endpoint: '....',
      onBeforeRequestSend: (req) => {
        const xhr = req.getUnderlyingObject()
        xhr.withCredentials = true
      },
      ....
    })
    

Try it

If you’d like to try it out, we have updated our demo to use tus-js-client v2.0 as well. The code for it can be found here. Do leave a comment there how it went!

Finally, we want to thank everyone who helped to make this release happen! If you also want to contribute, you can find our open source code at GitHub. If you don’t know where to start or have other questions, feel free to contact us!