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 - npm Package Compare versions

Comparing version 1.5.0 to 1.6.0

4

dist/handlers/BaseHandler.d.ts
/// <reference types="node" />
/// <reference types="node" />
import EventEmitter from 'node:events';
import type http from 'node:http';
import type { ServerOptions } from '../types';
import type { DataStore, CancellationContext } from '@tus/utils';
import type http from 'node:http';
import { Upload } from '@tus/utils';

@@ -21,3 +21,3 @@ export declare class BaseHandler extends EventEmitter {

protected acquireLock(req: http.IncomingMessage, id: string, context: CancellationContext): Promise<import("@tus/utils").Lock>;
protected writeToStore(req: http.IncomingMessage, id: string, offset: number, maxFileSize: number, context: CancellationContext): Promise<number>;
protected writeToStore(req: http.IncomingMessage, upload: Upload, maxFileSize: number, context: CancellationContext): Promise<number>;
getConfiguredMaxSize(req: http.IncomingMessage, id: string | null): number | Promise<number>;

@@ -24,0 +24,0 @@ /**

@@ -8,5 +8,6 @@ "use strict";

const node_events_1 = __importDefault(require("node:events"));
const promises_1 = __importDefault(require("node:stream/promises"));
const node_stream_1 = require("node:stream");
const utils_1 = require("@tus/utils");
const promises_1 = __importDefault(require("node:stream/promises"));
const stream_1 = require("stream");
const lodash_throttle_1 = __importDefault(require("lodash.throttle"));
const reExtractFileID = /([^/]+)\/?$/;

@@ -97,3 +98,3 @@ const reForwardedHost = /host="?([^";]+)/;

}
writeToStore(req, id, offset, maxFileSize, context) {
writeToStore(req, upload, maxFileSize, context) {
return new Promise(async (resolve, reject) => {

@@ -107,4 +108,4 @@ // Abort early if the operation has been cancelled.

// This allows for aborting the write process without affecting the incoming request stream.
const proxy = new stream_1.PassThrough();
(0, stream_1.addAbortSignal)(context.signal, proxy);
const proxy = new node_stream_1.PassThrough();
(0, node_stream_1.addAbortSignal)(context.signal, proxy);
proxy.on('error', (err) => {

@@ -114,2 +115,10 @@ req.unpipe(proxy);

});
const postReceive = (0, lodash_throttle_1.default)((offset) => {
this.emit(utils_1.EVENTS.POST_RECEIVE_V2, req, { ...upload, offset });
}, this.options.postReceiveInterval, { leading: false });
let tempOffset = upload.offset;
proxy.on('data', (chunk) => {
tempOffset += chunk.byteLength;
postReceive(tempOffset);
});
req.on('error', () => {

@@ -127,3 +136,3 @@ if (!proxy.closed) {

.pipeline(req.pipe(proxy), new utils_1.StreamLimiter(maxFileSize), async (stream) => {
return this.store.write(stream, id, offset);
return this.store.write(stream, upload.id, upload.offset);
})

@@ -130,0 +139,0 @@ .then(resolve)

@@ -81,3 +81,3 @@ "use strict";

const maxBodySize = await this.calculateMaxBodySize(req, upload, maxFileSize);
newOffset = await this.writeToStore(req, id, offset, maxBodySize, context);
newOffset = await this.writeToStore(req, upload, maxBodySize, context);
}

@@ -89,5 +89,29 @@ finally {

this.emit(utils_1.EVENTS.POST_RECEIVE, req, res, upload);
//Recommended response defaults
const responseData = {
status: 204,
headers: {
'Upload-Offset': newOffset,
},
body: '',
};
if (newOffset === upload.size && this.options.onUploadFinish) {
try {
res = await this.options.onUploadFinish(req, res, upload);
const resOrObject = await this.options.onUploadFinish(req, res, upload);
// Backwards compatibility, remove in next major
// Ugly check because we can't use `instanceof` because we mock the instance in tests
if (typeof resOrObject.write === 'function' &&
typeof resOrObject.writeHead === 'function') {
res = resOrObject;
}
else {
const obj = resOrObject;
res = obj.res;
if (obj.status_code)
responseData.status = obj.status_code;
if (obj.body)
responseData.body = obj.body;
if (obj.headers)
responseData.headers = Object.assign(obj.headers, responseData.headers);
}
}

@@ -99,5 +123,2 @@ catch (error) {

}
const headers = {
'Upload-Offset': newOffset,
};
if (this.store.hasExtension('expiration') &&

@@ -110,6 +131,6 @@ this.store.getExpiration() > 0 &&

const dateString = new Date(creation.getTime() + this.store.getExpiration()).toUTCString();
headers['Upload-Expires'] = dateString;
responseData.headers['Upload-Expires'] = dateString;
}
// The Server MUST acknowledge successful PATCH requests with the 204
const writtenRes = this.write(res, 204, headers);
const writtenRes = this.write(res, responseData.status, responseData.headers, responseData.body);
if (newOffset === upload.size) {

@@ -116,0 +137,0 @@ this.emit(utils_1.EVENTS.POST_FINISH, req, writtenRes, upload);

@@ -96,3 +96,8 @@ "use strict";

let url;
let headers;
//Recommended response defaults
const responseData = {
status: 201,
headers: {},
body: '',
};
try {

@@ -103,8 +108,7 @@ await this.store.create(upload);

isFinal = upload.size === 0 && !upload.sizeIsDeferred;
headers = {};
// The request MIGHT include a Content-Type header when using creation-with-upload extension
if ((0, HeaderValidator_1.validateHeader)('content-type', req.headers['content-type'])) {
const bodyMaxSize = await this.calculateMaxBodySize(req, upload, maxFileSize);
const newOffset = await this.writeToStore(req, id, 0, bodyMaxSize, context);
headers['Upload-Offset'] = newOffset.toString();
const newOffset = await this.writeToStore(req, upload, bodyMaxSize, context);
responseData.headers['Upload-Offset'] = newOffset.toString();
isFinal = newOffset === Number.parseInt(upload_length, 10);

@@ -123,3 +127,19 @@ upload.offset = newOffset;

try {
res = await this.options.onUploadFinish(req, res, upload);
const resOrObject = await this.options.onUploadFinish(req, res, upload);
// Backwards compatibility, remove in next major
// Ugly check because we can't use `instanceof` because we mock the instance in tests
if (typeof resOrObject.write === 'function' &&
typeof resOrObject.writeHead === 'function') {
res = resOrObject;
}
else {
const obj = resOrObject;
res = obj.res;
if (obj.status_code)
responseData.status = obj.status_code;
if (obj.body)
responseData.body = obj.body;
if (obj.headers)
responseData.headers = Object.assign(obj.headers, responseData.headers);
}
}

@@ -140,6 +160,11 @@ catch (error) {

// Value MUST be in RFC 7231 datetime format
headers['Upload-Expires'] = new Date(creation.getTime() + this.store.getExpiration()).toUTCString();
responseData.headers['Upload-Expires'] = new Date(creation.getTime() + this.store.getExpiration()).toUTCString();
}
}
const writtenRes = this.write(res, 201, { Location: url, ...headers });
//Only append Location header if its valid for the final http status (201 or 3xx)
if (responseData.status === 201 ||
(responseData.status >= 300 && responseData.status < 400)) {
responseData.headers['Location'] = url;
}
const writtenRes = this.write(res, responseData.status, responseData.headers, responseData.body);
if (isFinal) {

@@ -146,0 +171,0 @@ this.emit(utils_1.EVENTS.POST_FINISH, req, writtenRes, upload);

@@ -27,3 +27,5 @@ /// <reference types="node" />

[EVENTS.POST_CREATE]: (req: http.IncomingMessage, res: http.ServerResponse, upload: Upload, url: string) => void;
/** @deprecated this is almost the same as POST_FINISH, use POST_RECEIVE_V2 instead */
[EVENTS.POST_RECEIVE]: (req: http.IncomingMessage, res: http.ServerResponse, upload: Upload) => void;
[EVENTS.POST_RECEIVE_V2]: (req: http.IncomingMessage, upload: Upload) => void;
[EVENTS.POST_FINISH]: (req: http.IncomingMessage, res: http.ServerResponse, upload: Upload) => void;

@@ -30,0 +32,0 @@ [EVENTS.POST_TERMINATE]: (req: http.IncomingMessage, res: http.ServerResponse, id: string) => void;

@@ -39,2 +39,5 @@ "use strict";

}
if (!options.postReceiveInterval) {
options.postReceiveInterval = 1000;
}
const { datastore, ...rest } = options;

