UNPKG

@triply/tus-js-client

Version:

A pure JavaScript client for the tus resumable upload protocol

1,697 lines (1,358 loc) 1.14 MB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _isReactNative = _interopRequireDefault(require("./isReactNative")); var _uriToBlob = _interopRequireDefault(require("./uriToBlob")); var _isCordova = _interopRequireDefault(require("./isCordova")); var _readAsByteArray = _interopRequireDefault(require("./readAsByteArray")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var FileSource = /*#__PURE__*/function () { // Make this.size a method function FileSource(file) { _classCallCheck(this, FileSource); this._file = file; this.size = file.size; } _createClass(FileSource, [{ key: "slice", value: function slice(start, end) { // In Apache Cordova applications, a File must be resolved using // FileReader instances, see // https://cordova.apache.org/docs/en/8.x/reference/cordova-plugin-file/index.html#read-a-file if ((0, _isCordova["default"])()) { return (0, _readAsByteArray["default"])(this._file.slice(start, end)); } var value = this._file.slice(start, end); return Promise.resolve({ value: value }); } }, { key: "close", value: function close() {// Nothing to do here since we don't need to release any resources. } }]); return FileSource; }(); var StreamSource = /*#__PURE__*/function () { function StreamSource(reader, chunkSize) { _classCallCheck(this, StreamSource); this._chunkSize = chunkSize; this._buffer = undefined; this._bufferOffset = 0; this._reader = reader; this._done = false; } _createClass(StreamSource, [{ key: "slice", value: function slice(start, end) { if (start < this._bufferOffset) { return Promise.reject(new Error("Requested data is before the reader's current offset")); } return this._readUntilEnoughDataOrDone(start, end); } }, { key: "_readUntilEnoughDataOrDone", value: function _readUntilEnoughDataOrDone(start, end) { var _this = this; var hasEnoughData = end <= this._bufferOffset + len(this._buffer); if (this._done || hasEnoughData) { var value = this._getDataFromBuffer(start, end); var done = value == null ? this._done : false; return Promise.resolve({ value: value, done: done }); } return this._reader.read().then(function (_ref) { var value = _ref.value, done = _ref.done; if (done) { _this._done = true; } else if (_this._buffer === undefined) { _this._buffer = value; } else { _this._buffer = concat(_this._buffer, value); } return _this._readUntilEnoughDataOrDone(start, end); }); } }, { key: "_getDataFromBuffer", value: function _getDataFromBuffer(start, end) { // Remove data from buffer before `start`. // Data might be reread from the buffer if an upload fails, so we can only // safely delete data when it comes *before* what is currently being read. if (start > this._bufferOffset) { this._buffer = this._buffer.slice(start - this._bufferOffset); this._bufferOffset = start; } // If the buffer is empty after removing old data, all data has been read. var hasAllDataBeenRead = len(this._buffer) === 0; if (this._done && hasAllDataBeenRead) { return null; } // We already removed data before `start`, so we just return the first // chunk from the buffer. return this._buffer.slice(0, end - start); } }, { key: "close", value: function close() { if (this._reader.cancel) { this._reader.cancel(); } } }]); return StreamSource; }(); function len(blobOrArray) { if (blobOrArray === undefined) return 0; if (blobOrArray.size !== undefined) return blobOrArray.size; return blobOrArray.length; } /* Typed arrays and blobs don't have a concat method. This function helps StreamSource accumulate data to reach chunkSize. */ function concat(a, b) { if (a.concat) { // Is `a` an Array? return a.concat(b); } if (a instanceof Blob) { return new Blob([a, b], { type: a.type }); } if (a.set) { // Is `a` a typed array? var c = new a.constructor(a.length + b.length); c.set(a); c.set(b, a.length); return c; } throw new Error('Unknown data type'); } var FileReader = /*#__PURE__*/function () { function FileReader() { _classCallCheck(this, FileReader); } _createClass(FileReader, [{ key: "openFile", value: function openFile(input, chunkSize) { // In React Native, when user selects a file, instead of a File or Blob, // you usually get a file object {} with a uri property that contains // a local path to the file. We use XMLHttpRequest to fetch // the file blob, before uploading with tus. if ((0, _isReactNative["default"])() && input && typeof input.uri !== 'undefined') { return (0, _uriToBlob["default"])(input.uri).then(function (blob) { return new FileSource(blob); })["catch"](function (err) { throw new Error("tus: cannot fetch `file.uri` as Blob, make sure the uri is correct and accessible. ".concat(err)); }); } // Since we emulate the Blob type in our tests (not all target browsers // support it), we cannot use `instanceof` for testing whether the input value // can be handled. Instead, we simply check is the slice() function and the // size property are available. if (typeof input.slice === 'function' && typeof input.size !== 'undefined') { return Promise.resolve(new FileSource(input)); } if (typeof input.read === 'function') { chunkSize = +chunkSize; if (!isFinite(chunkSize)) { return Promise.reject(new Error('cannot create source for stream without a finite value for the `chunkSize` option')); } return Promise.resolve(new StreamSource(input, chunkSize)); } return Promise.reject(new Error('source object may only be an instance of File, Blob, or Reader in this environment')); } }]); return FileReader; }(); exports["default"] = FileReader; },{"./isCordova":5,"./isReactNative":6,"./readAsByteArray":7,"./uriToBlob":8}],2:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = fingerprint; var _isReactNative = _interopRequireDefault(require("./isReactNative")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } // TODO: Differenciate between input types /** * Generate a fingerprint for a file which will be used the store the endpoint * * @param {File} file * @param {Object} options * @param {Function} callback */ function fingerprint(file, options) { if ((0, _isReactNative["default"])()) { return Promise.resolve(reactNativeFingerprint(file, options)); } return Promise.resolve(['tus-br', file.name, file.type, file.size, file.lastModified, options.endpoint].join('-')); } function reactNativeFingerprint(file, options) { var exifHash = file.exif ? hashCode(JSON.stringify(file.exif)) : 'noexif'; return ['tus-rn', file.name || 'noname', file.size || 'nosize', exifHash, options.endpoint].join('/'); } function hashCode(str) { // from https://stackoverflow.com/a/8831937/151666 var hash = 0; if (str.length === 0) { return hash; } for (var i = 0; i < str.length; i++) { var _char = str.charCodeAt(i); hash = (hash << 5) - hash + _char; hash &= hash; // Convert to 32bit integer } return hash; } },{"./isReactNative":6}],3:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } /* global window */ var XHRHttpStack = /*#__PURE__*/function () { function XHRHttpStack() { _classCallCheck(this, XHRHttpStack); } _createClass(XHRHttpStack, [{ key: "createRequest", value: function createRequest(method, url) { return new Request(method, url); } }, { key: "getName", value: function getName() { return 'XHRHttpStack'; } }]); return XHRHttpStack; }(); exports["default"] = XHRHttpStack; var Request = /*#__PURE__*/function () { function Request(method, url) { _classCallCheck(this, Request); this._xhr = new XMLHttpRequest(); this._xhr.open(method, url, true); this._method = method; this._url = url; this._headers = {}; } _createClass(Request, [{ key: "getMethod", value: function getMethod() { return this._method; } }, { key: "getURL", value: function getURL() { return this._url; } }, { key: "setHeader", value: function setHeader(header, value) { this._xhr.setRequestHeader(header, value); this._headers[header] = value; } }, { key: "getHeader", value: function getHeader(header) { return this._headers[header]; } }, { key: "setProgressHandler", value: function setProgressHandler(progressHandler) { // Test support for progress events before attaching an event listener if (!('upload' in this._xhr)) { return; } this._xhr.upload.onprogress = function (e) { if (!e.lengthComputable) { return; } progressHandler(e.loaded); }; } }, { key: "send", value: function send() { var _this = this; var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; return new Promise(function (resolve, reject) { _this._xhr.onload = function () { resolve(new Response(_this._xhr)); }; _this._xhr.onerror = function (err) { reject(err); }; _this._xhr.send(body); }); } }, { key: "abort", value: function abort() { this._xhr.abort(); return Promise.resolve(); } }, { key: "getUnderlyingObject", value: function getUnderlyingObject() { return this._xhr; } }]); return Request; }(); var Response = /*#__PURE__*/function () { function Response(xhr) { _classCallCheck(this, Response); this._xhr = xhr; } _createClass(Response, [{ key: "getStatus", value: function getStatus() { return this._xhr.status; } }, { key: "getHeader", value: function getHeader(header) { return this._xhr.getResponseHeader(header); } }, { key: "getBody", value: function getBody() { return this._xhr.responseText; } }, { key: "getUnderlyingObject", value: function getUnderlyingObject() { return this._xhr; } }]); return Response; }(); },{}],4:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "enableDebugLog", { enumerable: true, get: function get() { return _logger.enableDebugLog; } }); Object.defineProperty(exports, "canStoreURLs", { enumerable: true, get: function get() { return _urlStorage.canStoreURLs; } }); Object.defineProperty(exports, "HttpStack", { enumerable: true, get: function get() { return _httpStack["default"]; } }); exports.isSupported = exports.defaultOptions = exports.Upload = void 0; var _upload = _interopRequireDefault(require("../upload")); var _noopUrlStorage = _interopRequireDefault(require("../noopUrlStorage")); var _logger = require("../logger"); var _urlStorage = require("./urlStorage"); var _httpStack = _interopRequireDefault(require("./httpStack")); var _fileReader = _interopRequireDefault(require("./fileReader")); var _fingerprint = _interopRequireDefault(require("./fingerprint")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /* global window */ var defaultOptions = _objectSpread(_objectSpread({}, _upload["default"].defaultOptions), {}, { httpStack: new _httpStack["default"](), fileReader: new _fileReader["default"](), urlStorage: _urlStorage.canStoreURLs ? new _urlStorage.WebStorageUrlStorage() : new _noopUrlStorage["default"](), fingerprint: _fingerprint["default"] }); exports.defaultOptions = defaultOptions; var Upload = /*#__PURE__*/function (_BaseUpload) { _inherits(Upload, _BaseUpload); var _super = _createSuper(Upload); function Upload() { var file = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, Upload); options = _objectSpread(_objectSpread({}, defaultOptions), options); return _super.call(this, file, options); } _createClass(Upload, null, [{ key: "terminate", value: function terminate(url, options, cb) { options = _objectSpread(_objectSpread({}, defaultOptions), options); return _upload["default"].terminate(url, options, cb); } }]); return Upload; }(_upload["default"]); exports.Upload = Upload; var _window = window, XMLHttpRequest = _window.XMLHttpRequest, Blob = _window.Blob; var isSupported = XMLHttpRequest && Blob && typeof Blob.prototype.slice === 'function'; exports.isSupported = isSupported; },{"../logger":11,"../noopUrlStorage":12,"../upload":13,"./fileReader":1,"./fingerprint":2,"./httpStack":3,"./urlStorage":9}],5:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var isCordova = function isCordova() { return typeof window != 'undefined' && (typeof window.PhoneGap != 'undefined' || typeof window.Cordova != 'undefined' || typeof window.cordova != 'undefined'); }; var _default = isCordova; exports["default"] = _default; },{}],6:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var isReactNative = function isReactNative() { return typeof navigator !== 'undefined' && typeof navigator.product === 'string' && navigator.product.toLowerCase() === 'reactnative'; }; var _default = isReactNative; exports["default"] = _default; },{}],7:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = readAsByteArray; /** * readAsByteArray converts a File object to a Uint8Array. * This function is only used on the Apache Cordova platform. * See https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html#read-a-file */ function readAsByteArray(chunk) { return new Promise(function (resolve, reject) { var reader = new FileReader(); reader.onload = function () { var value = new Uint8Array(reader.result); resolve({ value: value }); }; reader.onerror = function (err) { reject(err); }; reader.readAsArrayBuffer(chunk); }); } },{}],8:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = uriToBlob; /** * uriToBlob resolves a URI to a Blob object. This is used for * React Native to retrieve a file (identified by a file:// * URI) as a blob. */ function uriToBlob(uri) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); xhr.responseType = 'blob'; xhr.onload = function () { var blob = xhr.response; resolve(blob); }; xhr.onerror = function (err) { reject(err); }; xhr.open('GET', uri); xhr.send(); }); } },{}],9:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebStorageUrlStorage = exports.canStoreURLs = void 0; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } /* global window, localStorage */ var hasStorage = false; try { hasStorage = 'localStorage' in window; // Attempt to store and read entries from the local storage to detect Private // Mode on Safari on iOS (see #49) var key = 'tusSupport'; localStorage.setItem(key, localStorage.getItem(key)); } catch (e) { // If we try to access localStorage inside a sandboxed iframe, a SecurityError // is thrown. When in private mode on iOS Safari, a QuotaExceededError is // thrown (see #49) if (e.code === e.SECURITY_ERR || e.code === e.QUOTA_EXCEEDED_ERR) { hasStorage = false; } else { throw e; } } var canStoreURLs = hasStorage; exports.canStoreURLs = canStoreURLs; var WebStorageUrlStorage = /*#__PURE__*/function () { function WebStorageUrlStorage() { _classCallCheck(this, WebStorageUrlStorage); } _createClass(WebStorageUrlStorage, [{ key: "findAllUploads", value: function findAllUploads() { var results = this._findEntries('tus::'); return Promise.resolve(results); } }, { key: "findUploadsByFingerprint", value: function findUploadsByFingerprint(fingerprint) { var results = this._findEntries("tus::".concat(fingerprint, "::")); return Promise.resolve(results); } }, { key: "removeUpload", value: function removeUpload(urlStorageKey) { localStorage.removeItem(urlStorageKey); return Promise.resolve(); } }, { key: "addUpload", value: function addUpload(fingerprint, upload) { var id = Math.round(Math.random() * 1e12); var key = "tus::".concat(fingerprint, "::").concat(id); localStorage.setItem(key, JSON.stringify(upload)); return Promise.resolve(key); } }, { key: "_findEntries", value: function _findEntries(prefix) { var results = []; for (var i = 0; i < localStorage.length; i++) { var _key = localStorage.key(i); if (_key.indexOf(prefix) !== 0) continue; try { var upload = JSON.parse(localStorage.getItem(_key)); upload.urlStorageKey = _key; results.push(upload); } catch (e) {// The JSON parse error is intentionally ignored here, so a malformed // entry in the storage cannot prevent an upload. } } return results; } }]); return WebStorageUrlStorage; }(); exports.WebStorageUrlStorage = WebStorageUrlStorage; },{}],10:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } var DetailedError = /*#__PURE__*/function (_Error) { _inherits(DetailedError, _Error); var _super = _createSuper(DetailedError); function DetailedError(message) { var _this; var causingErr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var req = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; var res = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; _classCallCheck(this, DetailedError); _this = _super.call(this, message); _this.originalRequest = req; _this.originalResponse = res; _this.causingError = causingErr; if (causingErr != null) { message += ", caused by ".concat(causingErr.toString()); } if (req != null) { var requestId = req.getHeader('X-Request-ID') || 'n/a'; var method = req.getMethod(); var url = req.getURL(); var status = res ? res.getStatus() : 'n/a'; var body = res ? res.getBody() || '' : 'n/a'; message += ", originated from request (method: ".concat(method, ", url: ").concat(url, ", response code: ").concat(status, ", response text: ").concat(body, ", request id: ").concat(requestId, ")"); } _this.message = message; return _this; } return DetailedError; }( /*#__PURE__*/_wrapNativeSuper(Error)); var _default = DetailedError; exports["default"] = _default; },{}],11:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.enableDebugLog = enableDebugLog; exports.log = log; /* eslint no-console: "off" */ var isEnabled = false; function enableDebugLog() { isEnabled = true; } function log(msg) { if (!isEnabled) return; console.log(msg); } },{}],12:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } /* eslint no-unused-vars: "off" */ var NoopUrlStorage = /*#__PURE__*/function () { function NoopUrlStorage() { _classCallCheck(this, NoopUrlStorage); } _createClass(NoopUrlStorage, [{ key: "listAllUploads", value: function listAllUploads() { return Promise.resolve([]); } }, { key: "findUploadsByFingerprint", value: function findUploadsByFingerprint(fingerprint) { return Promise.resolve([]); } }, { key: "removeUpload", value: function removeUpload(urlStorageKey) { return Promise.resolve(); } }, { key: "addUpload", value: function addUpload(fingerprint, upload) { return Promise.resolve(null); } }]); return NoopUrlStorage; }(); exports["default"] = NoopUrlStorage; },{}],13:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _jsBase = require("js-base64"); var _urlParse = _interopRequireDefault(require("url-parse")); var _error = _interopRequireDefault(require("./error")); var _logger = require("./logger"); var _uuid = _interopRequireDefault(require("./uuid")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } /* global window */ var defaultOptions = { endpoint: null, uploadUrl: null, metadata: {}, fingerprint: null, uploadSize: null, onProgress: null, onChunkComplete: null, onSuccess: null, onError: null, _onUploadUrlAvailable: null, overridePatchMethod: false, headers: {}, addRequestId: false, onBeforeRequest: null, onAfterResponse: null, onShouldRetry: null, chunkSize: Infinity, retryDelays: [0, 1000, 3000, 5000], parallelUploads: 1, storeFingerprintForResuming: true, removeFingerprintOnSuccess: false, uploadLengthDeferred: false, uploadDataDuringCreation: false, urlStorage: null, fileReader: null, httpStack: null }; var BaseUpload = /*#__PURE__*/function () { function BaseUpload(file, options) { _classCallCheck(this, BaseUpload); // Warn about removed options from previous versions if ('resume' in options) { console.log('tus: The `resume` option has been removed in tus-js-client v2. Please use the URL storage API instead.'); // eslint-disable-line no-console } // The default options will already be added from the wrapper classes. this.options = options; // The storage module used to store URLs this._urlStorage = this.options.urlStorage; // The underlying File/Blob object this.file = file; // The URL against which the file will be uploaded this.url = null; // The underlying request object for the current PATCH request this._req = null; // The fingerpinrt for the current file (set after start()) this._fingerprint = null; // The key that the URL storage returned when saving an URL with a fingerprint, this._urlStorageKey = null; // The offset used in the current PATCH request this._offset = null; // True if the current PATCH request has been aborted this._aborted = false; // The file's size in bytes this._size = null; // The Source object which will wrap around the given file and provides us // with a unified interface for getting its size and slice chunks from its // content allowing us to easily handle Files, Blobs, Buffers and Streams. this._source = null; // The current count of attempts which have been made. Zero indicates none. this._retryAttempt = 0; // The timeout's ID which is used to delay the next retry this._retryTimeout = null; // The offset of the remote upload before the latest attempt was started. this._offsetBeforeRetry = 0; // An array of BaseUpload instances which are used for uploading the different // parts, if the parallelUploads option is used. this._parallelUploads = null; // An array of upload URLs which are used for uploading the different // parts, if the parallelUploads option is used. this._parallelUploadUrls = null; } /** * Use the Termination extension to delete an upload from the server by sending a DELETE * request to the specified upload URL. This is only possible if the server supports the * Termination extension. If the `options.retryDelays` property is set, the method will * also retry if an error ocurrs. * * @param {String} url The upload's URL which will be terminated. * @param {object} options Optional options for influencing HTTP requests. * @return {Promise} The Promise will be resolved/rejected when the requests finish. */ _createClass(BaseUpload, [{ key: "findPreviousUploads", value: function findPreviousUploads() { var _this = this; return this.options.fingerprint(this.file, this.options).then(function (fingerprint) { return _this._urlStorage.findUploadsByFingerprint(fingerprint); }); } }, { key: "resumeFromPreviousUpload", value: function resumeFromPreviousUpload(previousUpload) { this.url = previousUpload.uploadUrl || null; this._parallelUploadUrls = previousUpload.parallelUploadUrls || null; this._urlStorageKey = previousUpload.urlStorageKey; } }, { key: "start", value: function start() { var _this2 = this; var file = this.file; if (!file) { this._emitError(new Error('tus: no file or stream to upload provided')); return; } if (!this.options.endpoint && !this.options.uploadUrl) { this._emitError(new Error('tus: neither an endpoint or an upload URL is provided')); return; } var retryDelays = this.options.retryDelays; if (retryDelays != null && Object.prototype.toString.call(retryDelays) !== '[object Array]') { this._emitError(new Error('tus: the `retryDelays` option must either be an array or null')); return; } if (this.options.parallelUploads > 1) { // Test which options are incompatible with parallel uploads. ['uploadUrl', 'uploadSize', 'uploadLengthDeferred'].forEach(function (optionName) { if (_this2.options[optionName]) { _this2._emitError(new Error("tus: cannot use the ".concat(optionName, " option when parallelUploads is enabled"))); } }); } this.options.fingerprint(file, this.options).then(function (fingerprint) { if (fingerprint == null) { (0, _logger.log)('No fingerprint was calculated meaning that the upload cannot be stored in the URL storage.'); } else { (0, _logger.log)("Calculated fingerprint: ".concat(fingerprint)); } _this2._fingerprint = fingerprint; if (_this2._source) { return _this2._source; } return _this2.options.fileReader.openFile(file, _this2.options.chunkSize); }).then(function (source) { _this2._source = source; // If the upload was configured to use multiple requests or if we resume from // an upload which used multiple requests, we start a parallel upload. if (_this2.options.parallelUploads > 1 || _this2._parallelUploadUrls != null) { _this2._startParallelUpload(); } else { _this2._startSingleUpload(); } })["catch"](function (err) { _this2._emitError(err); }); } /** * Initiate the uploading procedure for a parallelized upload, where one file is split into * multiple request which are run in parallel. * * @api private */ }, { key: "_startParallelUpload", value: function _startParallelUpload() { var _this3 = this; var totalSize = this._size = this._source.size; var totalProgress = 0; this._parallelUploads = []; var partCount = this._parallelUploadUrls != null ? this._parallelUploadUrls.length : this.options.parallelUploads; // The input file will be split into multiple slices which are uploaded in separate // requests. Here we generate the start and end position for the slices. var parts = splitSizeIntoParts(this._source.size, partCount, this._parallelUploadUrls); // Create an empty list for storing the upload URLs this._parallelUploadUrls = new Array(parts.length); // Generate a promise for each slice that will be resolve if the respective // upload is completed. var uploads = parts.map(function (part, index) { var lastPartProgress = 0; return _this3._source.slice(part.start, part.end).then(function (_ref) { var value = _ref.value; return new Promise(function (resolve, reject) { // Merge with the user supplied options but overwrite some values. var options = _objectSpread(_objectSpread({}, _this3.options), {}, { // If available, the partial upload should be resumed from a previous URL. uploadUrl: part.uploadUrl || null, // We take manually care of resuming for partial uploads, so they should // not be stored in the URL storage. storeFingerprintForResuming: false, removeFingerprintOnSuccess: false, // Reset the parallelUploads option to not cause recursion. parallelUploads: 1, metadata: {}, // Add the header to indicate the this is a partial upload. headers: _objectSpread(_objectSpread({}, _this3.options.headers), {}, { 'Upload-Concat': 'partial' }), // Reject or resolve the promise if the upload errors or completes. onSuccess: resolve, onError: reject, // Based in the progress for this partial upload, calculate the progress // for the entire final upload. onProgress: function onProgress(newPartProgress) { totalProgress = totalProgress - lastPartProgress + newPartProgress; lastPartProgress = newPartProgress; _this3._emitProgress(totalProgress, totalSize); }, // Wait until every partial upload has an upload URL, so we can add // them to the URL storage. _onUploadUrlAvailable: function _onUploadUrlAvailable() { _this3._parallelUploadUrls[index] = upload.url; // Test if all uploads have received an URL if (_this3._parallelUploadUrls.filter(function (u) { return !!u; }).length === parts.length) { _this3._saveUploadInUrlStorage(); } } }); var upload = new BaseUpload(value, options); upload.start(); // Store the upload in an array, so we can later abort them if necessary. _this3._parallelUploads.push(upload); }); }); }); var req; // Wait until all partial uploads are finished and we can send the POST request for // creating the final upload. Promise.all(uploads).then(function () { req = _this3._openRequest('POST', _this3.options.endpoint); req.setHeader('Upload-Concat', "final;".concat(_this3._parallelUploadUrls.join(' '))); // Add metadata if values have been added var metadata = encodeMetadata(_this3.options.metadata); if (metadata !== '') { req.setHeader('Upload-Metadata', metadata); } return _this3._sendRequest(req, null); }).then(function (res) { if (!inStatusCategory(res.getStatus(), 200)) { _this3._emitHttpError(req, res, 'tus: unexpected response while creating upload'); return; } var location = res.getHeader('Location'); if (location == null) { _this3._emitHttpError(req, res, 'tus: invalid or missing Location header'); return; } _this3.url = resolveUrl(_this3.options.endpoint, location); (0, _logger.log)("Created upload at ".concat(_this3.url)); _this3._emitSuccess(); })["catch"](function (err) { _this3._emitError(err); }); } /** * Initiate the uploading procedure for a non-parallel upload. Here the entire file is * uploaded in a sequential matter. * * @api private */ }, { key: "_startSingleUpload", value: function _startSingleUpload() { // First, we look at the uploadLengthDeferred option. // Next, we check if the caller has supplied a manual upload size. // Finally, we try to use the calculated size from the source object. if (this.options.uploadLengthDeferred) { this._size = null; } else if (this.options.uploadSize != null) { this._size = +this.options.uploadSize; if (isNaN(this._size)) { this._emitError(new Error('tus: cannot convert `uploadSize` option into a number')); return; } } else { this._size = this._source.size; if (this._size == null) { this._emitError(new Error("tus: cannot automatically derive upload's size from input and must be specified manually using the `uploadSize` option")); return; } } // Reset the aborted flag when the upload is started or else the // _performUpload will stop before sending a request if the upload has been // aborted previously. this._aborted = false; // The upload had been started previously and we should reuse this URL. if (this.url != null) { (0, _logger.log)("Resuming upload from previous URL: ".concat(this.url)); this._resumeUpload(); return; } // A URL has manually been specified, so we try to resume if (this.options.uploadUrl != null) { (0, _logger.log)("Resuming upload from provided URL: ".concat(this.options.url)); this.url = this.options.uploadUrl; this._resumeUpload(); return; } // An upload has not started for the file yet, so we start a new one (0, _logger.log)('Creating a new upload'); this._createUpload(); } /** * Abort any running request and stop the current upload. After abort is called, no event * handler will be invoked anymore. You can use the `start` method to resume the upload * again. * If `shouldTerminate` is true, the `terminate` function will be called to remove the * current upload from the server. * * @param {boolean} shouldTerminate True if the upload should be deleted from the server. * @return {Promise} The Promise will be resolved/rejected when the requests finish. */ }, { key: "abort", value: function abort(shouldTerminate) { var _this4 = this; // Count the number of arguments to see if a callback is being provided in the old style required by tus-js-client 1.x, then throw an error if it is. // `arguments` is a JavaScript built-in variable that contains all of the function's arguments. if (arguments.length > 1 && typeof arguments[1] === 'function') { throw new Error('tus: the abort function does not accept a callback since v2 anymore; please use the returned Promise instead'); } // Stop any parallel partial uploads, that have been started in _star