@uppy/xhr-upload
Advanced tools
Comparing version 3.0.2 to 3.0.3
# @uppy/xhr-upload | ||
## 3.0.3 | ||
Released: 2022-10-19 | ||
Included in: Uppy v3.2.0 | ||
- @uppy/xhr-upload: fix `Timed out waiting for socket` (Antoine du Hamel / #4150) | ||
- @uppy/aws-s3,@uppy/xhr-upload: fix `Cannot mark a queued request as done` in `MiniXHRUpload` (Antoine du Hamel / #4151) | ||
- @uppy/xhr-upload: queue requests for socket token for remote files (Daniel Jones / #4123) | ||
## 3.0.2 | ||
@@ -4,0 +13,0 @@ |
201
lib/index.js
@@ -0,1 +1,7 @@ | ||
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 BasePlugin from '@uppy/core/lib/BasePlugin.js'; | ||
@@ -13,3 +19,3 @@ import { nanoid } from 'nanoid/non-secure'; | ||
const packageJson = { | ||
"version": "3.0.2" | ||
"version": "3.0.3" | ||
}; | ||
@@ -54,6 +60,35 @@ import locale from './locale.js'; | ||
var _queueRequestSocketToken = /*#__PURE__*/_classPrivateFieldLooseKey("queueRequestSocketToken"); | ||
var _requestSocketToken = /*#__PURE__*/_classPrivateFieldLooseKey("requestSocketToken"); | ||
export default class XHRUpload extends BasePlugin { | ||
// eslint-disable-next-line global-require | ||
constructor(uppy, opts) { | ||
super(uppy, opts); | ||
constructor(uppy, _opts) { | ||
super(uppy, _opts); | ||
Object.defineProperty(this, _queueRequestSocketToken, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, _requestSocketToken, { | ||
writable: true, | ||
value: async file => { | ||
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: opts.headers | ||
}); | ||
return res.token; | ||
} | ||
}); | ||
this.type = 'uploader'; | ||
@@ -66,3 +101,3 @@ this.id = this.opts.id || 'XHRUpload'; | ||
formData: true, | ||
fieldName: opts.bundle ? 'files[]' : 'file', | ||
fieldName: _opts.bundle ? 'files[]' : 'file', | ||
method: 'post', | ||
@@ -119,3 +154,3 @@ allowedMetaFields: null, | ||
this.opts = { ...defaultOptions, | ||
...opts | ||
..._opts | ||
}; | ||
@@ -135,3 +170,3 @@ this.i18nInit(); | ||
if ((opts == null ? void 0 : opts.allowedMetaFields) === undefined && 'metaFields' in this.opts) { | ||
if ((_opts == null ? void 0 : _opts.allowedMetaFields) === undefined && 'metaFields' in this.opts) { | ||
throw new Error('The `metaFields` option has been renamed to `allowedMetaFields`.'); | ||
@@ -141,2 +176,5 @@ } | ||
this.uploaderEvents = Object.create(null); | ||
_classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken] = this.requests.wrapPromiseFunction(_classPrivateFieldLooseBase(this, _requestSocketToken)[_requestSocketToken], { | ||
priority: -1 | ||
}); | ||
} | ||
@@ -348,59 +386,35 @@ | ||
uploadRemote(file) { | ||
const opts = this.getOptions(file); | ||
return new Promise((resolve, reject) => { | ||
async uploadRemote(file) { | ||
// TODO: we could rewrite this to use server-sent events instead of creating WebSockets. | ||
try { | ||
this.uppy.emit('upload-started', file); | ||
const fields = {}; | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) ? opts.allowedMetaFields // Send along all fields by default. | ||
: Object.keys(file.meta); | ||
allowedMetaFields.forEach(name => { | ||
fields[name] = file.meta[name]; | ||
if (file.serverToken) { | ||
return this.connectToServerSocket(file); | ||
} | ||
const serverToken = await _classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken](file); | ||
if (this.getState().files[file.id]) return undefined; | ||
this.uppy.setFileState(file.id, { | ||
serverToken | ||
}); | ||
const Client = file.remote.providerOptions.provider ? Provider : RequestClient; | ||
const client = new Client(this.uppy, file.remote.providerOptions); | ||
client.post(file.remote.url, { ...file.remote.body, | ||
protocol: 'multipart', | ||
endpoint: opts.endpoint, | ||
size: file.data.size, | ||
fieldname: opts.fieldName, | ||
metadata: fields, | ||
httpMethod: opts.method, | ||
useFormData: opts.formData, | ||
headers: opts.headers | ||
}).then(res => { | ||
const { | ||
token | ||
} = res; | ||
const host = getSocketHost(file.remote.companionUrl); | ||
const socket = new Socket({ | ||
target: `${host}/api/${token}`, | ||
autoOpen: false | ||
}); | ||
this.uploaderEvents[file.id] = new EventTracker(this.uppy); | ||
let queuedRequest; | ||
this.onFileRemove(file.id, () => { | ||
socket.send('cancel', {}); | ||
queuedRequest.abort(); | ||
resolve(`upload ${file.id} was removed`); | ||
}); | ||
this.onCancelAll(file.id, function (_temp) { | ||
let { | ||
reason | ||
} = _temp === void 0 ? {} : _temp; | ||
return this.connectToServerSocket(this.uppy.getFile(file.id)); | ||
} catch (err) { | ||
this.uppy.emit('upload-error', file, err); | ||
throw err; | ||
} | ||
} | ||
if (reason === 'user') { | ||
socket.send('cancel', {}); | ||
queuedRequest.abort(); | ||
} | ||
connectToServerSocket(file) { | ||
return new Promise((resolve, reject) => { | ||
const opts = this.getOptions(file); | ||
const token = file.serverToken; | ||
const host = getSocketHost(file.remote.companionUrl); | ||
let socket; | ||
resolve(`upload ${file.id} was canceled`); | ||
const createSocket = () => { | ||
if (socket != null) return; | ||
socket = new Socket({ | ||
target: `${host}/api/${token}` | ||
}); | ||
this.onRetry(file.id, () => { | ||
socket.send('pause', {}); | ||
socket.send('resume', {}); | ||
}); | ||
this.onRetryAll(file.id, () => { | ||
socket.send('pause', {}); | ||
socket.send('resume', {}); | ||
}); | ||
socket.on('progress', progressData => emitSocketProgress(this, progressData, file)); | ||
@@ -416,4 +430,6 @@ socket.on('success', data => { | ||
this.uppy.emit('upload-success', file, uploadResp); | ||
queuedRequest.done(); | ||
queuedRequest.done(); // eslint-disable-line no-use-before-define | ||
socket.close(); | ||
if (this.uploaderEvents[file.id]) { | ||
@@ -432,3 +448,3 @@ this.uploaderEvents[file.id].remove(); | ||
this.uppy.emit('upload-error', file, error); | ||
queuedRequest.done(); | ||
queuedRequest.done(); // eslint-disable-line no-use-before-define | ||
@@ -442,7 +458,53 @@ if (this.uploaderEvents[file.id]) { | ||
}); | ||
}; | ||
this.uploaderEvents[file.id] = new EventTracker(this.uppy); | ||
let queuedRequest = this.requests.run(() => { | ||
if (file.isPaused) { | ||
var _socket; | ||
(_socket = socket) == null ? void 0 : _socket.send('pause', {}); | ||
} else { | ||
createSocket(); | ||
} | ||
return () => socket.close(); | ||
}); | ||
this.onFileRemove(file.id, () => { | ||
var _socket2; | ||
(_socket2 = socket) == null ? void 0 : _socket2.send('cancel', {}); | ||
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(); | ||
} | ||
resolve(`upload ${file.id} was canceled`); | ||
}); | ||
const onRetryRequest = () => { | ||
if (socket == null) { | ||
queuedRequest.abort(); | ||
} else { | ||
socket.send('pause', {}); | ||
queuedRequest.done(); | ||
} | ||
queuedRequest = this.requests.run(() => { | ||
socket.open(); | ||
if (file.isPaused) { | ||
socket.send('pause', {}); | ||
if (!file.isPaused) { | ||
if (socket == null) { | ||
createSocket(); | ||
} else { | ||
socket.send('resume', {}); | ||
} | ||
} | ||
@@ -452,6 +514,9 @@ | ||
}); | ||
}).catch(err => { | ||
this.uppy.emit('upload-error', file, err); | ||
reject(err); | ||
}); | ||
}; | ||
this.onRetry(file.id, onRetryRequest); | ||
this.onRetryAll(file.id, onRetryRequest); | ||
}).catch(err => { | ||
this.uppy.emit('upload-error', file, err); | ||
return Promise.reject(err); | ||
}); | ||
@@ -458,0 +523,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.0.2", | ||
"version": "3.0.3", | ||
"license": "MIT", | ||
@@ -37,4 +37,4 @@ "main": "lib/index.js", | ||
"peerDependencies": { | ||
"@uppy/core": "^3.0.2" | ||
"@uppy/core": "^3.0.3" | ||
} | ||
} |
155
src/index.js
@@ -53,2 +53,4 @@ import BasePlugin from '@uppy/core/lib/BasePlugin.js' | ||
#queueRequestSocketToken | ||
constructor (uppy, opts) { | ||
@@ -133,2 +135,3 @@ super(uppy, opts) | ||
this.uploaderEvents = Object.create(null) | ||
this.#queueRequestSocketToken = this.requests.wrapPromiseFunction(this.#requestSocketToken, { priority: -1 }) | ||
} | ||
@@ -356,60 +359,55 @@ | ||
uploadRemote (file) { | ||
#requestSocketToken = async (file) => { | ||
const opts = this.getOptions(file) | ||
return new Promise((resolve, reject) => { | ||
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: opts.headers, | ||
}) | ||
return res.token | ||
} | ||
async uploadRemote (file) { | ||
// TODO: we could rewrite this to use server-sent events instead of creating WebSockets. | ||
try { | ||
this.uppy.emit('upload-started', file) | ||
if (file.serverToken) { | ||
return this.connectToServerSocket(file) | ||
} | ||
const serverToken = await this.#queueRequestSocketToken(file) | ||
const fields = {} | ||
const allowedMetaFields = Array.isArray(opts.allowedMetaFields) | ||
? opts.allowedMetaFields | ||
// Send along all fields by default. | ||
: Object.keys(file.meta) | ||
if (this.getState().files[file.id]) return undefined | ||
allowedMetaFields.forEach((name) => { | ||
fields[name] = file.meta[name] | ||
}) | ||
this.uppy.setFileState(file.id, { serverToken }) | ||
return this.connectToServerSocket(this.uppy.getFile(file.id)) | ||
} catch (err) { | ||
this.uppy.emit('upload-error', file, err) | ||
throw err | ||
} | ||
} | ||
const Client = file.remote.providerOptions.provider ? Provider : RequestClient | ||
const client = new Client(this.uppy, file.remote.providerOptions) | ||
client.post(file.remote.url, { | ||
...file.remote.body, | ||
protocol: 'multipart', | ||
endpoint: opts.endpoint, | ||
size: file.data.size, | ||
fieldname: opts.fieldName, | ||
metadata: fields, | ||
httpMethod: opts.method, | ||
useFormData: opts.formData, | ||
headers: opts.headers, | ||
}).then((res) => { | ||
const { token } = res | ||
const host = getSocketHost(file.remote.companionUrl) | ||
const socket = new Socket({ target: `${host}/api/${token}`, autoOpen: false }) | ||
this.uploaderEvents[file.id] = new EventTracker(this.uppy) | ||
let queuedRequest | ||
connectToServerSocket (file) { | ||
return new Promise((resolve, reject) => { | ||
const opts = this.getOptions(file) | ||
const token = file.serverToken | ||
const host = getSocketHost(file.remote.companionUrl) | ||
let socket | ||
this.onFileRemove(file.id, () => { | ||
socket.send('cancel', {}) | ||
queuedRequest.abort() | ||
resolve(`upload ${file.id} was removed`) | ||
}) | ||
const createSocket = () => { | ||
if (socket != null) return | ||
this.onCancelAll(file.id, ({ reason } = {}) => { | ||
if (reason === 'user') { | ||
socket.send('cancel', {}) | ||
queuedRequest.abort() | ||
} | ||
resolve(`upload ${file.id} was canceled`) | ||
}) | ||
socket = new Socket({ target: `${host}/api/${token}` }) | ||
this.onRetry(file.id, () => { | ||
socket.send('pause', {}) | ||
socket.send('resume', {}) | ||
}) | ||
this.onRetryAll(file.id, () => { | ||
socket.send('pause', {}) | ||
socket.send('resume', {}) | ||
}) | ||
socket.on('progress', (progressData) => emitSocketProgress(this, progressData, file)) | ||
@@ -428,3 +426,4 @@ | ||
this.uppy.emit('upload-success', file, uploadResp) | ||
queuedRequest.done() | ||
queuedRequest.done() // eslint-disable-line no-use-before-define | ||
socket.close() | ||
if (this.uploaderEvents[file.id]) { | ||
@@ -443,3 +442,3 @@ this.uploaderEvents[file.id].remove() | ||
this.uppy.emit('upload-error', file, error) | ||
queuedRequest.done() | ||
queuedRequest.done() // eslint-disable-line no-use-before-define | ||
if (this.uploaderEvents[file.id]) { | ||
@@ -451,7 +450,43 @@ this.uploaderEvents[file.id].remove() | ||
}) | ||
} | ||
this.uploaderEvents[file.id] = new EventTracker(this.uppy) | ||
let queuedRequest = this.requests.run(() => { | ||
if (file.isPaused) { | ||
socket?.send('pause', {}) | ||
} else { | ||
createSocket() | ||
} | ||
return () => socket.close() | ||
}) | ||
this.onFileRemove(file.id, () => { | ||
socket?.send('cancel', {}) | ||
queuedRequest.abort() | ||
resolve(`upload ${file.id} was removed`) | ||
}) | ||
this.onCancelAll(file.id, ({ reason } = {}) => { | ||
if (reason === 'user') { | ||
socket?.send('cancel', {}) | ||
queuedRequest.abort() | ||
} | ||
resolve(`upload ${file.id} was canceled`) | ||
}) | ||
const onRetryRequest = () => { | ||
if (socket == null) { | ||
queuedRequest.abort() | ||
} else { | ||
socket.send('pause', {}) | ||
queuedRequest.done() | ||
} | ||
queuedRequest = this.requests.run(() => { | ||
socket.open() | ||
if (file.isPaused) { | ||
socket.send('pause', {}) | ||
if (!file.isPaused) { | ||
if (socket == null) { | ||
createSocket() | ||
} else { | ||
socket.send('resume', {}) | ||
} | ||
} | ||
@@ -461,6 +496,8 @@ | ||
}) | ||
}).catch((err) => { | ||
this.uppy.emit('upload-error', file, err) | ||
reject(err) | ||
}) | ||
} | ||
this.onRetry(file.id, onRetryRequest) | ||
this.onRetryAll(file.id, onRetryRequest) | ||
}).catch((err) => { | ||
this.uppy.emit('upload-error', file, err) | ||
return Promise.reject(err) | ||
}) | ||
@@ -467,0 +504,0 @@ } |
Sorry, the diff of this file is not supported yet
101561
1358