Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

expo-server-sdk

Package Overview
Dependencies
Maintainers
13
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

expo-server-sdk - npm Package Compare versions

Comparing version 2.4.0 to 3.0.0-alpha.0

src/__tests__/ExpoClient-test.ts

661

build/ExpoClient.js

@@ -1,45 +0,21 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _toArray2 = require('babel-runtime/helpers/toArray');
var _toArray3 = _interopRequireDefault(_toArray2);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _invariant = require('invariant');
var _invariant2 = _interopRequireDefault(_invariant);
var _nodeFetch = require('node-fetch');
var _nodeFetch2 = _interopRequireDefault(_nodeFetch);
var _promiseLimit = require('promise-limit');
var _promiseLimit2 = _interopRequireDefault(_promiseLimit);
var _zlib = require('zlib');
var _zlib2 = _interopRequireDefault(_zlib);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
/**

@@ -50,8 +26,9 @@ * expo-server-sdk

* https://expo.io
*
*
*/
var BASE_URL = 'https://exp.host';
var BASE_API_URL = BASE_URL + '/--/api/v2';
const assert_1 = __importDefault(require("assert"));
const node_fetch_1 = __importStar(require("node-fetch"));
const promise_limit_1 = __importDefault(require("promise-limit"));
const zlib_1 = __importDefault(require("zlib"));
const BASE_URL = 'https://exp.host';
const BASE_API_URL = `${BASE_URL}/--/api/v2`;
/**

@@ -61,69 +38,36 @@ * The max number of push notifications to be sent at once. Since we can't automatically upgrade

*/
var PUSH_NOTIFICATION_CHUNK_LIMIT = 100;
const PUSH_NOTIFICATION_CHUNK_LIMIT = 100;
/**
* The max number of push notification receipts to request at once.
*/
const PUSH_NOTIFICATION_RECEIPT_CHUNK_LIMIT = 300;
/**
* The default max number of concurrent HTTP requests to send at once and spread out the load,
* increasing the reliability of notification delivery.
*/
var DEFAULT_CONCURRENT_REQUEST_LIMIT = 6;
const DEFAULT_CONCURRENT_REQUEST_LIMIT = 6;
// TODO: Eventually we'll want to have developers authenticate. Right now it's not necessary because
// push notifications are the only API we have and the push tokens are secret anyway.
var ExpoClient = function () {
function ExpoClient() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
(0, _classCallCheck3.default)(this, ExpoClient);
this._httpAgent = options.httpAgent;
this._limitConcurrentRequests = (0, _promiseLimit2.default)(options.maxConcurrentRequests != null ? options.maxConcurrentRequests : DEFAULT_CONCURRENT_REQUEST_LIMIT);
}
/**
* Returns `true` if the token is an Expo push token
*/
(0, _createClass3.default)(ExpoClient, [{
key: 'sendPushNotificationAsync',
class ExpoClient {
constructor(options = {}) {
this._httpAgent = options.httpAgent;
this._limitConcurrentRequests = promise_limit_1.default(options.maxConcurrentRequests != null
? options.maxConcurrentRequests
: DEFAULT_CONCURRENT_REQUEST_LIMIT);
}
/**
* Sends the given message to its recipient via a push notification
* Returns `true` if the token is an Expo push token
*/
value: function () {
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(message) {
var receipts;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return this.sendPushNotificationsAsync([message]);
case 2:
receipts = _context.sent;
(0, _invariant2.default)(receipts.length === 1, 'Expected exactly one push receipt');
return _context.abrupt('return', receipts[0]);
case 5:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
function sendPushNotificationAsync(_x2) {
return _ref.apply(this, arguments);
}
return sendPushNotificationAsync;
}()
static isExpoPushToken(token) {
return (typeof token === 'string' &&
(((token.startsWith('ExponentPushToken[') || token.startsWith('ExpoPushToken[')) &&
token.endsWith(']')) ||
/^[a-z\d]{8}-[a-z\d]{4}-[a-z\d]{4}-[a-z\d]{4}-[a-z\d]{12}$/i.test(token)));
}
/**
* Sends the given messages to their recipients via push notifications and returns an array of
* push receipts. Each receipt corresponds to the message at its respective index (the nth receipt
* is for the nth message).
* push tickets. Each ticket corresponds to the message at its respective index (the nth receipt
* is for the nth message) and contains a receipt ID. Later, after Expo attempts to deliver the
* messages to the underlying push notification services, the receipts with those IDs will be
* available for a period of time (approximately a day).
*

@@ -134,308 +78,133 @@ * There is a limit on the number of push notifications you can send at once. Use

*/
}, {
key: 'sendPushNotificationsAsync',
value: function () {
var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(messages) {
var data, apiError;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return this._requestAsync(BASE_API_URL + '/push/send', {
httpMethod: 'post',
body: messages,
shouldCompress: function shouldCompress(body) {
sendPushNotificationsAsync(messages) {
return __awaiter(this, void 0, void 0, function* () {
let data = yield this._requestAsync(`${BASE_API_URL}/push/send`, {
httpMethod: 'post',
body: messages,
shouldCompress(body) {
return body.length > 1024;
}
});
case 2:
data = _context2.sent;
if (!(!Array.isArray(data) || data.length !== messages.length)) {
_context2.next = 7;
break;
}
apiError = new Error('Expected Exponent to respond with ' + messages.length + ' ' + ((messages.length === 1 ? 'receipt' : 'receipts') + ' but got ') + ('' + data.length));
},
});
if (!Array.isArray(data) || data.length !== messages.length) {
let apiError = new Error(`Expected Expo to respond with ${messages.length} ${messages.length === 1
? 'ticket'
: 'tickets'} but got ${data.length}`);
apiError.data = data;
throw apiError;
case 7:
return _context2.abrupt('return', data);
case 8:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
function sendPushNotificationsAsync(_x3) {
return _ref2.apply(this, arguments);
}
return sendPushNotificationsAsync;
}()
}, {
key: 'chunkPushNotifications',
value: function chunkPushNotifications(messages) {
var chunks = [];
var chunk = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _message = _step.value;
chunk.push(_message);
if (chunk.length >= PUSH_NOTIFICATION_CHUNK_LIMIT) {
return data;
});
}
getPushNotificationReceiptsAsync(receiptIds) {
return __awaiter(this, void 0, void 0, function* () {
let data = yield this._requestAsync(`${BASE_API_URL}/push/getReceipts`, {
httpMethod: 'post',
body: { ids: receiptIds },
shouldCompress(body) {
return body.length > 1024;
},
});
if (!data || typeof data !== 'object' || Array.isArray(data)) {
let apiError = new Error(`Expected Expo to respond with a map from receipt IDs to receipts but received data of another type`);
apiError.data = data;
throw apiError;
}
return data;
});
}
chunkPushNotifications(messages) {
return this._chunkItems(messages, PUSH_NOTIFICATION_CHUNK_LIMIT);
}
chunkPushNotificationReceiptIds(receiptIds) {
return this._chunkItems(receiptIds, PUSH_NOTIFICATION_RECEIPT_CHUNK_LIMIT);
}
_chunkItems(items, chunkSize) {
let chunks = [];
let chunk = [];
for (let item of items) {
chunk.push(item);
if (chunk.length >= chunkSize) {
chunks.push(chunk);
chunk = [];
}
}
if (chunk.length) {
chunks.push(chunk);
chunk = [];
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (chunk.length) {
chunks.push(chunk);
}
return chunks;
return chunks;
}
}, {
key: '_requestAsync',
value: function () {
var _ref3 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(url, options) {
var sdkVersion, fetchOptions, json, response, apiError, textBody, result, _apiError, _apiError2;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
sdkVersion = require('../package.json').version;
fetchOptions = {
method: options.httpMethod,
body: JSON.stringify(options.body),
headers: new _nodeFetch.Headers({
Accept: 'application/json',
'Accept-Encoding': 'gzip, deflate',
'User-Agent': 'expo-server-sdk-node/' + sdkVersion
}),
agent: this._httpAgent
};
if (!(options.body != null)) {
_context3.next = 14;
break;
_requestAsync(url, options) {
return __awaiter(this, void 0, void 0, function* () {
let requestBody;
let sdkVersion = require('../package.json').version;
let requestHeaders = new node_fetch_1.Headers({
Accept: 'application/json',
'Accept-Encoding': 'gzip, deflate',
'User-Agent': `expo-server-sdk-node/${sdkVersion}`,
});
if (options.body != null) {
let json = JSON.stringify(options.body);
assert_1.default(json != null, `JSON request body must not be null`);
if (options.shouldCompress(json)) {
requestBody = yield _gzipAsync(Buffer.from(json));
requestHeaders.set('Content-Encoding', 'gzip');
}
json = JSON.stringify(options.body);
(0, _invariant2.default)(json != null, 'JSON request body must not be null');
if (!options.shouldCompress(json)) {
_context3.next = 12;
break;
else {
requestBody = json;
}
_context3.next = 8;
return _gzipAsync(Buffer.from(json));
case 8:
fetchOptions.body = _context3.sent;
fetchOptions.headers.set('Content-Encoding', 'gzip');
_context3.next = 13;
break;
case 12:
fetchOptions.body = json;
case 13:
fetchOptions.headers.set('Content-Type', 'application/json');
case 14:
_context3.next = 16;
return this._limitConcurrentRequests(function () {
return (0, _nodeFetch2.default)(url, fetchOptions);
});
case 16:
response = _context3.sent;
if (!(response.status !== 200)) {
_context3.next = 22;
break;
}
_context3.next = 20;
return this._parseErrorResponseAsync(response);
case 20:
apiError = _context3.sent;
requestHeaders.set('Content-Type', 'application/json');
}
let response = yield this._limitConcurrentRequests(() => node_fetch_1.default(url, {
method: options.httpMethod,
body: requestBody,
headers: requestHeaders,
agent: this._httpAgent,
}));
if (response.status !== 200) {
let apiError = yield this._parseErrorResponseAsync(response);
throw apiError;
case 22:
_context3.next = 24;
return response.text();
case 24:
textBody = _context3.sent;
// We expect the API response body to be JSON
result = void 0;
_context3.prev = 26;
}
let textBody = yield response.text();
// We expect the API response body to be JSON
let result;
try {
result = JSON.parse(textBody);
_context3.next = 36;
break;
case 30:
_context3.prev = 30;
_context3.t0 = _context3['catch'](26);
_context3.next = 34;
return this._getTextResponseErrorAsync(response, textBody);
case 34:
_apiError = _context3.sent;
throw _apiError;
case 36:
if (!result.errors) {
_context3.next = 39;
break;
}
_apiError2 = this._getErrorFromResult(result);
throw _apiError2;
case 39:
return _context3.abrupt('return', result.data);
case 40:
case 'end':
return _context3.stop();
}
}
}, _callee3, this, [[26, 30]]);
}));
function _requestAsync(_x4, _x5) {
return _ref3.apply(this, arguments);
}
return _requestAsync;
}()
}, {
key: '_parseErrorResponseAsync',
value: function () {
var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4(response) {
var textBody, result, apiError;
return _regenerator2.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return response.text();
case 2:
textBody = _context4.sent;
result = void 0;
_context4.prev = 4;
catch (e) {
let apiError = yield this._getTextResponseErrorAsync(response, textBody);
throw apiError;
}
if (result.errors) {
let apiError = this._getErrorFromResult(result);
throw apiError;
}
return result.data;
});
}
_parseErrorResponseAsync(response) {
return __awaiter(this, void 0, void 0, function* () {
let textBody = yield response.text();
let result;
try {
result = JSON.parse(textBody);
_context4.next = 13;
break;
case 8:
_context4.prev = 8;
_context4.t0 = _context4['catch'](4);
_context4.next = 12;
return this._getTextResponseErrorAsync(response, textBody);
case 12:
return _context4.abrupt('return', _context4.sent);
case 13:
if (!(!result.errors || !Array.isArray(result.errors) || !result.errors.length)) {
_context4.next = 19;
break;
}
_context4.next = 16;
return this._getTextResponseErrorAsync(response, textBody);
case 16:
apiError = _context4.sent;
}
catch (e) {
return yield this._getTextResponseErrorAsync(response, textBody);
}
if (!result.errors || !Array.isArray(result.errors) || !result.errors.length) {
let apiError = yield this._getTextResponseErrorAsync(response, textBody);
apiError.errorData = result;
return _context4.abrupt('return', apiError);
case 19:
return _context4.abrupt('return', this._getErrorFromResult(result));
case 20:
case 'end':
return _context4.stop();
return apiError;
}
}
}, _callee4, this, [[4, 8]]);
}));
function _parseErrorResponseAsync(_x6) {
return _ref4.apply(this, arguments);
}
return _parseErrorResponseAsync;
}()
}, {
key: '_getTextResponseErrorAsync',
value: function () {
var _ref5 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee5(response, text) {
var apiError;
return _regenerator2.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
apiError = new Error('Expo responded with an error with status code ' + response.status + ': ' + text);
apiError.statusCode = response.status;
apiError.errorText = text;
return _context5.abrupt('return', apiError);
case 4:
case 'end':
return _context5.stop();
}
}
}, _callee5, this);
}));
function _getTextResponseErrorAsync(_x7, _x8) {
return _ref5.apply(this, arguments);
}
return _getTextResponseErrorAsync;
}()
return this._getErrorFromResult(result);
});
}
_getTextResponseErrorAsync(response, text) {
return __awaiter(this, void 0, void 0, function* () {
let apiError = new Error(`Expo responded with an error with status code ${response.status}: ` + text);
apiError.statusCode = response.status;
apiError.errorText = text;
return apiError;
});
}
/**

@@ -445,79 +214,43 @@ * Returns an error for the first API error in the result, with an optional `others` field that

*/
}, {
key: '_getErrorFromResult',
value: function _getErrorFromResult(result) {
var _this = this;
(0, _invariant2.default)(result.errors && result.errors.length > 0, 'Expected at least one error from Expo');
var _result$errors = (0, _toArray3.default)(result.errors),
errorData = _result$errors[0],
otherErrorData = _result$errors.slice(1);
var error = this._getErrorFromResultError(errorData);
if (otherErrorData.length) {
error.others = otherErrorData.map(function (data) {
return _this._getErrorFromResultError(data);
});
}
return error;
_getErrorFromResult(result) {
assert_1.default(result.errors && result.errors.length > 0, `Expected at least one error from Expo`);
let [errorData, ...otherErrorData] = result.errors;
let error = this._getErrorFromResultError(errorData);
if (otherErrorData.length) {
error.others = otherErrorData.map(data => this._getErrorFromResultError(data));
}
return error;
}
/**
* Returns an error for a single API error
*/
}, {
key: '_getErrorFromResultError',
value: function _getErrorFromResultError(errorData) {
var error = new Error(errorData.message);
error.code = errorData.code;
if (errorData.details != null) {
error.details = errorData.details;
}
if (errorData.stack != null) {
error.serverStack = errorData.stack;
}
return error;
_getErrorFromResultError(errorData) {
let error = new Error(errorData.message);
error.code = errorData.code;
if (errorData.details != null) {
error.details = errorData.details;
}
if (errorData.stack != null) {
error.serverStack = errorData.stack;
}
return error;
}
}], [{
key: 'isExpoPushToken',
value: function isExpoPushToken(token) {
return typeof token === 'string' && (token.startsWith('ExponentPushToken[') || token.startsWith('ExpoPushToken[')) && token.endsWith(']');
}
/**
* Legacy alias for isExpoPushToken
*/
}, {
key: 'isExponentPushToken',
value: function isExponentPushToken(token) {
return ExpoClient.isExpoPushToken(token);
}
}]);
return ExpoClient;
}();
}
ExpoClient.pushNotificationChunkSizeLimit = PUSH_NOTIFICATION_CHUNK_LIMIT;
ExpoClient.pushNotificationReceiptChunkSizeLimit = PUSH_NOTIFICATION_RECEIPT_CHUNK_LIMIT;
exports.default = ExpoClient;
function _gzipAsync(data) {
return new Promise(function (resolve, reject) {
_zlib2.default.gzip(data, function (error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
return new Promise((resolve, reject) => {
zlib_1.default.gzip(data, (error, result) => {
if (error) {
reject(error);
}
else {
resolve(result);
}
});
});
});
}
module.exports = exports['default'];
class ExtensibleError extends Error {
}
//# sourceMappingURL=ExpoClient.js.map
{
"name": "expo-server-sdk",
"version": "2.4.0",
"version": "3.0.0-alpha.0",
"description": "Server side library for working with Expo using Node.js",
"main": "build/ExpoClient.js",
"types": "src/ExpoClient.ts",
"files": [
"build"
"build",
"src"
],

@@ -14,3 +16,4 @@ "scripts": {

"test": "jest",
"watch": "babel src --out-dir build --ignore __tests__ --source-maps --watch"
"tsc": "tsc",
"watch": "tsc --watch"
},

@@ -21,3 +24,18 @@ "jest": {

],
"testEnvironment": "node"
"moduleFileExtensions": [
"ts",
"js"
],
"transform": {
"^.+\\.ts$": "ts-jest"
},
"globals": {
"ts-jest": {
"tsConfigFile": "tsconfig.json"
}
},
"testEnvironment": "node",
"testMatch": [
"**/__tests__/*.+(js|ts)"
]
},

@@ -30,3 +48,2 @@ "repository": {

"expo",
"react-native",
"push-notifications"

@@ -41,4 +58,4 @@ ],

"dependencies": {
"babel-runtime": "^6.11.6",
"invariant": "^2.2.4",
"@types/invariant": "^2.2.29",
"@types/node-fetch": "^2.1.1",
"node-fetch": "^2.1.2",

@@ -48,12 +65,6 @@ "promise-limit": "^2.6.0"

"devDependencies": {
"babel-cli": "^6.24.0",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-class-properties": "^6.23.0",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-es2016": "^6.11.3",
"babel-preset-es2017": "^6.14.0",
"jest": "^23.1.0"
"jest": "^23.1.0",
"ts-jest": "^23.0.0",
"typescript": "^2.9.2"
}
}

@@ -12,4 +12,2 @@ # expo-server-sdk-node [![CircleCI](https://circleci.com/gh/expo/exponent-server-sdk-node.svg?style=svg)](https://circleci.com/gh/expo/exponent-server-sdk-node) [![codecov](https://codecov.io/gh/expo/exponent-server-sdk-node/branch/master/graph/badge.svg)](https://codecov.io/gh/expo/exponent-server-sdk-node)

**Note for Firebase:** You must have a paid plan to send push notifications with this library. As [Firebase's pricing page](https://firebase.google.com/pricing/) says, "The Spark plan allows outbound network requests only to Google-owned services."
```js

@@ -47,3 +45,3 @@ import Expo from 'expo-server-sdk';

let chunks = expo.chunkPushNotifications(messages);
let tickets = [];
(async () => {

@@ -55,4 +53,53 @@ // Send the chunks to the Expo push notification service. There are

try {
let receipts = await expo.sendPushNotificationsAsync(chunk);
let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
console.log(ticketChunk);
tickets.push(...ticketChunk);
} catch (error) {
console.error(error);
}
}
})();
...
// Later, after the Expo push notification service has delivered the
// notifications to Apple or Google (usually quickly, but allow the the service
// up to 30 minutes when under load), a "receipt" for each notification is
// created. The receipts will be available for at least a day; stale receipts
// are deleted.
//
// The ID of each receipt is sent back in the response "ticket" for each
// notification. In summary, sending a notification produces a ticket, which
// contains a receipt ID you later use to get the receipt.
//
// The receipts may contain error codes to which you must respond. In
// particular, Apple or Google may block apps that continue to send
// notifications to devices that have blocked notifications or have uninstalled
// your app. Expo does not control this policy and sends back the feedback from
// Apple and Google so you can handle it appropriately.
let receiptIds = tickets.map(ticket => ticket.id);
let receiptIdChunks = expo.chunkPushNotificationReceiptIds(receiptIds);
(async () => {
// Like sending notifications, there are different strategies you could use
// to retrieve batches of receipts from the Expo service.
for (let chunk of receiptIdChunks) {
try {
let receipts = await expo.getPushNotificationReceiptsAsync(chunk);
console.log(receipts);
// The receipts specify whether Apple or Google successfully received the
// notification and information about an error, if one occurred.
for (let receipt of receipts) {
if (receipt.status === 'ok') {
continue;
} else if (receipt.status === 'error') {
console.error(`There was an error sending a notification: ${receipt.message}`);
if (receipt.details && receipt.details.error) {
// The error codes are listed in the Expo documentation:
// https://docs.expo.io/versions/latest/guides/push-notifications#response-format
// You must handle the errors appropriately.
console.error(`The error code is ${receipt.details.error}`);
}
}
}
} catch (error) {

@@ -63,2 +110,3 @@ console.error(error);

})();
```

@@ -65,0 +113,0 @@

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