twilio-notifications
Advanced tools
Comparing version 0.0.1 to 0.1.0
@@ -9,2 +9,5 @@ 'use strict'; | ||
const cp = require('child_process'); | ||
const jsdoc = 'node_modules/jsdoc/jsdoc.js'; | ||
const pkg = require('./package'); | ||
@@ -47,2 +50,8 @@ | ||
const docs = { | ||
dir: product.packaged.dir + '/docs', | ||
conf: 'jsdoc.json', | ||
files: ['./lib/client.js'] | ||
}; | ||
gulp.task('clean', function() { | ||
@@ -53,5 +62,5 @@ }); | ||
return gulp.src(tests.lint.files) | ||
.pipe(eslint()) | ||
.pipe(eslint.format()) | ||
.pipe(eslint.failAfterError()); | ||
.pipe(eslint()) | ||
.pipe(eslint.format()) | ||
.pipe(eslint.failAfterError()); | ||
}); | ||
@@ -75,2 +84,11 @@ | ||
gulp.task('doc', function(cb) { | ||
cp.exec(['node', jsdoc, | ||
'-d', docs.dir, | ||
'-c', docs.conf, | ||
docs.files.join(' '), | ||
'./README.md', | ||
'-t ./node_modules/ink-docstrap/template'].join(' '), cb); | ||
}); | ||
gulp.task('default', function(done) { | ||
@@ -81,2 +99,3 @@ runSequence( | ||
'unit-test', | ||
'doc', | ||
done | ||
@@ -83,0 +102,0 @@ ); |
'use strict'; | ||
var EventEmitter = require('events').EventEmitter; | ||
var inherits = require('util').inherits; | ||
var log = require('loglevel'); | ||
const EventEmitter = require('events').EventEmitter; | ||
const inherits = require('util').inherits; | ||
const log = require('loglevel'); | ||
var NotificationConfig = require('./configuration'); | ||
var Registrar = require('./registrar'); | ||
const NotificationsConfig = require('./configuration'); | ||
const Registrar = require('./registrar'); | ||
/** | ||
* @class | ||
* @alias Notifications | ||
* @classdesc The helper library for the notification service. | ||
* Provides high level api for creating and managing notification subscriptions and receiving messages | ||
* Creates the instance of Notification helper library | ||
* | ||
* @constructor | ||
* @param {string} productId id of a product, which uses notification library | ||
* @param {string} token - Twilio token | ||
* @param {config} options Object with config values to override defaults | ||
* | ||
* @class NotificationClient | ||
* @classdesc The helper library for the notification service. | ||
* Provides high level api for creating and managing notification subscriptions and receiving messages | ||
* @param {AccessManager} accessManager - Twilio Access Manager instance | ||
*/ | ||
function NotificationClient(productId, accessManager, options) { | ||
function NotificationsClient(productId, accessManager, options) { | ||
if (!accessManager) { | ||
throw new Error('AccessManager is required for Notification client'); | ||
throw new Error('AccessManager is required for Notifications client'); | ||
} | ||
@@ -34,6 +35,6 @@ | ||
let config = new NotificationConfig(accessManager, options); | ||
let config = new NotificationsConfig(accessManager, options); | ||
Object.defineProperties(this, { | ||
_config: { value: config }, | ||
_registrar: { value: new Registrar(productId, transport, config) }, | ||
_registrar: { value: new Registrar(productId, transport, twilsock, config) }, | ||
_twilsock: { value: twilsock }, | ||
@@ -59,8 +60,9 @@ _reliableTransportState: { value: reliableTransportState } | ||
inherits(NotificationClient, EventEmitter); | ||
inherits(NotificationsClient, EventEmitter); | ||
/** | ||
* Routes messages to the external subscribers | ||
* Routes messages to the external subscribers | ||
* @private | ||
*/ | ||
NotificationClient.prototype._routeMessage = function(type, message) { | ||
NotificationsClient.prototype._routeMessage = function(type, message) { | ||
log.trace('Message arrived: ', type, message); | ||
@@ -70,3 +72,3 @@ this.emit('message', type, message); | ||
NotificationClient.prototype._onNeedReliableTransport = function(isNeeded) { | ||
NotificationsClient.prototype._onNeedReliableTransport = function(isNeeded) { | ||
if (isNeeded) { | ||
@@ -79,3 +81,3 @@ this._twilsock.connect(); | ||
NotificationClient.prototype._onRegistrationStateChange = function(state) { | ||
NotificationsClient.prototype._onRegistrationStateChange = function(state) { | ||
this._reliableTransportState.registration = (state === 'registered'); | ||
@@ -85,3 +87,3 @@ this._updateTransportState(); | ||
NotificationClient.prototype._onTransportStateChange = function(connected) { | ||
NotificationsClient.prototype._onTransportStateChange = function(connected) { | ||
this._reliableTransportState.transport = connected; | ||
@@ -91,10 +93,10 @@ this._updateTransportState(); | ||
NotificationClient.prototype._updateTransportState = function() { | ||
NotificationsClient.prototype._updateTransportState = function() { | ||
const overallState = this._reliableTransportState.transport | ||
&& this._reliableTransportState.registration; | ||
if (this._reliableTransportState.overall !== overallState) { | ||
this._reliableTransportState.overall = overallState; | ||
this._reliableTransportState.overall = overallState; | ||
log.info('NTFCN I: Transport ready ' + overallState); | ||
this.emit('transportReady', overallState); | ||
log.info('NTFCN I: Transport ready ' + overallState); | ||
this.emit('transportReady', overallState); | ||
} | ||
@@ -104,10 +106,11 @@ }; | ||
/** | ||
* Adds the subscription for the given message type | ||
* @param {string} messageType The type of message that you want to receive | ||
* @param {string} channelType. Supported are 'twilsock' and 'gcm' | ||
* Adds the subscription for the given message type | ||
* @param {string} messageType The type of message that you want to receive | ||
* @param {string} channelType. Supported are 'twilsock' and 'gcm' | ||
* @public | ||
*/ | ||
NotificationClient.prototype.subscribe = function(messageType, channelType) { | ||
log.trace('Add subscriptions for event type: ', messageType); | ||
NotificationsClient.prototype.subscribe = function(messageType, channelType) { | ||
channelType = channelType || 'twilsock'; | ||
log.trace('Add subscriptions for message type: ', messageType, channelType); | ||
channelType = channelType || 'twilsock'; | ||
return this._registrar.subscribe(messageType, channelType); | ||
@@ -117,7 +120,11 @@ }; | ||
/** | ||
* Remove the subscription for the particular message type | ||
* @param {string} messageType The type of message that you don't want to receive anymore | ||
* @param {string} Channel type. Supported are 'twilsock' and 'gcm' | ||
* Remove the subscription for the particular message type | ||
* @param {string} messageType The type of message that you don't want to receive anymore | ||
* @param {string} Channel type. Supported are 'twilsock' and 'gcm' | ||
* @public | ||
*/ | ||
NotificationClient.prototype.unsubscribe = function(messageType, channelType) { | ||
NotificationsClient.prototype.unsubscribe = function(messageType, channelType) { | ||
channelType = channelType || 'twilsock'; | ||
log.trace('Remove subscriptions for message type: ', messageType, channelType); | ||
return this._registrar.unsubscribe(messageType, channelType); | ||
@@ -127,6 +134,8 @@ }; | ||
/** | ||
* Handle incoming push notification. | ||
* Client application should call this method when it receives push notifications and pass the received data | ||
* Handle incoming push notification. | ||
* Client application should call this method when it receives push notifications and pass the received data | ||
* @param {Object} pushMessage - push message object | ||
* @public | ||
*/ | ||
NotificationClient.prototype.handlePushNotification = function(msg) { | ||
NotificationsClient.prototype.handlePushNotification = function(msg) { | ||
log.warn('Push message passed, but no functionality implemented yet: ' + msg); | ||
@@ -136,6 +145,7 @@ }; | ||
/** | ||
* Set GCM token to enable application register for a push messages | ||
* @param {string} gcmToken Token received from GCM system | ||
* Set GCM token to enable application register for a push messages | ||
* @param {string} gcmToken Token received from GCM system | ||
* @public | ||
*/ | ||
NotificationClient.prototype.setGCMToken = function(gcmToken) { | ||
NotificationsClient.prototype.setGCMToken = function(gcmToken) { | ||
this._registrar.setNotificationId('gcm', gcmToken); | ||
@@ -145,17 +155,11 @@ }; | ||
/** | ||
* Set authentication token | ||
* If token is already set, it will be replaced with the new one | ||
* | ||
* @param {String} Authentication token | ||
* Updates auth token for GCM registration | ||
* @private | ||
*/ | ||
NotificationClient.prototype._updateAuthToken = function() { | ||
NotificationsClient.prototype._updateAuthToken = function() { | ||
log.info('NTFCN I: authTokenUpdated'); | ||
this._registrar._updateGcmRegistration(); | ||
// Twilsock will reconnect on the tokenUpdated signal by itself | ||
// Reconnection of twilsock automatically triggers re-registration | ||
// So not doing anything about twilsock here | ||
this._registrar.updateToken(); | ||
}; | ||
Object.freeze(NotificationClient); | ||
Object.freeze(NotificationsClient); | ||
@@ -165,11 +169,12 @@ /** | ||
* @param {Object} message` | ||
* @event NotificationClient#message | ||
* @event NotificationsClient#message | ||
*/ | ||
/** | ||
* Fired when a Channel's attributes or metadata have been updated. | ||
* @param {boolean} transport state | ||
* @event NotificationClient#transportReady | ||
* @event NotificationsClient#transportReady | ||
*/ | ||
module.exports = NotificationClient; | ||
module.exports = NotificationsClient; | ||
@@ -9,6 +9,12 @@ 'use strict'; | ||
function toArray(_set) { | ||
let arr = []; | ||
_set.forEach(v => arr.push(v)); | ||
return arr; | ||
} | ||
/** | ||
* Creates new instance of the ERS registrar | ||
* | ||
* @class RegistrarClient | ||
* @class RegistrarConnector | ||
* @classdesc Manages the registrations on ERS service. | ||
@@ -22,3 +28,3 @@ * It deduplicates registrations and manages them automatically | ||
*/ | ||
function RegistrarClient(productId, transport, config, channelType) { | ||
function RegistrarConnector(context, transport, config, channelType) { | ||
let fsm = StateMachine.create({ | ||
@@ -57,11 +63,7 @@ initial: { state: 'unregistered', event: 'init', defer: true }, | ||
const platform = (typeof navigator !== 'undefined' ? navigator.userAgent : 'web') | ||
.substring(0, 128); | ||
Object.defineProperties(this, { | ||
_transport: { value: transport }, | ||
_context: { value: context }, | ||
_url: { value: config.registrarUri, writable: false }, | ||
_config: { value: config }, | ||
_productId: { value: productId }, | ||
_platform: { value: platform }, | ||
_fsm: { value: fsm }, | ||
@@ -71,4 +73,4 @@ _backoff: { value: backoff }, | ||
_registrationId: { value: false, writable: true }, | ||
_notificationId: { value: false }, | ||
_messageTypes: { value: [], writable: true }, | ||
_notificationId: { value: false, writable: true }, | ||
_messageTypes: { value: new Set(), writable: true }, | ||
_pendingUpdate: { value: null, writable: true } | ||
@@ -81,10 +83,65 @@ }); | ||
inherits(RegistrarClient, EventEmitter); | ||
inherits(RegistrarConnector, EventEmitter); | ||
RegistrarConnector.prototype.setNotificationId = function(notificationId) { | ||
if (this._notificationId === notificationId) { | ||
return; | ||
} | ||
this._notificationId = notificationId; | ||
this._updateRegistration(); | ||
}; | ||
RegistrarConnector.prototype.updateToken = function() { | ||
return this._updateRegistration(); | ||
}; | ||
RegistrarConnector.prototype.has = function(messageType) { | ||
return this._messageTypes.has(messageType); | ||
}; | ||
RegistrarConnector.prototype.subscribe = function(messageType) { | ||
if (this._messageTypes.has(messageType)) { | ||
log.warn('Message type already registered ', messageType); | ||
return false; | ||
} | ||
this._messageTypes.add(messageType); | ||
this._updateRegistration(); | ||
return true; | ||
}; | ||
RegistrarConnector.prototype.unsubscribe = function(messageType) { | ||
if (!this._messageTypes.has(messageType)) { | ||
return false; | ||
} | ||
this._messageTypes.delete(messageType); | ||
if (this._messageTypes.size > 0) { | ||
this._updateRegistration(); | ||
} else { | ||
this._removeRegistration(); | ||
} | ||
return true; | ||
}; | ||
RegistrarConnector.prototype._updateRegistration = function() { | ||
if (this._notificationId) { | ||
this._update(this._notificationId, toArray(this._messageTypes)); | ||
} | ||
}; | ||
RegistrarConnector.prototype._removeRegistration = function() { | ||
if (this._notificationId) { | ||
this._update(this._notificationId, toArray(this._messageTypes)); | ||
} | ||
}; | ||
/** | ||
* Update service registration | ||
* @param Array messageTypes Array of message type names | ||
* @public | ||
* @private | ||
*/ | ||
RegistrarClient.prototype.update = function(notificationId, messageTypes) { | ||
RegistrarConnector.prototype._update = function(notificationId, messageTypes) { | ||
let regData = { notificationId: notificationId, messageTypes: messageTypes }; | ||
@@ -104,7 +161,8 @@ | ||
RegistrarClient.prototype._setPendingUpdate = function(regData) { | ||
RegistrarConnector.prototype._setPendingUpdate = function(regData) { | ||
this._pendingUpdate = regData; | ||
}; | ||
RegistrarClient.prototype._checkPendingUpdate = function() { | ||
RegistrarConnector.prototype._checkPendingUpdate = function() { | ||
if (!this._pendingUpdate) { | ||
@@ -117,6 +175,6 @@ return; | ||
this.update(pendingUpdate.notificationId, pendingUpdate.messageTypes); | ||
this._updateRegistration(pendingUpdate.notificationId, pendingUpdate.messageTypes); | ||
}; | ||
RegistrarClient.prototype._initRetry = function(regData) { | ||
RegistrarConnector.prototype._initRetry = function(regData) { | ||
if (!this._pendingUpdate) { | ||
@@ -129,3 +187,3 @@ this._setPendingUpdate(regData); | ||
RegistrarClient.prototype._retry = function() { | ||
RegistrarConnector.prototype._retry = function() { | ||
if (!this._pendingUpdate) { return; } | ||
@@ -139,3 +197,3 @@ | ||
RegistrarClient.prototype._onRegistered = function() { | ||
RegistrarConnector.prototype._onRegistered = function() { | ||
this._backoff.reset(); | ||
@@ -146,3 +204,3 @@ this.emit('stateChanged', 'registered'); | ||
RegistrarClient.prototype._onUnregistered = function() { | ||
RegistrarConnector.prototype._onUnregistered = function() { | ||
this._backoff.reset(); | ||
@@ -153,6 +211,7 @@ this.emit('stateChanged', 'unregistered'); | ||
RegistrarClient.prototype._register = function(regData) { | ||
RegistrarConnector.prototype._register = function(regData) { | ||
/* eslint-disable camelcase */ | ||
let registrarRequest = { | ||
endpoint_platform: this._platform, | ||
endpoint_platform: this._context.platform, | ||
channel_type: this._channelType, | ||
@@ -171,3 +230,3 @@ version: '2', | ||
const uri = this._url + '?productId=' + this._productId; | ||
const uri = this._url + '?productId=' + this._context.productId; | ||
const headers = { | ||
@@ -195,3 +254,3 @@ 'Content-Type': 'application/json', | ||
RegistrarClient.prototype._unregister = function() { | ||
RegistrarConnector.prototype._unregister = function() { | ||
if (!this._registrationId) { | ||
@@ -201,3 +260,3 @@ return Promise.resolve(); | ||
const uri = this._url + '/' + this._registrationId + '?productId=' + this._productId; | ||
const uri = this._url + '/' + this._registrationId + '?productId=' + this._context.productId; | ||
const headers = { | ||
@@ -224,5 +283,4 @@ 'Content-Type': 'application/json', | ||
Object.freeze(RegistrarClient); | ||
Object.freeze(RegistrarConnector); | ||
module.exports = RegistrarClient; | ||
module.exports = RegistrarConnector; |
@@ -5,5 +5,5 @@ 'use strict'; | ||
const inherits = require('util').inherits; | ||
const log = require('loglevel'); | ||
const RegistrarClient = require('./registrar.connector'); | ||
const ErsConnector = require('./registrar.connector'); | ||
const TwilsockConnector = require('./twilsock.connector'); | ||
@@ -16,28 +16,16 @@ /** | ||
*/ | ||
function Registrar(productId, transport, config) { | ||
var subscriptions = { | ||
twilsock: new Set(), | ||
gcm: new Set() | ||
}; | ||
var notificationIds = { | ||
twilsock: null, | ||
gcm: null | ||
}; | ||
var twilsockRegistrarClient = new RegistrarClient(productId, transport, config, 'twilsock'); | ||
var gcmRegistrarClient = new RegistrarClient(productId, transport, config, 'gcm'); | ||
function Registrar(productId, transport, twilsock, config) { | ||
Object.defineProperties(this, { | ||
_conf: { value: config }, | ||
_subscriptions: { value: subscriptions }, | ||
_notificationIds: { value: notificationIds }, | ||
_twilsockRegistrar: { value: twilsockRegistrarClient }, | ||
_gcmRegistrar: { value: gcmRegistrarClient } | ||
_connectors: { value: new Map() } | ||
}); | ||
const platform = (typeof navigator !== 'undefined' ? navigator.userAgent : 'web') | ||
.substring(0, 128); | ||
this._connectors.set('twilsock', new TwilsockConnector({ productId, platform }, twilsock, config)); | ||
this._connectors.set('gcm', new ErsConnector({ productId, platform }, transport, config, 'gcm')); | ||
EventEmitter.call(this); | ||
} | ||
twilsockRegistrarClient.on('stateChanged', (value) => this.emit('stateChanged', value)); | ||
} | ||
inherits(Registrar, EventEmitter); | ||
@@ -52,129 +40,50 @@ | ||
Registrar.prototype.setNotificationId = function(channelType, notificationId) { | ||
log.trace('NTFCN I: Notification id for channel ', channelType, notificationId); | ||
if (this._notificationIds[channelType] !== notificationId) { | ||
this._notificationIds[channelType] = notificationId; | ||
this._updateRegistration(channelType); | ||
} | ||
this._connector(channelType).setNotificationId(notificationId); | ||
}; | ||
/** | ||
* Updates the subscriptions list | ||
* Should be called after reliable transport reconnect | ||
* Checks if subscription for given message and channel already exists | ||
*/ | ||
Registrar.prototype.refreshSubscriptions = function() { | ||
log.info('NTFCN: Refresh registrations'); | ||
this._updateTwilsockRegistration(); | ||
}; | ||
/** | ||
* Checks if subscription for given message and channel already exists | ||
*/ | ||
Registrar.prototype.hasSubscription = function(messageType, channelType) { | ||
if (channelType === 'twilsock') { | ||
return this._subscriptions.twilsock.has(messageType); | ||
} | ||
if (channelType === 'gcm') { | ||
return this._subscriptions.gcm.has(messageType); | ||
} | ||
throw new Error('Unknown channel type: ' + channelType); | ||
this._connector(channelType).has(messageType); | ||
}; | ||
/** | ||
* Subscribe for given type of message | ||
* Subscribe for given type of message | ||
* | ||
* @param {String} messageType Message type identifier | ||
* @param {String} channelType Channel type, can be 'twilsock' or 'gcm' | ||
* @public | ||
*/ | ||
Registrar.prototype.subscribe = function(messageType, channelType) { | ||
if (this.hasSubscription(messageType, channelType)) { | ||
return; | ||
} | ||
if (channelType === 'twilsock') { | ||
if (this._subscriptions.twilsock.size === 0) { | ||
this.emit('needReliableTransport', true); | ||
} | ||
this._subscriptions.twilsock.add(messageType); | ||
this._updateTwilsockRegistration(); | ||
} | ||
else if (channelType === 'gcm') { | ||
this._subscriptions.gcm.add(messageType); | ||
this._updateGcmRegistration(); | ||
} | ||
else { | ||
throw new Error('Can\'t subscribe to the channel type ' + channelType); | ||
} | ||
this._connector(channelType).subscribe(messageType); | ||
}; | ||
/** | ||
* Remove subscription | ||
* @param {String} messageType Message type | ||
* @param {String} channelType Channel type (twilsock or gcm) | ||
* Remove subscription | ||
* @param {String} messageType Message type | ||
* @param {String} channelType Channel type (twilsock or gcm) | ||
* @public | ||
*/ | ||
Registrar.prototype.unsubscribe = function(messageType, channelType) { | ||
if (!this.hasSubscription(messageType, channelType)) { | ||
return; | ||
} | ||
if (channelType === 'twilsock') { | ||
this._subscriptions.twilsock.delete(messageType); | ||
this._updateTwilsockRegistration(); | ||
if (this._subscriptions.twilsock.size === 0) { | ||
this.emit('needReliableTransport', false); | ||
} | ||
} else if (channelType === 'gcm') { | ||
this._subscriptions.gcm.delete(messageType); | ||
this._updateGcmRegistration(); | ||
} | ||
this._connector(channelType).unsubscribe(messageType); | ||
}; | ||
/** | ||
* Update all registrations for channel type | ||
*/ | ||
Registrar.prototype._updateRegistration = function(channelType) { | ||
if (channelType === 'twilsock') { | ||
return this._updateTwilsockRegistration(); | ||
} else if (channelType === 'gcm') { | ||
return this._updateGcmRegistration(); | ||
} | ||
Registrar.prototype.updateToken = function() { | ||
this._connectors.forEach(connector => connector.updateToken()); | ||
}; | ||
/** | ||
* Updates registration for the GCM channel | ||
* @private | ||
* @param {Strint} channelType Channel type | ||
* @throws {Error} Error with description | ||
* @private | ||
*/ | ||
Registrar.prototype._updateTwilsockRegistration = function() { | ||
if (!this._notificationIds.twilsock) { | ||
log.trace('Ignoring twilsock registration update request: no twilsock id in place'); | ||
return; // Can't make twilsock registration without transport url | ||
Registrar.prototype._connector = function(type) { | ||
let connector = this._connectors.get(type); | ||
if (!connector) { | ||
throw new Error('Unknown channel type: ' + type); | ||
} | ||
const notificationId = this._notificationIds.twilsock; | ||
let activeSubscriptions = []; | ||
this._subscriptions.twilsock.forEach(messageType => activeSubscriptions.push(messageType)); | ||
log.debug('Subscribing to the twilsock notifications'); | ||
this._twilsockRegistrar.update(notificationId, activeSubscriptions); | ||
return connector; | ||
}; | ||
/** | ||
* Updates registration for the GCM channel | ||
* @private | ||
*/ | ||
Registrar.prototype._updateGcmRegistration = function() { | ||
if (!this._notificationIds.gcm) { | ||
log.trace('Ignoring twilsock registration update request: no twilsock id in place'); | ||
return; // Can't make gcm registration without transport url | ||
} | ||
const notificationId = this._notificationIds.gcm; | ||
let activeSubscriptions = []; | ||
this._subscriptions.gcm.forEach(messageType => activeSubscriptions.push(messageType)); | ||
this._gcmRegistrar.update(notificationId, activeSubscriptions); | ||
}; | ||
Object.freeze(Registrar); | ||
@@ -181,0 +90,0 @@ |
{ | ||
"name": "twilio-notifications", | ||
"version": "0.0.1", | ||
"version": "0.1.0", | ||
"description": "Client library for Twilio Notifications service", | ||
"main": "lib/client.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/twilio/twilio-notifications.js" | ||
}, | ||
"scripts": { | ||
"test": "gulp test" | ||
"test": "gulp unit-test" | ||
}, | ||
@@ -20,8 +16,11 @@ "author": "Twilio", | ||
"twilio-transport": "0.0.1", | ||
"twilsock": "0.0.1" | ||
"twilsock": "0.1.0", | ||
"uuid": "^2.0.2" | ||
}, | ||
"devDependencies": { | ||
"async": "^2.0.0-rc.3", | ||
"babel-eslint": "^4.1.8", | ||
"chai": "^3.4.1", | ||
"chai-as-promised": "^5.2.0", | ||
"chai-spies": "^0.7.1", | ||
"event-to-promise": "^0.6.0", | ||
@@ -32,2 +31,5 @@ "gulp": "^3.9.0", | ||
"gulp-mocha": "^2.2.0", | ||
"ink-docstrap": "^1.1.4", | ||
"jsdoc": "^3.4.0", | ||
"jsdoc-babel": "^0.1.0", | ||
"proxyquire": "^1.7.3", | ||
@@ -34,0 +36,0 @@ "run-sequence": "^1.1.5", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
219873
41
6
18
1197
1
1
+ Addeduuid@^2.0.2
+ Addedtwilsock@0.1.0(transitive)
+ Addeduuid@2.0.3(transitive)
- Removedtwilsock@0.0.1(transitive)
Updatedtwilsock@0.1.0