New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@uppy/xhr-upload

Package Overview
Dependencies
Maintainers
6
Versions
114
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@uppy/xhr-upload - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

9

CHANGELOG.md
# @uppy/xhr-upload
## 3.3.0
Released: 2023-06-19
Included in: Uppy v3.10.0
- @uppy/aws-s3-multipart,@uppy/aws-s3,@uppy/tus,@uppy/utils,@uppy/xhr-upload: When file is removed (or all are canceled), controller.abort queued requests (Artur Paikin / #4504)
- @uppy/aws-s3-multipart,@uppy/tus,@uppy/xhr-upload: Don't close socket while upload is still in progress (Artur Paikin / #4479)
- @uppy/xhr-upload: add support for arrays in metadata (Vasiliy Matyushin / #4431)
## 3.2.0

@@ -4,0 +13,0 @@

234

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 BasePlugin from '@uppy/core/lib/BasePlugin.js';

@@ -12,3 +9,3 @@ import { nanoid } from 'nanoid/non-secure';

import getSocketHost from '@uppy/utils/lib/getSocketHost';
import EventTracker from '@uppy/utils/lib/EventTracker';
import EventManager from '@uppy/utils/lib/EventManager';
import ProgressTimeout from '@uppy/utils/lib/ProgressTimeout';

@@ -20,13 +17,12 @@ import { RateLimitedQueue, internalRateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue';

const packageJson = {
"version": "3.2.0"
"version": "3.3.0"
};
import locale from './locale.js';
function buildResponseError(xhr, err) {
let error = err; // No error message
if (!error) error = new Error('Upload error'); // Got an error message string
if (typeof error === 'string') error = new Error(error); // Got something else
let error = err;
// No error message
if (!error) error = new Error('Upload error');
// Got an error message string
if (typeof error === 'string') error = new Error(error);
// Got something else
if (!(error instanceof Error)) {

@@ -37,3 +33,2 @@ error = Object.assign(new Error('Upload error'), {

}
if (isNetworkError(xhr)) {

@@ -43,6 +38,6 @@ error = new NetworkError(error, xhr);

}
error.request = xhr;
return error;
}
/**

@@ -56,4 +51,2 @@ * Set `data.type` in the blob to `file.meta.type`,

*/
function setTypeInBlob(file) {

@@ -63,19 +56,10 @@ const dataWithUpdatedType = file.data.slice(0, file.data.size, file.meta.type);

}
var _queueRequestSocketToken = /*#__PURE__*/_classPrivateFieldLooseKey("queueRequestSocketToken");
var _upload = /*#__PURE__*/_classPrivateFieldLooseKey("upload");
var _requestSocketToken = /*#__PURE__*/_classPrivateFieldLooseKey("requestSocketToken");
var _uploadRemote = /*#__PURE__*/_classPrivateFieldLooseKey("uploadRemote");
var _uploadBundle = /*#__PURE__*/_classPrivateFieldLooseKey("uploadBundle");
var _uploadFiles = /*#__PURE__*/_classPrivateFieldLooseKey("uploadFiles");
var _handleUpload = /*#__PURE__*/_classPrivateFieldLooseKey("handleUpload");
export default class XHRUpload extends BasePlugin {
// eslint-disable-next-line global-require
constructor(uppy, _opts) {

@@ -89,2 +73,4 @@ super(uppy, _opts);

});
// NOTE! Keep this duplicated code in sync with other plugins
// TODO we should probably abstract this into a common function
Object.defineProperty(this, _uploadRemote, {

@@ -102,9 +88,11 @@ value: _uploadRemote2

writable: true,
value: async file => {
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.
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,
const res = await client.post(file.remote.url, {
...file.remote.body,
protocol: 'multipart',

@@ -118,3 +106,3 @@ endpoint: opts.endpoint,

headers: opts.headers
});
}, options);
return res.token;

@@ -129,10 +117,9 @@ }

return;
} // No limit configured by the user, and no RateLimitedQueue passed in by a "parent" plugin
}
// No limit configured by the user, and no RateLimitedQueue passed in by a "parent" plugin
// (basically just AwsS3) using the internal symbol
if (this.opts.limit === 0 && !this.opts[internalRateLimitedQueue]) {
this.uppy.log('[XHRUpload] 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/xhr-upload/#limit-0', 'warning');
}
this.uppy.log('[XHRUpload] Uploading...');

@@ -143,15 +130,11 @@ const files = this.uppy.getFilesByIds(fileIDs);

this.uppy.emit('upload-start', filesToEmit);
if (this.opts.bundle) {
// if bundle: true, we don’t support remote uploads
const isSomeFileRemote = filesFiltered.some(file => file.isRemote);
if (isSomeFileRemote) {
throw new Error('Can’t upload remote files when the `bundle: true` option is set');
}
if (typeof this.opts.headers === 'function') {
throw new TypeError('`headers` may not be a function when the `bundle: true` option is set');
}
await _classPrivateFieldLooseBase(this, _uploadBundle)[_uploadBundle](filesFiltered);

@@ -166,4 +149,5 @@ } else {

this.title = 'XHRUpload';
this.defaultLocale = locale; // Default options
this.defaultLocale = locale;
// Default options
const defaultOptions = {

@@ -181,3 +165,2 @@ formData: true,

responseType: '',
/**

@@ -188,3 +171,2 @@ * @param {string} responseText the response body string

let parsedResponse = {};
try {

@@ -195,6 +177,4 @@ parsedResponse = JSON.parse(responseText);

}
return parsedResponse;
},
/**

@@ -207,10 +187,7 @@ *

let error = new Error('Upload error');
if (isNetworkError(response)) {
error = new NetworkError(error, response);
}
return error;
},
/**

@@ -224,9 +201,10 @@ * Check if the response from the upload endpoint indicates that the upload was successful.

}
};
this.opts = { ...defaultOptions,
this.opts = {
...defaultOptions,
..._opts
};
this.i18nInit(); // Simultaneous upload limiting is shared across all uploads with this plugin.
this.i18nInit();
// Simultaneous upload limiting is shared across all uploads with this plugin.
if (internalRateLimitedQueue in this.opts) {

@@ -237,11 +215,8 @@ this.requests = this.opts[internalRateLimitedQueue];

}
if (this.opts.bundle && !this.opts.formData) {
throw new Error('`opts.formData` must be true when `opts.bundle` is enabled.');
}
if ((_opts == null ? void 0 : _opts.allowedMetaFields) === undefined && 'metaFields' in this.opts) {
throw new Error('The `metaFields` option has been renamed to `allowedMetaFields`.');
}
this.uploaderEvents = Object.create(null);

@@ -252,3 +227,2 @@ _classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken] = this.requests.wrapPromiseFunction(_classPrivateFieldLooseBase(this, _requestSocketToken)[_requestSocketToken], {

}
getOptions(file) {

@@ -259,7 +233,9 @@ const overrides = this.uppy.getState().xhrUpload;

} = this.opts;
const opts = { ...this.opts,
const opts = {
...this.opts,
...(overrides || {}),
...(file.xhrUpload || {}),
headers: {}
}; // Support for `headers` as a function, only in the XHRUpload settings.
};
// Support for `headers` as a function, only in the XHRUpload settings.
// Options set by other plugins in Uppy state or on the files themselves are still merged in afterward.

@@ -270,3 +246,2 @@ //

// ```
if (typeof headers === 'function') {

@@ -277,15 +252,12 @@ opts.headers = headers(file);

}
if (overrides) {
Object.assign(opts.headers, overrides.headers);
}
if (file.xhrUpload) {
Object.assign(opts.headers, file.xhrUpload.headers);
}
return opts;
} // eslint-disable-next-line class-methods-use-this
}
// eslint-disable-next-line class-methods-use-this
addMetadata(formData, meta, opts) {

@@ -295,6 +267,11 @@ const allowedMetaFields = Array.isArray(opts.allowedMetaFields) ? opts.allowedMetaFields : Object.keys(meta); // Send along all fields by default.

allowedMetaFields.forEach(item => {
formData.append(item, meta[item]);
if (Array.isArray(meta[item])) {
// In this case we don't transform `item` to add brackets, it's up to
// the user to add the brackets so it won't be overridden.
meta[item].forEach(subItem => formData.append(item, subItem));
} else {
formData.append(item, meta[item]);
}
});
}
createFormDataUpload(file, opts) {

@@ -304,3 +281,2 @@ const formPost = new FormData();

const dataWithUpdatedType = setTypeInBlob(file);
if (file.name) {

@@ -311,6 +287,4 @@ formPost.append(opts.fieldName, dataWithUpdatedType, file.meta.name);

}
return formPost;
}
createBundledUpload(files, opts) {

@@ -325,3 +299,2 @@ const formPost = new FormData();

const dataWithUpdatedType = setTypeInBlob(file);
if (file.name) {

@@ -335,3 +308,2 @@ formPost.append(options.fieldName, dataWithUpdatedType, file.name);

}
async connectToServerSocket(file) {

@@ -343,3 +315,2 @@ return new Promise((resolve, reject) => {

let socket;
const createSocket = () => {

@@ -361,5 +332,3 @@ if (socket != null) return;

queuedRequest.done(); // eslint-disable-line no-use-before-define
socket.close();
if (this.uploaderEvents[file.id]) {

@@ -369,3 +338,2 @@ this.uploaderEvents[file.id].remove();

}
return resolve();

@@ -380,3 +348,3 @@ });

queuedRequest.done(); // eslint-disable-line no-use-before-define
socket.close();
if (this.uploaderEvents[file.id]) {

@@ -386,12 +354,9 @@ this.uploaderEvents[file.id].remove();

}
reject(error);
});
};
this.uploaderEvents[file.id] = new EventTracker(this.uppy);
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', {});

@@ -401,9 +366,8 @@ } else {

}
return () => socket.close();
return () => {};
});
this.onFileRemove(file.id, () => {
var _socket2;
(_socket2 = socket) == null ? void 0 : _socket2.send('cancel', {});
socket.close();
queuedRequest.abort();

@@ -416,8 +380,7 @@ resolve(`upload ${file.id} was removed`);

} = _temp === void 0 ? {} : _temp;
if (reason === 'user') {
var _socket3;
(_socket3 = socket) == null ? void 0 : _socket3.send('cancel', {});
queuedRequest.abort();
// socket.close()
}

@@ -427,3 +390,2 @@

});
const onRetryRequest = () => {

@@ -433,19 +395,11 @@ if (socket == null) {

} else {
socket.send('pause', {});
queuedRequest.done();
}
queuedRequest = this.requests.run(() => {
if (!file.isPaused) {
if (socket == null) {
createSocket();
} else {
socket.send('resume', {});
}
if (socket == null) {
createSocket();
}
return () => socket.close();
return () => {};
});
};
this.onRetry(file.id, onRetryRequest);

@@ -458,3 +412,2 @@ this.onRetryAll(file.id, onRetryRequest);

}
onFileRemove(fileID, cb) {

@@ -465,3 +418,2 @@ this.uploaderEvents[fileID].on('file-removed', file => {

}
onRetry(fileID, cb) {

@@ -474,3 +426,2 @@ this.uploaderEvents[fileID].on('upload-retry', targetFileID => {

}
onRetryAll(fileID, cb) {

@@ -482,6 +433,4 @@ this.uploaderEvents[fileID].on('retry-all', () => {

}
onCancelAll(fileID, eventHandler) {
var _this = this;
this.uploaderEvents[fileID].on('cancel-all', function () {

@@ -492,3 +441,2 @@ if (!_this.uppy.getFile(fileID)) return;

}
install() {

@@ -500,3 +448,4 @@ if (this.opts.bundle) {

this.uppy.setState({
capabilities: { ...capabilities,
capabilities: {
...capabilities,
individualCancellation: false

@@ -506,6 +455,4 @@ }

}
this.uppy.addUploader(_classPrivateFieldLooseBase(this, _handleUpload)[_handleUpload]);
}
uninstall() {

@@ -517,3 +464,4 @@ if (this.opts.bundle) {

this.uppy.setState({
capabilities: { ...capabilities,
capabilities: {
...capabilities,
individualCancellation: true

@@ -523,8 +471,5 @@ }

}
this.uppy.removeUploader(_classPrivateFieldLooseBase(this, _handleUpload)[_handleUpload]);
}
}
async function _upload2(file, current, total) {

@@ -536,3 +481,3 @@ const opts = this.getOptions(file);

const xhr = new XMLHttpRequest();
this.uploaderEvents[file.id] = new EventTracker(this.uppy);
this.uploaderEvents[file.id] = new EventManager(this.uppy);
let queuedRequest;

@@ -550,7 +495,6 @@ const timer = new ProgressTimeout(opts.timeout, () => {

xhr.upload.addEventListener('progress', ev => {
this.uppy.log(`[XHRUpload] ${id} progress: ${ev.loaded} / ${ev.total}`); // Begin checking for timeouts when progress starts, instead of loading,
this.uppy.log(`[XHRUpload] ${id} progress: ${ev.loaded} / ${ev.total}`);
// Begin checking for timeouts when progress starts, instead of loading,
// to avoid timing out requests on browser concurrency queue
timer.progress();
if (ev.lengthComputable) {

@@ -568,3 +512,2 @@ this.uppy.emit('upload-progress', file, {

queuedRequest.done();
if (this.uploaderEvents[file.id]) {

@@ -574,3 +517,2 @@ this.uploaderEvents[file.id].remove();

}
if (opts.validateStatus(xhr.status, xhr.responseText, xhr)) {

@@ -585,10 +527,7 @@ const body = opts.getResponseData(xhr.responseText, xhr);

this.uppy.emit('upload-success', file, uploadResp);
if (uploadURL) {
this.uppy.log(`Download ${file.name} from ${uploadURL}`);
}
return resolve(file);
}
const body = opts.getResponseData(xhr.responseText, xhr);

@@ -607,3 +546,2 @@ const error = buildResponseError(xhr, opts.getResponseError(xhr.responseText, xhr));

queuedRequest.done();
if (this.uploaderEvents[file.id]) {

@@ -613,3 +551,2 @@ this.uploaderEvents[file.id].remove();

}
const error = buildResponseError(xhr, opts.getResponseError(xhr.responseText, xhr));

@@ -619,11 +556,9 @@ this.uppy.emit('upload-error', file, error);

});
xhr.open(opts.method.toUpperCase(), opts.endpoint, true); // IE10 does not allow setting `withCredentials` and `responseType`
xhr.open(opts.method.toUpperCase(), opts.endpoint, true);
// IE10 does not allow setting `withCredentials` and `responseType`
// before `open()` is called.
xhr.withCredentials = opts.withCredentials;
if (opts.responseType !== '') {
xhr.responseType = opts.responseType;
}
queuedRequest = this.requests.run(() => {

@@ -652,7 +587,5 @@ // When using an authentication system like JWT, the bearer token goes as a header. This

} = _ref;
if (reason === 'user') {
queuedRequest.abort();
}
reject(new Error('Upload cancelled'));

@@ -662,4 +595,3 @@ });

}
async function _uploadRemote2(file) {
async function _uploadRemote2(file, options) {
// TODO: we could rewrite this to use server-sent events instead of creating WebSockets.

@@ -670,4 +602,3 @@ try {

}
const serverToken = await _classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken](file);
const serverToken = await _classPrivateFieldLooseBase(this, _queueRequestSocketToken)[_queueRequestSocketToken](file, options).abortOn(options == null ? void 0 : options.signal);
if (!this.uppy.getState().files[file.id]) return undefined;

@@ -679,10 +610,14 @@ this.uppy.setFileState(file.id, {

} catch (err) {
this.uppy.setFileState(file.id, {
serverToken: undefined
});
this.uppy.emit('upload-error', file, err);
throw err;
var _err$cause;
if ((err == null ? void 0 : (_err$cause = err.cause) == null ? void 0 : _err$cause.name) !== 'AbortError') {
this.uppy.setFileState(file.id, {
serverToken: undefined
});
this.uppy.emit('upload-error', file, err);
throw err;
}
// The file upload was aborted, it’s not an error
return undefined;
}
}
function _uploadBundle2(files) {

@@ -697,7 +632,7 @@ return new Promise((resolve, reject) => {

const optsFromState = this.uppy.getState().xhrUpload;
const formData = this.createBundledUpload(files, { ...this.opts,
const formData = this.createBundledUpload(files, {
...this.opts,
...(optsFromState || {})
});
const xhr = new XMLHttpRequest();
const emitError = error => {

@@ -708,3 +643,2 @@ files.forEach(file => {

};
const timer = new ProgressTimeout(this.opts.timeout, () => {

@@ -733,3 +667,2 @@ const error = new Error(this.i18n('uploadStalled', {

timer.done();
if (this.opts.validateStatus(ev.target.status, xhr.responseText, xhr)) {

@@ -746,3 +679,2 @@ const body = this.opts.getResponseData(xhr.responseText, xhr);

}
const error = this.opts.getResponseError(xhr.responseText, xhr) || new Error('Upload error');

@@ -767,11 +699,9 @@ error.request = xhr;

});
xhr.open(method.toUpperCase(), endpoint, true); // IE10 does not allow setting `withCredentials` and `responseType`
xhr.open(method.toUpperCase(), endpoint, true);
// IE10 does not allow setting `withCredentials` and `responseType`
// before `open()` is called.
xhr.withCredentials = this.opts.withCredentials;
if (this.opts.responseType !== '') {
xhr.responseType = this.opts.responseType;
}
Object.keys(this.opts.headers).forEach(header => {

@@ -783,3 +713,2 @@ xhr.setRequestHeader(header, this.opts.headers[header]);

}
async function _uploadFiles2(files) {

@@ -789,11 +718,22 @@ await Promise.allSettled(files.map((file, i) => {

const total = files.length;
if (file.isRemote) {
return _classPrivateFieldLooseBase(this, _uploadRemote)[_uploadRemote](file, current, total);
const controller = new AbortController();
const removedHandler = removedFile => {
if (removedFile.id === file.id) controller.abort();
};
this.uppy.on('file-removed', removedHandler);
const uploadPromise = _classPrivateFieldLooseBase(this, _uploadRemote)[_uploadRemote](file, {
signal: controller.signal
});
this.requests.wrapSyncFunction(() => {
this.uppy.off('file-removed', removedHandler);
}, {
priority: -1
})();
return uploadPromise;
}
return _classPrivateFieldLooseBase(this, _upload)[_upload](file, current, total);
}));
}
// eslint-disable-next-line global-require
XHRUpload.VERSION = packageJson.version;
{
"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.2.0",
"version": "3.3.0",
"license": "MIT",

@@ -29,3 +29,3 @@ "main": "lib/index.js",

"@uppy/companion-client": "^3.1.3",
"@uppy/utils": "^5.3.0",
"@uppy/utils": "^5.4.0",
"nanoid": "^4.0.0"

@@ -38,4 +38,4 @@ },

"peerDependencies": {
"@uppy/core": "^3.2.0"
"@uppy/core": "^3.2.1"
}
}

@@ -6,3 +6,3 @@ import BasePlugin from '@uppy/core/lib/BasePlugin.js'

import getSocketHost from '@uppy/utils/lib/getSocketHost'
import EventTracker from '@uppy/utils/lib/EventTracker'
import EventManager from '@uppy/utils/lib/EventManager'
import ProgressTimeout from '@uppy/utils/lib/ProgressTimeout'

@@ -175,3 +175,9 @@ import { RateLimitedQueue, internalRateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue'

allowedMetaFields.forEach((item) => {
formData.append(item, meta[item])
if (Array.isArray(meta[item])) {
// In this case we don't transform `item` to add brackets, it's up to
// the user to add the brackets so it won't be overridden.
meta[item].forEach(subItem => formData.append(item, subItem))
} else {
formData.append(item, meta[item])
}
})

@@ -227,3 +233,3 @@ }

const xhr = new XMLHttpRequest()
this.uploaderEvents[file.id] = new EventTracker(this.uppy)
this.uploaderEvents[file.id] = new EventManager(this.uppy)
let queuedRequest

@@ -351,3 +357,3 @@

#requestSocketToken = async (file) => {
#requestSocketToken = async (file, options) => {
const opts = this.getOptions(file)

@@ -370,3 +376,3 @@ const Client = file.remote.providerOptions.provider ? Provider : RequestClient

headers: opts.headers,
})
}, options)
return res.token

@@ -377,3 +383,3 @@ }

// TODO we should probably abstract this into a common function
async #uploadRemote (file) {
async #uploadRemote (file, options) {
// TODO: we could rewrite this to use server-sent events instead of creating WebSockets.

@@ -384,3 +390,3 @@ try {

}
const serverToken = await this.#queueRequestSocketToken(file)
const serverToken = await this.#queueRequestSocketToken(file, options).abortOn(options?.signal)

@@ -392,5 +398,9 @@ if (!this.uppy.getState().files[file.id]) return undefined

} catch (err) {
this.uppy.setFileState(file.id, { serverToken: undefined })
this.uppy.emit('upload-error', file, err)
throw err
if (err?.cause?.name !== 'AbortError') {
this.uppy.setFileState(file.id, { serverToken: undefined })
this.uppy.emit('upload-error', file, err)
throw err
}
// The file upload was aborted, it’s not an error
return undefined
}

@@ -440,2 +450,3 @@ }

queuedRequest.done() // eslint-disable-line no-use-before-define
socket.close()
if (this.uploaderEvents[file.id]) {

@@ -448,3 +459,3 @@ this.uploaderEvents[file.id].remove()

}
this.uploaderEvents[file.id] = new EventTracker(this.uppy)
this.uploaderEvents[file.id] = new EventManager(this.uppy)

@@ -458,3 +469,3 @@ let queuedRequest = this.requests.run(() => {

return () => socket.close()
return () => {}
})

@@ -464,2 +475,3 @@

socket?.send('cancel', {})
socket.close()
queuedRequest.abort()

@@ -473,2 +485,3 @@ resolve(`upload ${file.id} was removed`)

queuedRequest.abort()
// socket.close()
}

@@ -482,15 +495,9 @@ resolve(`upload ${file.id} was canceled`)

} else {
socket.send('pause', {})
queuedRequest.done()
}
queuedRequest = this.requests.run(() => {
if (!file.isPaused) {
if (socket == null) {
createSocket()
} else {
socket.send('resume', {})
}
if (socket == null) {
createSocket()
}
return () => socket.close()
return () => {}
})

@@ -606,3 +613,16 @@ }

if (file.isRemote) {
return this.#uploadRemote(file, current, total)
const controller = new AbortController()
const removedHandler = (removedFile) => {
if (removedFile.id === file.id) controller.abort()
}
this.uppy.on('file-removed', removedHandler)
const uploadPromise = this.#uploadRemote(file, { signal: controller.signal })
this.requests.wrapSyncFunction(() => {
this.uppy.off('file-removed', removedHandler)
}, { priority: -1 })()
return uploadPromise
}

@@ -609,0 +629,0 @@ return this.#upload(file, current, total)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc