Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@tus/server

Package Overview
Dependencies
Maintainers
3
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tus/server

Tus resumable upload protocol in Node.js

  • 1.2.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
9.9K
decreased by-33.7%
Maintainers
3
Weekly downloads
 
Created
Source

@tus/server

👉 Note: since 1.0.0 packages are split and published under the @tus scope. The old package, tus-node-server, is considered unstable and will only receive security fixes. Make sure to use the new package.

Contents

Install

In Node.js (16.0+), install with npm:

npm install @tus/server

Use

A standalone server which stores files on disk.

const {Server} = require('@tus/server')
const {FileStore} = require('@tus/file-store')
const host = '127.0.0.1'
const port = 1080

const server = new Server({
  path: '/files',
  datastore: new FileStore({directory: './files'}),
})
server.listen({host, port})

API

This package exports Server and all constants, types, and models. There is no default export. You should only need the Server and EVENTS exports.

new Server(options)

Creates a new tus server with options.

options.path

The route to accept requests (string).

options.maxSize

Max file size (in bytes) allowed when uploading (number | ((req, id: string | null) => Promise<number> | number)). When providing a function during the OPTIONS request the id will be null.

options.relativeLocation

Return a relative URL as the Location header to the client (boolean).

options.respectForwardedHeaders

Allow Forwarded, X-Forwarded-Proto, and X-Forwarded-Host headers to override the Location header returned by the server (boolean).

options.allowedHeaders

Additional headers sent in Access-Control-Allow-Headers (string[]).

options.generateUrl

Control how the upload url is generated ((req, { proto, host, baseUrl, path, id }) => string))

options.getFileIdFromRequest

Control how the Upload-ID is extracted from the request ((req) => string | void)

options.namingFunction

Control how you want to name files ((req) => string)

It is important to make these unique to prevent data loss. Only use it if you need to. Default uses crypto.randomBytes(16).toString('hex').

options.onUploadCreate

onUploadCreate will be invoked before a new upload is created. ((req, res, upload) => Promise<res>).

If the function returns the (modified) response, the upload will be created. You can throw an Object and the HTTP request will be aborted with the provided body and status_code (or their fallbacks).

This can be used to implement validation of upload metadata or add headers.

options.onUploadFinish

onUploadFinish will be invoked after an upload is completed but before a response is returned to the client ((req, res, upload) => Promise<res>).

If the function returns the (modified) response, the upload will finish. You can throw an Object and the HTTP request will be aborted with the provided body and status_code (or their fallbacks).

This can be used to implement post-processing validation.

options.onIncomingRequest

onIncomingRequest is a middleware function invoked before all handlers ((req, res) => Promise<void>)

This can be used for things like access control. You can throw an Object and the HTTP request will be aborted with the provided body and status_code (or their fallbacks).

options.onResponseError

onResponseError will be invoked when an error response is about to be sent by the server. you use this function to map custom errors to tus errors or for custom observability. ((req, res, err) => Promise<{status_code: number; body: string} | void> | {status_code: number; body: string} | void)

server.handle(req, res)

The main server request handler invoked on every request. You only need to use this when you integrate tus into an existing Node.js server.

server.get(req, res)

You can implement your own GET handlers. For instance, to return all files.

const fs = require('node:fs/promises')
const {Server} require('@tus/server')
const {FileStore} require('@tus/file-store')

const server = new Server({
  path: '/files',
  datastore: new FileStore({ directory: './files' }),
})

server.get('/uploads', async (req, res) => {
  const files = await fs.readdir(server.datastore.directory)
  // Format and return
})
server.listen()

Start the tus server. Supported arguments are the same as server.listen() from node:net.

server.cleanUpExpiredUploads()

Clean up expired uploads. Your chosen datastore must support the expiration extension for this to work.

EVENTS

Events to subscribe to (Object<string>).

You can listen for events by using the .on() method on the Server instance.

POST_CREATE

Called after an upload has been created but before it's written to a store.