@@ -41,0 +44,0 @@ this.options = rest;

@@ -30,2 +30,6 @@ /// <reference types="node" />

/**
* Interval in milliseconds for sending progress of an upload over `EVENTS.POST_RECEIVE_V2`
*/
postReceiveInterval?: number;
/**
* Control how the upload URL is generated.

@@ -83,3 +87,4 @@ * @param req - The incoming HTTP request.

* `onUploadFinish` will be invoked after an upload is completed but before a response is returned to the client.
* If the function returns the (modified) response, the upload will finish.
* You can optionally return `status_code`, `headers` and `body` to modify the response.
* Note that the tus specification does not allow sending response body nor status code other than 204, but most clients support it.
* If an error is thrown, the HTTP request will be aborted, and the provided `body` and `status_code`

@@ -91,3 +96,8 @@ * (or their fallbacks) will be sent to the client. This can be used to implement post-processing validation.

*/
onUploadFinish?: (req: http.IncomingMessage, res: http.ServerResponse, upload: Upload) => Promise<http.ServerResponse>;
onUploadFinish?: (req: http.IncomingMessage, res: http.ServerResponse, upload: Upload) => Promise<http.ServerResponse | {
res: http.ServerResponse;
status_code?: number;
headers?: Record<string, string | number>;
body?: string;
}>;
/**

@@ -94,0 +104,0 @@ * `onIncomingRequest` will be invoked when an incoming request is received.

{
"$schema": "https://json.schemastore.org/package.json",
"name": "@tus/server",
"version": "1.5.0",
"version": "1.6.0",
"description": "Tus resumable upload protocol in Node.js",

@@ -24,7 +24,9 @@ "main": "dist/index.js",

"dependencies": {
"@tus/utils": "^0.1.0",
"debug": "^4.3.4"
"@tus/utils": "^0.2.0",
"debug": "^4.3.4",
"lodash.throttle": "^4.1.1"
},
"devDependencies": {
"@types/debug": "^4.1.12",
"@types/lodash.throttle": "^4.1.9",
"@types/mocha": "^10.0.6",

@@ -31,0 +33,0 @@ "@types/node": "^20.11.5",

@@ -72,2 +72,7 @@ # `@tus/server`

#### `options.postReceiveInterval`
Interval in milliseconds for sending progress of an upload over
[`POST_RECEIVE_V2`](#eventspost_receive_v2) (`number`).
#### `options.relativeLocation`

@@ -156,7 +161,9 @@

`onUploadFinish` will be invoked after an upload is completed but before a response is
returned to the client (`(req, res, upload) => Promise<res>`).
returned to the client (`(req, res, upload) => Promise<{ res: http.ServerResponse, status_code?: number, headers?: Record<string, string | number>, body?: string }>`).
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).
- You can optionally return `status_code`, `headers` and `body` to modify the response.
Note that the tus specification does not allow sending response body nor status code
other than 204, but most clients support it. Use at your own risk.
- You can `throw` an Object and the HTTP request will be aborted with the provided `body`
and `status_code` (or their fallbacks).

@@ -233,4 +240,9 @@ This can be used to implement post-processing validation.

Called every time a `PATCH` request is handled.
**Deprecated**.
Called every time an upload finished writing to the store. This event is emitted whenever
the request handling is completed (which is the same as `onUploadFinish`, almost the same
as `POST_FINISH`), whereas the `POST_RECEIVE_V2` event is emitted _while_ the request is
being handled.
```js

@@ -242,2 +254,19 @@ const {EVENTS} = require('@tus/server')

#### `POST_RECEIVE_V2`
Called every [`postReceiveInterval`](#optionspostreceiveinterval) milliseconds for every
upload while it‘s being written to the store.
This means you are not guaranteed to get (all) events for an upload. For instance if
`postReceiveInterval` is set to 1000ms and an PATCH request takes 500ms, no event is emitted.
If the PATCH request takes 2500ms, you would get the offset at 2000ms, but not at 2500ms.
Use `POST_FINISH` if you need to know when an upload is done.
```js
const {EVENTS} = require('@tus/server')
// ...
server.on(EVENTS.POST_RECEIVE_V2, (req, upload => {})
```
#### `POST_FINISH`

@@ -244,0 +273,0 @@

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