twilio-notifications
Advanced tools
Comparing version 0.2.0 to 0.2.1
171
gulpfile.js
@@ -1,20 +0,32 @@ | ||
'use strict'; | ||
const gulp = require('gulp'); | ||
const gutil = require('gulp-util'); | ||
const mocha = require('gulp-mocha'); | ||
const istanbul = require('gulp-istanbul'); | ||
const mocha = require('gulp-mocha'); | ||
const eslint = require('gulp-eslint'); | ||
const browserify = require('browserify'); | ||
const babelify = require('babelify'); | ||
const babel = require('babel-core/register'); | ||
const source = require('vinyl-source-stream'); | ||
const buffer = require('vinyl-buffer'); | ||
const exit = require('gulp-exit'); | ||
const insert = require('gulp-insert'); | ||
const runSequence = require('run-sequence'); | ||
const exit = require('gulp-exit'); | ||
const del = require('del'); | ||
const fs = require('fs'); | ||
const rename = require('gulp-rename'); | ||
const uglify = require('gulp-uglify'); | ||
const cheerio = require('cheerio'); | ||
const tap = require('gulp-tap'); | ||
const derequire = require('gulp-derequire'); | ||
const isparta = require('isparta'); | ||
const cp = require('child_process'); | ||
const jsdoc = 'node_modules/jsdoc/jsdoc.js'; | ||
const pkg = require('./package'); | ||
var cp = require('child_process'); | ||
var jsdoc = 'node_modules/jsdoc/jsdoc.js'; | ||
const product = { | ||
source: { | ||
dir: 'src', | ||
name: pkg.name + '.js', | ||
lib: 'lib/*.js' | ||
lib: 'src/*.js' | ||
}, | ||
@@ -27,3 +39,3 @@ packaged: { | ||
bundled: { | ||
dir: 'src', | ||
dir: 'build', | ||
name: pkg.name + '-bundle.js' | ||
@@ -37,3 +49,5 @@ }, | ||
files: [ | ||
'lib/*.js', | ||
'src/*.js', | ||
'!src/utils.js', | ||
'!src/jsondiff.js', | ||
'gulpfile.js' | ||
@@ -43,3 +57,3 @@ ] | ||
unit: { | ||
files: 'test/unit/**/*.js', | ||
files: 'test/unit/spec/*.js', | ||
index: 'test/unit/index.js' | ||
@@ -60,13 +74,13 @@ }, | ||
conf: 'jsdoc.json', | ||
files: ['./lib/client.js'] | ||
files: [ | ||
'./src/client.js' | ||
], | ||
publicConstructors: ['NotificationsClient'], | ||
}; | ||
gulp.task('clean', function() { | ||
}); | ||
gulp.task('lint', function() { | ||
return gulp.src(tests.lint.files) | ||
.pipe(eslint()) | ||
.pipe(eslint.format()) | ||
.pipe(eslint.failAfterError()); | ||
.pipe(eslint()) | ||
.pipe(eslint.format()) | ||
.pipe(eslint.failAfterError()); | ||
}); | ||
@@ -76,15 +90,15 @@ | ||
return gulp.src([product.source.lib]) | ||
.pipe(istanbul()) | ||
.pipe(istanbul({ | ||
instrumenter: isparta.Instrumenter, | ||
includeUntested: true | ||
})) | ||
.pipe(istanbul.hookRequire()); | ||
}); | ||
gulp.task('integration-test', function() { | ||
return gulp.src(tests.integration.index, { read: false }) | ||
.pipe(mocha({ reporter: 'spec', timeout: 5000 })) | ||
.pipe(exit()); | ||
}); | ||
gulp.task('unit-test', ['istanbul-setup'], function() { | ||
return gulp.src(tests.unit.index, { read: false }) | ||
.pipe(mocha({ reporter: 'spec' })) | ||
.pipe(mocha({ | ||
compilers: { js: babel }, | ||
reporter: 'spec' | ||
})) | ||
.pipe(istanbul.writeReports({ | ||
@@ -97,3 +111,57 @@ dir: coverage.dir, | ||
gulp.task('doc', function(cb) { | ||
gulp.task('integration-test', function() { | ||
return gulp.src(tests.integration.index, { read: false }) | ||
.pipe(mocha({ reporter: 'spec', timeout: 5000 })) | ||
.pipe(exit()); | ||
}); | ||
gulp.task('bundle', function(done) { | ||
browserify({ debug: false, standalone: 'Twilio.Notification.Client', entries: ['./src/index.js'] }) | ||
.exclude('ws') | ||
.transform(babelify, { | ||
global: true, | ||
ignore: /\/node_modules\/(?!twilio-transport|twilsock\/)/ | ||
}) | ||
.bundle() | ||
.pipe(source(product.bundled.name)) | ||
.pipe(buffer()) | ||
.pipe(derequire()) | ||
.pipe(gulp.dest(product.bundled.dir)) | ||
.once('end', done) | ||
.once('error', exit); | ||
}); | ||
gulp.task('license', function() { | ||
var licenseContents = fs.readFileSync(product.license); | ||
return gulp.src(product.bundled.dir + '/' + product.bundled.name) | ||
.pipe(insert.prepend( | ||
'/* ' + pkg.name + '.js ' + pkg.version + '\n' | ||
+ licenseContents | ||
+ '*/\n\n' | ||
)) | ||
.pipe(rename(product.packaged.name)) | ||
.pipe(gulp.dest(product.packaged.dir)); | ||
}); | ||
gulp.task('minify', function() { | ||
return gulp.src(product.packaged.dir + '/' + product.packaged.name) | ||
.pipe(uglify({ | ||
output: { | ||
ascii_only: true // eslint-disable-line camelcase | ||
}, | ||
preserveComments: 'license' | ||
}).on('error', gutil.log)) | ||
.pipe(rename(product.packaged.minified)) | ||
.pipe(gulp.dest(product.packaged.dir)); | ||
}); | ||
gulp.task('build', function(done) { | ||
runSequence('bundle', 'license', done); | ||
}); | ||
gulp.task('package', function(done) { | ||
runSequence('minify', done); | ||
}); | ||
gulp.task('generate-doc', function(cb) { | ||
cp.exec(['node', jsdoc, | ||
@@ -107,2 +175,47 @@ '-d', docs.dir, | ||
gulp.task('prettify-doc', function() { | ||
return gulp.src(docs.dir + '/*.html') | ||
.pipe(tap(function(file) { | ||
var $ = cheerio.load(file.contents.toString()); | ||
var filename = file.path.slice(file.base.length); | ||
var className = filename.split('.html')[0]; | ||
var div; | ||
// Prefix public constructors. | ||
if (docs.publicConstructors.indexOf(className) > -1) { | ||
div = $('.container-overview'); | ||
var name = $('h4.name', div); | ||
name.html(name.html().replace(/new /, 'new <span style="color: #999">Twilio.Notification.</span>')); | ||
} | ||
// Remove private constructors. | ||
if (docs.privateConstructors.indexOf(className) > -1) { | ||
div = $('.container-overview'); | ||
$('h2', div).remove(); | ||
$('h4.name', div).remove(); | ||
$('div.description', div).remove(); | ||
$('h5:contains(Parameters:)', div).remove(); | ||
$('table.params', div).remove(); | ||
} | ||
file.contents = new Buffer($.html()); | ||
return file; | ||
})) | ||
.pipe(gulp.dest(docs.dir)); | ||
}); | ||
gulp.task('doc', function(done) { | ||
runSequence('generate-doc', 'prettify-doc', done); | ||
}); | ||
gulp.task('clean', function() { | ||
return del([ | ||
product.packaged.dir + '/' + product.packaged.name, | ||
product.packaged.dir + '/' + product.packaged.minified, | ||
docs.dir, | ||
product.bundled.dir + '/' + product.bundled.name | ||
]); | ||
}); | ||
gulp.task('default', function(done) { | ||
@@ -113,2 +226,4 @@ runSequence( | ||
'unit-test', | ||
'build', | ||
'package', | ||
'doc', | ||
@@ -115,0 +230,0 @@ done |
'use strict'; | ||
const EventEmitter = require('events').EventEmitter; | ||
const inherits = require('util').inherits; | ||
const log = require('loglevel'); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const Bottleneck = require('bottleneck'); | ||
var _freeze = require('babel-runtime/core-js/object/freeze'); | ||
const NotificationsConfig = require('./configuration'); | ||
const Registrar = require('./registrar'); | ||
var _freeze2 = _interopRequireDefault(_freeze); | ||
const Twilsock = require('twilsock'); | ||
const Transport = require('twilio-transport'); | ||
var _promise = require('babel-runtime/core-js/promise'); | ||
var _promise2 = _interopRequireDefault(_promise); | ||
var _defineProperties = require('babel-runtime/core-js/object/define-properties'); | ||
var _defineProperties2 = _interopRequireDefault(_defineProperties); | ||
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); | ||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); | ||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); | ||
var _inherits2 = require('babel-runtime/helpers/inherits'); | ||
var _inherits3 = _interopRequireDefault(_inherits2); | ||
var _configuration = require('./configuration'); | ||
var _configuration2 = _interopRequireDefault(_configuration); | ||
var _events = require('events'); | ||
var _events2 = _interopRequireDefault(_events); | ||
var _logger = require('./logger'); | ||
var _logger2 = _interopRequireDefault(_logger); | ||
var _bottleneck = require('bottleneck'); | ||
var _bottleneck2 = _interopRequireDefault(_bottleneck); | ||
var _registrar = require('./registrar'); | ||
var _registrar2 = _interopRequireDefault(_registrar); | ||
var _twilsock = require('twilsock'); | ||
var _twilsock2 = _interopRequireDefault(_twilsock); | ||
var _twilioTransport = require('twilio-transport'); | ||
var _twilioTransport2 = _interopRequireDefault(_twilioTransport); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function limit(fn, to, per) { | ||
// overflow since no token is passed to arguments | ||
let limiter = new Bottleneck(to, per, 1, Bottleneck.strategy.LEAK); | ||
return function() { | ||
let args = Array.prototype.slice.call(arguments, 0); | ||
var limiter = new _bottleneck2.default(to, per, 1, _bottleneck2.default.strategy.LEAK); | ||
return function () { | ||
var args = Array.prototype.slice.call(arguments, 0); | ||
args.unshift(fn); | ||
@@ -36,172 +90,215 @@ return limiter.schedule.apply(limiter, args); | ||
*/ | ||
function NotificationsClient(token, options) { | ||
if (!token) { | ||
throw new Error('Token is required for Notifications client'); | ||
} | ||
EventEmitter.call(this); | ||
options = options || {}; | ||
var NotificationsClient = function (_EventEmitter) { | ||
(0, _inherits3.default)(NotificationsClient, _EventEmitter); | ||
options.logLevel = options.logLevel || 'error'; | ||
log.setLevel(options.logLevel); | ||
function NotificationsClient(token, options) { | ||
(0, _classCallCheck3.default)(this, NotificationsClient); | ||
const minTokenRefreshInterval = options.minTokenRefreshInterval || 10000; | ||
const productId = options.productId || 'notifications'; | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (NotificationsClient.__proto__ || (0, _getPrototypeOf2.default)(NotificationsClient)).call(this)); | ||
options.twilsockClient = options.twilsockClient || new Twilsock(token, options); | ||
options.transport = options.transport || new Transport(options.twilsockClient); | ||
if (!token) { | ||
throw new Error('Token is required for Notifications client'); | ||
} | ||
let twilsock = options.twilsockClient; | ||
let transport = options.transport; | ||
options = options || {}; | ||
let reliableTransportState = { | ||
overall: false, | ||
transport: false, | ||
registration: false | ||
}; | ||
options.logLevel = options.logLevel || 'error'; | ||
_logger2.default.setLevel(options.logLevel); | ||
let config = new NotificationsConfig(token, options); | ||
Object.defineProperties(this, { | ||
_config: { value: config }, | ||
_registrar: { value: new Registrar(productId, transport, twilsock, config) }, | ||
_twilsock: { value: twilsock }, | ||
_reliableTransportState: { value: reliableTransportState }, | ||
var minTokenRefreshInterval = options.minTokenRefreshInterval || 10000; | ||
var productId = options.productId || 'notifications'; | ||
updateToken: { value: limit(this._updateToken.bind(this), 1, minTokenRefreshInterval), enumerable: true }, | ||
connectionState: { | ||
get: () => { | ||
if (this._twilsock.state === 'disconnected') { | ||
return 'disconnected'; | ||
} else if (this._twilsock.state === 'disconnecting') { | ||
return 'disconnecting'; | ||
} else if (this._twilsock.state === 'connected' && this._reliableTransportState.registration) { | ||
return 'connected'; | ||
} else if (this._twilsock.state === 'rejected') { | ||
return 'denied'; | ||
options.twilsockClient = options.twilsockClient || new _twilsock2.default(token, options); | ||
options.transport = options.transport || new _twilioTransport2.default(options.twilsockClient); | ||
var twilsock = options.twilsockClient; | ||
var transport = options.transport; | ||
var reliableTransportState = { | ||
overall: false, | ||
transport: false, | ||
registration: false | ||
}; | ||
var config = new _configuration2.default(token, options); | ||
(0, _defineProperties2.default)(_this, { | ||
_config: { value: config }, | ||
_registrar: { value: new _registrar2.default(productId, transport, twilsock, config) }, | ||
_twilsock: { value: twilsock }, | ||
_reliableTransportState: { value: reliableTransportState }, | ||
updateToken: { value: limit(_this._updateToken.bind(_this), 1, minTokenRefreshInterval), enumerable: true }, | ||
connectionState: { | ||
get: function get() { | ||
if (_this._twilsock.state === 'disconnected') { | ||
return 'disconnected'; | ||
} else if (_this._twilsock.state === 'disconnecting') { | ||
return 'disconnecting'; | ||
} else if (_this._twilsock.state === 'connected' && _this._reliableTransportState.registration) { | ||
return 'connected'; | ||
} else if (_this._twilsock.state === 'rejected') { | ||
return 'denied'; | ||
} | ||
return 'connecting'; | ||
} | ||
} | ||
}); | ||
return 'connecting'; | ||
_this._onTransportStateChange(_this._twilsock.connected); | ||
_this._registrar.on('transportReady', function (state) { | ||
_this._onRegistrationStateChange(state ? 'registered' : ''); | ||
}); | ||
_this._registrar.on('stateChanged', function (state) { | ||
_this._onRegistrationStateChange(state); | ||
}); | ||
_this._registrar.on('needReliableTransport', _this._onNeedReliableTransport.bind(_this)); | ||
_this._twilsock.on('message', function (type, message) { | ||
return _this._routeMessage(type, message); | ||
}); | ||
_this._twilsock.on('connected', function (notificationId) { | ||
_this._onTransportStateChange(true); | ||
_this._registrar.setNotificationId('twilsock', notificationId); | ||
}); | ||
_this._twilsock.on('disconnected', function () { | ||
_this._onTransportStateChange(false); | ||
}); | ||
return _this; | ||
} | ||
/** | ||
* Routes messages to the external subscribers | ||
* @private | ||
*/ | ||
(0, _createClass3.default)(NotificationsClient, [{ | ||
key: '_routeMessage', | ||
value: function _routeMessage(type, message) { | ||
_logger2.default.trace('Message arrived: ', type, message); | ||
this.emit('message', type, message); | ||
} | ||
}, { | ||
key: '_onNeedReliableTransport', | ||
value: function _onNeedReliableTransport(isNeeded) { | ||
if (isNeeded) { | ||
this._twilsock.connect(); | ||
} else { | ||
this._twilsock.disconnect(); | ||
} | ||
} | ||
}); | ||
}, { | ||
key: '_onRegistrationStateChange', | ||
value: function _onRegistrationStateChange(state) { | ||
this._reliableTransportState.registration = state === 'registered'; | ||
this._updateTransportState(); | ||
} | ||
}, { | ||
key: '_onTransportStateChange', | ||
value: function _onTransportStateChange(connected) { | ||
this._reliableTransportState.transport = connected; | ||
this._updateTransportState(); | ||
} | ||
}, { | ||
key: '_updateTransportState', | ||
value: function _updateTransportState() { | ||
var overallState = this._reliableTransportState.transport && this._reliableTransportState.registration; | ||
this._onTransportStateChange(this._twilsock.connected); | ||
if (this._reliableTransportState.overall !== overallState) { | ||
this._reliableTransportState.overall = overallState; | ||
this._registrar.on('transportReady', state => { this._onRegistrationStateChange(state ? 'registered' : ''); }); | ||
this._registrar.on('stateChanged', (state) => { this._onRegistrationStateChange(state); }); | ||
this._registrar.on('needReliableTransport', this._onNeedReliableTransport.bind(this)); | ||
_logger2.default.info('Transport ready ' + overallState); | ||
this.emit('transportReady', overallState); | ||
this.emit('connectionStateChanged', this.connectionState); | ||
} | ||
} | ||
this._twilsock.on('message', (type, message) => this._routeMessage(type, message)); | ||
this._twilsock.on('connected', (notificationId) => { | ||
this._onTransportStateChange(true); | ||
this._registrar.setNotificationId('twilsock', notificationId); | ||
}); | ||
this._twilsock.on('disconnected', () => { this._onTransportStateChange(false); }); | ||
} | ||
/** | ||
* 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', 'gcm' and 'fcm' | ||
* @public | ||
*/ | ||
inherits(NotificationsClient, EventEmitter); | ||
}, { | ||
key: 'subscribe', | ||
value: function subscribe(messageType, channelType) { | ||
channelType = channelType || 'twilsock'; | ||
_logger2.default.trace('Add subscriptions for message type: ', messageType, channelType); | ||
/** | ||
* Routes messages to the external subscribers | ||
* @private | ||
*/ | ||
NotificationsClient.prototype._routeMessage = function(type, message) { | ||
log.trace('Message arrived: ', type, message); | ||
this.emit('message', type, message); | ||
}; | ||
return this._registrar.subscribe(messageType, channelType); | ||
} | ||
NotificationsClient.prototype._onNeedReliableTransport = function(isNeeded) { | ||
if (isNeeded) { | ||
this._twilsock.connect(); | ||
} else { | ||
this._twilsock.disconnect(); | ||
} | ||
}; | ||
/** | ||
* 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} channelType. Supported are 'twilsock', 'gcm' and 'fcm' | ||
* @public | ||
*/ | ||
NotificationsClient.prototype._onRegistrationStateChange = function(state) { | ||
this._reliableTransportState.registration = (state === 'registered'); | ||
this._updateTransportState(); | ||
}; | ||
}, { | ||
key: 'unsubscribe', | ||
value: function unsubscribe(messageType, channelType) { | ||
channelType = channelType || 'twilsock'; | ||
_logger2.default.trace('Remove subscriptions for message type: ', messageType, channelType); | ||
NotificationsClient.prototype._onTransportStateChange = function(connected) { | ||
this._reliableTransportState.transport = connected; | ||
this._updateTransportState(); | ||
}; | ||
return this._registrar.unsubscribe(messageType, channelType); | ||
} | ||
NotificationsClient.prototype._updateTransportState = function() { | ||
const overallState = this._reliableTransportState.transport | ||
&& this._reliableTransportState.registration; | ||
/** | ||
* Handle incoming push notification. | ||
* Client application should call this method when it receives push notifications and pass the received data | ||
* @param {Object} msg - push message object | ||
* @public | ||
*/ | ||
if (this._reliableTransportState.overall !== overallState) { | ||
this._reliableTransportState.overall = overallState; | ||
}, { | ||
key: 'handlePushNotification', | ||
value: function handlePushNotification(msg) { | ||
_logger2.default.warn('Push message passed, but no functionality implemented yet: ' + msg); | ||
} | ||
log.info('NTFCN I: Transport ready ' + overallState); | ||
this.emit('transportReady', overallState); | ||
this.emit('connectionStateChanged', this.connectionState); | ||
} | ||
}; | ||
/** | ||
* Set GCM/FCM token to enable application register for a push messages | ||
* @param {string} gcmToken/fcmToken Token received from GCM/FCM system | ||
* @public | ||
*/ | ||
/** | ||
* 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 | ||
*/ | ||
NotificationsClient.prototype.subscribe = function(messageType, channelType) { | ||
channelType = channelType || 'twilsock'; | ||
log.trace('Add subscriptions for message type: ', messageType, channelType); | ||
}, { | ||
key: 'setPushRegistrationId', | ||
value: function setPushRegistrationId(registrationId, type) { | ||
this._registrar.setNotificationId(type || 'gcm', registrationId); | ||
} | ||
return this._registrar.subscribe(messageType, channelType); | ||
}; | ||
/** | ||
* Updates auth token for registration | ||
* @param {string} token Authentication token for registrations | ||
* @public | ||
*/ | ||
/** | ||
* 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 | ||
*/ | ||
NotificationsClient.prototype.unsubscribe = function(messageType, channelType) { | ||
channelType = channelType || 'twilsock'; | ||
log.trace('Remove subscriptions for message type: ', messageType, channelType); | ||
}, { | ||
key: '_updateToken', | ||
value: function _updateToken(token) { | ||
_logger2.default.info('authTokenUpdated'); | ||
if (this._config.token !== token) { | ||
this._twilsock.updateToken(token); | ||
return this._registrar.unsubscribe(messageType, channelType); | ||
}; | ||
this._config.updateToken(token); | ||
this._registrar.updateToken(); | ||
} | ||
return _promise2.default.resolve(); | ||
} | ||
}]); | ||
return NotificationsClient; | ||
}(_events2.default); | ||
/** | ||
* 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 | ||
*/ | ||
NotificationsClient.prototype.handlePushNotification = function(msg) { | ||
log.warn('Push message passed, but no functionality implemented yet: ' + msg); | ||
}; | ||
exports.default = NotificationsClient; | ||
/** | ||
* Set GCM token to enable application register for a push messages | ||
* @param {string} gcmToken Token received from GCM system | ||
* @public | ||
*/ | ||
NotificationsClient.prototype.setPushRegistrationId = function(registrationId, type) { | ||
this._registrar.setNotificationId(type || 'gcm', registrationId); | ||
}; | ||
/** | ||
* Updates auth token for registration | ||
* @param {string} token Authentication token for registrations | ||
* @public | ||
*/ | ||
NotificationsClient.prototype._updateToken = function(token) { | ||
log.info('NTFCN I: authTokenUpdated'); | ||
if (this._config.token !== token) { | ||
this._twilsock.updateToken(token); | ||
(0, _freeze2.default)(NotificationsClient); | ||
this._config.updateToken(token); | ||
this._registrar.updateToken(); | ||
} | ||
return Promise.resolve(); | ||
}; | ||
Object.freeze(NotificationsClient); | ||
/** | ||
@@ -232,3 +329,2 @@ * Fired when new message arrived. | ||
module.exports = NotificationsClient; | ||
module.exports = exports['default']; |
'use strict'; | ||
const ERS_URI = 'https://ers.twilio.com'; | ||
const ERS_PATH = '/v1/registrations'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
/** | ||
* Notification library configuration provider | ||
*/ | ||
function NotificationConfig(token, options) { | ||
options = ( options || { } ).Notification || { }; | ||
const uri = options.ersUri || ERS_URI; | ||
var _defineProperties = require('babel-runtime/core-js/object/define-properties'); | ||
Object.defineProperties(this, { | ||
_registrarUri: { value: uri + ERS_PATH }, | ||
_token: { value: token, writable: true }, | ||
var _defineProperties2 = _interopRequireDefault(_defineProperties); | ||
registrarUri: { get: () => this._registrarUri }, | ||
token: { get: () => this._token } | ||
}); | ||
} | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
NotificationConfig.prototype.updateToken = function(token) { | ||
this._token = token; | ||
}; | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
module.exports = NotificationConfig; | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var ERS_URI = 'https://ers.twilio.com'; | ||
var ERS_PATH = '/v1/registrations'; | ||
var NotificationConfig = function () { | ||
function NotificationConfig(token, options) { | ||
var _this = this; | ||
(0, _classCallCheck3.default)(this, NotificationConfig); | ||
options = (options || {}).Notification || {}; | ||
var uri = options.ersUri || ERS_URI; | ||
(0, _defineProperties2.default)(this, { | ||
_registrarUri: { value: uri + ERS_PATH }, | ||
_token: { value: token, writable: true }, | ||
registrarUri: { get: function get() { | ||
return _this._registrarUri; | ||
} }, | ||
token: { get: function get() { | ||
return _this._token; | ||
} } | ||
}); | ||
} | ||
(0, _createClass3.default)(NotificationConfig, [{ | ||
key: 'updateToken', | ||
value: function updateToken(token) { | ||
this._token = token; | ||
} | ||
}]); | ||
return NotificationConfig; | ||
}(); | ||
exports.default = NotificationConfig; | ||
module.exports = exports['default']; |
'use strict'; | ||
const EventEmitter = require('events').EventEmitter; | ||
const inherits = require('util').inherits; | ||
const StateMachine = require('javascript-state-machine'); | ||
const Backoff = require('backoff'); | ||
const log = require('loglevel'); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var _freeze = require('babel-runtime/core-js/object/freeze'); | ||
var _freeze2 = _interopRequireDefault(_freeze); | ||
var _promise = require('babel-runtime/core-js/promise'); | ||
var _promise2 = _interopRequireDefault(_promise); | ||
var _set2 = require('babel-runtime/core-js/set'); | ||
var _set3 = _interopRequireDefault(_set2); | ||
var _defineProperties = require('babel-runtime/core-js/object/define-properties'); | ||
var _defineProperties2 = _interopRequireDefault(_defineProperties); | ||
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); | ||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); | ||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); | ||
var _inherits2 = require('babel-runtime/helpers/inherits'); | ||
var _inherits3 = _interopRequireDefault(_inherits2); | ||
var _events = require('events'); | ||
var _events2 = _interopRequireDefault(_events); | ||
var _logger = require('./logger'); | ||
var _logger2 = _interopRequireDefault(_logger); | ||
var _javascriptStateMachine = require('javascript-state-machine'); | ||
var _javascriptStateMachine2 = _interopRequireDefault(_javascriptStateMachine); | ||
var _backoff = require('backoff'); | ||
var _backoff2 = _interopRequireDefault(_backoff); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function toArray(_set) { | ||
let arr = []; | ||
_set.forEach(v => arr.push(v)); | ||
var arr = []; | ||
_set.forEach(function (v) { | ||
return arr.push(v); | ||
}); | ||
return arr; | ||
@@ -27,246 +81,280 @@ } | ||
*/ | ||
function RegistrarConnector(context, transport, config, channelType) { | ||
let fsm = StateMachine.create({ | ||
initial: { state: 'unregistered', event: 'init', defer: true }, | ||
events: [ | ||
{ name: 'userUpdate', from: ['unregistered'], to: 'registering' }, | ||
{ name: 'userUpdate', from: ['registered'], to: 'unregistering' }, | ||
{ name: 'registered', from: ['registering', | ||
'retrying'], to: 'registered' }, | ||
{ name: 'unregistered', from: ['unregistering'], to: 'unregistered' }, | ||
var RegistrarConnector = function (_EventEmitter) { | ||
(0, _inherits3.default)(RegistrarConnector, _EventEmitter); | ||
{ name: 'retry', from: ['retrying'], to: 'retrying' }, | ||
{ name: 'failure', from: ['registering'], to: 'retrying' }, | ||
{ name: 'failure', from: ['retrying'], to: 'retrying' }, | ||
{ name: 'failure', from: ['unregistering'], to: 'unregistered' } | ||
], | ||
callbacks: { | ||
onregistering: (event, from, to, arg) => this._register(arg), | ||
onunregistering: () => this._unregister(), | ||
onregistered: () => this._onRegistered(), | ||
onunregistered: () => this._onUnregistered(), | ||
onretrying: (event, from, to, arg) => this._initRetry(arg), | ||
onfailure: (event, from, to, arg) => { if (from === 'retrying') { this._initRetry(arg); } } | ||
} | ||
}); | ||
function RegistrarConnector(context, transport, config, channelType) { | ||
(0, _classCallCheck3.default)(this, RegistrarConnector); | ||
const backoff = Backoff.exponential({ | ||
randomisationFactor: 0.2, | ||
initialDelay: 2 * 1000, | ||
maxDelay: 2 * 60 * 1000 | ||
}); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (RegistrarConnector.__proto__ || (0, _getPrototypeOf2.default)(RegistrarConnector)).call(this)); | ||
backoff.on('ready', () => { this._retry(); }); | ||
var fsm = _javascriptStateMachine2.default.create({ | ||
initial: { state: 'unregistered', event: 'init', defer: true }, | ||
events: [{ name: 'userUpdate', from: ['unregistered'], to: 'registering' }, { name: 'userUpdate', from: ['registered'], to: 'unregistering' }, { name: 'registered', from: ['registering', 'retrying'], to: 'registered' }, { name: 'unregistered', from: ['unregistering'], to: 'unregistered' }, { name: 'retry', from: ['retrying'], to: 'retrying' }, { name: 'failure', from: ['registering'], to: 'retrying' }, { name: 'failure', from: ['retrying'], to: 'retrying' }, { name: 'failure', from: ['unregistering'], to: 'unregistered' }], | ||
callbacks: { | ||
onregistering: function onregistering(event, from, to, arg) { | ||
return _this._register(arg); | ||
}, | ||
onunregistering: function onunregistering() { | ||
return _this._unregister(); | ||
}, | ||
onregistered: function onregistered() { | ||
return _this._onRegistered(); | ||
}, | ||
onunregistered: function onunregistered() { | ||
return _this._onUnregistered(); | ||
}, | ||
onretrying: function onretrying(event, from, to, arg) { | ||
return _this._initRetry(arg); | ||
}, | ||
onfailure: function onfailure(event, from, to, arg) { | ||
if (from === 'retrying') { | ||
_this._initRetry(arg); | ||
} | ||
} | ||
} | ||
}); | ||
Object.defineProperties(this, { | ||
_transport: { value: transport }, | ||
_context: { value: context }, | ||
_url: { value: config.registrarUri, writable: false }, | ||
_config: { value: config }, | ||
_fsm: { value: fsm }, | ||
_backoff: { value: backoff }, | ||
_channelType: { value: channelType }, | ||
_registrationId: { value: false, writable: true }, | ||
_notificationId: { value: false, writable: true }, | ||
_messageTypes: { value: new Set(), writable: true }, | ||
_pendingUpdate: { value: null, writable: true } | ||
}); | ||
var backoff = _backoff2.default.exponential({ | ||
randomisationFactor: 0.2, | ||
initialDelay: 2 * 1000, | ||
maxDelay: 2 * 60 * 1000 | ||
}); | ||
EventEmitter.call(this); | ||
fsm.init(); | ||
} | ||
backoff.on('ready', function () { | ||
_this._retry(); | ||
}); | ||
inherits(RegistrarConnector, EventEmitter); | ||
(0, _defineProperties2.default)(_this, { | ||
_transport: { value: transport }, | ||
_context: { value: context }, | ||
_url: { value: config.registrarUri, writable: false }, | ||
_config: { value: config }, | ||
_fsm: { value: fsm }, | ||
_backoff: { value: backoff }, | ||
_channelType: { value: channelType }, | ||
_registrationId: { value: false, writable: true }, | ||
_notificationId: { value: false, writable: true }, | ||
_messageTypes: { value: new _set3.default(), writable: true }, | ||
_pendingUpdate: { value: null, writable: true } | ||
}); | ||
RegistrarConnector.prototype.setNotificationId = function(notificationId) { | ||
if (this._notificationId === notificationId) { | ||
return; | ||
fsm.init(); | ||
return _this; | ||
} | ||
this._notificationId = notificationId; | ||
this._updateRegistration(); | ||
}; | ||
(0, _createClass3.default)(RegistrarConnector, [{ | ||
key: 'setNotificationId', | ||
value: function setNotificationId(notificationId) { | ||
if (this._notificationId === notificationId) { | ||
return; | ||
} | ||
RegistrarConnector.prototype.updateToken = function() { | ||
return this._updateRegistration(); | ||
}; | ||
this._notificationId = notificationId; | ||
this._updateRegistration(); | ||
} | ||
}, { | ||
key: 'updateToken', | ||
value: function updateToken() { | ||
return this._updateRegistration(); | ||
} | ||
}, { | ||
key: 'has', | ||
value: function has(messageType) { | ||
return this._messageTypes.has(messageType); | ||
} | ||
}, { | ||
key: 'subscribe', | ||
value: function subscribe(messageType) { | ||
if (this._messageTypes.has(messageType)) { | ||
_logger2.default.debug('Message type already registered ', messageType); | ||
return false; | ||
} | ||
RegistrarConnector.prototype.has = function(messageType) { | ||
return this._messageTypes.has(messageType); | ||
}; | ||
this._messageTypes.add(messageType); | ||
this._updateRegistration(); | ||
return true; | ||
} | ||
}, { | ||
key: 'unsubscribe', | ||
value: function unsubscribe(messageType) { | ||
if (!this._messageTypes.has(messageType)) { | ||
return false; | ||
} | ||
RegistrarConnector.prototype.subscribe = function(messageType) { | ||
if (this._messageTypes.has(messageType)) { | ||
log.debug('Message type already registered ', messageType); | ||
return false; | ||
} | ||
this._messageTypes.delete(messageType); | ||
this._messageTypes.add(messageType); | ||
this._updateRegistration(); | ||
return true; | ||
}; | ||
if (this._messageTypes.size > 0) { | ||
this._updateRegistration(); | ||
} else { | ||
this._removeRegistration(); | ||
} | ||
return true; | ||
} | ||
}, { | ||
key: '_updateRegistration', | ||
value: function _updateRegistration() { | ||
if (this._notificationId) { | ||
this._update(this._notificationId, toArray(this._messageTypes)); | ||
} | ||
} | ||
}, { | ||
key: '_removeRegistration', | ||
value: function _removeRegistration() { | ||
if (this._notificationId) { | ||
this._update(this._notificationId, toArray(this._messageTypes)); | ||
} | ||
} | ||
RegistrarConnector.prototype.unsubscribe = function(messageType) { | ||
if (!this._messageTypes.has(messageType)) { | ||
return false; | ||
} | ||
/** | ||
* Update service registration | ||
* @param {Array} messageTypes Array of message type names | ||
* @private | ||
*/ | ||
this._messageTypes.delete(messageType); | ||
}, { | ||
key: '_update', | ||
value: function _update(notificationId, messageTypes) { | ||
var regData = { notificationId: notificationId, messageTypes: messageTypes }; | ||
if (this._messageTypes.size > 0) { | ||
this._updateRegistration(); | ||
} else { | ||
this._removeRegistration(); | ||
} | ||
return true; | ||
}; | ||
if (this._fsm.is('unregistered')) { | ||
if (regData.notificationId && regData.messageTypes.length > 0) { | ||
this._fsm.userUpdate(regData); | ||
} | ||
} else if (this._fsm.is('registered')) { | ||
this._fsm.userUpdate(regData); | ||
this._setPendingUpdate(regData); | ||
} else { | ||
this._setPendingUpdate(regData); | ||
} | ||
} | ||
}, { | ||
key: '_setPendingUpdate', | ||
value: function _setPendingUpdate(regData) { | ||
this._pendingUpdate = regData; | ||
} | ||
}, { | ||
key: '_checkPendingUpdate', | ||
value: function _checkPendingUpdate() { | ||
if (!this._pendingUpdate) { | ||
return; | ||
} | ||
RegistrarConnector.prototype._updateRegistration = function() { | ||
if (this._notificationId) { | ||
this._update(this._notificationId, toArray(this._messageTypes)); | ||
} | ||
}; | ||
var pendingUpdate = this._pendingUpdate; | ||
this._pendingUpdate = null; | ||
RegistrarConnector.prototype._removeRegistration = function() { | ||
if (this._notificationId) { | ||
this._update(this._notificationId, toArray(this._messageTypes)); | ||
} | ||
}; | ||
this._updateRegistration(pendingUpdate.notificationId, pendingUpdate.messageTypes); | ||
} | ||
}, { | ||
key: '_initRetry', | ||
value: function _initRetry(regData) { | ||
if (!this._pendingUpdate) { | ||
this._setPendingUpdate(regData); | ||
} | ||
/** | ||
* Update service registration | ||
* @param Array messageTypes Array of message type names | ||
* @private | ||
*/ | ||
RegistrarConnector.prototype._update = function(notificationId, messageTypes) { | ||
let regData = { notificationId: notificationId, messageTypes: messageTypes }; | ||
if (this._fsm.is('unregistered')) { | ||
if (regData.notificationId && regData.messageTypes.length > 0) { | ||
this._fsm.userUpdate(regData); | ||
this._backoff.backoff(); | ||
} | ||
} else if (this._fsm.is('registered')) { | ||
this._fsm.userUpdate(regData); | ||
this._setPendingUpdate(regData); | ||
} else { | ||
this._setPendingUpdate(regData); | ||
} | ||
}; | ||
}, { | ||
key: '_retry', | ||
value: function _retry() { | ||
if (!this._pendingUpdate) { | ||
return; | ||
} | ||
var pendingUpdate = this._pendingUpdate; | ||
this._pendingUpdate = null; | ||
RegistrarConnector.prototype._setPendingUpdate = function(regData) { | ||
this._pendingUpdate = regData; | ||
}; | ||
this._register(pendingUpdate); | ||
} | ||
}, { | ||
key: '_onRegistered', | ||
value: function _onRegistered() { | ||
this._backoff.reset(); | ||
this.emit('stateChanged', 'registered'); | ||
this._checkPendingUpdate(); | ||
} | ||
}, { | ||
key: '_onUnregistered', | ||
value: function _onUnregistered() { | ||
this._backoff.reset(); | ||
this.emit('stateChanged', 'unregistered'); | ||
this._checkPendingUpdate(); | ||
} | ||
}, { | ||
key: '_register', | ||
value: function _register(regData) { | ||
var _this2 = this; | ||
RegistrarConnector.prototype._checkPendingUpdate = function() { | ||
if (!this._pendingUpdate) { | ||
return; | ||
} | ||
/* eslint-disable camelcase */ | ||
var registrarRequest = { | ||
endpoint_platform: this._context.platform, | ||
channel_type: this._channelType, | ||
version: '2', | ||
message_types: regData.messageTypes, | ||
data: {}, | ||
ttl: 'PT24H' | ||
}; | ||
var pendingUpdate = this._pendingUpdate; | ||
this._pendingUpdate = null; | ||
if (this._channelType === 'twilsock') { | ||
registrarRequest.data.url = regData.notificationId; | ||
} else { | ||
registrarRequest.data.registration_id = regData.notificationId; | ||
} | ||
this._updateRegistration(pendingUpdate.notificationId, pendingUpdate.messageTypes); | ||
}; | ||
var uri = this._url + '?productId=' + this._context.productId; | ||
var headers = { | ||
'Content-Type': 'application/json', | ||
'X-Twilio-Token': this._config.token | ||
}; | ||
/* eslint-enable camelcase */ | ||
RegistrarConnector.prototype._initRetry = function(regData) { | ||
if (!this._pendingUpdate) { | ||
this._setPendingUpdate(regData); | ||
} | ||
_logger2.default.trace('Creating registration for channel ', this._channelType); | ||
return this._transport.post(uri, headers, registrarRequest).then(function (response) { | ||
_this2._registrationId = response.body.id; | ||
_this2._registrationData = regData; | ||
this._backoff.backoff(); | ||
}; | ||
_logger2.default.debug('Registration created: ', response); | ||
_this2._fsm.registered(); | ||
}).catch(function (error) { | ||
_logger2.default.error('Registration failed: ', error); | ||
_this2._fsm.failure(regData); | ||
return error; | ||
}); | ||
} | ||
}, { | ||
key: '_unregister', | ||
value: function _unregister() { | ||
var _this3 = this; | ||
RegistrarConnector.prototype._retry = function() { | ||
if (!this._pendingUpdate) { return; } | ||
if (!this._registrationId) { | ||
return _promise2.default.resolve(); | ||
} | ||
const pendingUpdate = this._pendingUpdate; | ||
this._pendingUpdate = null; | ||
var uri = this._url + '/' + this._registrationId + '?productId=' + this._context.productId; | ||
var headers = { | ||
'Content-Type': 'application/json', | ||
'X-Twilio-Token': this._config.token | ||
}; | ||
this._register(pendingUpdate); | ||
}; | ||
_logger2.default.trace('Removing registration for ', this._channelType); | ||
return this._transport.delete(uri, headers).then(function () { | ||
_logger2.default.debug('Registration removed for ', _this3._channelType); | ||
_this3._registrationId = false; | ||
_this3._fsm.unregistered(); | ||
}).catch(function (reason) { | ||
// failure to remove registration since being treated as "unregistered" state | ||
// because it is indicates that something wrong with server/connection | ||
_logger2.default.error('Failed to remove of registration ', _this3.channelType, reason); | ||
_this3._fsm.failure(); | ||
return reason; | ||
}); | ||
} | ||
}]); | ||
return RegistrarConnector; | ||
}(_events2.default); | ||
RegistrarConnector.prototype._onRegistered = function() { | ||
this._backoff.reset(); | ||
this.emit('stateChanged', 'registered'); | ||
this._checkPendingUpdate(); | ||
}; | ||
exports.default = RegistrarConnector; | ||
RegistrarConnector.prototype._onUnregistered = function() { | ||
this._backoff.reset(); | ||
this.emit('stateChanged', 'unregistered'); | ||
this._checkPendingUpdate(); | ||
}; | ||
RegistrarConnector.prototype._register = function(regData) { | ||
/* eslint-disable camelcase */ | ||
let registrarRequest = { | ||
endpoint_platform: this._context.platform, | ||
channel_type: this._channelType, | ||
version: '2', | ||
message_types: regData.messageTypes, | ||
data: { }, | ||
ttl: 'PT24H' | ||
}; | ||
if (this._channelType === 'twilsock') { | ||
registrarRequest.data.url = regData.notificationId; | ||
} else { | ||
registrarRequest.data.registration_id = regData.notificationId; | ||
} | ||
const uri = this._url + '?productId=' + this._context.productId; | ||
const headers = { | ||
'Content-Type': 'application/json', | ||
'X-Twilio-Token': this._config.token | ||
}; | ||
/* eslint-enable camelcase */ | ||
log.trace('NTFCN I: Creating registration for channel ', this._channelType); | ||
return this._transport.post(uri, headers, registrarRequest) | ||
.then((response) => { | ||
this._registrationId = response.body.id; | ||
this._registrationData = regData; | ||
log.debug('NTFCN I: Registration created: ', response); | ||
this._fsm.registered(); | ||
}) | ||
.catch((error) => { | ||
log.error('NTFCN E: Registration failed: ', error); | ||
this._fsm.failure(regData); | ||
return error; | ||
}); | ||
}; | ||
RegistrarConnector.prototype._unregister = function() { | ||
if (!this._registrationId) { | ||
return Promise.resolve(); | ||
} | ||
const uri = this._url + '/' + this._registrationId + '?productId=' + this._context.productId; | ||
const headers = { | ||
'Content-Type': 'application/json', | ||
'X-Twilio-Token': this._config.token | ||
}; | ||
log.trace('NTFCN I: removing registration for ', this._channelType); | ||
return this._transport.delete(uri, headers) | ||
.then(() => { | ||
log.debug('NTFCN I: registration removed for ', this._channelType); | ||
this._registrationId = false; | ||
this._fsm.unregistered(); | ||
}) | ||
.catch((reason) => { | ||
// failure to remove registration since being treated as "unregistered" state | ||
// because it is indicates that something wrong with server/connection | ||
log.error('NTFCN E: failed to remove of registration ', this.channelType, reason); | ||
this._fsm.failure(); | ||
return reason; | ||
}); | ||
}; | ||
Object.freeze(RegistrarConnector); | ||
module.exports = RegistrarConnector; | ||
(0, _freeze2.default)(RegistrarConnector); | ||
module.exports = exports['default']; |
'use strict'; | ||
const EventEmitter = require('events').EventEmitter; | ||
const inherits = require('util').inherits; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const ErsConnector = require('./registrar.connector'); | ||
const TwilsockConnector = require('./twilsock.connector'); | ||
var _freeze = require('babel-runtime/core-js/object/freeze'); | ||
var _freeze2 = _interopRequireDefault(_freeze); | ||
var _map = require('babel-runtime/core-js/map'); | ||
var _map2 = _interopRequireDefault(_map); | ||
var _defineProperties = require('babel-runtime/core-js/object/define-properties'); | ||
var _defineProperties2 = _interopRequireDefault(_defineProperties); | ||
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); | ||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); | ||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); | ||
var _inherits2 = require('babel-runtime/helpers/inherits'); | ||
var _inherits3 = _interopRequireDefault(_inherits2); | ||
var _events = require('events'); | ||
var _events2 = _interopRequireDefault(_events); | ||
var _registrar = require('./registrar.connector'); | ||
var _registrar2 = _interopRequireDefault(_registrar); | ||
var _twilsock = require('./twilsock.connector'); | ||
var _twilsock2 = _interopRequireDefault(_twilsock); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
@@ -15,81 +59,111 @@ * Creates the new instance of ERS registrar client | ||
*/ | ||
function Registrar(productId, transport, twilsock, config) { | ||
Object.defineProperties(this, { | ||
_conf: { value: config }, | ||
_connectors: { value: new Map() } | ||
}); | ||
var Registrar = function (_EventEmitter) { | ||
(0, _inherits3.default)(Registrar, _EventEmitter); | ||
const platform = (typeof navigator !== 'undefined' ? navigator.userAgent : 'web') | ||
.substring(0, 128); | ||
function Registrar(productId, transport, twilsock, config) { | ||
(0, _classCallCheck3.default)(this, Registrar); | ||
this._connectors.set('twilsock', new TwilsockConnector({ productId, platform }, twilsock, config)); | ||
this._connectors.set('gcm', new ErsConnector({ productId, platform }, transport, config, 'gcm')); | ||
this._connectors.set('apn', new ErsConnector({ productId, platform }, transport, config, 'apn')); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (Registrar.__proto__ || (0, _getPrototypeOf2.default)(Registrar)).call(this)); | ||
this._connectors.get('twilsock') | ||
.on('transportReady', state => this.emit('transportReady', state)); | ||
(0, _defineProperties2.default)(_this, { | ||
_conf: { value: config }, | ||
_connectors: { value: new _map2.default() } | ||
}); | ||
EventEmitter.call(this); | ||
} | ||
var platform = (typeof navigator !== 'undefined' ? navigator.userAgent : 'web').substring(0, 128); | ||
inherits(Registrar, EventEmitter); | ||
_this._connectors.set('twilsock', new _twilsock2.default({ productId: productId, platform: platform }, twilsock, config)); | ||
_this._connectors.set('gcm', new _registrar2.default({ productId: productId, platform: platform }, transport, config, 'gcm')); | ||
_this._connectors.set('fcm', new _registrar2.default({ productId: productId, platform: platform }, transport, config, 'fcm')); | ||
_this._connectors.set('apn', new _registrar2.default({ productId: productId, platform: platform }, transport, config, 'apn')); | ||
/** | ||
* Sets notification ID. | ||
* If new URI is different from previous, it triggers updating of registration for given channel | ||
* | ||
* @param {string} uri The notification ID | ||
*/ | ||
Registrar.prototype.setNotificationId = function(channelType, notificationId) { | ||
this._connector(channelType).setNotificationId(notificationId); | ||
}; | ||
_this._connectors.get('twilsock').on('transportReady', function (state) { | ||
return _this.emit('transportReady', state); | ||
}); | ||
/** | ||
* Checks if subscription for given message and channel already exists | ||
*/ | ||
Registrar.prototype.hasSubscription = function(messageType, channelType) { | ||
this._connector(channelType).has(messageType); | ||
}; | ||
return _this; | ||
} | ||
/** | ||
* 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) { | ||
this._connector(channelType).subscribe(messageType); | ||
}; | ||
/** | ||
* Sets notification ID. | ||
* If new URI is different from previous, it triggers updating of registration for given channel | ||
* | ||
* @param {string} channelType channel type (apn|gcm|fcm|twilsock) | ||
* @param {string} notificationId The notification ID | ||
*/ | ||
/** | ||
* Remove subscription | ||
* @param {String} messageType Message type | ||
* @param {String} channelType Channel type (twilsock or gcm) | ||
* @public | ||
*/ | ||
Registrar.prototype.unsubscribe = function(messageType, channelType) { | ||
this._connector(channelType).unsubscribe(messageType); | ||
}; | ||
Registrar.prototype.updateToken = function() { | ||
this._connectors.forEach(connector => connector.updateToken()); | ||
}; | ||
(0, _createClass3.default)(Registrar, [{ | ||
key: 'setNotificationId', | ||
value: function setNotificationId(channelType, notificationId) { | ||
this._connector(channelType).setNotificationId(notificationId); | ||
} | ||
/** | ||
* @param {Strint} channelType Channel type | ||
* @throws {Error} Error with description | ||
* @private | ||
*/ | ||
Registrar.prototype._connector = function(type) { | ||
let connector = this._connectors.get(type); | ||
if (!connector) { | ||
throw new Error('Unknown channel type: ' + type); | ||
} | ||
return connector; | ||
}; | ||
/** | ||
* Checks if subscription for given message and channel already exists | ||
*/ | ||
Object.freeze(Registrar); | ||
}, { | ||
key: 'hasSubscription', | ||
value: function hasSubscription(messageType, channelType) { | ||
this._connector(channelType).has(messageType); | ||
} | ||
module.exports = Registrar; | ||
/** | ||
* Subscribe for given type of message | ||
* | ||
* @param {String} messageType Message type identifier | ||
* @param {String} channelType Channel type, can be 'twilsock', 'gcm' or 'fcm' | ||
* @public | ||
*/ | ||
}, { | ||
key: 'subscribe', | ||
value: function subscribe(messageType, channelType) { | ||
this._connector(channelType).subscribe(messageType); | ||
} | ||
/** | ||
* Remove subscription | ||
* @param {String} messageType Message type | ||
* @param {String} channelType Channel type (twilsock or gcm/fcm) | ||
* @public | ||
*/ | ||
}, { | ||
key: 'unsubscribe', | ||
value: function unsubscribe(messageType, channelType) { | ||
this._connector(channelType).unsubscribe(messageType); | ||
} | ||
}, { | ||
key: 'updateToken', | ||
value: function updateToken() { | ||
this._connectors.forEach(function (connector) { | ||
return connector.updateToken(); | ||
}); | ||
} | ||
/** | ||
* @param {String} type Channel type | ||
* @throws {Error} Error with description | ||
* @private | ||
*/ | ||
}, { | ||
key: '_connector', | ||
value: function _connector(type) { | ||
var connector = this._connectors.get(type); | ||
if (!connector) { | ||
throw new Error('Unknown channel type: ' + type); | ||
} | ||
return connector; | ||
} | ||
}]); | ||
return Registrar; | ||
}(_events2.default); | ||
exports.default = Registrar; | ||
(0, _freeze2.default)(Registrar); | ||
module.exports = exports['default']; |
'use strict'; | ||
const EventEmitter = require('events').EventEmitter; | ||
const inherits = require('util').inherits; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const uuid = require('uuid'); | ||
const log = require('loglevel'); | ||
var _freeze = require('babel-runtime/core-js/object/freeze'); | ||
const DEFAULT_TTL = 60 * 60 * 48; | ||
var _freeze2 = _interopRequireDefault(_freeze); | ||
var _set2 = require('babel-runtime/core-js/set'); | ||
var _set3 = _interopRequireDefault(_set2); | ||
var _defineProperties = require('babel-runtime/core-js/object/define-properties'); | ||
var _defineProperties2 = _interopRequireDefault(_defineProperties); | ||
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); | ||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); | ||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); | ||
var _inherits2 = require('babel-runtime/helpers/inherits'); | ||
var _inherits3 = _interopRequireDefault(_inherits2); | ||
var _uuid = require('uuid'); | ||
var _uuid2 = _interopRequireDefault(_uuid); | ||
var _logger = require('./logger'); | ||
var _logger2 = _interopRequireDefault(_logger); | ||
var _events = require('events'); | ||
var _events2 = _interopRequireDefault(_events); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var DEFAULT_TTL = 60 * 60 * 48; | ||
function toArray(_set) { | ||
let arr = []; | ||
_set.forEach(v => arr.push(v)); | ||
var arr = []; | ||
_set.forEach(function (v) { | ||
return arr.push(v); | ||
}); | ||
return arr; | ||
@@ -23,90 +69,138 @@ } | ||
*/ | ||
function TwilsockConnector(context, twilsock, config) { | ||
context.id = uuid.v4(); | ||
Object.defineProperties(this, { | ||
_twilsock: { value: twilsock }, | ||
_messageTypes: { value: new Set() }, | ||
config: { value: config }, | ||
context: { value: context } | ||
}); | ||
var TwilsockConnector = function (_EventEmitter) { | ||
(0, _inherits3.default)(TwilsockConnector, _EventEmitter); | ||
twilsock.on('stateChanged', state => { | ||
if (state !== 'connected') { | ||
this.emit('transportReady', false); | ||
function TwilsockConnector(context, twilsock, config) { | ||
(0, _classCallCheck3.default)(this, TwilsockConnector); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (TwilsockConnector.__proto__ || (0, _getPrototypeOf2.default)(TwilsockConnector)).call(this)); | ||
context.id = _uuid2.default.v4(); | ||
(0, _defineProperties2.default)(_this, { | ||
_twilsock: { value: twilsock }, | ||
_messageTypes: { value: new _set3.default() }, | ||
config: { value: config }, | ||
context: { value: context } | ||
}); | ||
twilsock.on('stateChanged', function (state) { | ||
if (state !== 'connected') { | ||
_this.emit('transportReady', false); | ||
} | ||
}); | ||
twilsock.on('registered', function (id) { | ||
if (context && id === context.id && twilsock.state === 'connected') { | ||
_this.emit('transportReady', true); | ||
} | ||
}); | ||
return _this; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
(0, _createClass3.default)(TwilsockConnector, [{ | ||
key: 'setNotificationId', | ||
value: function setNotificationId() { | ||
return false; | ||
} | ||
}); | ||
twilsock.on('registered', id => { | ||
if (context && id === context.id && twilsock.state === 'connected') { | ||
this.emit('transportReady', true); | ||
/** | ||
* @public | ||
*/ | ||
}, { | ||
key: 'updateToken', | ||
value: function updateToken() { | ||
this._twilsock.removeNotificationsContext(this.context.id); | ||
this.context.id = _uuid2.default.v4(); | ||
this._updateContext(); | ||
} | ||
}); | ||
EventEmitter.call(this); | ||
} | ||
inherits(TwilsockConnector, EventEmitter); | ||
/** | ||
* @public | ||
*/ | ||
TwilsockConnector.prototype.setNotificationId = function() { | ||
return false; | ||
}; | ||
}, { | ||
key: 'has', | ||
value: function has(messageType) { | ||
return this._messageTypes.has(messageType); | ||
} | ||
TwilsockConnector.prototype.updateToken = function() { | ||
this._twilsock.removeNotificationsContext(this.context.id); | ||
this.context.id = uuid.v4(); | ||
this._updateContext(); | ||
}; | ||
/** | ||
* @public | ||
*/ | ||
TwilsockConnector.prototype.has = function(messageType) { | ||
return this._messageTypes.has(messageType); | ||
}; | ||
}, { | ||
key: 'subscribe', | ||
value: function subscribe(messageType) { | ||
if (this._messageTypes.has(messageType)) { | ||
_logger2.default.trace('Message type already registered ', messageType); | ||
return false; | ||
} | ||
TwilsockConnector.prototype.subscribe = function(messageType) { | ||
if (this._messageTypes.has(messageType)) { | ||
log.trace('Message type already registered ', messageType); | ||
return false; | ||
} | ||
this._messageTypes.add(messageType); | ||
this._updateContext(); | ||
return true; | ||
} | ||
this._messageTypes.add(messageType); | ||
this._updateContext(); | ||
return true; | ||
}; | ||
/** | ||
* @public | ||
*/ | ||
TwilsockConnector.prototype.unsubscribe = function(messageType) { | ||
if (!this._messageTypes.has(messageType)) { | ||
return false; | ||
} | ||
}, { | ||
key: 'unsubscribe', | ||
value: function unsubscribe(messageType) { | ||
if (!this._messageTypes.has(messageType)) { | ||
return false; | ||
} | ||
this._messageTypes.delete(messageType); | ||
this._messageTypes.delete(messageType); | ||
if (this._messageTypes.size > 0) { | ||
this._updateContext(); | ||
} else { | ||
this._twilsock.removeNotificationsContext(this.context.id); | ||
} | ||
if (this._messageTypes.size > 0) { | ||
this._updateContext(); | ||
} else { | ||
this._twilsock.removeNotificationsContext(this.context.id); | ||
} | ||
return true; | ||
}; | ||
return true; | ||
} | ||
TwilsockConnector.prototype._updateContext = function() { | ||
let messageTypes = toArray(this._messageTypes); | ||
/** | ||
* @private | ||
*/ | ||
/* eslint-disable camelcase */ | ||
let context = { | ||
product_id: this.context.productId, | ||
notification_protocol_version: 4, | ||
endpoint_platform: this.context.platform, | ||
ttl: DEFAULT_TTL, | ||
token: this.config.token, | ||
message_types: messageTypes | ||
}; | ||
/* eslint-enable camelcase */ | ||
}, { | ||
key: '_updateContext', | ||
value: function _updateContext() { | ||
var messageTypes = toArray(this._messageTypes); | ||
this.emit('transportReady', false); | ||
this._twilsock.setNotificationsContext(this.context.id, context); | ||
}; | ||
/* eslint-disable camelcase */ | ||
var context = { | ||
product_id: this.context.productId, | ||
notification_protocol_version: 4, | ||
endpoint_platform: this.context.platform, | ||
ttl: DEFAULT_TTL, | ||
token: this.config.token, | ||
message_types: messageTypes | ||
}; | ||
/* eslint-enable camelcase */ | ||
this.emit('transportReady', false); | ||
this._twilsock.setNotificationsContext(this.context.id, context); | ||
} | ||
}]); | ||
return TwilsockConnector; | ||
}(_events2.default); | ||
Object.freeze(TwilsockConnector); | ||
exports.default = TwilsockConnector; | ||
module.exports = TwilsockConnector; | ||
(0, _freeze2.default)(TwilsockConnector); | ||
module.exports = exports['default']; |
{ | ||
"name": "twilio-notifications", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Client library for Twilio Notifications service", | ||
"main": "lib/client.js", | ||
"main": "lib/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/twilio/twilio-notifications.js" | ||
}, | ||
"scripts": { | ||
"test": "gulp unit-test" | ||
"test": "gulp unit-test", | ||
"prepublish": "node_modules/babel-cli/bin/babel.js src --out-dir lib" | ||
}, | ||
@@ -22,13 +27,29 @@ "author": "Twilio", | ||
"async": "^2.1.2", | ||
"babel-eslint": "^7.1.1", | ||
"babel-cli": "^6.14.0", | ||
"babel-eslint": "^7.0.0", | ||
"babel-plugin-add-module-exports": "^0.2.1", | ||
"babel-plugin-transform-object-assign": "^6.8.0", | ||
"babel-plugin-transform-runtime": "^6.15.0", | ||
"babel-preset-es2015": "^6.9.0", | ||
"babelify": "^7.3.0", | ||
"browserify": "^13.1.0", | ||
"chai": "^3.5.0", | ||
"chai-as-promised": "^6.0.0", | ||
"chai-spies": "^0.7.1", | ||
"cheerio": "^0.22.0", | ||
"event-to-promise": "^0.7.0", | ||
"gulp": "^3.9.1", | ||
"gulp-derequire": "^2.1.0", | ||
"gulp-eslint": "^3.0.1", | ||
"gulp-exit": "0.0.2", | ||
"gulp-istanbul": "^1.1.1", | ||
"gulp-insert": "^0.5.0", | ||
"gulp-istanbul": "^1.0.0", | ||
"gulp-mocha": "^3.0.1", | ||
"gulp-rename": "^1.2.2", | ||
"gulp-replace": "^0.5.4", | ||
"gulp-tap": "^0.1.3", | ||
"gulp-uglify": "^2.0.0", | ||
"gulp-util": "^3.0.7", | ||
"ink-docstrap": "^1.3.0", | ||
"isparta": "^4.0.0", | ||
"jsdoc": "^3.4.3", | ||
@@ -40,4 +61,7 @@ "proxyquire": "^1.7.10", | ||
"sinon-chai": "^2.8.0", | ||
"twilio": "^2.11.1" | ||
"jsonwebtoken": "^7.1.6", | ||
"vinyl-buffer": "^1.0.0", | ||
"vinyl-source-stream": "^1.1.0", | ||
"twilio": "^3.3.0-edge" | ||
} | ||
} |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 2 instances in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
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
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
1369998
47
25641
38
1
3
17
22