const {EVENTS} = require('@tus/server')
// ...
server.on(EVENTS.POST_CREATE, (req, res, upload => {})
POST_RECEIVE

Called every time a PATCH request is handled.

const {EVENTS} = require('@tus/server')
// ...
server.on(EVENTS.POST_RECEIVE, (req, res, upload => {})
POST_FINISH

Called an upload has completed and after a response has been sent to the client.

const {EVENTS} = require('@tus/server')
// ...
server.on(EVENTS.POST_FINISH, (req, res, upload => {})
POST_TERMINATE

Called after an upload has been terminated and a response has been sent to the client.

const {EVENTS} = require('@tus/server')
// ...
server.on(EVENTS.POST_TERMINATE, (req, res, id => {})

Examples

Example: integrate tus into Express

const {Server} = require('@tus/server')
const {FileStore} = require('@tus/file-store')
const express = require('express')

const host = '127.0.0.1'
const port = 1080
const app = express()
const uploadApp = express()
const server = new Server({
  path: '/uploads',
  datastore: new FileStore({directory: '/files'}),
})

uploadApp.all('*', server.handle.bind(server))
app.use('/uploads', uploadApp)
app.listen(port, host)

Example: integrate tus into Koa

const http = require('node:http')
const url = require('node:url')
const Koa = require('koa')
const {Server} = require('@tus/server')
const {FileStore} = require('@tus/file-store')

const app = new Koa()
const appCallback = app.callback()
const port = 1080
const tusServer = new Server({
  path: '/files',
  datastore: new FileStore({directory: '/files'}),
})

const server = http.createServer((req, res) => {
  const urlPath = url.parse(req.url).pathname

  // handle any requests with the `/files/*` pattern
  if (/^\/files\/.+/.test(urlPath.toLowerCase())) {
    return tusServer.handle(req, res)
  }

  appCallback(req, res)
})

server.listen(port)

Example: integrate tus into Fastify

const fastify = require('fastify')({logger: true})
const {Server} = require('@tus/server')
const {FileStore} = require('@tus/file-store')

const tusServer = new Server({
  path: '/files',
  datastore: new FileStore({directory: './files'}),
})

/**
 * add new content-type to fastify forewards request
 * without any parser to leave body untouched
 * @see https://www.fastify.io/docs/latest/Reference/ContentTypeParser/
 */
fastify.addContentTypeParser(
  'application/offset+octet-stream',
  (request, payload, done) => done(null)
)

/**
 * let tus handle preparation and filehandling requests
 * fastify exposes raw nodejs http req/res via .raw property
 * @see https://www.fastify.io/docs/latest/Reference/Request/
 * @see https://www.fastify.io/docs/latest/Reference/Reply/#raw
 */
fastify.all('/files', (req, res) => {
  tusServer.handle(req.raw, res.raw)
})
fastify.all('/files/*', (req, res) => {
  tusServer.handle(req.raw, res.raw)
})
fastify.listen(3000, (err) => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

Example: integrate tus into Next.js

Attach the tus server handler to a Next.js route handler in an optional catch-all route file

/pages/api/upload/[[...file]].ts

import type {NextApiRequest, NextApiResponse} from 'next'
import {Server, Upload} from '@tus/server'
import {FileStore} from '@tus/file-store'

/**
 * !Important. This will tell Next.js NOT Parse the body as tus requires
 * @see https://nextjs.org/docs/api-routes/request-helpers
 */
export const config = {
  api: {
    bodyParser: false,
  },
}

const tusServer = new Server({
  // `path` needs to match the route declared by the next file router
  // ie /api/upload
  path: '/api/upload',
  datastore: new FileStore({directory: './files'}),
})

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  return tusServer.handle(req, res)
}

Example: validate metadata when an upload is created

const {Server} = require('@tus/server')
// ...

const server = new Server({
  // ..
  async onUploadCreate(req, res, upload) {
    const {ok, expected, received} = validateMetadata(upload)
    if (!ok) {
      const body = `Expected "${expected}" in "Upload-Metadata" but received "${received}"`
      throw {status_code: 500, body} // if undefined, falls back to 500 with "Internal server error".
    }
    // We have to return the (modified) response.
    return res
  },
})

Example: access control

Access control is opinionated and can be done in different ways. This example is psuedo-code for what it could look like with JSON Web Tokens.

const { Server } = require("@tus/server");
// ...

const server = new Server({
  // ..
  async onIncomingRequest(req, res) {
    const token = req.headers.authorization;

    if (!token) {
      throw { status_code: 401, body: 'Unauthorized' }
    }

    try {
      const decodedToken = await jwt.verify(token, 'your_secret_key')
      req.user = decodedToken
    } catch (error) {
      throw { status_code: 401, body: 'Invalid token' }
    }

    if (req.user.role !== 'admin') {
      throw { status_code: 403, body: 'Access denied' }
    }
  },
});

Types

This package is fully typed with TypeScript.

Compatibility

This package requires Node.js 16.0+.

Contribute

See contributing.md.

License

MIT © tus

FAQs

Package last updated on 21 Dec 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc