@uppy/xhr-upload
Advanced tools
Comparing version 3.3.2 to 3.4.0
# @uppy/xhr-upload | ||
## 3.4.0 | ||
Released: 2023-09-05 | ||
Included in: Uppy v3.15.0 | ||
- @uppy/aws-s3-multipart,@uppy/aws-s3,@uppy/companion-client,@uppy/core,@uppy/tus,@uppy/utils,@uppy/xhr-upload: Move remote file upload logic into companion-client (Merlijn Vos / #4573) | ||
## 3.3.2 | ||
@@ -4,0 +11,0 @@ |
207
lib/index.js
function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } | ||
var id = 0; | ||
function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; } | ||
import UploaderPlugin from '@uppy/core/lib/UploaderPlugin.js'; | ||
import BasePlugin from '@uppy/core/lib/BasePlugin.js'; | ||
import { nanoid } from 'nanoid/non-secure'; | ||
import { Provider, RequestClient, Socket } from '@uppy/companion-client'; | ||
import emitSocketProgress from '@uppy/utils/lib/emitSocketProgress'; | ||
import getSocketHost from '@uppy/utils/lib/getSocketHost'; | ||
import { Provider, RequestClient } from '@uppy/companion-client'; | ||
import EventManager from '@uppy/utils/lib/EventManager'; | ||
@@ -16,3 +14,3 @@ import ProgressTimeout from '@uppy/utils/lib/ProgressTimeout'; | ||
const packageJson = { | ||
"version": "3.3.2" | ||
"version": "3.4.0" | ||
}; | ||
@@ -52,8 +50,8 @@ import locale from './locale.js'; | ||
} | ||
var _upload = /*#__PURE__*/_classPrivateFieldLooseKey("upload"); | ||
var _requestSocketToken = /*#__PURE__*/_classPrivateFieldLooseKey("requestSocketToken"); | ||
var _uploadLocalFile = /*#__PURE__*/_classPrivateFieldLooseKey("uploadLocalFile"); | ||
var _uploadBundle = /*#__PURE__*/_classPrivateFieldLooseKey("uploadBundle"); | ||
var _getCompanionClientArgs = /*#__PURE__*/_classPrivateFieldLooseKey("getCompanionClientArgs"); | ||
var _uploadFiles = /*#__PURE__*/_classPrivateFieldLooseKey("uploadFiles"); | ||
var _handleUpload = /*#__PURE__*/_classPrivateFieldLooseKey("handleUpload"); | ||
export default class XHRUpload extends UploaderPlugin { | ||
export default class XHRUpload extends BasePlugin { | ||
constructor(uppy, _opts) { | ||
@@ -64,31 +62,11 @@ super(uppy, _opts); | ||
}); | ||
Object.defineProperty(this, _getCompanionClientArgs, { | ||
value: _getCompanionClientArgs2 | ||
}); | ||
Object.defineProperty(this, _uploadBundle, { | ||
value: _uploadBundle2 | ||
}); | ||
Object.defineProperty(this, _upload, { | ||
value: _upload2 | ||
Object.defineProperty(this, _uploadLocalFile, { | ||
value: _uploadLocalFile2 | ||
}); | ||
Object.defineProperty(this, _requestSocketToken, { | ||
writable: true, | ||
value: async (file, options) => { | ||
const opts = this.getOptions(file); | ||
const Client = file.remote.providerOptions.provider ? Provider : RequestClient; | ||
const client = new Client(this.uppy, file.remote.providerOptions); | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) ? opts.allowedMetaFields | ||
// Send along all fields by default. | ||
: Object.keys(file.meta); | ||
const res = await client.post(file.remote.url, { | ||
...file.remote.body, | ||
protocol: 'multipart', | ||
endpoint: opts.endpoint, | ||
size: file.data.size, | ||
fieldname: opts.fieldName, | ||
metadata: Object.fromEntries(allowedMetaFields.map(name => [name, file.meta[name]])), | ||
httpMethod: opts.method, | ||
useFormData: opts.formData, | ||
headers: typeof opts.headers === 'function' ? opts.headers(file) : opts.headers | ||
}, options); | ||
return res.token; | ||
} | ||
}); | ||
Object.defineProperty(this, _handleUpload, { | ||
@@ -136,3 +114,3 @@ writable: true, | ||
fieldName: _opts.bundle ? 'files[]' : 'file', | ||
method: 'POST', | ||
method: 'post', | ||
allowedMetaFields: null, | ||
@@ -198,5 +176,2 @@ responseUrlFieldName: 'url', | ||
this.uploaderEvents = Object.create(null); | ||
this.setQueueRequestSocketToken(this.requests.wrapPromiseFunction(_classPrivateFieldLooseBase(this, _requestSocketToken)[_requestSocketToken], { | ||
priority: -1 | ||
})); | ||
} | ||
@@ -276,121 +251,2 @@ getOptions(file) { | ||
} | ||
async connectToServerSocket(file) { | ||
return new Promise((resolve, reject) => { | ||
const opts = this.getOptions(file); | ||
const token = file.serverToken; | ||
const host = getSocketHost(file.remote.companionUrl); | ||
let socket; | ||
const createSocket = () => { | ||
if (socket != null) return; | ||
socket = new Socket({ | ||
target: `${host}/api/${token}` | ||
}); | ||
socket.on('progress', progressData => emitSocketProgress(this, progressData, file)); | ||
socket.on('success', data => { | ||
const body = opts.getResponseData(data.response.responseText, data.response); | ||
const uploadURL = body[opts.responseUrlFieldName]; | ||
const uploadResp = { | ||
status: data.response.status, | ||
body, | ||
uploadURL | ||
}; | ||
this.uppy.emit('upload-success', file, uploadResp); | ||
queuedRequest.done(); // eslint-disable-line no-use-before-define | ||
socket.close(); | ||
if (this.uploaderEvents[file.id]) { | ||
this.uploaderEvents[file.id].remove(); | ||
this.uploaderEvents[file.id] = null; | ||
} | ||
return resolve(); | ||
}); | ||
socket.on('error', errData => { | ||
const resp = errData.response; | ||
const error = resp ? opts.getResponseError(resp.responseText, resp) : Object.assign(new Error(errData.error.message), { | ||
cause: errData.error | ||
}); | ||
this.uppy.emit('upload-error', file, error); | ||
queuedRequest.done(); // eslint-disable-line no-use-before-define | ||
socket.close(); | ||
if (this.uploaderEvents[file.id]) { | ||
this.uploaderEvents[file.id].remove(); | ||
this.uploaderEvents[file.id] = null; | ||
} | ||
reject(error); | ||
}); | ||
}; | ||
this.uploaderEvents[file.id] = new EventManager(this.uppy); | ||
let queuedRequest = this.requests.run(() => { | ||
if (file.isPaused) { | ||
var _socket; | ||
(_socket = socket) == null ? void 0 : _socket.send('pause', {}); | ||
} else { | ||
createSocket(); | ||
} | ||
return () => {}; | ||
}); | ||
this.onFileRemove(file.id, () => { | ||
var _socket2; | ||
(_socket2 = socket) == null ? void 0 : _socket2.send('cancel', {}); | ||
socket.close(); | ||
queuedRequest.abort(); | ||
resolve(`upload ${file.id} was removed`); | ||
}); | ||
this.onCancelAll(file.id, function (_temp) { | ||
let { | ||
reason | ||
} = _temp === void 0 ? {} : _temp; | ||
if (reason === 'user') { | ||
var _socket3; | ||
(_socket3 = socket) == null ? void 0 : _socket3.send('cancel', {}); | ||
queuedRequest.abort(); | ||
// socket.close() | ||
} | ||
resolve(`upload ${file.id} was canceled`); | ||
}); | ||
const onRetryRequest = () => { | ||
if (socket == null) { | ||
queuedRequest.abort(); | ||
} else { | ||
queuedRequest.done(); | ||
} | ||
queuedRequest = this.requests.run(() => { | ||
if (socket == null) { | ||
createSocket(); | ||
} | ||
return () => {}; | ||
}); | ||
}; | ||
this.onRetry(file.id, onRetryRequest); | ||
this.onRetryAll(file.id, onRetryRequest); | ||
}).catch(err => { | ||
this.uppy.emit('upload-error', file, err); | ||
return Promise.reject(err); | ||
}); | ||
} | ||
onFileRemove(fileID, cb) { | ||
this.uploaderEvents[fileID].on('file-removed', file => { | ||
if (fileID === file.id) cb(file.id); | ||
}); | ||
} | ||
onRetry(fileID, cb) { | ||
this.uploaderEvents[fileID].on('upload-retry', targetFileID => { | ||
if (fileID === targetFileID) { | ||
cb(); | ||
} | ||
}); | ||
} | ||
onRetryAll(fileID, cb) { | ||
this.uploaderEvents[fileID].on('retry-all', () => { | ||
if (!this.uppy.getFile(fileID)) return; | ||
cb(); | ||
}); | ||
} | ||
onCancelAll(fileID, eventHandler) { | ||
var _this = this; | ||
this.uploaderEvents[fileID].on('cancel-all', function () { | ||
if (!_this.uppy.getFile(fileID)) return; | ||
eventHandler(...arguments); | ||
}); | ||
} | ||
install() { | ||
@@ -425,3 +281,3 @@ if (this.opts.bundle) { | ||
} | ||
async function _upload2(file, current, total) { | ||
async function _uploadLocalFile2(file, current, total) { | ||
const opts = this.getOptions(file); | ||
@@ -432,3 +288,4 @@ this.uppy.log(`uploading ${current} of ${total}`); | ||
const xhr = new XMLHttpRequest(); | ||
this.uploaderEvents[file.id] = new EventManager(this.uppy); | ||
const eventManager = new EventManager(this.uppy); | ||
this.uploaderEvents[file.id] = eventManager; | ||
let queuedRequest; | ||
@@ -523,7 +380,7 @@ const timer = new ProgressTimeout(opts.timeout, () => { | ||
}); | ||
this.onFileRemove(file.id, () => { | ||
eventManager.onFileRemove(file.id, () => { | ||
queuedRequest.abort(); | ||
reject(new Error('File removed')); | ||
}); | ||
this.onCancelAll(file.id, _ref => { | ||
eventManager.onCancelAll(file.id, _ref => { | ||
let { | ||
@@ -603,6 +460,6 @@ reason | ||
}); | ||
this.uppy.on('cancel-all', function (_temp2) { | ||
this.uppy.on('cancel-all', function (_temp) { | ||
let { | ||
reason | ||
} = _temp2 === void 0 ? {} : _temp2; | ||
} = _temp === void 0 ? {} : _temp; | ||
if (reason !== 'user') return; | ||
@@ -625,2 +482,19 @@ timer.done(); | ||
} | ||
function _getCompanionClientArgs2(file) { | ||
const opts = this.getOptions(file); | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) ? opts.allowedMetaFields | ||
// Send along all fields by default. | ||
: Object.keys(file.meta); | ||
return { | ||
...file.remote.body, | ||
protocol: 'multipart', | ||
endpoint: opts.endpoint, | ||
size: file.data.size, | ||
fieldname: opts.fieldName, | ||
metadata: Object.fromEntries(allowedMetaFields.map(name => [name, file.meta[name]])), | ||
httpMethod: opts.method, | ||
useFormData: opts.formData, | ||
headers: opts.headers | ||
}; | ||
} | ||
async function _uploadFiles2(files) { | ||
@@ -631,2 +505,7 @@ await Promise.allSettled(files.map((file, i) => { | ||
if (file.isRemote) { | ||
// INFO: the url plugin needs to use RequestClient, | ||
// while others use Provider | ||
const Client = file.remote.providerOptions.provider ? Provider : RequestClient; | ||
const getQueue = () => this.requests; | ||
const client = new Client(this.uppy, file.remote.providerOptions, getQueue); | ||
const controller = new AbortController(); | ||
@@ -637,3 +516,3 @@ const removedHandler = removedFile => { | ||
this.uppy.on('file-removed', removedHandler); | ||
const uploadPromise = this.uploadRemoteFile(file, { | ||
const uploadPromise = client.uploadRemoteFile(file, _classPrivateFieldLooseBase(this, _getCompanionClientArgs)[_getCompanionClientArgs](file), { | ||
signal: controller.signal | ||
@@ -648,3 +527,3 @@ }); | ||
} | ||
return _classPrivateFieldLooseBase(this, _upload)[_upload](file, current, total); | ||
return _classPrivateFieldLooseBase(this, _uploadLocalFile)[_uploadLocalFile](file, current, total); | ||
})); | ||
@@ -651,0 +530,0 @@ } |
{ | ||
"name": "@uppy/xhr-upload", | ||
"description": "Plain and simple classic HTML multipart form uploads with Uppy, as well as uploads using the HTTP PUT method.", | ||
"version": "3.3.2", | ||
"version": "3.4.0", | ||
"license": "MIT", | ||
@@ -28,4 +28,4 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@uppy/companion-client": "^3.3.0", | ||
"@uppy/utils": "^5.4.3", | ||
"@uppy/companion-client": "^3.4.0", | ||
"@uppy/utils": "^5.5.0", | ||
"nanoid": "^4.0.0" | ||
@@ -38,4 +38,4 @@ }, | ||
"peerDependencies": { | ||
"@uppy/core": "^3.4.0" | ||
"@uppy/core": "^3.5.0" | ||
} | ||
} |
201
src/index.js
@@ -1,6 +0,4 @@ | ||
import UploaderPlugin from '@uppy/core/lib/UploaderPlugin.js' | ||
import BasePlugin from '@uppy/core/lib/BasePlugin.js' | ||
import { nanoid } from 'nanoid/non-secure' | ||
import { Provider, RequestClient, Socket } from '@uppy/companion-client' | ||
import emitSocketProgress from '@uppy/utils/lib/emitSocketProgress' | ||
import getSocketHost from '@uppy/utils/lib/getSocketHost' | ||
import { Provider, RequestClient } from '@uppy/companion-client' | ||
import EventManager from '@uppy/utils/lib/EventManager' | ||
@@ -49,3 +47,3 @@ import ProgressTimeout from '@uppy/utils/lib/ProgressTimeout' | ||
export default class XHRUpload extends UploaderPlugin { | ||
export default class XHRUpload extends BasePlugin { | ||
// eslint-disable-next-line global-require | ||
@@ -66,3 +64,3 @@ static VERSION = packageJson.version | ||
fieldName: opts.bundle ? 'files[]' : 'file', | ||
method: 'POST', | ||
method: 'post', | ||
allowedMetaFields: null, | ||
@@ -132,3 +130,2 @@ responseUrlFieldName: 'url', | ||
this.uploaderEvents = Object.create(null) | ||
this.setQueueRequestSocketToken(this.requests.wrapPromiseFunction(this.#requestSocketToken, { priority: -1 })) | ||
} | ||
@@ -222,3 +219,3 @@ | ||
async #upload (file, current, total) { | ||
async #uploadLocalFile (file, current, total) { | ||
const opts = this.getOptions(file) | ||
@@ -233,3 +230,4 @@ | ||
const xhr = new XMLHttpRequest() | ||
this.uploaderEvents[file.id] = new EventManager(this.uppy) | ||
const eventManager = new EventManager(this.uppy) | ||
this.uploaderEvents[file.id] = eventManager | ||
let queuedRequest | ||
@@ -343,3 +341,3 @@ | ||
this.onFileRemove(file.id, () => { | ||
eventManager.onFileRemove(file.id, () => { | ||
queuedRequest.abort() | ||
@@ -349,3 +347,3 @@ reject(new Error('File removed')) | ||
this.onCancelAll(file.id, ({ reason }) => { | ||
eventManager.onCancelAll(file.id, ({ reason }) => { | ||
if (reason === 'user') { | ||
@@ -359,122 +357,2 @@ queuedRequest.abort() | ||
#requestSocketToken = async (file, options) => { | ||
const opts = this.getOptions(file) | ||
const Client = file.remote.providerOptions.provider ? Provider : RequestClient | ||
const client = new Client(this.uppy, file.remote.providerOptions) | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) | ||
? opts.allowedMetaFields | ||
// Send along all fields by default. | ||
: Object.keys(file.meta) | ||
const res = await client.post(file.remote.url, { | ||
...file.remote.body, | ||
protocol: 'multipart', | ||
endpoint: opts.endpoint, | ||
size: file.data.size, | ||
fieldname: opts.fieldName, | ||
metadata: Object.fromEntries(allowedMetaFields.map(name => [name, file.meta[name]])), | ||
httpMethod: opts.method, | ||
useFormData: opts.formData, | ||
headers: typeof opts.headers === 'function' ? opts.headers(file) : opts.headers, | ||
}, options) | ||
return res.token | ||
} | ||
async connectToServerSocket (file) { | ||
return new Promise((resolve, reject) => { | ||
const opts = this.getOptions(file) | ||
const token = file.serverToken | ||
const host = getSocketHost(file.remote.companionUrl) | ||
let socket | ||
const createSocket = () => { | ||
if (socket != null) return | ||
socket = new Socket({ target: `${host}/api/${token}` }) | ||
socket.on('progress', (progressData) => emitSocketProgress(this, progressData, file)) | ||
socket.on('success', (data) => { | ||
const body = opts.getResponseData(data.response.responseText, data.response) | ||
const uploadURL = body[opts.responseUrlFieldName] | ||
const uploadResp = { | ||
status: data.response.status, | ||
body, | ||
uploadURL, | ||
} | ||
this.uppy.emit('upload-success', file, uploadResp) | ||
queuedRequest.done() // eslint-disable-line no-use-before-define | ||
socket.close() | ||
if (this.uploaderEvents[file.id]) { | ||
this.uploaderEvents[file.id].remove() | ||
this.uploaderEvents[file.id] = null | ||
} | ||
return resolve() | ||
}) | ||
socket.on('error', (errData) => { | ||
const resp = errData.response | ||
const error = resp | ||
? opts.getResponseError(resp.responseText, resp) | ||
: Object.assign(new Error(errData.error.message), { cause: errData.error }) | ||
this.uppy.emit('upload-error', file, error) | ||
queuedRequest.done() // eslint-disable-line no-use-before-define | ||
socket.close() | ||
if (this.uploaderEvents[file.id]) { | ||
this.uploaderEvents[file.id].remove() | ||
this.uploaderEvents[file.id] = null | ||
} | ||
reject(error) | ||
}) | ||
} | ||
this.uploaderEvents[file.id] = new EventManager(this.uppy) | ||
let queuedRequest = this.requests.run(() => { | ||
if (file.isPaused) { | ||
socket?.send('pause', {}) | ||
} else { | ||
createSocket() | ||
} | ||
return () => {} | ||
}) | ||
this.onFileRemove(file.id, () => { | ||
socket?.send('cancel', {}) | ||
socket.close() | ||
queuedRequest.abort() | ||
resolve(`upload ${file.id} was removed`) | ||
}) | ||
this.onCancelAll(file.id, ({ reason } = {}) => { | ||
if (reason === 'user') { | ||
socket?.send('cancel', {}) | ||
queuedRequest.abort() | ||
// socket.close() | ||
} | ||
resolve(`upload ${file.id} was canceled`) | ||
}) | ||
const onRetryRequest = () => { | ||
if (socket == null) { | ||
queuedRequest.abort() | ||
} else { | ||
queuedRequest.done() | ||
} | ||
queuedRequest = this.requests.run(() => { | ||
if (socket == null) { | ||
createSocket() | ||
} | ||
return () => {} | ||
}) | ||
} | ||
this.onRetry(file.id, onRetryRequest) | ||
this.onRetryAll(file.id, onRetryRequest) | ||
}).catch((err) => { | ||
this.uppy.emit('upload-error', file, err) | ||
return Promise.reject(err) | ||
}) | ||
} | ||
#uploadBundle (files) { | ||
@@ -574,2 +452,21 @@ return new Promise((resolve, reject) => { | ||
#getCompanionClientArgs (file) { | ||
const opts = this.getOptions(file) | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) | ||
? opts.allowedMetaFields | ||
// Send along all fields by default. | ||
: Object.keys(file.meta) | ||
return { | ||
...file.remote.body, | ||
protocol: 'multipart', | ||
endpoint: opts.endpoint, | ||
size: file.data.size, | ||
fieldname: opts.fieldName, | ||
metadata: Object.fromEntries(allowedMetaFields.map(name => [name, file.meta[name]])), | ||
httpMethod: opts.method, | ||
useFormData: opts.formData, | ||
headers: opts.headers, | ||
} | ||
} | ||
async #uploadFiles (files) { | ||
@@ -581,2 +478,7 @@ await Promise.allSettled(files.map((file, i) => { | ||
if (file.isRemote) { | ||
// INFO: the url plugin needs to use RequestClient, | ||
// while others use Provider | ||
const Client = file.remote.providerOptions.provider ? Provider : RequestClient | ||
const getQueue = () => this.requests | ||
const client = new Client(this.uppy, file.remote.providerOptions, getQueue) | ||
const controller = new AbortController() | ||
@@ -589,3 +491,7 @@ | ||
const uploadPromise = this.uploadRemoteFile(file, { signal: controller.signal }) | ||
const uploadPromise = client.uploadRemoteFile( | ||
file, | ||
this.#getCompanionClientArgs(file), | ||
{ signal: controller.signal }, | ||
) | ||
@@ -598,34 +504,7 @@ this.requests.wrapSyncFunction(() => { | ||
} | ||
return this.#upload(file, current, total) | ||
return this.#uploadLocalFile(file, current, total) | ||
})) | ||
} | ||
onFileRemove (fileID, cb) { | ||
this.uploaderEvents[fileID].on('file-removed', (file) => { | ||
if (fileID === file.id) cb(file.id) | ||
}) | ||
} | ||
onRetry (fileID, cb) { | ||
this.uploaderEvents[fileID].on('upload-retry', (targetFileID) => { | ||
if (fileID === targetFileID) { | ||
cb() | ||
} | ||
}) | ||
} | ||
onRetryAll (fileID, cb) { | ||
this.uploaderEvents[fileID].on('retry-all', () => { | ||
if (!this.uppy.getFile(fileID)) return | ||
cb() | ||
}) | ||
} | ||
onCancelAll (fileID, eventHandler) { | ||
this.uploaderEvents[fileID].on('cancel-all', (...args) => { | ||
if (!this.uppy.getFile(fileID)) return | ||
eventHandler(...args) | ||
}) | ||
} | ||
#handleUpload = async (fileIDs) => { | ||
@@ -632,0 +511,0 @@ if (fileIDs.length === 0) { |
Sorry, the diff of this file is not supported yet
88375
1137
Updated@uppy/utils@^5.5.0