@uppy/tus
Advanced tools
Comparing version 3.0.6 to 3.1.0
714
lib/index.js
@@ -12,3 +12,2 @@ function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } | ||
import getSocketHost from '@uppy/utils/lib/getSocketHost'; | ||
import settle from '@uppy/utils/lib/settle'; | ||
import EventTracker from '@uppy/utils/lib/EventTracker'; | ||
@@ -19,5 +18,6 @@ import NetworkError from '@uppy/utils/lib/NetworkError'; | ||
import hasProperty from '@uppy/utils/lib/hasProperty'; | ||
import { filterNonFailedFiles, filterFilesToEmitUploadStarted } from '@uppy/utils/lib/fileFilters'; | ||
import getFingerprint from './getFingerprint.js'; | ||
const packageJson = { | ||
"version": "3.0.6" | ||
"version": "3.1.0" | ||
}; | ||
@@ -68,4 +68,12 @@ /** @typedef {import('..').TusOptions} TusOptions */ | ||
var _upload = /*#__PURE__*/_classPrivateFieldLooseKey("upload"); | ||
var _requestSocketToken = /*#__PURE__*/_classPrivateFieldLooseKey("requestSocketToken"); | ||
var _uploadRemote = /*#__PURE__*/_classPrivateFieldLooseKey("uploadRemote"); | ||
var _uploadFiles = /*#__PURE__*/_classPrivateFieldLooseKey("uploadFiles"); | ||
var _handleUpload = /*#__PURE__*/_classPrivateFieldLooseKey("handleUpload"); | ||
export default class Tus extends BasePlugin { | ||
@@ -80,2 +88,11 @@ /** | ||
super(uppy, _opts); | ||
Object.defineProperty(this, _uploadFiles, { | ||
value: _uploadFiles2 | ||
}); | ||
Object.defineProperty(this, _uploadRemote, { | ||
value: _uploadRemote2 | ||
}); | ||
Object.defineProperty(this, _upload, { | ||
value: _upload2 | ||
}); | ||
Object.defineProperty(this, _retryDelayIterator, { | ||
@@ -113,2 +130,19 @@ writable: true, | ||
}); | ||
Object.defineProperty(this, _handleUpload, { | ||
writable: true, | ||
value: async fileIDs => { | ||
if (fileIDs.length === 0) { | ||
this.uppy.log('[Tus] No files to upload'); | ||
return; | ||
} | ||
if (this.opts.limit === 0) { | ||
this.uppy.log('[Tus] When uploading multiple files at once, consider setting the `limit` option (to `10` for example), to limit the number of concurrent uploads, which helps prevent memory and network issues: https://uppy.io/docs/tus/#limit-0', 'warning'); | ||
} | ||
this.uppy.log('[Tus] Uploading...'); | ||
const filesToUpload = this.uppy.getFilesByIds(fileIDs); | ||
await _classPrivateFieldLooseBase(this, _uploadFiles)[_uploadFiles](filesToUpload); | ||
} | ||
}); | ||
this.type = 'uploader'; | ||
@@ -151,3 +185,2 @@ this.id = this.opts.id || 'Tus'; | ||
this.handleResetProgress = this.handleResetProgress.bind(this); | ||
this.handleUpload = this.handleUpload.bind(this); | ||
_classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken] = this.requests.wrapPromiseFunction(_classPrivateFieldLooseBase(this, _requestSocketToken)[_requestSocketToken], { | ||
@@ -247,308 +280,3 @@ priority: -1 | ||
upload(file) { | ||
var _this = this; | ||
this.resetUploaderReferences(file.id); // Create a new tus upload | ||
return new Promise((resolve, reject) => { | ||
let queuedRequest; | ||
let qRequest; | ||
let upload; | ||
this.uppy.emit('upload-started', file); | ||
const opts = { ...this.opts, | ||
...(file.tus || {}) | ||
}; | ||
if (typeof opts.headers === 'function') { | ||
opts.headers = opts.headers(file); | ||
} | ||
/** @type {RawTusOptions} */ | ||
const uploadOptions = { ...tusDefaultOptions, | ||
...opts | ||
}; // We override tus fingerprint to uppy’s `file.id`, since the `file.id` | ||
// now also includes `relativePath` for files added from folders. | ||
// This means you can add 2 identical files, if one is in folder a, | ||
// the other in folder b. | ||
uploadOptions.fingerprint = getFingerprint(file); | ||
uploadOptions.onBeforeRequest = req => { | ||
const xhr = req.getUnderlyingObject(); | ||
xhr.withCredentials = !!opts.withCredentials; | ||
let userProvidedPromise; | ||
if (typeof opts.onBeforeRequest === 'function') { | ||
userProvidedPromise = opts.onBeforeRequest(req, file); | ||
} | ||
if (hasProperty(queuedRequest, 'shouldBeRequeued')) { | ||
if (!queuedRequest.shouldBeRequeued) return Promise.reject(); | ||
let done; | ||
const p = new Promise(res => { | ||
// eslint-disable-line promise/param-names | ||
done = res; | ||
}); | ||
queuedRequest = this.requests.run(() => { | ||
if (file.isPaused) { | ||
queuedRequest.abort(); | ||
} | ||
done(); | ||
return () => {}; | ||
}); // If the request has been requeued because it was rate limited by the | ||
// remote server, we want to wait for `RateLimitedQueue` to dispatch | ||
// the re-try request. | ||
// Therefore we create a promise that the queue will resolve when | ||
// enough time has elapsed to expect not to be rate-limited again. | ||
// This means we can hold the Tus retry here with a `Promise.all`, | ||
// together with the returned value of the user provided | ||
// `onBeforeRequest` option callback (in case it returns a promise). | ||
return Promise.all([p, userProvidedPromise]); | ||
} | ||
return userProvidedPromise; | ||
}; | ||
uploadOptions.onError = err => { | ||
var _queuedRequest; | ||
this.uppy.log(err); | ||
const xhr = err.originalRequest ? err.originalRequest.getUnderlyingObject() : null; | ||
if (isNetworkError(xhr)) { | ||
// eslint-disable-next-line no-param-reassign | ||
err = new NetworkError(err, xhr); | ||
} | ||
this.resetUploaderReferences(file.id); | ||
(_queuedRequest = queuedRequest) == null ? void 0 : _queuedRequest.abort(); | ||
this.uppy.emit('upload-error', file, err); | ||
reject(err); | ||
}; | ||
uploadOptions.onProgress = (bytesUploaded, bytesTotal) => { | ||
this.onReceiveUploadUrl(file, upload.url); | ||
this.uppy.emit('upload-progress', file, { | ||
uploader: this, | ||
bytesUploaded, | ||
bytesTotal | ||
}); | ||
}; | ||
uploadOptions.onSuccess = () => { | ||
const uploadResp = { | ||
uploadURL: upload.url | ||
}; | ||
this.resetUploaderReferences(file.id); | ||
queuedRequest.done(); | ||
this.uppy.emit('upload-success', file, uploadResp); | ||
if (upload.url) { | ||
this.uppy.log(`Download ${upload.file.name} from ${upload.url}`); | ||
} | ||
resolve(upload); | ||
}; | ||
const defaultOnShouldRetry = err => { | ||
var _err$originalResponse; | ||
const status = err == null ? void 0 : (_err$originalResponse = err.originalResponse) == null ? void 0 : _err$originalResponse.getStatus(); | ||
if (status === 429) { | ||
// HTTP 429 Too Many Requests => to avoid the whole download to fail, pause all requests. | ||
if (!this.requests.isPaused) { | ||
var _classPrivateFieldLoo; | ||
const next = (_classPrivateFieldLoo = _classPrivateFieldLooseBase(this, _retryDelayIterator)[_retryDelayIterator]) == null ? void 0 : _classPrivateFieldLoo.next(); | ||
if (next == null || next.done) { | ||
return false; | ||
} | ||
this.requests.rateLimit(next.value); | ||
} | ||
} else if (status > 400 && status < 500 && status !== 409) { | ||
// HTTP 4xx, the server won't send anything, it's doesn't make sense to retry | ||
return false; | ||
} else if (typeof navigator !== 'undefined' && navigator.onLine === false) { | ||
// The navigator is offline, let's wait for it to come back online. | ||
if (!this.requests.isPaused) { | ||
this.requests.pause(); | ||
window.addEventListener('online', () => { | ||
this.requests.resume(); | ||
}, { | ||
once: true | ||
}); | ||
} | ||
} | ||
queuedRequest.abort(); | ||
queuedRequest = { | ||
shouldBeRequeued: true, | ||
abort() { | ||
this.shouldBeRequeued = false; | ||
}, | ||
done() { | ||
throw new Error('Cannot mark a queued request as done: this indicates a bug'); | ||
}, | ||
fn() { | ||
throw new Error('Cannot run a queued request: this indicates a bug'); | ||
} | ||
}; | ||
return true; | ||
}; | ||
if (opts.onShouldRetry != null) { | ||
uploadOptions.onShouldRetry = function () { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return opts.onShouldRetry(...args, defaultOnShouldRetry); | ||
}; | ||
} else { | ||
uploadOptions.onShouldRetry = defaultOnShouldRetry; | ||
} | ||
const copyProp = (obj, srcProp, destProp) => { | ||
if (hasProperty(obj, srcProp) && !hasProperty(obj, destProp)) { | ||
// eslint-disable-next-line no-param-reassign | ||
obj[destProp] = obj[srcProp]; | ||
} | ||
}; | ||
/** @type {Record<string, string>} */ | ||
const meta = {}; | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) ? opts.allowedMetaFields // Send along all fields by default. | ||
: Object.keys(file.meta); | ||
allowedMetaFields.forEach(item => { | ||
meta[item] = file.meta[item]; | ||
}); // tusd uses metadata fields 'filetype' and 'filename' | ||
copyProp(meta, 'type', 'filetype'); | ||
copyProp(meta, 'name', 'filename'); | ||
uploadOptions.metadata = meta; | ||
upload = new tus.Upload(file.data, uploadOptions); | ||
this.uploaders[file.id] = upload; | ||
this.uploaderEvents[file.id] = new EventTracker(this.uppy); // eslint-disable-next-line prefer-const | ||
qRequest = () => { | ||
if (!file.isPaused) { | ||
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 | ||
// 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 | ||
// related to this upload to handle pauses. | ||
return () => {}; | ||
}; | ||
upload.findPreviousUploads().then(previousUploads => { | ||
const previousUpload = previousUploads[0]; | ||
if (previousUpload) { | ||
this.uppy.log(`[Tus] Resuming upload of ${file.id} started at ${previousUpload.creationTime}`); | ||
upload.resumeFromPreviousUpload(previousUpload); | ||
} | ||
}); | ||
queuedRequest = this.requests.run(qRequest); | ||
this.onFileRemove(file.id, targetFileID => { | ||
queuedRequest.abort(); | ||
this.resetUploaderReferences(file.id, { | ||
abort: !!upload.url | ||
}); | ||
resolve(`upload ${targetFileID} was removed`); | ||
}); | ||
this.onPause(file.id, isPaused => { | ||
queuedRequest.abort(); | ||
if (isPaused) { | ||
// Remove this file from the queue so another file can start in its place. | ||
upload.abort(); | ||
} else { | ||
// Resuming an upload should be queued, else you could pause and then | ||
// resume a queued upload to make it skip the queue. | ||
queuedRequest = this.requests.run(qRequest); | ||
} | ||
}); | ||
this.onPauseAll(file.id, () => { | ||
queuedRequest.abort(); | ||
upload.abort(); | ||
}); | ||
this.onCancelAll(file.id, function (_temp) { | ||
let { | ||
reason | ||
} = _temp === void 0 ? {} : _temp; | ||
if (reason === 'user') { | ||
queuedRequest.abort(); | ||
_this.resetUploaderReferences(file.id, { | ||
abort: !!upload.url | ||
}); | ||
} | ||
resolve(`upload ${file.id} was canceled`); | ||
}); | ||
this.onResumeAll(file.id, () => { | ||
queuedRequest.abort(); | ||
if (file.error) { | ||
upload.abort(); | ||
} | ||
queuedRequest = this.requests.run(qRequest); | ||
}); | ||
}).catch(err => { | ||
this.uppy.emit('upload-error', file, err); | ||
throw err; | ||
}); | ||
} | ||
// NOTE! Keep this duplicated code in sync with other plugins | ||
// TODO we should probably abstract this into a common function | ||
/** | ||
* @param {UppyFile} file for use with upload | ||
* @returns {Promise<void>} | ||
*/ | ||
async uploadRemote(file) { | ||
this.resetUploaderReferences(file.id); // Don't double-emit upload-started for Golden Retriever-restored files that were already started | ||
if (!file.progress.uploadStarted || !file.isRestored) { | ||
this.uppy.emit('upload-started', file); | ||
} | ||
try { | ||
if (file.serverToken) { | ||
return await this.connectToServerSocket(file); | ||
} | ||
const serverToken = await _classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken](file); | ||
if (!this.uppy.getState().files[file.id]) return undefined; | ||
this.uppy.setFileState(file.id, { | ||
serverToken | ||
}); | ||
return await this.connectToServerSocket(this.uppy.getFile(file.id)); | ||
} catch (err) { | ||
this.uppy.setFileState(file.id, { | ||
serverToken: undefined | ||
}); | ||
this.uppy.emit('upload-error', file, err); | ||
throw err; | ||
} | ||
} | ||
/** | ||
* See the comment on the upload() method. | ||
@@ -561,6 +289,4 @@ * | ||
*/ | ||
async connectToServerSocket(file) { | ||
var _this2 = this; | ||
var _this = this; | ||
@@ -603,6 +329,6 @@ return new Promise((resolve, reject) => { | ||
}); | ||
this.onCancelAll(file.id, function (_temp2) { | ||
this.onCancelAll(file.id, function (_temp) { | ||
let { | ||
reason | ||
} = _temp2 === void 0 ? {} : _temp2; | ||
} = _temp === void 0 ? {} : _temp; | ||
@@ -613,3 +339,3 @@ if (reason === 'user') { | ||
_this2.resetUploaderReferences(file.id); | ||
_this.resetUploaderReferences(file.id); | ||
} | ||
@@ -790,6 +516,6 @@ | ||
onCancelAll(fileID, eventHandler) { | ||
var _this3 = this; | ||
var _this2 = this; | ||
this.uploaderEvents[fileID].on('cancel-all', function () { | ||
if (!_this3.uppy.getFile(fileID)) return; | ||
if (!_this2.uppy.getFile(fileID)) return; | ||
eventHandler(...arguments); | ||
@@ -815,71 +541,333 @@ }); | ||
uploadFiles(files) { | ||
const promises = files.map((file, i) => { | ||
const current = i + 1; | ||
const total = files.length; | ||
install() { | ||
this.uppy.setState({ | ||
capabilities: { ...this.uppy.getState().capabilities, | ||
resumableUploads: true | ||
} | ||
}); | ||
this.uppy.addUploader(_classPrivateFieldLooseBase(this, _handleUpload)[_handleUpload]); | ||
this.uppy.on('reset-progress', this.handleResetProgress); | ||
} | ||
if ('error' in file && file.error) { | ||
return Promise.reject(new Error(file.error)); | ||
uninstall() { | ||
this.uppy.setState({ | ||
capabilities: { ...this.uppy.getState().capabilities, | ||
resumableUploads: false | ||
} | ||
}); | ||
this.uppy.removeUploader(_classPrivateFieldLooseBase(this, _handleUpload)[_handleUpload]); | ||
} | ||
if (file.isRemote) { | ||
// We emit upload-started here, so that it's also emitted for files | ||
// that have to wait due to the `limit` option. | ||
// Don't double-emit upload-started for Golden Retriever-restored files that were already started | ||
if (!file.progress.uploadStarted || !file.isRestored) { | ||
this.uppy.emit('upload-started', file); | ||
} | ||
} | ||
return this.uploadRemote(file, current, total); | ||
} // Don't double-emit upload-started for Golden Retriever-restored files that were already started | ||
function _upload2(file) { | ||
var _this3 = this; | ||
this.resetUploaderReferences(file.id); // Create a new tus upload | ||
if (!file.progress.uploadStarted || !file.isRestored) { | ||
this.uppy.emit('upload-started', file); | ||
return new Promise((resolve, reject) => { | ||
let queuedRequest; | ||
let qRequest; | ||
let upload; | ||
const opts = { ...this.opts, | ||
...(file.tus || {}) | ||
}; | ||
if (typeof opts.headers === 'function') { | ||
opts.headers = opts.headers(file); | ||
} | ||
/** @type {RawTusOptions} */ | ||
const uploadOptions = { ...tusDefaultOptions, | ||
...opts | ||
}; // We override tus fingerprint to uppy’s `file.id`, since the `file.id` | ||
// now also includes `relativePath` for files added from folders. | ||
// This means you can add 2 identical files, if one is in folder a, | ||
// the other in folder b. | ||
uploadOptions.fingerprint = getFingerprint(file); | ||
uploadOptions.onBeforeRequest = req => { | ||
const xhr = req.getUnderlyingObject(); | ||
xhr.withCredentials = !!opts.withCredentials; | ||
let userProvidedPromise; | ||
if (typeof opts.onBeforeRequest === 'function') { | ||
userProvidedPromise = opts.onBeforeRequest(req, file); | ||
} | ||
return this.upload(file, current, total); | ||
}); | ||
return settle(promises); | ||
} | ||
/** | ||
* @param {string[]} fileIDs | ||
*/ | ||
if (hasProperty(queuedRequest, 'shouldBeRequeued')) { | ||
if (!queuedRequest.shouldBeRequeued) return Promise.reject(); | ||
let done; | ||
const p = new Promise(res => { | ||
// eslint-disable-line promise/param-names | ||
done = res; | ||
}); | ||
queuedRequest = this.requests.run(() => { | ||
if (file.isPaused) { | ||
queuedRequest.abort(); | ||
} | ||
done(); | ||
return () => {}; | ||
}); // If the request has been requeued because it was rate limited by the | ||
// remote server, we want to wait for `RateLimitedQueue` to dispatch | ||
// the re-try request. | ||
// Therefore we create a promise that the queue will resolve when | ||
// enough time has elapsed to expect not to be rate-limited again. | ||
// This means we can hold the Tus retry here with a `Promise.all`, | ||
// together with the returned value of the user provided | ||
// `onBeforeRequest` option callback (in case it returns a promise). | ||
handleUpload(fileIDs) { | ||
if (fileIDs.length === 0) { | ||
this.uppy.log('[Tus] No files to upload'); | ||
return Promise.resolve(); | ||
} | ||
return Promise.all([p, userProvidedPromise]); | ||
} | ||
if (this.opts.limit === 0) { | ||
this.uppy.log('[Tus] When uploading multiple files at once, consider setting the `limit` option (to `10` for example), to limit the number of concurrent uploads, which helps prevent memory and network issues: https://uppy.io/docs/tus/#limit-0', 'warning'); | ||
return userProvidedPromise; | ||
}; | ||
uploadOptions.onError = err => { | ||
var _queuedRequest; | ||
this.uppy.log(err); | ||
const xhr = err.originalRequest ? err.originalRequest.getUnderlyingObject() : null; | ||
if (isNetworkError(xhr)) { | ||
// eslint-disable-next-line no-param-reassign | ||
err = new NetworkError(err, xhr); | ||
} | ||
this.resetUploaderReferences(file.id); | ||
(_queuedRequest = queuedRequest) == null ? void 0 : _queuedRequest.abort(); | ||
this.uppy.emit('upload-error', file, err); | ||
reject(err); | ||
}; | ||
uploadOptions.onProgress = (bytesUploaded, bytesTotal) => { | ||
this.onReceiveUploadUrl(file, upload.url); | ||
this.uppy.emit('upload-progress', file, { | ||
uploader: this, | ||
bytesUploaded, | ||
bytesTotal | ||
}); | ||
}; | ||
uploadOptions.onSuccess = () => { | ||
const uploadResp = { | ||
uploadURL: upload.url | ||
}; | ||
this.resetUploaderReferences(file.id); | ||
queuedRequest.done(); | ||
this.uppy.emit('upload-success', file, uploadResp); | ||
if (upload.url) { | ||
this.uppy.log(`Download ${upload.file.name} from ${upload.url}`); | ||
} | ||
resolve(upload); | ||
}; | ||
const defaultOnShouldRetry = err => { | ||
var _err$originalResponse; | ||
const status = err == null ? void 0 : (_err$originalResponse = err.originalResponse) == null ? void 0 : _err$originalResponse.getStatus(); | ||
if (status === 429) { | ||
// HTTP 429 Too Many Requests => to avoid the whole download to fail, pause all requests. | ||
if (!this.requests.isPaused) { | ||
var _classPrivateFieldLoo; | ||
const next = (_classPrivateFieldLoo = _classPrivateFieldLooseBase(this, _retryDelayIterator)[_retryDelayIterator]) == null ? void 0 : _classPrivateFieldLoo.next(); | ||
if (next == null || next.done) { | ||
return false; | ||
} | ||
this.requests.rateLimit(next.value); | ||
} | ||
} else if (status > 400 && status < 500 && status !== 409) { | ||
// HTTP 4xx, the server won't send anything, it's doesn't make sense to retry | ||
return false; | ||
} else if (typeof navigator !== 'undefined' && navigator.onLine === false) { | ||
// The navigator is offline, let's wait for it to come back online. | ||
if (!this.requests.isPaused) { | ||
this.requests.pause(); | ||
window.addEventListener('online', () => { | ||
this.requests.resume(); | ||
}, { | ||
once: true | ||
}); | ||
} | ||
} | ||
queuedRequest.abort(); | ||
queuedRequest = { | ||
shouldBeRequeued: true, | ||
abort() { | ||
this.shouldBeRequeued = false; | ||
}, | ||
done() { | ||
throw new Error('Cannot mark a queued request as done: this indicates a bug'); | ||
}, | ||
fn() { | ||
throw new Error('Cannot run a queued request: this indicates a bug'); | ||
} | ||
}; | ||
return true; | ||
}; | ||
if (opts.onShouldRetry != null) { | ||
uploadOptions.onShouldRetry = function () { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return opts.onShouldRetry(...args, defaultOnShouldRetry); | ||
}; | ||
} else { | ||
uploadOptions.onShouldRetry = defaultOnShouldRetry; | ||
} | ||
this.uppy.log('[Tus] Uploading...'); | ||
const filesToUpload = fileIDs.map(fileID => this.uppy.getFile(fileID)); | ||
return this.uploadFiles(filesToUpload).then(() => null); | ||
} | ||
const copyProp = (obj, srcProp, destProp) => { | ||
if (hasProperty(obj, srcProp) && !hasProperty(obj, destProp)) { | ||
// eslint-disable-next-line no-param-reassign | ||
obj[destProp] = obj[srcProp]; | ||
} | ||
}; | ||
/** @type {Record<string, string>} */ | ||
install() { | ||
this.uppy.setState({ | ||
capabilities: { ...this.uppy.getState().capabilities, | ||
resumableUploads: true | ||
const meta = {}; | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) ? opts.allowedMetaFields // Send along all fields by default. | ||
: Object.keys(file.meta); | ||
allowedMetaFields.forEach(item => { | ||
meta[item] = file.meta[item]; | ||
}); // tusd uses metadata fields 'filetype' and 'filename' | ||
copyProp(meta, 'type', 'filetype'); | ||
copyProp(meta, 'name', 'filename'); | ||
uploadOptions.metadata = meta; | ||
upload = new tus.Upload(file.data, uploadOptions); | ||
this.uploaders[file.id] = upload; | ||
this.uploaderEvents[file.id] = new EventTracker(this.uppy); // eslint-disable-next-line prefer-const | ||
qRequest = () => { | ||
if (!file.isPaused) { | ||
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 | ||
// 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 | ||
// related to this upload to handle pauses. | ||
return () => {}; | ||
}; | ||
upload.findPreviousUploads().then(previousUploads => { | ||
const previousUpload = previousUploads[0]; | ||
if (previousUpload) { | ||
this.uppy.log(`[Tus] Resuming upload of ${file.id} started at ${previousUpload.creationTime}`); | ||
upload.resumeFromPreviousUpload(previousUpload); | ||
} | ||
}); | ||
this.uppy.addUploader(this.handleUpload); | ||
this.uppy.on('reset-progress', this.handleResetProgress); | ||
} | ||
queuedRequest = this.requests.run(qRequest); | ||
this.onFileRemove(file.id, targetFileID => { | ||
queuedRequest.abort(); | ||
this.resetUploaderReferences(file.id, { | ||
abort: !!upload.url | ||
}); | ||
resolve(`upload ${targetFileID} was removed`); | ||
}); | ||
this.onPause(file.id, isPaused => { | ||
queuedRequest.abort(); | ||
uninstall() { | ||
this.uppy.setState({ | ||
capabilities: { ...this.uppy.getState().capabilities, | ||
resumableUploads: false | ||
if (isPaused) { | ||
// Remove this file from the queue so another file can start in its place. | ||
upload.abort(); | ||
} else { | ||
// Resuming an upload should be queued, else you could pause and then | ||
// resume a queued upload to make it skip the queue. | ||
queuedRequest = this.requests.run(qRequest); | ||
} | ||
}); | ||
this.uppy.removeUploader(this.handleUpload); | ||
this.onPauseAll(file.id, () => { | ||
queuedRequest.abort(); | ||
upload.abort(); | ||
}); | ||
this.onCancelAll(file.id, function (_temp2) { | ||
let { | ||
reason | ||
} = _temp2 === void 0 ? {} : _temp2; | ||
if (reason === 'user') { | ||
queuedRequest.abort(); | ||
_this3.resetUploaderReferences(file.id, { | ||
abort: !!upload.url | ||
}); | ||
} | ||
resolve(`upload ${file.id} was canceled`); | ||
}); | ||
this.onResumeAll(file.id, () => { | ||
queuedRequest.abort(); | ||
if (file.error) { | ||
upload.abort(); | ||
} | ||
queuedRequest = this.requests.run(qRequest); | ||
}); | ||
}).catch(err => { | ||
this.uppy.emit('upload-error', file, err); | ||
throw err; | ||
}); | ||
} | ||
async function _uploadRemote2(file) { | ||
this.resetUploaderReferences(file.id); | ||
try { | ||
if (file.serverToken) { | ||
return await this.connectToServerSocket(file); | ||
} | ||
const serverToken = await _classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken](file); | ||
if (!this.uppy.getState().files[file.id]) return undefined; | ||
this.uppy.setFileState(file.id, { | ||
serverToken | ||
}); | ||
return await this.connectToServerSocket(this.uppy.getFile(file.id)); | ||
} catch (err) { | ||
this.uppy.setFileState(file.id, { | ||
serverToken: undefined | ||
}); | ||
this.uppy.emit('upload-error', file, err); | ||
throw err; | ||
} | ||
} | ||
async function _uploadFiles2(files) { | ||
const filesFiltered = filterNonFailedFiles(files); | ||
const filesToEmit = filterFilesToEmitUploadStarted(filesFiltered); | ||
this.uppy.emit('upload-start', filesToEmit); | ||
await Promise.allSettled(filesFiltered.map((file, i) => { | ||
const current = i + 1; | ||
const total = files.length; | ||
if (file.isRemote) { | ||
return _classPrivateFieldLooseBase(this, _uploadRemote)[_uploadRemote](file, current, total); | ||
} | ||
return _classPrivateFieldLooseBase(this, _upload)[_upload](file, current, total); | ||
})); | ||
} | ||
Tus.VERSION = packageJson.version; |
{ | ||
"name": "@uppy/tus", | ||
"description": "Resumable uploads for Uppy using Tus.io", | ||
"version": "3.0.6", | ||
"version": "3.1.0", | ||
"license": "MIT", | ||
@@ -26,4 +26,4 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@uppy/companion-client": "^3.1.2", | ||
"@uppy/utils": "^5.2.0", | ||
"@uppy/companion-client": "^3.1.3", | ||
"@uppy/utils": "^5.3.0", | ||
"tus-js-client": "^3.0.0" | ||
@@ -35,4 +35,4 @@ }, | ||
"peerDependencies": { | ||
"@uppy/core": "^3.1.2" | ||
"@uppy/core": "^3.2.0" | ||
} | ||
} |
# @uppy/tus | ||
<img src="https://uppy.io/images/logos/uppy-dog-head-arrow.svg" width="120" alt="Uppy logo: a superman puppy in a pink suit" align="right"> | ||
<img src="https://uppy.io/img/logo.svg" width="120" alt="Uppy logo: a smiling puppy above a pink upwards arrow" align="right"> | ||
@@ -5,0 +5,0 @@ [![npm version](https://img.shields.io/npm/v/@uppy/tus.svg?style=flat-square)](https://www.npmjs.com/package/@uppy/tus) |
@@ -6,3 +6,2 @@ import BasePlugin from '@uppy/core/lib/BasePlugin.js' | ||
import getSocketHost from '@uppy/utils/lib/getSocketHost' | ||
import settle from '@uppy/utils/lib/settle' | ||
import EventTracker from '@uppy/utils/lib/EventTracker' | ||
@@ -13,2 +12,3 @@ import NetworkError from '@uppy/utils/lib/NetworkError' | ||
import hasProperty from '@uppy/utils/lib/hasProperty' | ||
import { filterNonFailedFiles, filterFilesToEmitUploadStarted } from '@uppy/utils/lib/fileFilters' | ||
import getFingerprint from './getFingerprint.js' | ||
@@ -107,3 +107,2 @@ | ||
this.handleResetProgress = this.handleResetProgress.bind(this) | ||
this.handleUpload = this.handleUpload.bind(this) | ||
this.#queueRequestSocketToken = this.requests.wrapPromiseFunction(this.#requestSocketToken, { priority: -1 }) | ||
@@ -189,3 +188,3 @@ } | ||
*/ | ||
upload (file) { | ||
#upload (file) { | ||
this.resetUploaderReferences(file.id) | ||
@@ -199,4 +198,2 @@ | ||
this.uppy.emit('upload-started', file) | ||
const opts = { | ||
@@ -470,10 +467,5 @@ ...this.opts, | ||
*/ | ||
async uploadRemote (file) { | ||
async #uploadRemote (file) { | ||
this.resetUploaderReferences(file.id) | ||
// Don't double-emit upload-started for Golden Retriever-restored files that were already started | ||
if (!file.progress.uploadStarted || !file.isRestored) { | ||
this.uppy.emit('upload-started', file) | ||
} | ||
try { | ||
@@ -739,26 +731,16 @@ if (file.serverToken) { | ||
*/ | ||
uploadFiles (files) { | ||
const promises = files.map((file, i) => { | ||
async #uploadFiles (files) { | ||
const filesFiltered = filterNonFailedFiles(files) | ||
const filesToEmit = filterFilesToEmitUploadStarted(filesFiltered) | ||
this.uppy.emit('upload-start', filesToEmit) | ||
await Promise.allSettled(filesFiltered.map((file, i) => { | ||
const current = i + 1 | ||
const total = files.length | ||
if ('error' in file && file.error) { | ||
return Promise.reject(new Error(file.error)) | ||
} if (file.isRemote) { | ||
// We emit upload-started here, so that it's also emitted for files | ||
// that have to wait due to the `limit` option. | ||
// Don't double-emit upload-started for Golden Retriever-restored files that were already started | ||
if (!file.progress.uploadStarted || !file.isRestored) { | ||
this.uppy.emit('upload-started', file) | ||
} | ||
return this.uploadRemote(file, current, total) | ||
if (file.isRemote) { | ||
return this.#uploadRemote(file, current, total) | ||
} | ||
// Don't double-emit upload-started for Golden Retriever-restored files that were already started | ||
if (!file.progress.uploadStarted || !file.isRestored) { | ||
this.uppy.emit('upload-started', file) | ||
} | ||
return this.upload(file, current, total) | ||
}) | ||
return settle(promises) | ||
return this.#upload(file, current, total) | ||
})) | ||
} | ||
@@ -769,6 +751,6 @@ | ||
*/ | ||
handleUpload (fileIDs) { | ||
#handleUpload = async (fileIDs) => { | ||
if (fileIDs.length === 0) { | ||
this.uppy.log('[Tus] No files to upload') | ||
return Promise.resolve() | ||
return | ||
} | ||
@@ -784,6 +766,5 @@ | ||
this.uppy.log('[Tus] Uploading...') | ||
const filesToUpload = fileIDs.map((fileID) => this.uppy.getFile(fileID)) | ||
const filesToUpload = this.uppy.getFilesByIds(fileIDs) | ||
return this.uploadFiles(filesToUpload) | ||
.then(() => null) | ||
await this.#uploadFiles(filesToUpload) | ||
} | ||
@@ -795,3 +776,3 @@ | ||
}) | ||
this.uppy.addUploader(this.handleUpload) | ||
this.uppy.addUploader(this.#handleUpload) | ||
@@ -805,4 +786,4 @@ this.uppy.on('reset-progress', this.handleResetProgress) | ||
}) | ||
this.uppy.removeUploader(this.handleUpload) | ||
this.uppy.removeUploader(this.#handleUpload) | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
115317
1510
Updated@uppy/utils@^5.3.0