}
* @private
*/
}, {
key: "topic",
value: function topic(arg) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee11() {
var _this5 = this;
var _decompose4, id, mode, optimistic, topicFromInMemoryCache, topicDescriptor, topicRemovalHandler, syncTopic;
return _regenerator2.default.wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
_context11.next = 2;
return this.ensureReady();
case 2:
_decompose4 = decompose(arg), id = _decompose4.id, mode = _decompose4.mode, optimistic = _decompose4.optimistic;
topicFromInMemoryCache = this.getCached(id, synctopic_1.SyncTopic.type);
if (!topicFromInMemoryCache) {
_context11.next = 8;
break;
}
return _context11.abrupt("return", topicFromInMemoryCache);
case 8:
_context11.next = 10;
return this._getTopic(id, optimistic);
case 10:
topicDescriptor = _context11.sent;
if (topicDescriptor) {
_context11.next = 29;
break;
}
if (!(mode === 'open')) {
_context11.next = 16;
break;
}
throw new syncerror_1.default('Not found', 404);
case 16:
_context11.prev = 16;
_context11.next = 19;
return this._createTopic(id);
case 19:
topicDescriptor = _context11.sent;
_context11.next = 29;
break;
case 22:
_context11.prev = 22;
_context11.t0 = _context11["catch"](16);
if (!(_context11.t0.status === 409)) {
_context11.next = 28;
break;
}
return _context11.abrupt("return", this.topic(arg));
case 28:
throw _context11.t0;
case 29:
this.storeRootInSessionCache(synctopic_1.SyncTopic.type, id, topicDescriptor);
topicRemovalHandler = function topicRemovalHandler(type, sid, uniqueName) {
return _this5.removeFromCacheAndSession(type, sid, uniqueName);
};
syncTopic = new synctopic_1.SyncTopic(this.services, topicDescriptor, topicRemovalHandler);
syncTopic = this.entities.store(syncTopic);
return _context11.abrupt("return", subscribe(syncTopic));
case 34:
case "end":
return _context11.stop();
}
}
}, _callee11, this, [[16, 22]]);
}));
}
/**
* Gracefully shutdown the libray
* Currently it is not properly implemented and being used only in tests
* But should be made a part of public API
* @private
*/
}, {
key: "shutdown",
value: function shutdown() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee12() {
return _regenerator2.default.wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
_context12.next = 2;
return this.services.subscriptions.shutdown();
case 2:
_context12.next = 4;
return this.services.twilsock.disconnect();
case 4:
case "end":
return _context12.stop();
}
}
}, _callee12, this);
}));
}
/**
* Set new auth token
* @param {string} token New token to set
* @return {Promise}
* @public
*/
}, {
key: "updateToken",
value: function updateToken(fpaToken) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee13() {
var response;
return _regenerator2.default.wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
_context13.next = 2;
return this.services.emsClient.setToken(fpaToken);
case 2:
response = _context13.sent;
this.services.config.updateToken(response.token);
_context13.next = 6;
return _promise2.default.all([this.services.notifications.updateToken(fpaToken), this.services.twilsock.updateToken(fpaToken)]);
case 6:
this.fpaToken = fpaToken;
case 7:
case "end":
return _context13.stop();
}
}
}, _callee13, this);
}));
}
}, {
key: "connectionState",
get: function get() {
return this.services.notifications.connectionState;
}
}], [{
key: "version",
get: function get() {
return SDK_VERSION;
}
}]);
return SyncClient;
}(events_1.EventEmitter);
exports.SyncClient = SyncClient;
exports.Client = SyncClient;
exports.default = SyncClient;
/**
* Indicates current state of connection between the client and Sync service.
* Valid options are as follows:
*
'connecting' - client is offline and connection attempt is in process.
* 'connected' - client is online and ready.
* 'disconnecting' - client is going offline as disconnection is in process.
* 'disconnected' - client is offline and no connection attempt is in process.
* 'denied' - client connection is denied because of invalid JWT access token. User must refresh token in order to proceed.
* 'error' - client connection is in a permanent erroneous state. Client re-initialization is required.
* @typedef {String} Client#ConnectionState
*/
/**
* These options can be passed to Client constructor
* @typedef {Object} Client#ClientOptions
* @property {String} [logLevel='error'] - The level of logging to enable. Valid options
* (from strictest to broadest): ['silent', 'error', 'warn', 'info', 'debug', 'trace']
*/
/**
* Fired when connection state has been changed.
* @param {Client#ConnectionState} connectionState Contains current service connection state.
* @event Client#connectionStateChanged
*/
},{"../package.json":271,"./clientInfo":249,"./configuration":250,"./entitiesCache":251,"./logger":255,"./network":257,"./router":260,"./services/storage":261,"./subscriptions":262,"./syncdocument":264,"./syncerror":265,"./synclist":266,"./syncmap":267,"./topics/synctopic":268,"./utils":269,"./utils/deferred":270,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"babel-runtime/regenerator":57,"events":214,"twilio-ems-client":229,"twilio-notifications":242,"twilio-transport":273,"twilsock":276,"xxhashjs":288}],249:[function(_dereq_,module,exports){
"use strict";
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var platform = _dereq_("platform");
var ClientInfo = function ClientInfo(version) {
(0, _classCallCheck3.default)(this, ClientInfo);
this.sdk = 'js';
this.sdkVer = version;
this.os = platform.os.family;
this.osVer = platform.os.version;
this.pl = platform.name;
this.plVer = platform.version;
};
exports.ClientInfo = ClientInfo;
exports.default = ClientInfo;
},{"babel-runtime/helpers/classCallCheck":50,"platform":221}],250:[function(_dereq_,module,exports){
"use strict";
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var CDS_URI = 'https://cds.twilio.com';
var SUBSCRIPTIONS_PATH = '/v4/Subscriptions';
var MAPS_PATH = '/v3/Maps';
var LISTS_PATH = '/v3/Lists';
var DOCUMENTS_PATH = '/v3/Documents';
var TOPICS_PATH = '/v3/Topics';
function getWithDefault(container, key, defaultValue) {
if (container && typeof container[key] !== 'undefined') {
return container[key];
}
return defaultValue;
}
/**
* Settings container for Sync library
*/
var Configuration = function () {
/**
* @param {String} token - authentication token
*/
function Configuration(token, options) {
(0, _classCallCheck3.default)(this, Configuration);
options = options || {};
options = options.Sync || options.DataSync || {};
var baseUri = options.cdsUri || CDS_URI;
this._token = token;
this.settings = {
subscriptionsUri: baseUri + SUBSCRIPTIONS_PATH,
documentsUri: baseUri + DOCUMENTS_PATH,
listsUri: baseUri + LISTS_PATH,
mapsUri: baseUri + MAPS_PATH,
topicsUri: baseUri + TOPICS_PATH,
sessionStorageEnabled: getWithDefault(options, 'enableSessionStorage', true)
};
}
(0, _createClass3.default)(Configuration, [{
key: "updateToken",
value: function updateToken(token) {
this._token = token;
}
}, {
key: "token",
get: function get() {
return this._token;
}
}, {
key: "subscriptionsUri",
get: function get() {
return this.settings.subscriptionsUri;
}
}, {
key: "documentsUri",
get: function get() {
return this.settings.documentsUri;
}
}, {
key: "listsUri",
get: function get() {
return this.settings.listsUri;
}
}, {
key: "mapsUri",
get: function get() {
return this.settings.mapsUri;
}
}, {
key: "topicsUri",
get: function get() {
return this.settings.topicsUri;
}
}, {
key: "backoffConfig",
get: function get() {
return this.settings.backoffConfig || {};
}
}, {
key: "sessionStorageEnabled",
get: function get() {
return this.settings.sessionStorageEnabled;
}
}]);
return Configuration;
}();
exports.Configuration = Configuration;
},{"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],251:[function(_dereq_,module,exports){
"use strict";
var _map = _dereq_("babel-runtime/core-js/map");
var _map2 = _interopRequireDefault(_map);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Container for entities which are known by the client
* It's needed for deduplication when client obtain the same object several times
*/
var EntitiesCache = function () {
function EntitiesCache() {
(0, _classCallCheck3.default)(this, EntitiesCache);
this.names = new _map2.default();
this.entities = new _map2.default();
}
(0, _createClass3.default)(EntitiesCache, [{
key: "store",
value: function store(entity) {
var stored = this.entities.get(entity.sid);
if (stored) {
return stored;
}
this.entities.set(entity.sid, entity);
if (entity.uniqueName) {
this.names.set(entity.type + '::' + entity.uniqueName, entity.sid);
}
return entity;
}
}, {
key: "getResolved",
value: function getResolved(id, type) {
var resolvedSid = this.names.get(type + '::' + id);
return resolvedSid ? this.entities.get(resolvedSid) : null;
}
}, {
key: "get",
value: function get(id, type) {
return this.entities.get(id) || this.getResolved(id, type) || null;
}
}, {
key: "remove",
value: function remove(sid) {
var cached = this.entities.get(sid);
if (cached) {
this.entities.delete(sid);
if (cached.uniqueName) {
this.names.delete(cached.type + '::' + cached.uniqueName);
}
}
}
}]);
return EntitiesCache;
}();
exports.EntitiesCache = EntitiesCache;
},{"babel-runtime/core-js/map":35,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],252:[function(_dereq_,module,exports){
"use strict";
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = _dereq_("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = _dereq_("events");
var SyncEntity = function (_events_1$EventEmitte) {
(0, _inherits3.default)(SyncEntity, _events_1$EventEmitte);
function SyncEntity(services, removalHandler) {
(0, _classCallCheck3.default)(this, SyncEntity);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncEntity.__proto__ || (0, _getPrototypeOf2.default)(SyncEntity)).call(this));
_this.services = services;
_this.removalHandler = removalHandler;
_this.subscriptionState = 'none';
return _this;
}
(0, _createClass3.default)(SyncEntity, [{
key: "_advanceLastEventId",
value: function _advanceLastEventId(eventId, revision) {}
}, {
key: "reportFailure",
value: function reportFailure(err) {
if (err.status === 404) {
// assume that 404 means that entity has been removed while we were away
this.onRemoved(false);
} else {
this.emit('failure', err);
}
}
/**
* Subscribe to changes of data entity
* @private
*/
}, {
key: "_subscribe",
value: function _subscribe() {
this.services.router.subscribe(this.sid, this);
return this;
}
/**
* Unsubscribe from changes of current data entity
* @private
*/
}, {
key: "_unsubscribe",
value: function _unsubscribe() {
this.services.router.unsubscribe(this.sid, this);
return this;
}
}, {
key: "_setSubscriptionState",
value: function _setSubscriptionState(newState) {
this.subscriptionState = newState;
this.emit('_subscriptionStateChanged', newState);
}
/**
* @public
*/
}, {
key: "close",
value: function close() {
this._unsubscribe();
this.removalHandler(this.type, this.sid, this.uniqueName);
}
}]);
return SyncEntity;
}(events_1.EventEmitter);
exports.SyncEntity = SyncEntity;
exports.default = SyncEntity;
},{"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"events":214}],253:[function(_dereq_,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var client_1 = _dereq_("./client");
exports.SyncClient = client_1.SyncClient;
var syncdocument_1 = _dereq_("./syncdocument");
exports.SyncDocument = syncdocument_1.SyncDocument;
var synclist_1 = _dereq_("./synclist");
exports.SyncList = synclist_1.SyncList;
var listitem_1 = _dereq_("./listitem");
exports.SyncListItem = listitem_1.ListItem;
var syncmap_1 = _dereq_("./syncmap");
exports.SyncMap = syncmap_1.SyncMap;
var mapitem_1 = _dereq_("./mapitem");
exports.SyncMapItem = mapitem_1.MapItem;
exports.default = client_1.SyncClient;
module.exports = client_1.SyncClient;
module.exports.SyncClient = client_1.SyncClient;
},{"./client":248,"./listitem":254,"./mapitem":256,"./syncdocument":264,"./synclist":266,"./syncmap":267}],254:[function(_dereq_,module,exports){
"use strict";
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @class
* @classdesc Represents an individual element in a List collection.
* @alias ListItem
* @property {Number} index The index, within the containing List, of this item. This index is stable;
* even if lower-indexed Items are removed, this index will remain as is.
* @property {Object} value The contents of the item.
*/
var ListItem = function () {
/**
* @private
* @constructor
* @param {Object} data Item descriptor
* @param {Number} data.index Item identifier
* @param {String} data.uri Item URI
* @param {Object} data.value Item data
*/
function ListItem(data) {
(0, _classCallCheck3.default)(this, ListItem);
this.data = data;
}
(0, _createClass3.default)(ListItem, [{
key: "update",
/**
* Update item data
* @param {Number} EventId Update event id
* @param {String} Revision Updated item revision
* @param {Object} Value Updated item data
* @private
*/
value: function update(eventId, revision, value) {
this.data.lastEventId = eventId;
this.data.revision = revision;
this.data.value = value;
return this;
}
}, {
key: "uri",
get: function get() {
return this.data.uri;
}
}, {
key: "revision",
get: function get() {
return this.data.revision;
}
}, {
key: "lastEventId",
get: function get() {
return this.data.lastEventId;
}
}, {
key: "index",
get: function get() {
return this.data.index;
}
}, {
key: "value",
get: function get() {
return this.data.value;
}
}]);
return ListItem;
}();
exports.ListItem = ListItem;
exports.default = ListItem;
},{"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],255:[function(_dereq_,module,exports){
"use strict";
var _from = _dereq_("babel-runtime/core-js/array/from");
var _from2 = _interopRequireDefault(_from);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var log = _dereq_("loglevel");
function prepareLine(prefix, args) {
return [prefix].concat((0, _from2.default)(args));
}
exports.default = {
setLevel: function setLevel(level) {
log.setLevel(level);
},
trace: function trace() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
log.trace.apply(null, prepareLine('Sync T:', args));
},
debug: function debug() {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
log.debug.apply(null, prepareLine('Sync D:', args));
},
info: function info() {
for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
args[_key3] = arguments[_key3];
}
log.info.apply(null, prepareLine('Sync I:', args));
},
warn: function warn() {
for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
args[_key4] = arguments[_key4];
}
log.warn.apply(null, prepareLine('Sync W:', args));
},
error: function error() {
for (var _len5 = arguments.length, args = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
args[_key5] = arguments[_key5];
}
log.error.apply(null, prepareLine('Sync E:', args));
}
};
},{"babel-runtime/core-js/array/from":31,"loglevel":219}],256:[function(_dereq_,module,exports){
"use strict";
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @class
* @classdesc Represents an individual element in a List collection.
* @alias MapItem
* @property {String} key The identifier that maps to this item within the containing Map.
* @property {Object} value The contents of the item.
*/
var MapItem = function () {
/**
* @private
* @constructor
* @param {Object} data Item descriptor
* @param {String} data.key Item identifier
* @param {String} data.uri Item URI
* @param {Object} data.value Item data
*/
function MapItem(descriptor) {
(0, _classCallCheck3.default)(this, MapItem);
this.descriptor = descriptor;
}
(0, _createClass3.default)(MapItem, [{
key: "update",
/**
* Update item data
* @param {Number} EventId Update event id
* @param {String} Revision Updated item revision
* @param {Object} Value Updated item data
* @private
*/
value: function update(eventId, revision, value) {
this.descriptor.last_event_id = eventId;
this.descriptor.revision = revision;
this.descriptor.data = value;
return this;
}
}, {
key: "uri",
get: function get() {
return this.descriptor.url;
}
}, {
key: "revision",
get: function get() {
return this.descriptor.revision;
}
}, {
key: "lastEventId",
get: function get() {
return this.descriptor.last_event_id;
}
}, {
key: "key",
get: function get() {
return this.descriptor.key;
}
}, {
key: "value",
get: function get() {
return this.descriptor.data;
}
}]);
return MapItem;
}();
exports.MapItem = MapItem;
exports.default = MapItem;
},{"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],257:[function(_dereq_,module,exports){
"use strict";
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var _extends2 = _dereq_("babel-runtime/helpers/extends");
var _extends3 = _interopRequireDefault(_extends2);
var _stringify = _dereq_("babel-runtime/core-js/json/stringify");
var _stringify2 = _interopRequireDefault(_stringify);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var uuid = _dereq_("uuid");
var logger_1 = _dereq_("./logger");
var syncerror_1 = _dereq_("./syncerror");
var syncNetworkError_1 = _dereq_("./syncNetworkError");
var operation_retrier_1 = _dereq_("operation-retrier");
var twilio_transport_1 = _dereq_("twilio-transport");
var MINIMUM_RETRY_DELAY = 4000;
var MAXIMUM_RETRY_DELAY = 60000;
var MAXIMUM_ATTEMPTS_TIME = 90000;
var RETRY_DELAY_RANDOMNESS = 0.2;
function messageFromErrorBody(trasportError) {
if (trasportError.body) {
if (trasportError.body.message) {
return trasportError.body.message;
}
}
switch (trasportError.status) {
case 429:
return 'Throttled by server';
case 404:
return 'Not found from server';
default:
return 'Error from server';
}
}
function codeFromErrorBody(trasportError) {
if (trasportError.body) {
return trasportError.body.code;
}
return 0;
}
function mapTransportError(transportError) {
if (transportError.status === 409) {
return new syncNetworkError_1.SyncNetworkError(messageFromErrorBody(transportError), transportError.status, codeFromErrorBody(transportError), transportError.body);
} else if (transportError.status) {
return new syncerror_1.SyncError(messageFromErrorBody(transportError), transportError.status, codeFromErrorBody(transportError));
} else if (transportError instanceof twilio_transport_1.TwilsockUnavailableError) {
return transportError;
} else {
return new syncerror_1.SyncError(transportError.message, 0, 0);
}
}
/**
* @classdesc Incapsulates network operations to make it possible to add some optimization/caching strategies
*/
var Network = function () {
function Network(productId, clientInfo, config, transport) {
(0, _classCallCheck3.default)(this, Network);
this.productId = productId;
this.clientInfo = clientInfo;
this.config = config;
this.transport = transport;
}
(0, _createClass3.default)(Network, [{
key: "createHeaders",
value: function createHeaders() {
return {
'Content-Type': 'application/json',
'Twilio-Sync-Client-Info': (0, _stringify2.default)(this.clientInfo),
'Twilio-Request-Id': 'RQ' + uuid.v4().replace(/-/g, ''),
'X-Twilio-Product-Id': this.productId,
'X-Twilio-Token': this.config.token
};
}
}, {
key: "backoffConfig",
value: function backoffConfig() {
return (0, _extends3.default)({ min: MINIMUM_RETRY_DELAY,
max: MAXIMUM_RETRY_DELAY,
maxAttemptsTime: MAXIMUM_ATTEMPTS_TIME,
randomness: RETRY_DELAY_RANDOMNESS }, this.config.backoffConfig);
}
}, {
key: "executeWithRetry",
value: function executeWithRetry(request) {
var _this = this;
var retryWhenThrottled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
return new _promise2.default(function (resolve, reject) {
var codesToRetryOn = [502, 503, 504];
if (retryWhenThrottled) {
codesToRetryOn.push(429);
}
var retrier = new operation_retrier_1.default(_this.backoffConfig());
retrier.on('attempt', function () {
request().then(function (result) {
return retrier.succeeded(result);
}).catch(function (err) {
if (codesToRetryOn.indexOf(err.status) !== -1) {
var delayOverride = parseInt(err.headers ? err.headers['Retry-After'] : null);
retrier.failed(mapTransportError(err), isNaN(delayOverride) ? null : delayOverride * 1000);
} else if (err.message === 'Twilsock disconnected') {
// Ugly hack. We must make a proper exceptions for twilsock
retrier.failed(mapTransportError(err));
} else {
// Fatal error
retrier.removeAllListeners();
retrier.cancel();
reject(mapTransportError(err));
}
});
});
retrier.on('succeeded', function (result) {
resolve(result);
});
retrier.on('cancelled', function (err) {
return reject(mapTransportError(err));
});
retrier.on('failed', function (err) {
return reject(mapTransportError(err));
});
retrier.start();
});
}
/**
* Make a GET request by given URI
* @Returns Promise Result of successful get request
*/
}, {
key: "get",
value: function get(uri) {
var _this2 = this;
var headers = this.createHeaders();
logger_1.default.debug('GET', uri, 'ID:', headers['Twilio-Request-Id']);
return this.executeWithRetry(function () {
return _this2.transport.get(uri, headers);
}, true);
}
}, {
key: "post",
value: function post(uri, body, revision, twilsockOnly) {
var _this3 = this;
var headers = this.createHeaders();
if (typeof revision !== 'undefined' && revision !== null) {
headers['If-Match'] = revision;
}
logger_1.default.debug('POST', uri, 'ID:', headers['Twilio-Request-Id']);
return this.executeWithRetry(function () {
return _this3.transport.post(uri, headers, body, twilsockOnly);
}, false);
}
}, {
key: "put",
value: function put(uri, body, revision) {
var _this4 = this;
var headers = this.createHeaders();
if (typeof revision !== 'undefined' && revision !== null) {
headers['If-Match'] = revision;
}
logger_1.default.debug('PUT', uri, 'ID:', headers['Twilio-Request-Id']);
return this.executeWithRetry(function () {
return _this4.transport.put(uri, headers, body);
}, false);
}
}, {
key: "delete",
value: function _delete(uri) {
var _this5 = this;
var headers = this.createHeaders();
logger_1.default.debug('DELETE', uri, 'ID:', headers['Twilio-Request-Id']);
return this.executeWithRetry(function () {
return _this5.transport.delete(uri, headers);
}, false);
}
}]);
return Network;
}();
exports.Network = Network;
exports.default = Network;
},{"./logger":255,"./syncNetworkError":263,"./syncerror":265,"babel-runtime/core-js/json/stringify":34,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/extends":52,"operation-retrier":220,"twilio-transport":273,"uuid":283}],258:[function(_dereq_,module,exports){
"use strict";
var _regenerator = _dereq_("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
return new (P || (P = _promise2.default))(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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @class Paginator
* @classdesc Pagination helper class
*
* @property {Array} items Array of elements on current page
* @property {boolean} hasNextPage Indicates the existence of next page
* @property {boolean} hasPrevPage Indicates the existence of previous page
*/
var Paginator = function () {
/*
* @constructor
* @param {Array} items Array of element for current page
* @param {Object} params
* @private
*/
function Paginator(items, source, prevToken, nextToken) {
(0, _classCallCheck3.default)(this, Paginator);
this.prevToken = prevToken;
this.nextToken = nextToken;
this.items = items;
this.source = source;
}
(0, _createClass3.default)(Paginator, [{
key: "nextPage",
/**
* Request next page.
* Does not modify existing object
* @return {Promise}
*/
value: function nextPage() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (this.hasNextPage) {
_context.next = 2;
break;
}
throw new Error('No next page');
case 2:
return _context.abrupt("return", this.source(this.nextToken));
case 3:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
}
/**
* Request previous page.
* Does not modify existing object
* @return {Promise}
*/
}, {
key: "prevPage",
value: function prevPage() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee2() {
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (this.hasPrevPage) {
_context2.next = 2;
break;
}
throw new Error('No previous page');
case 2:
return _context2.abrupt("return", this.source(this.prevToken));
case 3:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
}
}, {
key: "hasNextPage",
get: function get() {
return !!this.nextToken;
}
}, {
key: "hasPrevPage",
get: function get() {
return !!this.prevToken;
}
}]);
return Paginator;
}();
exports.Paginator = Paginator;
exports.default = Paginator;
},{"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/regenerator":57}],259:[function(_dereq_,module,exports){
"use strict";
var _freeze = _dereq_("babel-runtime/core-js/object/freeze");
var _freeze2 = _interopRequireDefault(_freeze);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var RetryingQueue = function () {
function RetryingQueue() {
(0, _classCallCheck3.default)(this, RetryingQueue);
this.queue = new Array();
this.isActive = false;
}
(0, _createClass3.default)(RetryingQueue, [{
key: "wakeupQueue",
value: function wakeupQueue() {
var _this = this;
if (!this.isActive && this.queue.length > 0) {
this.isActive = true;
setTimeout(function () {
return _this.executeTask(_this.queue[0]);
}, 0);
}
}
}, {
key: "pickNext",
value: function pickNext() {
var _this2 = this;
this.queue.shift();
if (this.queue.length === 0) {
this.isActive = false;
return;
}
setTimeout(function () {
return _this2.executeTask(_this2.queue[0]);
}, 0);
}
}, {
key: "pickSame",
value: function pickSame(arg) {
var _this3 = this;
this.queue[0].arg = arg;
setTimeout(function () {
return _this3.executeTask(_this3.queue[0]);
}, 0);
}
}, {
key: "executeTask",
value: function executeTask(task) {
var _this4 = this;
task.task(task.context, task.arg).then(function (result) {
_this4.pickNext();
task.resolve(result);
}).catch(function (error) {
try {
if (task.handle) {
task.handle(error).then(function (result) {
return _this4.pickSame(result);
}).catch(task.reject);
} else {
throw error;
}
} catch (e) {
task.reject(error);
}
});
}
}, {
key: "add",
value: function add(task, context, arg, errorHandler) {
var _this5 = this;
return new _promise2.default(function (resolve, reject) {
_this5.queue.push({
task: task,
context: context,
arg: arg,
handle: errorHandler,
resolve: resolve,
reject: reject
});
_this5.wakeupQueue();
});
}
}]);
return RetryingQueue;
}();
exports.RetryingQueue = RetryingQueue;
(0, _freeze2.default)(RetryingQueue);
exports.default = RetryingQueue;
},{"babel-runtime/core-js/object/freeze":41,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],260:[function(_dereq_,module,exports){
"use strict";
var _regenerator = _dereq_("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
return new (P || (P = _promise2.default))(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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
var logger_1 = _dereq_("./logger");
var SYNC_DOCUMENT_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.document';
var SYNC_LIST_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.list';
var SYNC_MAP_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.map';
var SYNC_NOTIFICATION_TYPE = 'twilio.sync.event';
/**
* @class Router
* @classdesc Routes all incoming messages to the consumers
*/
var Router = function () {
function Router(params) {
var _this = this;
(0, _classCallCheck3.default)(this, Router);
this.config = params.config;
this.subscriptions = params.subscriptions;
this.notifications = params.notifications;
this.notifications.subscribe(SYNC_NOTIFICATION_TYPE);
this.notifications.subscribe(SYNC_DOCUMENT_NOTIFICATION_TYPE);
this.notifications.subscribe(SYNC_LIST_NOTIFICATION_TYPE);
this.notifications.subscribe(SYNC_MAP_NOTIFICATION_TYPE);
this.notifications.on('message', function (messageType, payload) {
return _this.onMessage(messageType, payload);
});
this.notifications.on('transportReady', function (isConnected) {
return _this.onConnectionStateChanged(isConnected);
});
}
/**
* Entry point for all incoming messages
* @param {String} type - Type of incoming message
* @param {Object} message - Message to route
*/
(0, _createClass3.default)(Router, [{
key: "onMessage",
value: function onMessage(type, message) {
logger_1.default.trace('Notification type:', type, 'content:', message);
switch (type) {
case SYNC_DOCUMENT_NOTIFICATION_TYPE:
case SYNC_LIST_NOTIFICATION_TYPE:
case SYNC_MAP_NOTIFICATION_TYPE:
this.subscriptions.acceptMessage(message, false);
break;
case SYNC_NOTIFICATION_TYPE:
this.subscriptions.acceptMessage(message, true);
break;
}
}
/**
* Subscribe for events
*/
}, {
key: "subscribe",
value: function subscribe(sid, entity) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return this.subscriptions.add(sid, entity);
case 2:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
}
/**
* Unsubscribe from events
*/
}, {
key: "unsubscribe",
value: function unsubscribe(sid, entity) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee2() {
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return this.subscriptions.remove(sid);
case 2:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
}
/**
* Handle transport establishing event
* If we have any subscriptions - we should check object for modifications
*/
}, {
key: "onConnectionStateChanged",
value: function onConnectionStateChanged(isConnected) {
this.subscriptions.onConnectionStateChanged(isConnected);
}
}]);
return Router;
}();
exports.Router = Router;
exports.default = Router;
},{"./logger":255,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/regenerator":57}],261:[function(_dereq_,module,exports){
"use strict";
var _extends2 = _dereq_("babel-runtime/helpers/extends");
var _extends3 = _interopRequireDefault(_extends2);
var _stringify = _dereq_("babel-runtime/core-js/json/stringify");
var _stringify2 = _interopRequireDefault(_stringify);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var SessionStorage = function () {
function SessionStorage(config, storage) {
(0, _classCallCheck3.default)(this, SessionStorage);
this.config = config;
this.storageId = null;
try {
this.storage = storage || sessionStorage;
} catch (e) {}
}
(0, _createClass3.default)(SessionStorage, [{
key: "storageKey",
value: function storageKey(type, key) {
return this.storageId + "::" + type + "::" + key;
}
}, {
key: "updateStorageId",
value: function updateStorageId(storageId) {
this.storageId = storageId;
}
}, {
key: "store",
value: function store(type, id, value) {
if (!this.isReady) {
return null;
}
return this._store(this.storageKey(type, id), value);
}
}, {
key: "read",
value: function read(type, id) {
if (!this.isReady) {
return null;
}
return this._read(this.storageKey(type, id));
}
}, {
key: "remove",
value: function remove(type, sid, uniqueName) {
if (!this.isReady) {
return null;
}
try {
this.storage.removeItem(this.storageKey(type, sid));
if (uniqueName) {
this.storage.removeItem(this.storageKey(type, uniqueName));
}
} catch (e) {}
}
}, {
key: "update",
value: function update(type, sid, uniqueName, patch) {
if (!this.isReady) {
return null;
}
// Currently cache may have root stored twice - by sid and by uniqueName
// Maybe need to create some index if needed
this._apply(this.storageKey(type, sid), patch);
if (uniqueName) {
this._apply(this.storageKey(type, uniqueName), patch);
}
}
}, {
key: "_store",
value: function _store(key, value) {
try {
this.storage.setItem(key, (0, _stringify2.default)(value));
} catch (e) {}
}
}, {
key: "_read",
value: function _read(key) {
try {
var storedData = this.storage.getItem(key);
if (storedData) {
return JSON.parse(storedData);
}
} catch (e) {}
return null;
}
}, {
key: "_apply",
value: function _apply(key, patch) {
var value = this._read(key);
if (!value) {
return false;
}
this._store(key, (0, _extends3.default)(value, patch));
}
}, {
key: "isReady",
get: function get() {
return this.config.sessionStorageEnabled && !!this.storageId;
}
}]);
return SessionStorage;
}();
exports.SessionStorage = SessionStorage;
},{"babel-runtime/core-js/json/stringify":34,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/extends":52}],262:[function(_dereq_,module,exports){
"use strict";
var _regenerator = _dereq_("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _slicedToArray2 = _dereq_("babel-runtime/helpers/slicedToArray");
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
var _getIterator2 = _dereq_("babel-runtime/core-js/get-iterator");
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _extends2 = _dereq_("babel-runtime/helpers/extends");
var _extends3 = _interopRequireDefault(_extends2);
var _map = _dereq_("babel-runtime/core-js/map");
var _map2 = _interopRequireDefault(_map);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
return new (P || (P = _promise2.default))(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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable key-spacing */
var Backoff = _dereq_("backoff");
var logger_1 = _dereq_("./logger");
var syncerror_1 = _dereq_("./syncerror");
var twilio_transport_1 = _dereq_("twilio-transport");
/**
* A data container used by the Subscriptions class to track subscribed entities' local
* representations and their state.
*/
var SubscribedEntity = function () {
function SubscribedEntity(entity) {
(0, _classCallCheck3.default)(this, SubscribedEntity);
this.localObject = entity;
this.pendingCorrelationId = null;
this.established = false;
this.retryCount = 0;
}
(0, _createClass3.default)(SubscribedEntity, [{
key: "update",
value: function update(event, isStrictlyOrderd) {
this.localObject._update(event, isStrictlyOrderd);
}
}, {
key: "reset",
value: function reset() {
this.pendingCorrelationId = null;
this.retryCount = 0;
this.established = false;
this.localObject._setSubscriptionState('none');
}
}, {
key: "markAsFailed",
value: function markAsFailed(message) {
this.rejectedWithError = message.error;
this.pendingCorrelationId = null;
this.localObject.reportFailure(new syncerror_1.SyncError("Failed to subscribe on service events: " + message.error.message, message.error.status, message.error.code));
}
}, {
key: "complete",
value: function complete(eventId) {
this.pendingCorrelationId = null;
this.established = true;
this.localObject._advanceLastEventId(eventId);
}
}, {
key: "sid",
get: function get() {
return this.localObject.sid;
}
}, {
key: "type",
get: function get() {
return this.localObject.type;
}
}, {
key: "lastEventId",
get: function get() {
return this.localObject.lastEventId;
}
}, {
key: "isInTransition",
get: function get() {
return this.pendingCorrelationId !== null;
}
}, {
key: "isEstablished",
get: function get() {
return this.established;
}
}]);
return SubscribedEntity;
}();
/**
* @class Subscriptions
* @classdesc A manager which, in batches of varying size, continuously persists the
* subscription intent of the caller to the Sync backend until it achieves a
* converged state.
*/
var Subscriptions = function () {
/**
* @constructor
* Prepares a new Subscriptions manager object with zero subscribed or persisted subscriptions.
*
* @param {object} config may include a key 'backoffConfig', wherein any of the parameters
* of Backoff.exponential (from npm 'backoff') are valid and will override the defaults.
*
* @param {Network} must be a viable running Sync Network object, useful for routing requests.
*/
function Subscriptions(services) {
var _this = this;
(0, _classCallCheck3.default)(this, Subscriptions);
this.isConnected = false;
this.maxBatchSize = 100;
// If the server includes a `ttl_in_s` attribute in the poke response, subscriptionTtlTimer is started for that duration
// such that when it fires, it repokes the entire sync set (i.e., emulates a reconnect). Every reconnect resets the timer.
// After the timer has fired, the first poke request includes a `reason: ttl` attribute in the body.
this.subscriptionTtlTimer = null;
this.pendingPokeReason = null;
this.services = services;
this.subscriptions = new _map2.default();
this.persisted = new _map2.default();
this.latestPokeResponseArrivalTimestampByCorrelationId = new _map2.default();
var defaultBackoffConfig = {
randomisationFactor: 0.2,
initialDelay: 100,
maxDelay: 2 * 60 * 1000
};
this.backoff = Backoff.exponential((0, _extends3.default)(defaultBackoffConfig, this.services.config.backoffConfig));
// This block is triggered by #_persist. Every request is executed in a series of (ideally 1)
// backoff 'ready' event, at which point a new subscription set is calculated.
this.backoff.on('ready', function () {
var _getSubscriptionUpdat = _this.getSubscriptionUpdateBatch(),
action = _getSubscriptionUpdat.action,
subscriptionRequests = _getSubscriptionUpdat.subscriptions;
if (action) {
_this.applyNewSubscriptionUpdateBatch(action, subscriptionRequests);
} else {
_this.backoff.reset();
logger_1.default.info('All subscriptions resolved.');
}
});
}
(0, _createClass3.default)(Subscriptions, [{
key: "getSubscriptionUpdateBatch",
value: function getSubscriptionUpdateBatch() {
function substract(these, those, ignoreCurrentOp, limit) {
var result = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator3.default)(these), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _step$value = (0, _slicedToArray3.default)(_step.value, 2),
thisKey = _step$value[0],
thisValue = _step$value[1];
var otherValue = those.get(thisKey);
if (!otherValue && (ignoreCurrentOp || !thisValue.isInTransition) && !thisValue.rejectedWithError) {
result.push(thisValue);
if (limit && result.length >= limit) {
break;
}
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return result;
}
var listToAdd = substract(this.subscriptions, this.persisted, false, this.maxBatchSize);
if (listToAdd.length > 0) {
return { action: 'establish', subscriptions: listToAdd };
}
var listToRemove = substract(this.persisted, this.subscriptions, true, this.maxBatchSize);
if (listToRemove.length > 0) {
return { action: 'cancel', subscriptions: listToRemove };
}
return { action: null, subscriptions: null };
}
}, {
key: "persist",
value: function persist() {
try {
this.backoff.backoff();
} catch (e) {} // eslint-disable-line no-empty
}
}, {
key: "applyNewSubscriptionUpdateBatch",
value: function applyNewSubscriptionUpdateBatch(action, requests) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
var _this2 = this;
var correlationId, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, subscribed, reason, response, newMaxBatchSize, subscriptionTtlInS, isNumeric, isValidTtl, estimatedDeliveryInMs, _isNumeric, isValidTimeout, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, attemptedSubscription;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (this.isConnected) {
_context.next = 4;
break;
}
logger_1.default.debug("Twilsock connection (required for subscription) not ready; waiting\u2026");
this.backoff.reset();
return _context.abrupt("return");
case 4:
// Keeping in mind that events may begin flowing _before_ we receive the response
requests = this.processLocalActions(action, requests);
correlationId = new Date().getTime();
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
_context.prev = 9;
for (_iterator2 = (0, _getIterator3.default)(requests); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
subscribed = _step2.value;
this.recordActionAttemptOn(subscribed, action, correlationId);
}
_context.next = 17;
break;
case 13:
_context.prev = 13;
_context.t0 = _context["catch"](9);
_didIteratorError2 = true;
_iteratorError2 = _context.t0;
case 17:
_context.prev = 17;
_context.prev = 18;
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
case 20:
_context.prev = 20;
if (!_didIteratorError2) {
_context.next = 23;
break;
}
throw _iteratorError2;
case 23:
return _context.finish(20);
case 24:
return _context.finish(17);
case 25:
reason = this.pendingPokeReason;
this.pendingPokeReason = null;
// Send this batch to the service
_context.prev = 27;
_context.next = 30;
return this.request(action, correlationId, reason, requests);
case 30:
response = _context.sent;
newMaxBatchSize = response.body.max_batch_size;
if (!isNaN(parseInt(newMaxBatchSize)) && isFinite(newMaxBatchSize) && newMaxBatchSize > 0) {
this.maxBatchSize = newMaxBatchSize;
}
if (!this.subscriptionTtlTimer) {
subscriptionTtlInS = response.body.ttl_in_s;
isNumeric = !isNaN(parseFloat(subscriptionTtlInS)) && isFinite(subscriptionTtlInS);
isValidTtl = isNumeric && subscriptionTtlInS > 0;
if (isValidTtl) {
this.subscriptionTtlTimer = setTimeout(function () {
return _this2.onSubscriptionTtlElapsed();
}, subscriptionTtlInS * 1000);
}
}
if (action === 'establish') {
estimatedDeliveryInMs = response.body.estimated_delivery_in_ms;
_isNumeric = !isNaN(parseFloat(estimatedDeliveryInMs)) && isFinite(estimatedDeliveryInMs);
isValidTimeout = _isNumeric && estimatedDeliveryInMs > 0;
if (isValidTimeout) {
setTimeout(function () {
return _this2.verifyPokeDelivery(correlationId, estimatedDeliveryInMs, requests);
}, estimatedDeliveryInMs);
} else {
logger_1.default.error("Invalid timeout: " + estimatedDeliveryInMs);
}
requests.filter(function (r) {
return r.pendingCorrelationId === correlationId;
}).forEach(function (r) {
return r.localObject._setSubscriptionState('response_in_flight');
});
}
this.backoff.reset();
_context.next = 60;
break;
case 38:
_context.prev = 38;
_context.t1 = _context["catch"](27);
_iteratorNormalCompletion3 = true;
_didIteratorError3 = false;
_iteratorError3 = undefined;
_context.prev = 43;
for (_iterator3 = (0, _getIterator3.default)(requests); !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
attemptedSubscription = _step3.value;
this.recordActionFailureOn(attemptedSubscription, action);
}
_context.next = 51;
break;
case 47:
_context.prev = 47;
_context.t2 = _context["catch"](43);
_didIteratorError3 = true;
_iteratorError3 = _context.t2;
case 51:
_context.prev = 51;
_context.prev = 52;
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
case 54:
_context.prev = 54;
if (!_didIteratorError3) {
_context.next = 57;
break;
}
throw _iteratorError3;
case 57:
return _context.finish(54);
case 58:
return _context.finish(51);
case 59:
if (_context.t1 instanceof twilio_transport_1.TwilsockUnavailableError) {
logger_1.default.debug("Twilsock connection (required for subscription) not ready (c:" + correlationId + "); waiting\u2026");
this.backoff.reset();
} else {
logger_1.default.debug("Failed an attempt to " + action + " subscriptions (c:" + correlationId + "); retrying", _context.t1);
this.persist();
}
case 60:
case "end":
return _context.stop();
}
}
}, _callee, this, [[9, 13, 17, 25], [18,, 20, 24], [27, 38], [43, 47, 51, 59], [52,, 54, 58]]);
}));
}
}, {
key: "verifyPokeDelivery",
value: function verifyPokeDelivery(correlationId, estimatedDeliveryInMs, requests) {
var _this3 = this;
var lastReceived = this.latestPokeResponseArrivalTimestampByCorrelationId.get(correlationId);
var silencePeriod = lastReceived ? new Date().getTime() - lastReceived : estimatedDeliveryInMs;
if (silencePeriod >= estimatedDeliveryInMs) {
// If we haven't received _any_ responses from that poke request for the duration of estimated_delivery_in_ms, poke again
requests.filter(function (r) {
return r.pendingCorrelationId === correlationId;
}).forEach(function (r) {
r.pendingCorrelationId = null;
r.retryCount++;
_this3.persisted.delete(r.sid);
});
this.persist();
this.latestPokeResponseArrivalTimestampByCorrelationId.delete(correlationId);
} else {
// Otherwise, the poke responses are probably in transit and we should wait for them
var timeoutExtension = estimatedDeliveryInMs - silencePeriod;
setTimeout(function () {
return _this3.verifyPokeDelivery(correlationId, estimatedDeliveryInMs, requests);
}, timeoutExtension);
}
}
}, {
key: "processLocalActions",
value: function processLocalActions(action, requests) {
if (action === 'cancel') {
return requests.filter(function (request) {
return !request.rejectedWithError;
});
}
return requests;
}
}, {
key: "recordActionAttemptOn",
value: function recordActionAttemptOn(attemptedSubscription, action, correlationId) {
attemptedSubscription.localObject._setSubscriptionState('request_in_flight');
if (action === 'establish') {
this.persisted.set(attemptedSubscription.sid, attemptedSubscription);
attemptedSubscription.pendingCorrelationId = correlationId;
} else {
var persistedSubscription = this.persisted.get(attemptedSubscription.sid);
if (persistedSubscription) {
persistedSubscription.pendingCorrelationId = correlationId;
}
}
}
}, {
key: "recordActionFailureOn",
value: function recordActionFailureOn(attemptedSubscription, action) {
attemptedSubscription.localObject._setSubscriptionState('none');
attemptedSubscription.pendingCorrelationId = null;
if (action === 'establish') {
this.persisted.delete(attemptedSubscription.sid);
}
}
}, {
key: "request",
value: function request(action, correlationId, reason, objects) {
var requests = objects.map(function (object) {
return {
object_sid: object.sid,
object_type: object.type,
last_event_id: action === 'establish' ? object.lastEventId : undefined // eslint-disable-line no-undefined, camelcase
};
});
var retriedRequests = objects.filter(function (a) {
return a.retryCount > 0;
}).length;
logger_1.default.debug("Attempting '" + action + "' request (c:" + correlationId + "):", requests);
/* eslint-disable camelcase */
var requestBody = {
event_protocol_version: 3,
action: action,
correlation_id: correlationId,
retried_requests: retriedRequests,
ttl_in_s: -1,
requests: requests
};
if (reason === 'ttl') {
requestBody.reason = reason;
}
/* eslint-enable camelcase */
return this.services.network.post(this.services.config.subscriptionsUri, requestBody, null, true);
}
/**
* Establishes intent to be subscribed to this entity. That subscription will be effected
* asynchronously.
* If subscription to the given sid already exists, it will be overwritten.
*
* @param {string} sid should be a well-formed SID, uniquely identifying a single instance of a Sync entity.
* @param {object} entity should represent the (singular) local representation of this entity.
* Incoming events and modifications to the entity will be directed at the _update() function
* of this provided reference.
*
* @return undefined
*/
}, {
key: "add",
value: function add(sid, entity) {
logger_1.default.debug("Establishing intent to subscribe to " + sid);
var existingSubscription = this.subscriptions.get(sid);
if (existingSubscription && existingSubscription.lastEventId === entity.lastEventId) {
// If last event id is the same as before - we're fine
return;
}
this.persisted.delete(sid);
this.subscriptions.set(sid, new SubscribedEntity(entity));
this.persist();
}
/**
* Establishes the caller's intent to no longer be subscribed to this entity. Following this
* call, no further events shall be routed to the local representation of the entity, even
* though a server-side subscription may take more time to actually terminate.
*
* @param {string} sid should be any well-formed SID, uniquely identifying a Sync entity.
* This call only has meaningful effect if that entity is subscribed at the
* time of call. Otherwise does nothing.
*
* @return undefined
*/
}, {
key: "remove",
value: function remove(sid) {
logger_1.default.debug("Establishing intent to unsubscribe from " + sid);
var removed = this.subscriptions.delete(sid);
if (removed) {
this.persist();
}
}
/**
* The point of ingestion for remote incoming messages (e.g. new data was written to a map
* to which we are subscribed).
*
* @param {object} message is the full, unaltered body of the incoming notification.
*
* @return undefined
*/
}, {
key: "acceptMessage",
value: function acceptMessage(message, isStrictlyOrdered) {
logger_1.default.trace('Subscriptions received', message);
if (message.correlation_id) {
this.latestPokeResponseArrivalTimestampByCorrelationId.set(message.correlation_id, new Date().getTime());
}
switch (message.event_type) {
case 'subscription_established':
this.applySubscriptionEstablishedMessage(message.event, message.correlation_id);
break;
case 'subscription_canceled':
this.applySubscriptionCancelledMessage(message.event, message.correlation_id);
break;
case 'subscription_failed':
this.applySubscriptionFailedMessage(message.event, message.correlation_id);
break;
case (message.event_type.match(/^(?:map|list|document|topic)_/) || {}).input:
{
var typedSid = function typedSid() {
if (message.event_type.match(/^map_/)) {
return message.event.map_sid;
} else if (message.event_type.match(/^list_/)) {
return message.event.list_sid;
} else if (message.event_type.match(/^document_/)) {
return message.event.document_sid;
} else if (message.event_type.match(/^topic_/)) {
return message.event.topic_sid;
} else {
return undefined;
}
};
;
this.applyEventToSubscribedEntity(typedSid(), message, isStrictlyOrdered);
}
break;
default:
logger_1.default.debug("Dropping unknown message type " + message.event_type);
break;
}
}
}, {
key: "applySubscriptionEstablishedMessage",
value: function applySubscriptionEstablishedMessage(message, correlationId) {
var sid = message.object_sid;
var subscriptionIntent = this.persisted.get(message.object_sid);
if (subscriptionIntent && subscriptionIntent.pendingCorrelationId === correlationId) {
if (message.replay_status === 'interrupted') {
logger_1.default.debug("Event Replay for subscription to " + sid + " (c:" + correlationId + ") interrupted; continuing eagerly.");
subscriptionIntent.pendingCorrelationId = null;
this.persisted.delete(subscriptionIntent.sid);
this.backoff.reset();
} else if (message.replay_status === 'completed') {
logger_1.default.debug("Event Replay for subscription to " + sid + " (c:" + correlationId + ") completed. Subscription is ready.");
subscriptionIntent.complete(message.last_event_id);
this.persisted.set(message.object_sid, subscriptionIntent);
subscriptionIntent.localObject._setSubscriptionState('established');
this.backoff.reset();
}
} else {
logger_1.default.debug("Late message for " + message.object_sid + " (c:" + correlationId + ") dropped.");
}
this.persist();
}
}, {
key: "applySubscriptionCancelledMessage",
value: function applySubscriptionCancelledMessage(message, correlationId) {
var persistedSubscription = this.persisted.get(message.object_sid);
if (persistedSubscription && persistedSubscription.pendingCorrelationId === correlationId) {
persistedSubscription.pendingCorrelationId = null;
persistedSubscription.localObject._setSubscriptionState('none');
this.persisted.delete(message.object_sid);
} else {
logger_1.default.debug("Late message for " + message.object_sid + " (c:" + correlationId + ") dropped.");
}
this.persist();
}
}, {
key: "applySubscriptionFailedMessage",
value: function applySubscriptionFailedMessage(message, correlationId) {
var sid = message.object_sid;
var subscriptionIntent = this.subscriptions.get(sid);
var subscription = this.persisted.get(sid);
if (subscriptionIntent && subscription) {
if (subscription.pendingCorrelationId === correlationId) {
logger_1.default.error("Failed to subscribe on " + subscription.sid, message.error);
subscription.markAsFailed(message);
subscription.localObject._setSubscriptionState('none');
}
} else if (!subscriptionIntent && subscription) {
this.persisted.delete(sid);
subscription.localObject._setSubscriptionState('none');
}
this.persist();
}
}, {
key: "applyEventToSubscribedEntity",
value: function applyEventToSubscribedEntity(sid, message, isStrictlyOrdered) {
var _this4 = this;
if (!sid) {
return;
}
// Looking for subscription descriptor to check if poke has been completed
isStrictlyOrdered = isStrictlyOrdered || function () {
var subscription = _this4.persisted.get(sid);
return subscription && subscription.isEstablished;
}();
// Still searching for subscriptionIntents. User could remove subscription already
var subscriptionIntent = this.subscriptions.get(sid);
if (subscriptionIntent) {
message.event.type = message.event_type;
subscriptionIntent.update(message.event, isStrictlyOrdered);
} else {
logger_1.default.debug("Message dropped for SID '" + sid + "', for which there is no subscription.");
}
}
}, {
key: "onConnectionStateChanged",
value: function onConnectionStateChanged(isConnected) {
this.isConnected = isConnected;
if (isConnected) {
this.poke('reconnect');
}
}
}, {
key: "onSubscriptionTtlElapsed",
value: function onSubscriptionTtlElapsed() {
if (this.isConnected) {
this.poke('ttl');
}
}
/**
* Prompts a playback of any missed changes made to any subscribed object. This method
* should be invoked whenever the connectivity layer has experienced cross-cutting
* delivery failures that would affect the entire local sync set. Any tangible result
* of this operation will result in calls to the _update() function of subscribed
* Sync entities.
*/
}, {
key: "poke",
value: function poke(reason) {
logger_1.default.info("Triggering event replay for all subscriptions, reason=" + reason);
this.pendingPokeReason = reason;
if (this.subscriptionTtlTimer) {
clearTimeout(this.subscriptionTtlTimer);
this.subscriptionTtlTimer = null;
}
var failedSubscriptions = [];
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = (0, _getIterator3.default)(this.persisted.values()), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var it = _step4.value;
it.reset();
if (it.rejectedWithError) {
failedSubscriptions.push(it);
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
this.persisted.clear();
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = (0, _getIterator3.default)(failedSubscriptions), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var _it = _step5.value;
this.persisted.set(_it.sid, _it);
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
this.persist();
}
/**
* Stops all communication, clears any subscription intent, and returns.
*/
}, {
key: "shutdown",
value: function shutdown() {
this.backoff.reset();
this.subscriptions.clear();
}
}]);
return Subscriptions;
}();
exports.Subscriptions = Subscriptions;
exports.default = Subscriptions;
},{"./logger":255,"./syncerror":265,"babel-runtime/core-js/get-iterator":32,"babel-runtime/core-js/map":35,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/extends":52,"babel-runtime/helpers/slicedToArray":55,"babel-runtime/regenerator":57,"backoff":58,"twilio-transport":273}],263:[function(_dereq_,module,exports){
"use strict";
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = _dereq_("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var syncerror_1 = _dereq_("./syncerror");
var SyncNetworkError = function (_syncerror_1$SyncErro) {
(0, _inherits3.default)(SyncNetworkError, _syncerror_1$SyncErro);
function SyncNetworkError(message) {
var status = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var code = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var body = arguments[3];
(0, _classCallCheck3.default)(this, SyncNetworkError);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncNetworkError.__proto__ || (0, _getPrototypeOf2.default)(SyncNetworkError)).call(this, message, status, code));
_this.body = body;
return _this;
}
return SyncNetworkError;
}(syncerror_1.SyncError);
exports.SyncNetworkError = SyncNetworkError;
exports.default = SyncNetworkError;
},{"./syncerror":265,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54}],264:[function(_dereq_,module,exports){
"use strict";
var _extends2 = _dereq_("babel-runtime/helpers/extends");
var _extends3 = _interopRequireDefault(_extends2);
var _regenerator = _dereq_("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = _dereq_("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
return new (P || (P = _promise2.default))(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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
var logger_1 = _dereq_("./logger");
var entity_1 = _dereq_("./entity");
var rfc6902_1 = _dereq_("rfc6902");
var retryingqueue_1 = _dereq_("./retryingqueue");
var utils_1 = _dereq_("./utils");
/**
* @class
* @alias Document
* @classdesc Represents a Sync Document, the contents of which is a single JSON object.
* @property {String} sid The immutable identifier of this document, assigned by the system.
* @property {String} [uniqueName=null] An optional immutable identifier that may be assigned by the programmer
* to this document during creation. Globally unique among other Documents.
* @property {Object} value The contents of this document.
*
* @fires Document#removed
* @fires Document#removedRemotely
* @fires Document#updated
* @fires Document#updatedRemotely
*/
var SyncDocument = function (_entity_1$SyncEntity) {
(0, _inherits3.default)(SyncDocument, _entity_1$SyncEntity);
/**
* @private
*/
function SyncDocument(services, descriptor, removalHandler) {
(0, _classCallCheck3.default)(this, SyncDocument);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncDocument.__proto__ || (0, _getPrototypeOf2.default)(SyncDocument)).call(this, services, removalHandler));
_this.actionQueue = new retryingqueue_1.RetryingQueue();
_this.descriptor = descriptor;
_this.descriptor.data = _this.descriptor.data || {};
return _this;
}
// private props
(0, _createClass3.default)(SyncDocument, [{
key: "_update",
/**
* Update data entity with new data
* @private
*/
value: function _update(update) {
switch (update.type) {
case 'document_updated':
if (update.id > this.lastEventId) {
var originalData = this.descriptor.data;
this.descriptor.last_event_id = update.id;
this.descriptor.revision = update.document_revision;
this.descriptor.data = update.document_data;
this.traverse(originalData, update.document_data, false);
this.emit('updated', update.document_data, false);
this.emit('updatedRemotely', update.document_data);
this.services.storage.update(this.type, this.sid, this.uniqueName, { last_event_id: update.id, revision: update.document_revision, data: update.document_data });
}
break;
case 'document_removed':
this.onRemoved(false);
break;
}
}
/**
* Calculate diff between old and new data
* @private
*/
}, {
key: "traverse",
value: function traverse(originalData, updatedData, isLocalEvent) {
var _this2 = this;
var diff = rfc6902_1.createPatch(originalData, updatedData);
diff.forEach(function (row) {
if (row.op === 'add') {
_this2.emit('keyAdded', row.path, row.value, isLocalEvent);
if (!isLocalEvent) {
_this2.emit('keyAddedRemotely', row.path, row.value);
}
} else if (row.op === 'replace') {
_this2.emit('keyUpdated', row.path, row.value, isLocalEvent);
if (!isLocalEvent) {
_this2.emit('keyUpdatedRemotely', row.path, row.value);
}
} else if (row.op === 'remove') {
_this2.emit('keyRemoved', row.path, isLocalEvent);
if (!isLocalEvent) {
_this2.emit('keyRemovedRemotely', row.path);
}
}
});
}
/**
* @returns {Object} Internal data of entity
* For now use a 'value' property instead
* @private
*/
}, {
key: "get",
value: function get(path) {
// return !path ? this.value : this.value(path);
return this.value;
}
/**
* Assign new contents to this document.
* @param {Object} value The new contents to assign.
* @param {Boolean} [conditional=false] Determines whether to detect remote modifications that would race
* with this new value.
* @returns {Promise} A promise describing the outcome of the set.
* Among common network failures and incorrect permissions, this promise will be rejected if value was
* remotely modified and the `conditional` flag was set.
* @public
*/
}, {
key: "set",
value: function set(value, conditional) {
return this._actualSet(value, conditional ? function () {
throw new Error('Revision mismatch');
} : null);
}
/**
* @private
*/
}, {
key: "_actualSet",
value: function _actualSet(data, conflictResolver) {
var _this3 = this;
var resolver = void 0;
var arg = { data: data,
revision: conflictResolver ? this.revision : undefined };
if (conflictResolver) {
resolver = function resolver(err) {
return __awaiter(_this3, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (!(err.status === 412)) {
_context.next = 4;
break;
}
_context.next = 3;
return this.softSync();
case 3:
return _context.abrupt("return", { revision: this.revision,
data: conflictResolver(utils_1.deepClone(this.value)) });
case 4:
throw err;
case 5:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
};
}
return this.actionQueue.add(this._set.bind(this), this.uri, arg, resolver).then(function (result) {
if (result.last_event_id > _this3.descriptor.last_event_id) {
// Ignore returned value if we already got a newer one
_this3.descriptor.revision = result.revision;
_this3.descriptor.data = result.data;
_this3.descriptor.last_event_id = result.last_event_id;
_this3.services.storage.update(_this3.type, _this3.sid, _this3.uniqueName, { last_event_id: result.last_event_id, revision: result.revision, data: result.data });
}
_this3.emit('updated', _this3.value, true);
return _this3.value;
});
}
/**
* Schedules a modification to this document that will apply a mutation function.
* @param {Document~Mutator} mutator A function that outputs a new value based on the existing value.
* May be called multiple times, particularly if this Document is modified concurrently by remote code.
* If the mutation ultimately succeeds, the Document will have made the particular transition described
* by this function.
* @return {Promise}
* @public
*/
}, {
key: "mutate",
value: function mutate(mutator) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee2() {
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
return _context2.abrupt("return", this._actualSet(mutator(utils_1.deepClone(this.value)), mutator));
case 1:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
}
/**
* Modify a document by appending new fields (or by overwriting existing ones) with the values from the provided Object.
* @param {Object} obj Specifies the particular (top-level) attributes that will receive new values.
* @return {Promise} A promise resolving to the modified item in its new state.
* @public
*/
}, {
key: "update",
value: function update(obj) {
return this.mutate(function (remote) {
return (0, _extends3.default)(remote, obj);
});
}
}, {
key: "_set",
value: function _set(context, param) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee3() {
var response;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return this.services.network.post(this.uri, { data: param.data }, param.revision);
case 2:
response = _context3.sent;
return _context3.abrupt("return", { revision: response.body.revision, data: param.data, last_event_id: response.body.last_event_id });
case 4:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
}
/**
* Get new data from server
* @private
*/
}, {
key: "softSync",
value: function softSync() {
var _this4 = this;
return this.services.network.get(this.uri).then(function (response) {
_this4._update({ type: 'document_updated',
id: response.body.last_event_id,
document_revision: response.body.revision,
document_data: response.body.data }); // eslint-disable-line camelcase
return _this4;
}).catch(function (err) {
if (err.status === 404) {
_this4.onRemoved(false);
} else {
logger_1.default.error("Can't get updates for " + _this4.sid + ":", err);
}
});
}
/**
* Get value by given path
* @param {string} path JSON path
* @private
*/
/*
_value(path) {
let result;
try {
let pathArr = path.replace(/^\/|\/$/gm, '').split('/');
let obj = this.data;
pathArr.forEach((el) => { obj = obj[el]; });
result = obj;
} catch (e) {
log.warn('Failed to get value:', e);
}
return result;
}
*/
}, {
key: "onRemoved",
value: function onRemoved(locally) {
this._unsubscribe();
this.removalHandler(this.type, this.sid, this.uniqueName);
// Should also do some cleanup here
this.emit('removed', locally);
if (!locally) {
this.emit('removedRemotely');
}
}
/**
* Delete a document
* @return {Promise} A promise which resolves if (and only if) the document is ultimately deleted.
* @public
*/
}, {
key: "removeDocument",
value: function removeDocument() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee4() {
return _regenerator2.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return this.services.network.delete(this.uri);
case 2:
this.onRemoved(true);
case 3:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
}
}, {
key: "uri",
get: function get() {
return this.descriptor.url;
}
}, {
key: "revision",
get: function get() {
return this.descriptor.revision;
}
}, {
key: "lastEventId",
get: function get() {
return this.descriptor.last_event_id;
}
}, {
key: "type",
get: function get() {
return 'document';
}
// public props, documented along with class description
}, {
key: "sid",
get: function get() {
return this.descriptor.sid;
}
}, {
key: "value",
get: function get() {
return this.descriptor.data;
}
}, {
key: "uniqueName",
get: function get() {
return this.descriptor.unique_name || null;
}
}], [{
key: "type",
get: function get() {
return 'document';
}
}]);
return SyncDocument;
}(entity_1.SyncEntity);
exports.SyncDocument = SyncDocument;
exports.default = SyncDocument;
/**
* Applies a transformation to the document value.
* @callback Document~Mutator
* @param {Object} data The current value of the item in the cloud.
* @return {Object} The desired new value for the item.
*/
/**
* Fired when the document is removed, whether the remover was local or remote.
* @event Document#removed
* @param {Boolean} - 'true' if the item was removed by local code, 'false' otherwise
*/
/**
* Fired when the document is removed by remote code.
* @event Document#removedRemotely
*/
/**
* Fired when the document's contents have changed, whether the updater was local or remote.
* @event Document#updated
* @param {Object} - A snapshot of the document's new contents.
* @param {Boolean} - Equals 'true' if item was removed by local actor, 'false' otherwise
*/
/**
* Fired when a document's contents were changed by remote code.
* @event Document#updatedRemotely
* @param {Object} - A snapshot of the document's new contents.
*/
},{"./entity":252,"./logger":255,"./retryingqueue":259,"./utils":269,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/extends":52,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"babel-runtime/regenerator":57,"rfc6902":228}],265:[function(_dereq_,module,exports){
"use strict";
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = _dereq_("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Generic SyncLibrary error class
*/
var SyncError = function (_Error) {
(0, _inherits3.default)(SyncError, _Error);
function SyncError(message) {
var status = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var code = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
(0, _classCallCheck3.default)(this, SyncError);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncError.__proto__ || (0, _getPrototypeOf2.default)(SyncError)).call(this));
_this.name = _this.constructor.name;
_this.message = message;
_this.status = status;
_this.code = code;
return _this;
}
return SyncError;
}(Error);
exports.SyncError = SyncError;
exports.default = SyncError;
},{"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54}],266:[function(_dereq_,module,exports){
"use strict";
var _extends2 = _dereq_("babel-runtime/helpers/extends");
var _extends3 = _interopRequireDefault(_extends2);
var _regenerator = _dereq_("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = _dereq_("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
return new (P || (P = _promise2.default))(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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
var utils_1 = _dereq_("./utils");
var logger_1 = _dereq_("./logger");
var entity_1 = _dereq_("./entity");
var retryingqueue_1 = _dereq_("./retryingqueue");
var listitem_1 = _dereq_("./listitem");
var paginator_1 = _dereq_("./paginator");
var cache_1 = _dereq_("./cache");
/**
* @class
* @alias List
* @classdesc Represents a Sync List, which stores an ordered list of values.
* @property {String} sid - List unique id, immutable identifier assigned by the system
* @property {String} [uniqueName=null] - List unique name, immutable identifier that can be assigned to list during creation
*
* @fires List#collectionRemoved
* @fires List#collectionRemovedRemotely
* @fires List#itemAdded
* @fires List#itemAddedRemotely
* @fires List#itemRemoved
* @fires List#itemRemovedRemotely
* @fires List#itemUpdated
* @fires List#itemUpdatedRemotely
*/
var SyncList = function (_entity_1$SyncEntity) {
(0, _inherits3.default)(SyncList, _entity_1$SyncEntity);
/**
* @private
*/
function SyncList(services, descriptor, removalHandler) {
(0, _classCallCheck3.default)(this, SyncList);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncList.__proto__ || (0, _getPrototypeOf2.default)(SyncList)).call(this, services, removalHandler));
_this.actionQueue = new retryingqueue_1.RetryingQueue();
_this.cache = new cache_1.Cache();
_this.descriptor = descriptor;
return _this;
}
// private props
(0, _createClass3.default)(SyncList, [{
key: "__set",
value: function __set(location, param) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
var response;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return this.services.network.post(location, { data: param.data }, param.revision);
case 2:
response = _context.sent;
response.body.data = param.data;
return _context.abrupt("return", response.body);
case 5:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
}
/**
* Add a new item to the list.
* @param {Object} value Value to be added
* @returns {Promise} A newly added item.
* @public
*/
}, {
key: "push",
value: function push(value) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee2() {
var response, index, item;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return this.services.network.post(this.links.items, { data: value });
case 2:
response = _context2.sent;
index = Number(response.body.index);
item = this.cache.store(index, new listitem_1.ListItem({ index: index,
revision: response.body.revision,
lastEventId: response.body.last_event_id,
uri: response.body.url,
value: value }), response.body.last_event_id);
this.emit('itemAdded', item, true);
return _context2.abrupt("return", item);
case 7:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
}
/**
* Assign new value to an existing item, given its index.
* @param {Number} index Index of an item to be updated
* @param {Object} value New value to be assigned to an item
* @returns {Promise} A promise with updated item containing latest known value.
* A promise will be rejected if value was remotely modified.
* @public
*/
}, {
key: "set",
value: function set(index, value) {
return this._actualSet(index, value);
}
/**
* @private
*/
}, {
key: "_actualSet",
value: function _actualSet(index, value, resolver) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee4() {
var _this2 = this;
var item, updatedItemDescriptor, _resolver;
return _regenerator2.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return this.get(index);
case 2:
item = _context4.sent;
updatedItemDescriptor = void 0;
if (resolver) {
_context4.next = 10;
break;
}
_context4.next = 7;
return this.__set(item.uri, { data: value, revision: undefined });
case 7:
updatedItemDescriptor = _context4.sent;
_context4.next = 14;
break;
case 10:
_resolver = function _resolver(err) {
return __awaiter(_this2, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee3() {
var refreshedItem;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
if (!(err.status === 412)) {
_context3.next = 5;
break;
}
_context3.next = 3;
return this._get(item.index);
case 3:
refreshedItem = _context3.sent;
return _context3.abrupt("return", {
revision: refreshedItem.revision,
data: resolver(utils_1.deepClone(refreshedItem.value))
});
case 5:
throw err;
case 6:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
};
_context4.next = 13;
return this.actionQueue.add(this.__set.bind(this), item.uri, { revision: item.revision, data: value }, _resolver);
case 13:
updatedItemDescriptor = _context4.sent;
case 14:
item = this.cache.get(item.index);
if (item && updatedItemDescriptor.last_event_id > item.lastEventId) {
item.update(updatedItemDescriptor.last_event_id, updatedItemDescriptor.revision, updatedItemDescriptor.data);
this.emit('itemUpdated', item, true);
}
return _context4.abrupt("return", item);
case 17:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
}
/**
* Modify an existing item by applying a mutation function to it.
* @param {Number} index Index of an item to be changed
* @param {List~Mutator} mutator A function that outputs a new value based on the existing value
* @returns {Promise} A promise with a modified item containing latest known value.
* A promise will be rejected if an item was not found.
* @public
*/
}, {
key: "mutate",
value: function mutate(index, mutator) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee5() {
var item;
return _regenerator2.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return this.get(index);
case 2:
item = _context5.sent;
return _context5.abrupt("return", this._actualSet(index, mutator(utils_1.deepClone(item.value)), mutator));
case 4:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
}
/**
* Modify an existing item by appending new fields (or overwriting existing ones) with the values from Object.
* @param {Number} index Index of an item to be changed
* @param {Object} obj Set of fields to update
* @returns {Promise} A promise with a modified item containing latest known value.
* A promise will be rejected if an item was not found.
* @public
*/
}, {
key: "update",
value: function update(index, obj) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee6() {
return _regenerator2.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
return _context6.abrupt("return", this.mutate(index, function (remote) {
return (0, _extends3.default)(remote, obj);
}));
case 1:
case "end":
return _context6.stop();
}
}
}, _callee6, this);
}));
}
/**
* Delete an item, given its key.
* @param {number} index Index of an item to be removed
* @returns {Promise} A promise to remove an item.
* A promise will be rejected if an item was not found.
* @public
*/
}, {
key: "remove",
value: function remove(index) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee7() {
var item, response;
return _regenerator2.default.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
_context7.next = 2;
return this.get(index);
case 2:
item = _context7.sent;
_context7.next = 5;
return this.services.network.delete(item.uri);
case 5:
response = _context7.sent;
this.cache.delete(index, response.body.last_event_id);
this.emit('itemRemoved', index, true);
case 8:
case "end":
return _context7.stop();
}
}
}, _callee7, this);
}));
}
/**
* Retrieve an item by List key.
* @param {Number} index Item index in a List
* @returns {Promise} A promise with an item containing latest known value.
* A promise will be rejected if an item was not found.
* @public
*/
}, {
key: "get",
value: function get(index) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee8() {
var cachedItem;
return _regenerator2.default.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
cachedItem = this.cache.get(index);
if (!cachedItem) {
_context8.next = 3;
break;
}
return _context8.abrupt("return", cachedItem);
case 3:
return _context8.abrupt("return", this._get(index));
case 4:
case "end":
return _context8.stop();
}
}
}, _callee8, this);
}));
}
}, {
key: "_get",
value: function _get(index) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee9() {
var result;
return _regenerator2.default.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
_context9.next = 2;
return this.queryItems({ index: index });
case 2:
result = _context9.sent;
if (!(result.items.length < 1)) {
_context9.next = 5;
break;
}
throw new Error('No item with index ' + index + ' found');
case 5:
return _context9.abrupt("return", result.items[0]);
case 6:
case "end":
return _context9.stop();
}
}
}, _callee9, this);
}));
}
/**
* Query items from the List
* @private
*/
}, {
key: "queryItems",
value: function queryItems(arg) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee10() {
var _this3 = this;
var url, response, items, meta;
return _regenerator2.default.wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
arg = arg || {};
url = new utils_1.UriBuilder(this.links.items).queryParam('From', arg.from).queryParam('PageSize', arg.limit).queryParam('Index', arg.index).queryParam('PageToken', arg.pageToken).queryParam('Order', arg.order).build();
_context10.next = 4;
return this.services.network.get(url);
case 4:
response = _context10.sent;
items = response.body.items.map(function (el) {
var itemInCache = _this3.cache.get(el.index);
if (itemInCache) {
_this3._handleItemUpdated(el.index, el.url, el.last_event_id, el.revision, el.data);
} else {
_this3.cache.store(Number(el.index), new listitem_1.ListItem({ index: Number(el.index),
uri: el.url,
revision: el.revision,
lastEventId: el.last_event_id,
value: el.data }), el.last_event_id);
}
return _this3.cache.get(el.index);
});
meta = response.body.meta;
return _context10.abrupt("return", new paginator_1.Paginator(items, function (pageToken) {
return _this3.queryItems({ pageToken: pageToken });
}, meta.previous_token, meta.next_token));
case 8:
case "end":
return _context10.stop();
}
}
}, _callee10, this);
}));
}
/**
* Query a list of items from collection.
* @param {Object} args Arguments for query
* @param {Number} args.from Item, which should be used as an anchor. If undefined, starts from the beginning or end depending on args.order
* @param {Number} args.pageSize Results page size
* @param {String} args.order Lexicographical order of results, should be 'asc' or 'desc'
* @returns {Promise>}
* @public
*/
}, {
key: "getItems",
value: function getItems(args) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee11() {
return _regenerator2.default.wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
args = args || {};
args.limit = args.pageSize || args.limit || 50;
args.order = args.order || 'asc';
return _context11.abrupt("return", this.queryItems(args));
case 4:
case "end":
return _context11.stop();
}
}
}, _callee11, this);
}));
}
/**
* @return {Promise} Context of List
* @private
*/
}, {
key: "getContext",
value: function getContext() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee12() {
var response;
return _regenerator2.default.wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
if (this.context) {
_context12.next = 5;
break;
}
_context12.next = 3;
return this.services.network.get(this.links.context);
case 3:
response = _context12.sent;
// store fetched context if we have't received any newer update
if (!this.context || response.body.last_event_id > this.lastEventId) {
this.context = response.body.data;
}
case 5:
return _context12.abrupt("return", this.context);
case 6:
case "end":
return _context12.stop();
}
}
}, _callee12, this);
}));
}
/**
* @private
*/
}, {
key: "updateContext",
value: function updateContext(context) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee13() {
return _regenerator2.default.wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
_context13.prev = 0;
_context13.next = 3;
return this.services.network.post(this.links.context, { data: context });
case 3:
this.context = context;
this.emit('contextUpdated', context, true);
return _context13.abrupt("return", this);
case 8:
_context13.prev = 8;
_context13.t0 = _context13["catch"](0);
logger_1.default.error('Failed to update context', _context13.t0);
throw _context13.t0;
case 12:
case "end":
return _context13.stop();
}
}
}, _callee13, this, [[0, 8]]);
}));
}
/**
* Delete this list. It will be impossible to restore it.
* @return {Promise} A promise that resolves when the list has been deleted.
* @public
*/
}, {
key: "removeList",
value: function removeList() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee14() {
return _regenerator2.default.wrap(function _callee14$(_context14) {
while (1) {
switch (_context14.prev = _context14.next) {
case 0:
_context14.next = 2;
return this.services.network.delete(this.uri);
case 2:
this.onRemoved(true);
case 3:
case "end":
return _context14.stop();
}
}
}, _callee14, this);
}));
}
}, {
key: "onRemoved",
value: function onRemoved(locally) {
this._unsubscribe();
this.removalHandler(this.type, this.sid, this.uniqueName);
// Should also do some cleanup here
this.emit('collectionRemoved', locally);
if (!locally) {
this.emit('collectionRemovedRemotely');
}
}
}, {
key: "shouldIgnoreEvent",
value: function shouldIgnoreEvent(key, eventId) {
return this.cache.isKnown(key, eventId);
}
/**
* Handle update, which came from the server
* @private
*/
}, {
key: "_update",
value: function _update(update, isStrictlyOrdered) {
var itemIndex = Number(update.item_index);
switch (update.type) {
case 'list_item_added':
{
this._handleItemAdded(itemIndex, update.item_url, update.id, update.item_revision, update.item_data);
}
break;
case 'list_item_updated':
{
this._handleItemUpdated(itemIndex, update.item_url, update.id, update.item_revision, update.item_data);
}
break;
case 'list_item_removed':
{
this._handleItemRemoved(itemIndex, update.id, update.item_data);
}
break;
case 'list_context_updated':
{
this._handleContextUpdate(update.context_data, update.id);
}
break;
case 'list_removed':
{
this.onRemoved(false);
}
break;
}
if (isStrictlyOrdered) {
this._advanceLastEventId(update.id, update.list_revision);
}
}
}, {
key: "_advanceLastEventId",
value: function _advanceLastEventId(eventId, revision) {
if (this.lastEventId < eventId) {
this.descriptor.last_event_id = eventId;
if (revision) {
this.descriptor.revision = revision;
}
}
}
/**
* Handle item insertion event, coming from server
* @private
*/
}, {
key: "_handleItemAdded",
value: function _handleItemAdded(index, uri, eventId, revision, value) {
if (!this.cache.isKnown(index, eventId)) {
var item = new listitem_1.ListItem({ index: index, uri: uri, lastEventId: eventId, revision: revision, value: value });
this.cache.store(index, item, eventId);
this.emit('itemAdded', item, false);
this.emit('itemAddedRemotely', item);
}
}
/**
* Handle new value of item, coming from server
* @private
*/
}, {
key: "_handleItemUpdated",
value: function _handleItemUpdated(index, uri, eventId, revision, value) {
var item = this.cache.get(index);
if (!item && !this.shouldIgnoreEvent(index, eventId)) {
item = this.cache.store(index, new listitem_1.ListItem({ index: index, uri: uri, lastEventId: eventId, revision: revision, value: value }), eventId);
this.emit('itemUpdated', item, false);
this.emit('itemUpdatedRemotely', item);
} else if (item && eventId > item.lastEventId) {
item.update(eventId, revision, value);
this.emit('itemUpdated', item, false);
this.emit('itemUpdatedRemotely', item);
}
}
}, {
key: "_handleItemRemoved",
value: function _handleItemRemoved(index, eventId, oldData) {
this.cache.delete(index, eventId);
this.emit('itemRemoved', index, false);
this.emit('itemRemovedRemotely', index, oldData);
}
}, {
key: "_handleContextUpdate",
value: function _handleContextUpdate(data, eventId) {
if (this.lastEventId < eventId) {
this.context = data;
this.emit('contextUpdated', data, false);
this.emit('contextUpdatedRemotely', data);
}
}
}, {
key: "uri",
get: function get() {
return this.descriptor.url;
}
}, {
key: "revision",
get: function get() {
return this.descriptor.revision;
}
}, {
key: "lastEventId",
get: function get() {
return this.descriptor.last_event_id;
}
}, {
key: "links",
get: function get() {
return this.descriptor.links;
}
}, {
key: "type",
get: function get() {
return 'list';
}
// public props, documented along with class description
}, {
key: "sid",
get: function get() {
return this.descriptor.sid;
}
}, {
key: "uniqueName",
get: function get() {
return this.descriptor.unique_name || null;
}
}], [{
key: "type",
get: function get() {
return 'list';
}
}]);
return SyncList;
}(entity_1.SyncEntity);
exports.SyncList = SyncList;
exports.default = SyncList;
/**
* Applies a transformation to the item value. May be called multiple times on the
* same datum in case of collisions with remote code.
* @callback List~Mutator
* @param {Object} data The current value of the item in the cloud.
* @return {Object} The desired new value for the item.
*/
/**
* Fired when a new item appears in the list, whether its creator was local or remote.
* @event List#itemAdded
* @param {ListItem} - Added item
* @param {Boolean} - Equals 'true' if item was added by local actor, 'false' otherwise
*/
/**
* Fired when remote code adds a new item to the list.
* @event List#itemAddedRemotely
* @param {ListItem} - Added item
*/
/**
* Fired when a list item is updated (not added or removed, but changed), whether the updater was local or remote.
* @event List#itemUpdated
* @param {ListItem} - Updated item
* @param {Boolean} - Equals 'true' if item was updated by local actor, 'false' otherwise
*/
/**
* Fired when a remote actor updates a list item.
* @event List#itemUpdatedRemotely
* @param {ListItem} - Updated item
*/
/**
* Fired when a list item is removed, whether the remover was local or remote.
* @event List#itemRemoved
* @param {Number} - An index of removed item
* @param {Boolean} - Equals 'true' if item was removed by local actor, 'false' otherwise
*/
/**
* Fired when a remote actor removes a list item.
* @event List#itemRemovedRemotely
* @param {Number} - An index of removed item
* @param {Object} - A snapshot of item data before removal
*/
/**
* Fired when a list is deleted entirely, by any actor local or remote.
* @event List#collectionRemoved
* @param {Boolean} - Equals 'true' if list was removed by local actor, 'false' otherwise
*/
/**
* Fired when remote code deletes a list.
* @event List#collectionRemovedRemotely
*/
},{"./cache":247,"./entity":252,"./listitem":254,"./logger":255,"./paginator":258,"./retryingqueue":259,"./utils":269,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/extends":52,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"babel-runtime/regenerator":57}],267:[function(_dereq_,module,exports){
"use strict";
var _extends2 = _dereq_("babel-runtime/helpers/extends");
var _extends3 = _interopRequireDefault(_extends2);
var _regenerator = _dereq_("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = _dereq_("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
return new (P || (P = _promise2.default))(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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
var utils_1 = _dereq_("./utils");
var entity_1 = _dereq_("./entity");
var retryingqueue_1 = _dereq_("./retryingqueue");
var mapitem_1 = _dereq_("./mapitem");
var paginator_1 = _dereq_("./paginator");
var cache_1 = _dereq_("./cache");
/**
* @class
* @alias Map
* @classdesc Represents a Sync Map, which stores an unordered set of key:value pairs.
* @property {String} sid An immutable identifier (a SID) assigned by the system on creation.
* @property {String} [uniqueName=null] - An optional immutable identifier that may be assigned by the
* programmer to this map on creation. Unique among other Maps.
*
*
* @fires Map#collectionRemoved
* @fires Map#collectionRemovedRemotely
* @fires Map#itemAdded
* @fires Map#itemAddedRemotely
* @fires Map#itemRemoved
* @fires Map#itemRemovedRemotely
* @fires Map#itemUpdated
* @fires Map#itemUpdatedRemotely
*/
var SyncMap = function (_entity_1$SyncEntity) {
(0, _inherits3.default)(SyncMap, _entity_1$SyncEntity);
/**
* @private
*/
function SyncMap(services, descriptor, removalHandler) {
(0, _classCallCheck3.default)(this, SyncMap);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncMap.__proto__ || (0, _getPrototypeOf2.default)(SyncMap)).call(this, services, removalHandler));
_this.actionQueue = new retryingqueue_1.RetryingQueue();
_this.cache = new cache_1.Cache();
_this.descriptor = descriptor;
if (descriptor.items) {
descriptor.items.forEach(function (itemDescriptor) {
_this.cache.store(itemDescriptor.key, new mapitem_1.MapItem(itemDescriptor), itemDescriptor.last_event_id);
});
}
return _this;
}
// private props
(0, _createClass3.default)(SyncMap, [{
key: "_get",
value: function _get(key) {
return this.queryItems({ key: key }).then(function (result) {
if (result.items.length < 1) {
throw new Error('No item with key ' + key + ' found');
}
return result.items[0];
});
}
}, {
key: "__set",
value: function __set(location, param) {
return this.services.network.post(location, { data: param.data }, param.revision).then(function (response) {
response = response.body;
response.data = param.data;
return response;
});
}
/**
* Update known existing element
* @private
*/
}, {
key: "_set",
value: function _set(location, keyValue, resolver) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee2() {
var _this2 = this;
var _resolver;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (resolver) {
_context2.next = 2;
break;
}
return _context2.abrupt("return", this.__set(location, { data: keyValue.data }));
case 2:
_resolver = function _resolver(err) {
return __awaiter(_this2, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
var item;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (!(err.status === 412)) {
_context.next = 5;
break;
}
_context.next = 3;
return this._get(keyValue.key);
case 3:
item = _context.sent;
return _context.abrupt("return", {
revision: item.revision,
data: resolver(utils_1.deepClone(item.value))
});
case 5:
throw err;
case 6:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
};
return _context2.abrupt("return", this.actionQueue.add(this.__set.bind(this), location, { revision: keyValue.revision, data: keyValue.data }, _resolver));
case 4:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
}
/**
* Create element or update if already existing
* @private
*/
}, {
key: "_tryAddOrUpdate",
value: function _tryAddOrUpdate(uri, keyValue, resolver) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee3() {
var response, existingItemLocation, value, _response, resolvedData, _value;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.prev = 0;
_context3.next = 3;
return this.services.network.post(uri, keyValue);
case 3:
response = _context3.sent;
response.body.data = keyValue.data;
return _context3.abrupt("return", { added: true, value: response.body });
case 8:
_context3.prev = 8;
_context3.t0 = _context3["catch"](0);
if (!(_context3.t0.status !== 409)) {
_context3.next = 12;
break;
}
throw _context3.t0;
case 12:
existingItemLocation = _context3.t0.body.links.item;
if (resolver) {
_context3.next = 20;
break;
}
_context3.next = 16;
return this._set(existingItemLocation, keyValue, resolver);
case 16:
value = _context3.sent;
return _context3.abrupt("return", { added: false, value: value });
case 20:
_context3.next = 22;
return this.services.network.get(existingItemLocation);
case 22:
_response = _context3.sent;
resolvedData = resolver(utils_1.deepClone(_response.body.data));
_context3.next = 26;
return this._set(existingItemLocation, {
key: _response.body.key,
revision: _response.body.revision,
data: resolvedData
}, resolver);
case 26:
_value = _context3.sent;
return _context3.abrupt("return", { added: false, value: _value });
case 28:
case "end":
return _context3.stop();
}
}
}, _callee3, this, [[0, 8]]);
}));
}
/**
* @return Promise Context of collection
* @private
*/
}, {
key: "getContext",
value: function getContext() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee4() {
var response;
return _regenerator2.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
if (this.context) {
_context4.next = 5;
break;
}
_context4.next = 3;
return this.services.network.get(this.links.context);
case 3:
response = _context4.sent;
// store fetched context if we have't received any newer update
if (!this.context || response.body.last_event_id > this.lastEventId) {
this.context = response.body.data;
}
case 5:
return _context4.abrupt("return", this.context);
case 6:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
}
/**
* @param context {Object} New context value
* @returns {Promise}
* @private
*/
}, {
key: "updateContext",
value: function updateContext(context) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee5() {
return _regenerator2.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return this.services.network.post(this.links.context, { data: context });
case 2:
this.context = context;
this.emit('contextUpdated', context, true);
case 4:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
}
/**
* Add a new item to the map with the given key:value pair. Overwrites any value that might already exist at that key.
* @param {String} key Unique item identifier
* @param {Object} value Value to be set
* @returns {Promise} Newly added item, or modified one if already exists, with the latest known value.
* @public
*/
}, {
key: "set",
value: function set(key, value) {
return this._actualSet(key, value);
}
/**
* @private
*/
}, {
key: "_actualSet",
value: function _actualSet(key, value, resolver) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee6() {
var descriptor, added, item, arg, addOrUpdateResult;
return _regenerator2.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
descriptor = void 0;
added = void 0;
item = this.cache.get(key);
if (!item) {
_context6.next = 11;
break;
}
arg = { key: key, data: value, revision: item.revision || undefined };
_context6.next = 7;
return this._set(item.uri, arg, resolver);
case 7:
descriptor = _context6.sent;
added = false;
_context6.next = 16;
break;
case 11:
_context6.next = 13;
return this._tryAddOrUpdate(this.links.items, { key: key, data: value }, resolver);
case 13:
addOrUpdateResult = _context6.sent;
descriptor = addOrUpdateResult.value;
added = addOrUpdateResult.added;
case 16:
item = this.cache.get(key);
if (item && descriptor.last_event_id > item.lastEventId) {
item.update(descriptor.last_event_id, descriptor.revision, descriptor.data);
this.emit('itemUpdated', item, true);
} else if (!item) {
item = this.cache.store(key, new mapitem_1.MapItem(descriptor), descriptor.last_event_id);
if (added) {
this.emit('itemAdded', item, true);
} else {
this.emit('itemUpdated', item, true);
}
}
return _context6.abrupt("return", item);
case 19:
case "end":
return _context6.stop();
}
}
}, _callee6, this);
}));
}
/**
* Retrieve an item by key.
* @param {String} key Identifies the desired item.
* @returns {Promise} A promise that resolves when the item has been fetched.
* This promise will be rejected if item was not found.
* @public
*/
}, {
key: "get",
value: function get(key) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee7() {
var result;
return _regenerator2.default.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
if (!this.cache.has(key)) {
_context7.next = 2;
break;
}
return _context7.abrupt("return", this.cache.get(key));
case 2:
_context7.next = 4;
return this.queryItems({ key: key });
case 4:
result = _context7.sent;
if (!(result.items.length < 1)) {
_context7.next = 7;
break;
}
throw new Error('No item with key ' + key + ' found');
case 7:
return _context7.abrupt("return", result.items[0]);
case 8:
case "end":
return _context7.stop();
}
}
}, _callee7, this);
}));
}
/**
* Schedules a modification to this document that will apply a mutation function.
* @param {String} key selects the map item to be mutated.
* @param {Map~Mutator} mutator A function that outputs a new value based on the existing value.
* May be called multiple times, particularly if this Document is modified concurrently by remote code.
* If the mutation ultimately succeeds, the Document will have made the particular transition described
* by this function.
* @returns {Promise} Resolves with the modified item, with its latest contents.
* @public
*/
}, {
key: "mutate",
value: function mutate(key, mutator) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee8() {
var value;
return _regenerator2.default.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
_context8.next = 2;
return this.get(key).then(function (item) {
return item.value;
}).catch(function () {
return {};
});
case 2:
value = _context8.sent;
return _context8.abrupt("return", this._actualSet(key, mutator(utils_1.deepClone(value)), mutator));
case 4:
case "end":
return _context8.stop();
}
}
}, _callee8, this);
}));
}
/**
* Modify the keyed map item by appending new fields (or by overwriting existing ones) with the values from
* the provided Object. Creates a new item if no item by this key exists, copying all given fields and values
* into it.
* @param {String} key selects the map item to update.
* @param {Object} obj Specifies the particular (top-level) attributes that will receive new values.
* @returns {Promise} A promise resolving to the modified item in its new state.
* @public
*/
}, {
key: "update",
value: function update(key, obj) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee9() {
return _regenerator2.default.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
return _context9.abrupt("return", this.mutate(key, function (remote) {
return (0, _extends3.default)(remote, obj);
}));
case 1:
case "end":
return _context9.stop();
}
}
}, _callee9, this);
}));
}
/**
* Delete an item, given its key.
* @param {String} key selects the item to delete.
* @returns {Promise} A promise to remove an item.
* The promise will be rejected if 'key' is undefined or an item was not found.
* @public
*/
}, {
key: "remove",
value: function remove(key) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee10() {
var item, response;
return _regenerator2.default.wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
if (!(typeof key === 'undefined')) {
_context10.next = 2;
break;
}
throw new Error('Key argument is invalid');
case 2:
_context10.next = 4;
return this.get(key);
case 4:
item = _context10.sent;
_context10.next = 7;
return this.services.network.delete(item.uri);
case 7:
response = _context10.sent;
this.cache.delete(key, response.body.last_event_id);
this.emit('itemRemoved', key, true);
case 10:
case "end":
return _context10.stop();
}
}
}, _callee10, this);
}));
}
/**
* @private
*/
}, {
key: "queryItems",
value: function queryItems(args) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee11() {
var _this3 = this;
var uri, response, items, meta;
return _regenerator2.default.wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
args = args || {};
uri = new utils_1.UriBuilder(this.links.items).queryParam('From', args.from).queryParam('PageSize', args.limit).queryParam('Key', args.key).queryParam('PageToken', args.pageToken).queryParam('Order', args.order).build();
_context11.next = 4;
return this.services.network.get(uri);
case 4:
response = _context11.sent;
items = response.body.items.map(function (el) {
var itemInCache = _this3.cache.get(el.key);
if (itemInCache) {
_this3._handleItemUpdated(el.key, el.url, el.last_event_id, el.revision, el.data);
} else {
_this3.cache.store(el.key, new mapitem_1.MapItem(el), el.last_event_id);
}
return _this3.cache.get(el.key);
});
meta = response.body.meta;
return _context11.abrupt("return", new paginator_1.Paginator(items, function (pageToken) {
return _this3.queryItems({ pageToken: pageToken });
}, meta.previous_token, meta.next_token));
case 8:
case "end":
return _context11.stop();
}
}
}, _callee11, this);
}));
}
/**
* Get a complete list of items from the map.
* @param {Object} args Arguments for query
* @param {String} args.from Item, which should be used as an anchor. If undefined, starts from the beginning or end depending on args.order
* @param {Number} args.pageSize Result page size
* @param {String} args.order Lexicographical order of results, should be 'asc' or 'desc'
* @return {Promise>}
* @public
*/
}, {
key: "getItems",
value: function getItems(args) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee12() {
return _regenerator2.default.wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
args = args || {};
args.limit = args.pageSize || args.limit || 50;
args.order = args.order || 'asc';
return _context12.abrupt("return", this.queryItems(args));
case 4:
case "end":
return _context12.stop();
}
}
}, _callee12, this);
}));
}
/**
* Enumerate all items in this Map.
* This always triggers server interaction when being called for the first time on a Map; this may be latent.
* This method not supported now and not meant to be used externally.
* @param {Function} handler Function to handle each argument
* @private
*/
}, {
key: "forEach",
value: function forEach(handler) {
var _this4 = this;
return new _promise2.default(function (resolve, reject) {
function processPage(page) {
page.items.forEach(function (x) {
return handler(x);
});
if (page.hasNextPage) {
page.nextPage().then(processPage).catch(reject);
} else {
resolve();
}
}
_this4.queryItems().then(processPage).catch(reject);
});
}
}, {
key: "shouldIgnoreEvent",
value: function shouldIgnoreEvent(key, eventId) {
return this.cache.isKnown(key, eventId);
}
/**
* Handle update from the server
* @private
*/
}, {
key: "_update",
value: function _update(update, isStrictlyOrdered) {
switch (update.type) {
case 'map_item_added':
{
this._handleItemAdded(update.item_key, update.item_url, update.id, update.item_revision, update.item_data);
}
break;
case 'map_item_updated':
{
this._handleItemUpdated(update.item_key, update.item_url, update.id, update.item_revision, update.item_data);
}
break;
case 'map_item_removed':
{
this._handleItemRemoved(update.item_key, update.id, update.item_data);
}
break;
case 'map_context_updated':
{
this._handleContextUpdate(update.context_data, update.id);
}
break;
case 'map_removed':
{
this.onRemoved(false);
}
break;
}
if (isStrictlyOrdered) {
this._advanceLastEventId(update.id, update.map_revision);
}
}
}, {
key: "_advanceLastEventId",
value: function _advanceLastEventId(eventId, revision) {
if (this.lastEventId < eventId) {
this.descriptor.last_event_id = eventId;
if (revision) {
this.descriptor.revision = revision;
}
}
}
/**
* Handle entity insertion event, coming from server
* @private
*/
}, {
key: "_handleItemAdded",
value: function _handleItemAdded(key, url, eventId, revision, value) {
if (!this.cache.has(key) && !this.shouldIgnoreEvent(key, eventId)) {
var item = new mapitem_1.MapItem({ key: key, url: url, last_event_id: eventId, revision: revision, data: value });
this.cache.store(key, item, eventId);
this.emit('itemAdded', item, false);
this.emit('itemAddedRemotely', item);
}
}
/**
* Handle new value of entity, coming from server
* @private
*/
}, {
key: "_handleItemUpdated",
value: function _handleItemUpdated(key, url, eventId, revision, value) {
var item = this.cache.get(key);
if (!item && !this.shouldIgnoreEvent(key, eventId)) {
item = new mapitem_1.MapItem({ key: key, url: url, last_event_id: eventId, revision: revision, data: value });
this.cache.store(key, item, eventId);
this.emit('itemUpdated', item, false);
this.emit('itemUpdatedRemotely', item);
} else if (item && eventId > item.lastEventId) {
item.update(eventId, revision, value);
this.emit('itemUpdated', item, false);
this.emit('itemUpdatedRemotely', item);
}
}
/**
* @private
*/
}, {
key: "_handleItemRemoved",
value: function _handleItemRemoved(key, eventId, oldData) {
this.cache.delete(key, eventId);
this.emit('itemRemoved', key, false);
this.emit('itemRemovedRemotely', key, oldData);
}
}, {
key: "_handleContextUpdate",
value: function _handleContextUpdate(data, eventId) {
if (this.lastEventId < eventId) {
this.context = data;
this.emit('contextUpdated', data, false);
this.emit('contextUpdatedRemotely', data);
}
}
}, {
key: "onRemoved",
value: function onRemoved(locally) {
this._unsubscribe();
this.removalHandler(this.type, this.sid, this.uniqueName);
//
// Should also do some cleanup here
this.emit('collectionRemoved', locally);
if (!locally) {
this.emit('collectionRemovedRemotely');
}
}
/**
* Delete this map. It will be impossible to restore it.
* @return {Promise} A promise that resolves when the map has been deleted.
* @public
*/
}, {
key: "removeMap",
value: function removeMap() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee13() {
return _regenerator2.default.wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
_context13.next = 2;
return this.services.network.delete(this.uri);
case 2:
this.onRemoved(true);
case 3:
case "end":
return _context13.stop();
}
}
}, _callee13, this);
}));
}
}, {
key: "uri",
get: function get() {
return this.descriptor.url;
}
}, {
key: "links",
get: function get() {
return this.descriptor.links;
}
}, {
key: "revision",
get: function get() {
return this.descriptor.revision;
}
}, {
key: "lastEventId",
get: function get() {
return this.descriptor.last_event_id;
}
}, {
key: "type",
get: function get() {
return 'map';
}
// public props, documented along with class description
}, {
key: "sid",
get: function get() {
return this.descriptor.sid;
}
}, {
key: "uniqueName",
get: function get() {
return this.descriptor.unique_name || null;
}
}], [{
key: "type",
get: function get() {
return 'map';
}
}]);
return SyncMap;
}(entity_1.SyncEntity);
exports.SyncMap = SyncMap;
// export { SyncMap, MapDescriptor, Mutator };
exports.default = SyncMap;
/**
* Applies a transformation to the item value. May be called multiple times on the
* same datum in case of collisions with remote code.
* @callback Map~Mutator
* @param {Object} data The current value of the item in the cloud.
* @return {Object} The desired new value for the item.
*/
/**
* Fired when a new item appears in the map, whether its creator was local or remote.
* @event Map#itemAdded
* @param {MapItem} - Added item
* @param {Boolean} - Equals 'true' if item was added by local actor, 'false' otherwise
*/
/**
* Fired when remote code creates a new item in the map.
* @event Map#itemAddedRemotely
* @param {MapItem} - Added item
*/
/**
* Fired when a map item is updated (not added or removed, but changed), whether the updater was local or remote.
* @event Map#itemUpdated
* @param {MapItem} - Updated item
* @param {Boolean} - Equals 'true' if item was updated by local actor, 'false' otherwise
*/
/**
* Fired when a remote actor updates a map item.
* @event Map#itemUpdatedRemotely
* @param {MapItem} - Updated item
*/
/**
* Fired when a map item is removed, whether the remover was local or remote.
* @event Map#itemRemoved
* @param {String} - A key of removed item
* @param {Boolean} - Equals 'true' if item was removed by local actor, 'false' otherwise
*/
/**
* Fired when a remote actor removes a map item.
* @event Map#itemRemovedRemotely
* @param {String} - A key of removed item
* @param {Object} - A snapshot of item data before removal
*/
/**
* Fired when a map is deleted entirely, by any actor local or remote.
* @event Map#collectionRemoved
* @param {Boolean} - Equals 'true' if map was removed by local actor, 'false' otherwise
*/
/**
* Fired when remote code deletes a map.
* @event Map#collectionRemovedRemotely
*/
},{"./cache":247,"./entity":252,"./mapitem":256,"./paginator":258,"./retryingqueue":259,"./utils":269,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/extends":52,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"babel-runtime/regenerator":57}],268:[function(_dereq_,module,exports){
"use strict";
var _regenerator = _dereq_("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = _dereq_("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
return new (P || (P = _promise2.default))(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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
var entity_1 = _dereq_("../entity");
/**
* @class
* @alias Topic
* @classdesc A Sync primitive for high-throughput pub-sub
* @property {String} sid - Topic SID
* @property {String} uniqueName - Topic unique name
*/
var SyncTopic = function (_entity_1$SyncEntity) {
(0, _inherits3.default)(SyncTopic, _entity_1$SyncEntity);
/**
* @private
*/
function SyncTopic(services, descriptor, removalHandler) {
(0, _classCallCheck3.default)(this, SyncTopic);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncTopic.__proto__ || (0, _getPrototypeOf2.default)(SyncTopic)).call(this, services, removalHandler));
_this.descriptor = descriptor;
return _this;
}
(0, _createClass3.default)(SyncTopic, [{
key: "publishMessage",
/**
* Publish a Message to the Topic.
* @param {Object} value Topic Message value
* @return {Promise}
* @public
*/
value: function publishMessage(value) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
var requestBody, response, responseBody, event;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
requestBody = { data: value };
_context.next = 3;
return this.services.network.post(this.links.messages, requestBody);
case 3:
response = _context.sent;
responseBody = response.body;
event = this._handleMessagePublished(responseBody.sid, value, false);
return _context.abrupt("return", event);
case 7:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
}
/**
* Permanently delete the Topic.
* @return {Promise} Promise to delete the Topic
* @public
*/
}, {
key: "removeTopic",
value: function removeTopic() {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee2() {
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return this.services.network.delete(this.uri);
case 2:
this.onRemoved(true);
case 3:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
}
/**
* Handle event from the server
* @private
*/
}, {
key: "_update",
value: function _update(update) {
switch (update.type) {
case 'topic_message_published':
{
this._handleMessagePublished(update.message_sid, update.message_data, true);
break;
}
case 'topic_removed':
{
this.onRemoved(false);
break;
}
}
}
}, {
key: "_handleMessagePublished",
value: function _handleMessagePublished(sid, data, remote) {
var event = {
sid: sid,
value: data,
remote: remote
};
this.emit('messagePublished', event);
if (remote) {
this.emit('messagePublishedRemotely', event);
}
return event;
}
}, {
key: "onRemoved",
value: function onRemoved(isLocal) {
this._unsubscribe();
this.removalHandler(this.type, this.sid, this.uniqueName);
this.emit('topicRemoved', isLocal);
if (!isLocal) {
this.emit('topicRemovedRemotely');
}
}
}, {
key: "sid",
get: function get() {
return this.descriptor.sid;
}
}, {
key: "uniqueName",
get: function get() {
return this.descriptor.unique_name || null;
}
}, {
key: "uri",
get: function get() {
return this.descriptor.url;
}
}, {
key: "links",
get: function get() {
return this.descriptor.links;
}
}, {
key: "type",
get: function get() {
return 'topic';
}
}, {
key: "lastEventId",
get: function get() {
return null;
}
}], [{
key: "type",
get: function get() {
return 'topic';
}
}]);
return SyncTopic;
}(entity_1.SyncEntity);
exports.SyncTopic = SyncTopic;
exports.default = SyncTopic;
/**
* @class TopicMessage
* @classdesc Topic Message descriptor
* @property {String} sid - Topic Message SID
* @property {Object} value - Topic Message value
* @property {boolean} remote - Indicates whether the Message was published by a remote actor
*/
/**
* Fired when a Message is published to the Topic, either locally or by a remote actor
* @event Topic#messagePublished
* @type {TopicMessage} Topic Message descriptor
*/
/**
* Fired when a Message is published to the Topic by a remote actor
* @event Topic#messagePublishedRemotely
* @type {TopicMessage} Topic Message descriptor
*/
/**
* Fired when the Topic is deleted
* @event Topic#removed
*/
/**
* Fired when the Topic is deleted by a remote actor
* @event Topic#removedRemotely
*/
},{"../entity":252,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"babel-runtime/regenerator":57}],269:[function(_dereq_,module,exports){
"use strict";
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _stringify = _dereq_("babel-runtime/core-js/json/stringify");
var _stringify2 = _interopRequireDefault(_stringify);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Deep-clone an object. Note that this does not work on object containing
* functions.
* @param {object} obj - the object to deep-clone
* @returns {object}
*/
function deepClone(obj) {
return JSON.parse((0, _stringify2.default)(obj));
}
exports.deepClone = deepClone;
/**
* Construct URI with query parameters
*/
var UriBuilder = function () {
function UriBuilder(base) {
(0, _classCallCheck3.default)(this, UriBuilder);
this.base = base;
this.args = new Array();
this.paths = new Array();
}
(0, _createClass3.default)(UriBuilder, [{
key: "pathSegment",
value: function pathSegment(name) {
this.paths.push(encodeURIComponent(name));
return this;
}
}, {
key: "queryParam",
value: function queryParam(name, value) {
if (typeof value !== 'undefined') {
this.args.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
}
return this;
}
}, {
key: "build",
value: function build() {
var result = this.base;
if (this.paths.length) {
result += '/' + this.paths.join('/');
}
if (this.args.length) {
result += '?' + this.args.join('&');
}
return result;
}
}]);
return UriBuilder;
}();
exports.UriBuilder = UriBuilder;
},{"babel-runtime/core-js/json/stringify":34,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],270:[function(_dereq_,module,exports){
"use strict";
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", { value: true });
var Deferred = function () {
function Deferred() {
var _this = this;
(0, _classCallCheck3.default)(this, Deferred);
this._promise = new _promise2.default(function (resolve, reject) {
_this._resolve = resolve;
_this._reject = reject;
});
}
(0, _createClass3.default)(Deferred, [{
key: "update",
value: function update(value) {
this._resolve(value);
}
}, {
key: "set",
value: function set(value) {
this.current = value;
this._resolve(value);
}
}, {
key: "fail",
value: function fail(e) {
this._reject(e);
}
}, {
key: "promise",
get: function get() {
return this._promise;
}
}]);
return Deferred;
}();
exports.Deferred = Deferred;
},{"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],271:[function(_dereq_,module,exports){
module.exports={
"_args": [
[
{
"raw": "twilio-sync@^0.5.10",
"scope": null,
"escapedName": "twilio-sync",
"name": "twilio-sync",
"rawSpec": "^0.5.10",
"spec": ">=0.5.10 <0.6.0",
"type": "range"
},
"/var/lib/jenkins/jobs/twilio-chat.js/workspace"
]
],
"_from": "twilio-sync@>=0.5.10 <0.6.0",
"_id": "twilio-sync@0.5.10",
"_inCache": true,
"_location": "/twilio-sync",
"_nodeVersion": "7.7.1",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/twilio-sync-0.5.10.tgz_1503303914949_0.8794955047778785"
},
"_npmUser": {
"name": "twilio-ci",
"email": "mroberts+twilio-ci@twilio.com"
},
"_npmVersion": "4.1.2",
"_phantomChildren": {},
"_requested": {
"raw": "twilio-sync@^0.5.10",
"scope": null,
"escapedName": "twilio-sync",
"name": "twilio-sync",
"rawSpec": "^0.5.10",
"spec": ">=0.5.10 <0.6.0",
"type": "range"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/twilio-sync/-/twilio-sync-0.5.10.tgz",
"_shasum": "38fcfbd31fe72b48ac0fe29b37baf8c215d0bc76",
"_shrinkwrap": null,
"_spec": "twilio-sync@^0.5.10",
"_where": "/var/lib/jenkins/jobs/twilio-chat.js/workspace",
"author": {
"name": "Twilio"
},
"browser": "browser/index.js",
"dependencies": {
"babel-runtime": "^6.23.0",
"karibu": "^1.0.1",
"loglevel": "^1.4.1",
"operation-retrier": "^1.1.2",
"platform": "^1.3.3",
"rfc6902": "^1.3.0",
"twilio-ems-client": "^0.2.0",
"twilio-notifications": "^0.4.0",
"twilio-transport": "^0.1.2",
"twilsock": "^0.3.0",
"uuid": "^3.0.1",
"xxhashjs": "^0.2.1"
},
"description": "Twilio Sync client library",
"devDependencies": {
"@types/chai": "^3.4.35",
"@types/chai-as-promised": "0.0.29",
"@types/loglevel": "^1.4.29",
"@types/mocha": "^2.2.39",
"@types/node": "^7.0.5",
"@types/sinon": "^2.3.3",
"@types/sinon-chai": "^2.7.27",
"async-test-tools": "^1.0.6",
"babel-cli": "^6.23.0",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-array-includes": "^2.0.3",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.22.0",
"babelify": "^7.3.0",
"backoff": "^2.5.0",
"browserify": "^14.1.0",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"cheerio": "^0.22.0",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-derequire": "^2.1.0",
"gulp-exit": "0.0.2",
"gulp-insert": "^0.5.0",
"gulp-istanbul": "^1.1.1",
"gulp-mocha": "^4.0.1",
"gulp-rename": "^1.2.2",
"gulp-replace": "^0.5.4",
"gulp-tap": "^0.1.3",
"gulp-tslint": "^7.1.0",
"gulp-typescript": "^3.1.5",
"gulp-uglify": "^2.0.1",
"gulp-util": "^3.0.8",
"ink-docstrap": "^1.3.0",
"isparta": "^4.0.0",
"jsdoc": "^3.4.3",
"jsonwebtoken": "^7.3.0",
"karma": "^1.5.0",
"karma-browserify": "^5.1.1",
"karma-browserstack-launcher": "^1.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.2",
"run-sequence": "^1.2.2",
"sinon": "^2.3.3",
"sinon-chai": "^2.8.0",
"ts-node": "^3.0.0",
"tslint": "^4.5.1",
"twilio": "^3.3.0-edge",
"typescript": "2.2.1",
"underscore": "^1.8.3",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.9.0"
},
"directories": {},
"dist": {
"shasum": "38fcfbd31fe72b48ac0fe29b37baf8c215d0bc76",
"tarball": "https://registry.npmjs.org/twilio-sync/-/twilio-sync-0.5.10.tgz"
},
"engines": {
"node": ">=6"
},
"gitHead": "cfefba94f7be630b924854ff63a9766218b2bdcd",
"license": "MIT",
"main": "lib/index.js",
"maintainers": [
{
"name": "schertkov",
"email": "schertkov@twilio.com"
},
{
"name": "twilio-ci",
"email": "mroberts+twilio-ci@twilio.com"
}
],
"name": "twilio-sync",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"scripts": {
"prepublish": "gulp build",
"test": "gulp unit-test"
},
"version": "0.5.10"
}
},{}],272:[function(_dereq_,module,exports){
'use strict';
var _stringify = _dereq_("babel-runtime/core-js/json/stringify");
var _stringify2 = _interopRequireDefault(_stringify);
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var _defineProperty = _dereq_("babel-runtime/core-js/object/define-property");
var _defineProperty2 = _interopRequireDefault(_defineProperty);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;(0, _defineProperty2.default)(target, descriptor.key, descriptor);
}
}return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var XHR = typeof XMLHttpRequest === 'undefined' ? _dereq_('xmlhttprequest').XMLHttpRequest : XMLHttpRequest;
function parseResponseHeaders(headerString) {
if (!headerString) {
return {};
}
return headerString.split('\r\n').map(function (el) {
return el.split(': ');
}).filter(function (el) {
return el.length === 2 && el[1].length > 0;
}).reduce(function (prev, curr) {
prev[curr[0]] = curr[1];return prev;
}, {});
}
function extractBody(xhr) {
var contentType = xhr.getResponseHeader('Content-Type');
if (!contentType || contentType.indexOf('application/json') !== 0 || xhr.responseText.length === 0) {
return xhr.responseText;
}
try {
return JSON.parse(xhr.responseText);
} catch (e) {
return xhr.responseText;
}
}
/**
* Use XMLHttpRequest to get a network resource.
* @param {String} method - HTTP Method
* @param {Object} params - Request parameters
* @param {String} params.url - URL of the resource
* @param {Array} params.headers - An array of headers to pass [{ headerName : headerBody }]
* @param {Object} params.body - A JSON body to send to the resource
* @returns {Promise}
**/
var Request = function () {
function Request() {
_classCallCheck(this, Request);
}
_createClass(Request, null, [{
key: 'request',
value: function request(method, params) {
return new _promise2.default(function (resolve, reject) {
var xhr = new XHR();
xhr.open(method, params.url, true);
xhr.onreadystatechange = function onreadystatechange() {
if (xhr.readyState !== 4) {
return;
}
var headers = parseResponseHeaders(xhr.getAllResponseHeaders());
var body = extractBody(xhr);
if (200 <= xhr.status && xhr.status < 300) {
resolve({ status: xhr.status, headers: headers, body: body });
} else {
reject({ status: xhr.status, description: xhr.statusText, headers: headers, body: body });
}
};
for (var headerName in params.headers) {
xhr.setRequestHeader(headerName, params.headers[headerName]);
if (headerName === 'Content-Type' && params.headers[headerName] === 'application/json') {
params.body = (0, _stringify2.default)(params.body);
}
}
xhr.send(params.body);
});
}
/**
* Sugar function for request('GET', params);
* @param {Object} params - Request parameters
* @returns {Promise}
*/
}, {
key: 'get',
value: function get(params) {
return this.request('GET', params);
}
/**
* Sugar function for request('POST', params);
* @param {Object} params - Request parameters
* @returns {Promise}
*/
}, {
key: 'post',
value: function post(params) {
return this.request('POST', params);
}
/**
* Sugar function for request('PUT', params);
* @param {Object} params - Request parameters
* @returns {Promise}
*/
}, {
key: 'put',
value: function put(params) {
return this.request('PUT', params);
}
/**
* Sugar function for request('DELETE', params);
* @param {Object} params - Request parameters
* @returns {Promise}
*/
}, {
key: 'delete',
value: function _delete(params) {
return this.request('DELETE', params);
}
}]);
return Request;
}();
exports.default = Request;
module.exports = Request;
module.exports = exports['default'];
},{"babel-runtime/core-js/json/stringify":34,"babel-runtime/core-js/object/define-property":40,"babel-runtime/core-js/promise":45,"xmlhttprequest":70}],273:[function(_dereq_,module,exports){
'use strict';
var _promise = _dereq_("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault2(_promise);
var _map = _dereq_("babel-runtime/core-js/map");
var _map2 = _interopRequireDefault2(_map);
var _defineProperties = _dereq_("babel-runtime/core-js/object/define-properties");
var _defineProperties2 = _interopRequireDefault2(_defineProperties);
var _keys = _dereq_("babel-runtime/core-js/object/keys");
var _keys2 = _interopRequireDefault2(_keys);
var _getPrototypeOf = _dereq_("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault2(_getPrototypeOf);
var _from = _dereq_("babel-runtime/core-js/array/from");
var _from2 = _interopRequireDefault2(_from);
var _construct = _dereq_("babel-runtime/core-js/reflect/construct");
var _construct2 = _interopRequireDefault2(_construct);
var _setPrototypeOf = _dereq_("babel-runtime/core-js/object/set-prototype-of");
var _setPrototypeOf2 = _interopRequireDefault2(_setPrototypeOf);
var _create = _dereq_("babel-runtime/core-js/object/create");
var _create2 = _interopRequireDefault2(_create);
var _typeof2 = _dereq_("babel-runtime/helpers/typeof");
var _typeof3 = _interopRequireDefault2(_typeof2);
var _defineProperty = _dereq_("babel-runtime/core-js/object/define-property");
var _defineProperty2 = _interopRequireDefault2(_defineProperty);
function _interopRequireDefault2(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TwilsockUnavailableError = exports.Transport = undefined;
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;(0, _defineProperty2.default)(target, descriptor.key, descriptor);
}
}return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
};
}();
var _httprequest = _dereq_('./httprequest');
var _httprequest2 = _interopRequireDefault(_httprequest);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}return call && ((typeof call === "undefined" ? "undefined" : (0, _typeof3.default)(call)) === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : (0, _typeof3.default)(superClass)));
}subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass;
}
function _extendableBuiltin(cls) {
function ExtendableBuiltin() {
var instance = (0, _construct2.default)(cls, (0, _from2.default)(arguments));
(0, _setPrototypeOf2.default)(instance, (0, _getPrototypeOf2.default)(this));
return instance;
}
ExtendableBuiltin.prototype = (0, _create2.default)(cls.prototype, {
constructor: {
value: cls,
enumerable: false,
writable: true,
configurable: true
}
});
if (_setPrototypeOf2.default) {
(0, _setPrototypeOf2.default)(ExtendableBuiltin, cls);
} else {
ExtendableBuiltin.__proto__ = cls;
}
return ExtendableBuiltin;
}
function parseUri(uri) {
var match = uri.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)(\/[^?#]*)(\?[^#]*|)(#.*|)$/);
if (match) {
var uriStruct = {
protocol: match[1],
host: match[2],
hostname: match[3],
port: match[4],
pathname: match[5],
search: match[6],
hash: match[7]
};
if (uriStruct.search.length > 0) {
var paramsString = uriStruct.search.substring(1);
uriStruct.params = paramsString.split('&').map(function (el) {
return el.split('=');
}).reduce(function (prev, curr) {
if (!prev.hasOwnProperty(curr[0])) {
prev[curr[0]] = curr[1];
} else if (Array.isArray(prev[curr[0]])) {
prev[curr[0]].push(curr[1]);
} else {
prev[curr[0]] = [prev[curr[0]], curr[1]];
}
return prev;
}, {});
}
return uriStruct;
}
throw new Error('Incorrect URI: ' + uri);
}
function twilsockAddress(method, uri) {
var parsedUri = parseUri(uri);
var to = {
method: method,
host: parsedUri.host,
path: parsedUri.pathname
};
if (parsedUri.params) {
to.params = parsedUri.params;
}
return to;
}
function twilsockParams(type, uri, headers, body) {
return {
to: twilsockAddress(type, uri),
headers: headers,
body: body
};
}
function adaptTwilsockResponse(response) {
return { status: response.header.http_status,
headers: response.header.http_headers,
body: response.body };
}
function httpParams(uri, headers, body) {
return {
url: uri,
headers: headers,
body: body
};
}
function adaptHttpResponse(response) {
try {
response.body = JSON.parse(response.body);
} catch (e) {} // eslint-disable-line no-empty
return response;
}
/**
* By RFC header names are case-insensitive
* though it is much easier to work with them in code
* when they have any specific case.
* So we forcefully lowercase all headers
*/
function lowercaseHeaders(response) {
var keys = (0, _keys2.default)(response.headers);
var n = keys.length;
var headers = {};
while (n--) {
var key = keys[n];
headers[key.toLowerCase()] = response.headers[key];
}
response.headers = headers;
return response;
}
/**
* Transport specific error.
* Being fired when twilsock-only transmission requested but not available
* @inherits Error
*/
var TwilsockUnavailableError = function (_extendableBuiltin2) {
_inherits(TwilsockUnavailableError, _extendableBuiltin2);
function TwilsockUnavailableError() {
_classCallCheck(this, TwilsockUnavailableError);
return _possibleConstructorReturn(this, (TwilsockUnavailableError.__proto__ || (0, _getPrototypeOf2.default)(TwilsockUnavailableError)).call(this));
}
return TwilsockUnavailableError;
}(_extendableBuiltin(Error));
/**
* Provides generic network interface
*/
var Transport = function () {
function Transport(twilsock) {
var _this2 = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Transport);
(0, _defineProperties2.default)(this, {
_activeGetRequests: { value: new _map2.default() },
_twilsock: { value: twilsock },
_http: { value: _httprequest2.default },
_twilsockIsAvailable: { get: function get() {
return _this2._twilsock && _this2._twilsock.isConnected;
} },
_concurrentHttpRequestLimit: { value: options.concurrentHttpRequestLimit || Infinity },
_concurrentHttpRequestCount: { value: 0, writable: true },
_requestQueue: { value: [] }
});
if (twilsock) {
twilsock.connect();
twilsock.on('connected', function () {
return _this2._processQueuedRequests();
});
}
}
/**
* Make a GET request by given URI
*
* This function applies "multiplexing" optimization.
* If several requests for the same URI happen on the same time,
* only one will really happen, but all clients will see th result.
*
* @Returns Promise Result of successful get request
*/
_createClass(Transport, [{
key: 'get',
value: function get(uri, headers, forceTwilsock) {
var _this3 = this;
if (this._activeGetRequests.has(uri)) {
return this._activeGetRequests.get(uri);
}
var promise = this._get(uri, headers, forceTwilsock).then(function (response) {
_this3._activeGetRequests.delete(uri);
return response;
}).catch(function (error) {
_this3._activeGetRequests.delete(uri);
throw error;
});
this._activeGetRequests.set(uri, promise);
return promise;
}
/**
* @private
*/
}, {
key: '_oneOfBasedOnChannelAvailability',
value: function _oneOfBasedOnChannelAvailability(sendingOptions, forceTwilsock) {
var _this4 = this;
var requestVia = function requestVia(paths) {
var sendViaTwilsock = paths.sendViaTwilsock,
sendDirectHttp = paths.sendDirectHttp;
if (_this4._twilsockIsAvailable) {
return sendViaTwilsock();
} else if (forceTwilsock) {
return _promise2.default.reject(new TwilsockUnavailableError());
} else if (_this4._concurrentHttpRequestCount >= _this4._concurrentHttpRequestLimit) {
return new _promise2.default(function (resolve, reject) {
return _this4._requestQueue.push({ sendingOptions: sendingOptions, resolve: resolve, reject: reject });
});
}
_this4._concurrentHttpRequestCount++;
return sendDirectHttp().then(function (r) {
_this4._concurrentHttpRequestCount--;
_this4._processQueuedRequests();
return r;
}).catch(function (err) {
_this4._concurrentHttpRequestCount--;
_this4._processQueuedRequests();
throw err;
});
};
return requestVia(sendingOptions).then(lowercaseHeaders);
}
/**
* @private
*/
}, {
key: '_processQueuedRequests',
value: function _processQueuedRequests() {
while (this._requestQueue.length > 0 && (this._twilsockIsAvailable || this._concurrentHttpRequestCount < this._concurrentHttpRequestLimit)) {
var r = this._requestQueue.shift();
this._oneOfBasedOnChannelAvailability(r.sendingOptions, false).then(r.resolve).catch(r.reject);
}
}
/**
* @private
*/
}, {
key: '_get',
value: function _get(uri, headers, forceTwilsock) {
var _this5 = this;
return this._oneOfBasedOnChannelAvailability({
sendViaTwilsock: function sendViaTwilsock() {
return _this5._twilsock.send(twilsockParams('GET', uri, headers)).then(adaptTwilsockResponse);
},
sendDirectHttp: function sendDirectHttp() {
return _this5._http.get(httpParams(uri, headers)).then(adaptHttpResponse);
}
}, forceTwilsock);
}
/**
* Make a POST request by given URI
* @returns {Promise} Result of successful request
*/
}, {
key: 'post',
value: function post(uri, headers, body, forceTwilsock) {
var _this6 = this;
return this._oneOfBasedOnChannelAvailability({
sendViaTwilsock: function sendViaTwilsock() {
return _this6._twilsock.send(twilsockParams('POST', uri, headers, body)).then(adaptTwilsockResponse);
},
sendDirectHttp: function sendDirectHttp() {
return _this6._http.post(httpParams(uri, headers, body)).then(adaptHttpResponse);
}
}, forceTwilsock);
}
/**
* Make a PUT request by given URI
* @returns Promise Result of successful request
*/
}, {
key: 'put',
value: function put(uri, headers, body, forceTwilsock) {
var _this7 = this;
return this._oneOfBasedOnChannelAvailability({
sendViaTwilsock: function sendViaTwilsock() {
return _this7._twilsock.send(twilsockParams('PUT', uri, headers, body)).then(adaptTwilsockResponse);
},
sendDirectHttp: function sendDirectHttp() {
return _this7._http.put(httpParams(uri, headers, body)).then(adaptHttpResponse);
}
}, forceTwilsock);
}
/**
* Make a DELETE request by given URI
* @returns {Promise} Result of successful request
*/
}, {
key: 'delete',
value: function _delete(uri, headers, forceTwilsock) {
var _this8 = this;
return this._oneOfBasedOnChannelAvailability({
sendViaTwilsock: function sendViaTwilsock() {
return _this8._twilsock.send(twilsockParams('DELETE', uri, headers)).then(adaptTwilsockResponse);
},
sendDirectHttp: function sendDirectHttp() {
return _this8._http.delete(httpParams(uri, headers)).then(adaptHttpResponse);
}
}, forceTwilsock);
}
}]);
return Transport;
}();
exports.default = Transport;
exports.Transport = Transport;
exports.TwilsockUnavailableError = TwilsockUnavailableError;
},{"./httprequest":272,"babel-runtime/core-js/array/from":31,"babel-runtime/core-js/map":35,"babel-runtime/core-js/object/create":38,"babel-runtime/core-js/object/define-properties":39,"babel-runtime/core-js/object/define-property":40,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/object/keys":43,"babel-runtime/core-js/object/set-prototype-of":44,"babel-runtime/core-js/promise":45,"babel-runtime/core-js/reflect/construct":46,"babel-runtime/helpers/typeof":56}],274:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _freeze = _dereq_('babel-runtime/core-js/object/freeze');
var _freeze2 = _interopRequireDefault(_freeze);
var _set = _dereq_('babel-runtime/core-js/set');
var _set2 = _interopRequireDefault(_set);
var _promise = _dereq_('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _map = _dereq_('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _defineProperties = _dereq_('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _events = _dereq_('events');
var _events2 = _interopRequireDefault(_events);
var _logger = _dereq_('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _uuid = _dereq_('uuid');
var _uuid2 = _interopRequireDefault(_uuid);
var _configuration = _dereq_('./configuration');
var _configuration2 = _interopRequireDefault(_configuration);
var _twilsock = _dereq_('./twilsock');
var _twilsock2 = _interopRequireDefault(_twilsock);
var _packetinterface = _dereq_('./packetinterface');
var _packetinterface2 = _interopRequireDefault(_packetinterface);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
/**
* @class
* @alias Twilsock
* @classdesc Client library for the Twilsock protocol
* @property {Boolean} connected Indicates the twilsock connection state
*
* @constructor
* @param {string} Token Twilio access token
*/
var TwilsockClient = function (_EventEmitter) {
(0, _inherits3.default)(TwilsockClient, _EventEmitter);
function TwilsockClient(token, options) {
(0, _classCallCheck3.default)(this, TwilsockClient);
var _this = (0, _possibleConstructorReturn3.default)(this, (TwilsockClient.__proto__ || (0, _getPrototypeOf2.default)(TwilsockClient)).call(this));
options = options || {};
options.logLevel = options.logLevel || 'error';
_logger2.default.setLevel(options.logLevel);
var config = new _configuration2.default(token, options);
var twilsock = new _twilsock2.default(config);
var packetInterface = new _packetinterface2.default(twilsock);
(0, _defineProperties2.default)(_this, {
_config: { value: config },
_socket: { value: twilsock },
_packet: { value: packetInterface },
_registrations: { value: new _map2.default() },
_registrationsInProgress: { value: new _map2.default() },
isConnected: { get: function get() {
return _this._socket.isConnected;
} },
connected: { get: function get() {
return _this._socket.isConnected;
} },
state: { get: function get() {
return _this._socket.state;
} }
});
_this._socket.on('message', function (type, message) {
return setTimeout(function () {
_this.emit('message', type, message);
}, 0);
});
_this._socket.on('connected', function () {
return _this._updateRegistrations();
});
_this._socket.on('connected', function () {
return _this.emit('connected');
});
_this._socket.on('disconnected', function () {
return _this.emit('disconnected');
});
_this._socket.on('stateChanged', function (state) {
return _this.emit('stateChanged', state);
});
return _this;
}
/**
* Send a message
* @param {Twilsock#Message} message Message structure with header, body and remote address
* @public
* @returns {Promise} Result from remote side
*/
(0, _createClass3.default)(TwilsockClient, [{
key: 'send',
value: function send(message) {
return this._packet.send(message.to, message.headers, message.body);
}
/**
* Update token
* @param {String} token
* @public
*/
}, {
key: 'updateToken',
value: function updateToken(token) {
_logger2.default.info('updateToken');
if (this._config.token === token) {
return _promise2.default.resolve();
}
this._config.updateToken(token);
this._socket.updateToken();
return _promise2.default.resolve();
}
}, {
key: '_updateRegistration',
value: function _updateRegistration(contextId, context) {
var _this2 = this;
_logger2.default.info('update registration for context', contextId);
var registrationAttempts = this._registrationsInProgress.get(contextId);
if (!registrationAttempts) {
registrationAttempts = new _set2.default();
this._registrationsInProgress.set(contextId, registrationAttempts);
}
var attemptId = _uuid2.default.v4();
registrationAttempts.add(attemptId);
return this._packet.putNotificationContext(contextId, context).then(function () {
_logger2.default.info('registration attempt succeeded for context', context);
registrationAttempts.delete(attemptId);
// Hack for broken react-native polyfill
// Remove when not needed anymore
var attemptsSize = typeof registrationAttempts.size !== 'undefined' ? registrationAttempts.size : (registrationAttempts._c || {}).size;
if (attemptsSize === 0) {
_this2._registrationsInProgress.delete(contextId);
_this2.emit('registered', contextId);
}
}).catch(function (err) {
_logger2.default.info('registration attempt failed for context', context);
_logger2.default.debug(err);
registrationAttempts.delete(attemptId);
// Hack for broken react-native polyfill
// Remove when not needed anymore
var attemptsSize = typeof registrationAttempts.size !== 'undefined' ? registrationAttempts.size : (registrationAttempts._c || {}).size;
if (attemptsSize === 0) {
_this2._registrationsInProgress.delete(contextId);
_this2.emit('registrationFailed', contextId, err);
}
});
}
}, {
key: '_updateRegistrations',
value: function _updateRegistrations() {
var _this3 = this;
_logger2.default.info('refreshing all registrations');
this._registrations.forEach(function (context, id) {
_this3._updateRegistration(id, context);
});
}
}, {
key: 'setNotificationsContext',
value: function setNotificationsContext(contextId, context) {
if (!contextId || !context) {
throw new Error('Invalid arguments provided');
}
this._registrations.set(contextId, context);
if (this._socket.isConnected) {
this._updateRegistration(contextId, context);
}
}
}, {
key: 'removeNotificationsContext',
value: function removeNotificationsContext(contextId) {
if (!this._registrations.has(contextId)) {
return;
}
this._registrations.delete(contextId);
if (this._socket.isConnected) {
this._packet.deleteNotificationContext(contextId);
}
}
/**
* Connect to the server
* @fires TwilsockClient#connected
* @public
*/
}, {
key: 'connect',
value: function connect() {
return this._socket.connect();
}
/**
* Connect to the server
* @fires TwilsockClient#disconnected
* @public
*/
}, {
key: 'disconnect',
value: function disconnect() {
return this._socket.disconnect();
}
}]);
return TwilsockClient;
}(_events2.default);
exports.default = TwilsockClient;
(0, _freeze2.default)(TwilsockClient);
/**
* Twilsock destination address descriptor
* @typedef {Object} Twilsock#Address
* @property {String} method - HTTP method. (POST, PUT, etc)
* @property {String} host - host name without path. (e.g. my.company.com)
* @property {String} path - path on the host (e.g. /my/app/to/call.php)
*/
/**
* Twilsock upstream message
* @typedef {Object} Twilsock#Message
* @property {Twilsock#Address} to - destination address
* @property {Object} headers - HTTP headers
* @property {Object} body - Body
*/
/**
* Fired when new message received
* @param {Object} message
* @event TwilsockClient#message
*/
/**
* Fired when socket connected
* @param {String} URI of endpoint
* @event TwilsockClient#connected
*/
/**
* Fired when socket disconnected
* @event TwilsockClient#disconnected
*/
module.exports = exports['default'];
},{"./configuration":275,"./logger":277,"./packetinterface":278,"./twilsock":279,"babel-runtime/core-js/map":35,"babel-runtime/core-js/object/define-properties":39,"babel-runtime/core-js/object/freeze":41,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/promise":45,"babel-runtime/core-js/set":47,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"events":214,"uuid":283}],275:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperties = _dereq_('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var TWILSOCK_URI = 'wss://tsock.twilio.com';
var TWILSOCK_PATH = '/v3/wsconnect';
/**
* @param {String} token - authentication token
* @param {Object} options - options to override defaults
*
* @class TwilsockConfig
* @classdesc Settings container for the Twilsock client library
*/
var TwilsockConfig = function () {
function TwilsockConfig(token, options) {
var _this = this;
(0, _classCallCheck3.default)(this, TwilsockConfig);
options = options || {};
var _options = options.Twilsock || {};
var twilsockUri = _options.uri || options.wsServer || TWILSOCK_URI;
(0, _defineProperties2.default)(this, {
_twilsockWsHost: { value: twilsockUri + TWILSOCK_PATH },
_token: { value: token, writable: true },
twilsockUri: { get: function get() {
return _this._twilsockWsHost;
} },
token: { get: function get() {
return _this._token;
} }
});
}
(0, _createClass3.default)(TwilsockConfig, [{
key: 'updateToken',
value: function updateToken(token) {
this._token = token;
}
}]);
return TwilsockConfig;
}();
exports.default = TwilsockConfig;
module.exports = exports['default'];
},{"babel-runtime/core-js/object/define-properties":39,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],276:[function(_dereq_,module,exports){
arguments[4][242][0].apply(exports,arguments)
},{"./client":274,"dup":242}],277:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _from = _dereq_('babel-runtime/core-js/array/from');
var _from2 = _interopRequireDefault(_from);
var _loglevel = _dereq_('loglevel');
var _loglevel2 = _interopRequireDefault(_loglevel);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
function prepareLine(prefix, args) {
return [prefix].concat((0, _from2.default)(args));
}
exports.default = {
setLevel: function setLevel(level) {
_loglevel2.default.setLevel(level);
},
trace: function trace() {
_loglevel2.default.trace.apply(null, prepareLine('Twilsock T:', arguments));
},
debug: function debug() {
_loglevel2.default.debug.apply(null, prepareLine('Twilsock D:', arguments));
},
info: function info() {
_loglevel2.default.info.apply(null, prepareLine('Twilsock I:', arguments));
},
warn: function warn() {
_loglevel2.default.warn.apply(null, prepareLine('Twilsock W:', arguments));
},
error: function error() {
_loglevel2.default.error.apply(null, prepareLine('Twilsock E:', arguments));
}
};
module.exports = exports['default'];
},{"babel-runtime/core-js/array/from":31,"loglevel":219}],278:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _promise = _dereq_('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _map = _dereq_('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _defineProperties = _dereq_('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _logger = _dereq_('./logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var REQUEST_TIMEOUT = 30000;
function isHttpSuccess(code) {
return code >= 200 && code < 300;
}
function isHttpReply(packet) {
return packet && packet.header && packet.header.http_status;
}
var PacketInterface = function () {
function PacketInterface(socket) {
var _this = this;
(0, _classCallCheck3.default)(this, PacketInterface);
(0, _defineProperties2.default)(this, {
_activeRequests: { value: new _map2.default() },
_socket: { value: socket }
});
this._socket.on('reply', this._processReply.bind(this));
this._socket.on('disconnected', function () {
_this._activeRequests.forEach(function (descriptor) {
clearTimeout(descriptor.timeout);
descriptor.reject(new Error('Twilsock disconnected'));
});
_this._activeRequests.clear();
});
}
(0, _createClass3.default)(PacketInterface, [{
key: '_processReply',
value: function _processReply(reply) {
var request = this._activeRequests.get(reply.id);
if (request) {
clearTimeout(request.timeout);
this._activeRequests.delete(reply.id);
setTimeout(function () {
// User shouldn't intercept connection handling, thus making it asynchronous
if (!isHttpSuccess(reply.status.code)) {
request.reject(new Error('Transport failure: ' + reply.status.status));
} else if (isHttpReply(reply) && !isHttpSuccess(reply.header.http_status.code)) {
request.reject({
status: reply.header.http_status.code,
description: reply.header.http_status.status,
body: reply.body
});
} else {
request.resolve(reply);
}
}, 0);
}
}
}, {
key: '_storeRequest',
value: function _storeRequest(id, resolve, reject) {
var requestDescriptor = {
resolve: resolve,
reject: reject,
timeout: setTimeout(function () {
_logger2.default.debug('request', id, 'is timed out');
reject(new Error('Twilsock: request timeout: ' + id));
}, REQUEST_TIMEOUT)
};
this._activeRequests.set(id, requestDescriptor);
}
}, {
key: 'send',
value: function send(address, headers, body) {
var _this2 = this;
return new _promise2.default(function (resolve, reject) {
if (!_this2._socket.isConnected) {
_logger2.default.info('Can not send upstream message. Twilsock is not in connected state');
reject(new Error('Twilsock is not connected'));
}
var id = _this2._socket.sendUpstreamMessage(address, headers, body);
_logger2.default.trace('message sent: ', { id: id, address: address, headers: headers, body: body });
_this2._storeRequest(id, resolve, reject);
});
}
}, {
key: 'putNotificationContext',
value: function putNotificationContext(contextId, context) {
var _this3 = this;
return new _promise2.default(function (resolve, reject) {
if (!_this3._socket.isConnected) {
_logger2.default.info('Can not send put notification context. Twilsock is not in connected state');
reject(new Error('Twilsock is not connected'));
}
var header = { method: 'put_notification_ctx', notification_ctx_id: contextId }; // eslint-disable-line camelcase
var id = _this3._socket.send(header, context);
_this3._storeRequest(id, resolve, reject);
});
}
}, {
key: 'deleteNotificationContext',
value: function deleteNotificationContext(contextId) {
var _this4 = this;
return new _promise2.default(function (resolve, reject) {
if (!_this4._socket.isConnected) {
_logger2.default.info('Can not send delete notification context. Twilsock is not in connected state');
reject(new Error('Twilsock is not connected'));
}
var packet = { method: 'delete_notification_ctx', notification_ctx_id: contextId }; // eslint-disable-line camelcase
var id = _this4._socket.send(packet);
_this4._storeRequest(id, resolve, reject);
});
}
}, {
key: 'shutdown',
value: function shutdown() {
this._activeRequests.forEach(function (descriptor) {
clearTimeout(descriptor.timeout);
descriptor.reject(new Error('Twilsock: request cancelled by user'));
});
this._activeRequests.clear();
}
}]);
return PacketInterface;
}();
exports.default = PacketInterface;
module.exports = exports['default'];
},{"./logger":277,"babel-runtime/core-js/map":35,"babel-runtime/core-js/object/define-properties":39,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51}],279:[function(_dereq_,module,exports){
(function (global){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _freeze = _dereq_('babel-runtime/core-js/object/freeze');
var _freeze2 = _interopRequireDefault(_freeze);
var _promise = _dereq_('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _slicedToArray2 = _dereq_('babel-runtime/helpers/slicedToArray');
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
var _getIterator2 = _dereq_('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _map = _dereq_('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _defineProperties = _dereq_('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = _dereq_('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = _dereq_('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _stringify = _dereq_('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _typeof2 = _dereq_('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _events = _dereq_('events');
var _events2 = _interopRequireDefault(_events);
var _logger = _dereq_('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _uuid = _dereq_('uuid');
var _uuid2 = _interopRequireDefault(_uuid);
var _backoff = _dereq_('backoff');
var _backoff2 = _interopRequireDefault(_backoff);
var _javascriptStateMachine = _dereq_('javascript-state-machine');
var _javascriptStateMachine2 = _interopRequireDefault(_javascriptStateMachine);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var WebSocket = global.WebSocket || global.MozWebSocket || _dereq_('ws');
var ACTIVITY_CHECK_INTERVAL = 5000;
var ACTIVITY_TIMEOUT = 43000;
var INIT_TIMEOUT = 5000;
var UPDATE_TIMEOUT = 5000;
var DISCONNECTING_TIMEOUT = 3000;
function byteLength(s) {
var escstr = encodeURIComponent(s);
var binstr = escstr.replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
});
return binstr.length;
}
function stringToUint8Array(s) {
var escstr = encodeURIComponent(s);
var binstr = escstr.replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
});
var ua = new Uint8Array(binstr.length);
Array.prototype.forEach.call(binstr, function (ch, i) {
ua[i] = ch.charCodeAt(0);
});
return ua;
}
function uint8ArrayToString(ua) {
var binstr = Array.prototype.map.call(ua, function (ch) {
return String.fromCharCode(ch);
}).join('');
var escstr = binstr.replace(/(.)/g, function (m, p) {
var code = p.charCodeAt(0).toString(16).toUpperCase();
if (code.length < 2) {
code = '0' + code;
}
return '%' + code;
});
return decodeURIComponent(escstr);
}
function getMagic(buffer) {
var strMagic = '';
var idx = 0;
for (; idx < buffer.length; ++idx) {
var chr = String.fromCharCode(buffer[idx]);
strMagic += chr;
if (chr === '\r') {
idx += 2;
break;
}
}
var magics = strMagic.split(' ');
return {
size: idx,
protocol: magics[0],
version: magics[1],
headerSize: Number(magics[2])
};
}
/**
* Makes sure that body is properly stringified
*/
function preparePayload(payload) {
switch (typeof payload === 'undefined' ? 'undefined' : (0, _typeof3.default)(payload)) {
case 'undefined':
return '';
case 'object':
return (0, _stringify2.default)(payload);
default:
return payload;
}
}
/**
* @param {Uint8Array} array
* @returns {Object}
*/
function getJsonObject(array) {
var str = uint8ArrayToString(array);
try {
return JSON.parse(str);
} catch (e) {
_logger2.default.error('failed to parse input: ', str);
throw e;
}
}
/**
* @class TwilsockChannel
* @classdesc Twilsock connection
*
* @param config
*/
var TwilsockChannel = function (_EventEmitter) {
(0, _inherits3.default)(TwilsockChannel, _EventEmitter);
function TwilsockChannel(config) {
(0, _classCallCheck3.default)(this, TwilsockChannel);
var _this = (0, _possibleConstructorReturn3.default)(this, (TwilsockChannel.__proto__ || (0, _getPrototypeOf2.default)(TwilsockChannel)).call(this));
if (config.logLevel) {
_logger2.default.setLevel(config.logLevel);
}
var backoff = _backoff2.default.exponential({
randomisationFactor: 0.2,
initialDelay: 2 * 1000,
maxDelay: 2 * 60 * 1000
});
backoff.on('ready', function () {
_this._retry();
});
_this.on('reply', function (reply) {
_this._processReply(reply);
});
(0, _defineProperties2.default)(_this, {
_config: { value: config },
_transportReady: { value: false, writable: true },
_disconnectedPromiseResolve: { value: null, writable: true },
_backoffDefault: { value: backoff },
_backoff: { value: backoff, writable: true },
_fsm: { value: null, writable: true },
_watchTimer: { value: null, writable: true },
_timestamp: { value: 0, writable: true },
_socket: { value: null, writable: true },
_activeToken: { value: null, writable: true },
activeToken: { enumerable: true, get: function get() {
return _this._activeToken;
} },
state: { enumberable: true, get: function get() {
return _this._getState();
} },
isConnected: { enumberable: true, get: function get() {
return _this._isConnected();
} },
_activeRequests: { value: new _map2.default() },
_disconnectingTimer: { value: null, writable: true },
_isDeferredUpdate: { value: false, writable: true }
});
_this._fsm = _javascriptStateMachine2.default.create({
initial: 'disconnected',
events: [{ name: 'userConnect', from: ['disconnected', 'rejected'], to: 'connecting' }, { name: 'userConnect', from: ['connecting', 'connected'] }, // ignore event
{ name: 'userDisconnect', from: ['connecting', 'initialising', 'connected', 'updating', 'retrying', 'rejected', 'waitSocketClosed', 'waitOffloadSocketClosed'], to: 'disconnecting' }, { name: 'userRetry', from: ['retrying'], to: 'connecting' }, { name: 'socketConnected', from: ['connecting'], to: 'initialising' }, { name: 'socketClosed', from: ['connecting', 'initialising', 'connected', 'updating', 'error', 'waitOffloadSocketClosed'], to: 'retrying' }, { name: 'socketClosed', from: ['disconnecting'], to: 'disconnected' }, { name: 'socketClosed', from: ['waitSocketClosed'], to: 'disconnected' }, { name: 'socketClosed', from: ['rejected'], to: 'rejected' }, { name: 'initSuccess', from: ['initialising'], to: 'connected' }, { name: 'initError', from: ['initialising'], to: 'error' }, { name: 'tokenRejected', from: ['initialising', 'updating'], to: 'rejected' }, { name: 'protocolError', from: ['initialising', 'connected', 'updating'], to: 'error' }, { name: 'receiveClose', from: ['initialising', 'connected', 'updating'], to: 'waitSocketClosed' }, { name: 'receiveOffload', from: ['initialising', 'connected', 'updating'], to: 'waitOffloadSocketClosed' }, { name: 'unsupportedProtocol', from: ['initialising', 'connected', 'updating'], to: 'unsupported' }, { name: 'receiveFatalClose', from: ['initialising', 'connected', 'updating'], to: 'unsupported' }, { name: 'userUpdateToken', from: ['disconnected', 'rejected', 'connecting', 'retrying'], to: 'connecting' }, { name: 'userUpdateToken', from: ['connected'], to: 'updating' }, { name: 'updateSuccess', from: ['updating'], to: 'connected' }, { name: 'updateError', from: ['updating'], to: 'error' }],
callbacks: {
onconnecting: function onconnecting() {
_this._startWatchdogTimer();
_this._setupSocket();
_this.emit('connecting');
},
onenterinitialising: function onenterinitialising() {
_this._sendInit();
},
onleaveinitialising: function onleaveinitialising() {
_this._cancelInit();
},
onenterupdating: function onenterupdating() {
_this._sendUpdate();
},
onleaveupdating: function onleaveupdating() {
_this._cancelUpdate();
},
onenterretrying: function onenterretrying() {
_this._initRetry();
_this.emit('connecting');
},
onenterconnected: function onenterconnected() {
_this._resetBackoff();
_this._onConnected();
},
onuserUpdateToken: function onuserUpdateToken() {
_this._resetBackoff();
},
ontokenRejected: function ontokenRejected() {
_this._resetBackoff();
_this._closeSocket();
_this._finalizeSocket();
},
onuserDisconnect: function onuserDisconnect() {
_this._closeSocket();
},
onenterdisconnecting: function onenterdisconnecting() {
_this._startDisconnectTimer();
},
onleavedisconnecting: function onleavedisconnecting() {
_this._cancelDisconnectTimer();
},
onenterwaitSocketClosed: function onenterwaitSocketClosed() {
_this._startDisconnectTimer();
},
onleavewaitSocketClosed: function onleavewaitSocketClosed() {
_this._cancelDisconnectTimer();
},
onenterwaitOffloadSocketClosed: function onenterwaitOffloadSocketClosed() {
_this._startDisconnectTimer();
},
onleavewaitOffloadSocketClosed: function onleavewaitOffloadSocketClosed() {
_this._cancelDisconnectTimer();
},
ondisconnected: function ondisconnected() {
_this._resetBackoff();
_this._finalizeSocket();
},
onreceiveClose: function onreceiveClose(event, from, to, args) {
_logger2.default.debug('onreceiveClose: ', args);
_this._onCloseReceived(args);
},
onreceiveOffload: function onreceiveOffload(event, from, to, args) {
_logger2.default.debug('onreceiveoffload: ', args);
_this._modifyBackoff(args.body);
_this._onCloseReceived(args.status);
},
onunsupported: function onunsupported() {
_this._closeSocket();
_this._finalizeSocket();
},
onerror: function onerror() {
_this._closeSocket();
_this._finalizeSocket();
},
onenterstate: function onenterstate(event, from, to) {
_this._changeState(event, from, to);
}
},
error: function error() {
_logger2.default.warn('FSM: unexpected transition', arguments);
}
});
return _this;
}
(0, _createClass3.default)(TwilsockChannel, [{
key: '_changeState',
value: function _changeState(event, from, to) {
var _this2 = this;
_logger2.default.debug('FSM: ', event, ': ', from, '>>', to);
this.emit('stateChanged', this.state);
if (this._isDeferredUpdate) {
this._isDeferredUpdate = false;
setTimeout(function () {
_this2.updateToken();
}, 0);
}
}
}, {
key: '_resetBackoff',
value: function _resetBackoff() {
_logger2.default.trace('_resetBackoff');
this._backoff = this._backoffDefault;
this._backoff.reset();
}
}, {
key: '_modifyBackoff',
value: function _modifyBackoff(body) {
_logger2.default.trace('_modifyBackoff', body);
var backoffPolicy = body ? body.backoff_policy : null;
if (backoffPolicy) {
var min = backoffPolicy.reconnect_min_ms || 2 * 1000;
var max = backoffPolicy.reconnect_max_ms || 2 * 60 * 1000;
_logger2.default.debug('new backoff policy', min, max);
this._backoff = _backoff2.default.exponential({
randomisationFactor: 0.2,
initialDelay: min,
maxDelay: max
});
}
}
}, {
key: '_startDisconnectTimer',
value: function _startDisconnectTimer() {
var _this3 = this;
_logger2.default.trace('_startDisconnectTimer');
if (this._disconnectingTimer) {
clearTimeout(this._disconnectingTimer);
this._disconnectingTimer = null;
}
this._disconnectingTimer = setTimeout(function () {
_logger2.default.debug('disconnecting is timed out');
_this3._closeSocket();
}, DISCONNECTING_TIMEOUT);
}
}, {
key: '_cancelDisconnectTimer',
value: function _cancelDisconnectTimer() {
_logger2.default.trace('_cancelDisconnectTimer');
if (this._disconnectingTimer) {
clearTimeout(this._disconnectingTimer);
this._disconnectingTimer = null;
}
}
}, {
key: '_processReply',
value: function _processReply(reply) {
_logger2.default.debug('receive reply:', reply);
var request = this._activeRequests.get(reply.id);
if (request) {
clearTimeout(request.timeout);
this._activeRequests.delete(reply.id);
switch (request.reqType) {
case 'init':
if (reply.status.code >= 200 && reply.status.code < 300) {
this._fsm.initSuccess(reply.body);
} else if (reply.status.code === 401 || reply.status.code === 403) {
this._fsm.tokenRejected(reply.status);
} else if (reply.status.code === 429) {
this._modifyBackoff(reply.body);
this._fsm.initError(reply.status);
} else {
this._fsm.initError(reply.status);
}
break;
case 'update':
if (reply.status.code >= 200 && reply.status.code < 300) {
this._fsm.updateSuccess(reply.body);
} else if (reply.status.code === 401 || reply.status.code === 403) {
this._fsm.tokenRejected(reply.status);
} else if (reply.status.code === 429) {
this._modifyBackoff(reply.body);
this._fsm.updateError(reply.status);
} else {
this._fsm.updateError(reply.status);
}
break;
default:
_logger2.default.error('unexpected reply');
}
}
}
}, {
key: '_storeRequest',
value: function _storeRequest(id, type, timeoutMs) {
var _this4 = this;
_logger2.default.trace('_storeRequest');
var requestDescriptor = {
reqType: type,
timeout: setTimeout(function () {
_logger2.default.debug('request', type, ': ', id, 'is timed out');
if (type !== 'init' && type !== 'update') {
_logger2.default.error('unknown request type', type);
}
_this4._closeSocket();
}, timeoutMs)
};
this._activeRequests.set(id, requestDescriptor);
}
/**
* Checks if connection established
* @public
*/
}, {
key: '_isConnected',
value: function _isConnected() {
return this.state === TwilsockChannel.state.CONNECTED && this._socket && this._socket.readyState === 1;
}
/**
* @returns {Number} Connection state
* @public
*/
}, {
key: '_getState',
value: function _getState() {
if (!this._fsm) {
return TwilsockChannel.state.DISCONNECTED;
}
switch (this._fsm.current) {
case 'connecting':
case 'initialising':
case 'retrying':
case 'error':
return TwilsockChannel.state.CONNECTING;
case 'updating':
case 'connected':
return TwilsockChannel.state.CONNECTED;
case 'rejected':
return TwilsockChannel.state.REJECTED;
case 'disconnecting':
case 'waitSocketClosed':
case 'waitOffloadSocketClosed':
return TwilsockChannel.state.DISCONNECTING;
case 'disconnected':
default:
return TwilsockChannel.state.DISCONNECTED;
}
}
}, {
key: '_initRetry',
value: function _initRetry() {
_logger2.default.trace('_initRetry');
this._backoff.backoff();
}
}, {
key: '_retry',
value: function _retry() {
_logger2.default.trace('_retry');
this._socket = null;
this._activeToken = null;
this._fsm.userRetry();
}
}, {
key: '_onConnected',
value: function _onConnected() {
this.emit('connected');
}
}, {
key: '_finalizeSocket',
value: function _finalizeSocket() {
_logger2.default.trace('_finalizeSocket');
this._stopWatchdogTimer();
this._onDisconnected();
if (this._disconnectedPromiseResolve) {
var resolve = this._disconnectedPromiseResolve;
this._disconnectedPromiseResolve = null;
resolve();
}
}
}, {
key: '_onDisconnected',
value: function _onDisconnected() {
this._socket = null;
this._activeToken = null;
this.emit('disconnected');
}
}, {
key: '_setupSocket',
value: function _setupSocket() {
_logger2.default.trace('_setupSocket:', this._config.token);
var self = this;
var uri = this._config.twilsockUri;
_logger2.default.debug('try to connect to:', uri);
var socket = new WebSocket(uri);
socket.binaryType = 'arraybuffer';
socket.onopen = function () {
_logger2.default.info('socket opened');
self._fsm.socketConnected();
};
socket.onclose = function (e) {
_logger2.default.info('socket closed', e);
self._fsm.socketClosed();
};
socket.onerror = function (e) {
_logger2.default.error('error: ', e);
};
socket.onmessage = function (message) {
_logger2.default.trace('data: ', message.data);
var fieldMargin = 2;
var dataView = new Uint8Array(message.data);
var magic = getMagic(dataView);
if (magic.protocol !== 'TWILSOCK' || magic.version !== 'V3.0') {
_logger2.default.error('unsupported protocol: ' + magic.protocol + ' ver ' + magic.version);
self._fsm.unsupportedProtocol();
return;
}
var header = null;
try {
header = getJsonObject(dataView.subarray(magic.size, magic.size + magic.headerSize));
} catch (e) {
_logger2.default.error('failed to parse message header', e, message);
self._fsm.protocolError();
return;
}
_logger2.default.trace('message received: ', header);
var payload = null;
if (header.payload_size > 0) {
var payloadOffset = fieldMargin + magic.size + magic.headerSize;
var payloadSize = header.payload_size;
if (!header.hasOwnProperty('payload_type') || header.payload_type.indexOf('application/json') === 0) {
try {
payload = getJsonObject(dataView.subarray(payloadOffset, payloadOffset + payloadSize));
} catch (e) {
_logger2.default.error('failed to parse message body', e, message);
self._fsm.protocolError();
return;
}
} else if (header.payload_type.indexOf('text/plain') === 0) {
payload = uint8ArrayToString(dataView.subarray(payloadOffset, payloadOffset + payloadSize));
}
}
self._updateActivityTimestamp();
if (header.method === 'notification') {
self._confirmReceiving(header);
self.emit('message', header.message_type, payload);
} else if (header.method === 'reply') {
self.emit('reply', {
id: header.id,
status: header.status,
header: header,
body: payload
});
} else if (header.method === 'ping') {
self._confirmReceiving(header);
} else if (header.method === 'close') {
_logger2.default.trace('connection close initated by server');
self._confirmReceiving(header);
if (header.status.code === 308) {
_logger2.default.info('connection has been offloaded');
self._fsm.receiveOffload({ status: header.status.status, body: payload });
} else if (header.status.code === 406) {
// Not acceptable message
_logger2.default.error('connection has been rejected because server can not parse protocol');
self._fsm.receiveFatalClose();
} else if (header.status.code === 417) {
// Protocol error
_logger2.default.info('connection has been rejected because server could not understand client`s reply');
self._fsm.receiveFatalClose(header.status.status);
} else if (header.status.code === 410) {
// Expired connection
_logger2.default.info('connection has expired');
self._fsm.receiveClose(header.status.status);
} else if (header.status.code === 401) {
// Authentication fail
_logger2.default.info('connection is not authenticate');
self._fsm.receiveClose(header.status.status);
} else {
_logger2.default.error('unexpected close: ', header.status);
// Try to reconnect
self._fsm.receiveOffload({ status: header.status.status, body: null });
}
}
};
this._activeToken = this._config.token;
this._socket = socket;
}
}, {
key: '_sendInit',
value: function _sendInit() {
_logger2.default.trace('_sendInit');
var header = {
id: _uuid2.default.v4(),
method: 'init',
token: this._activeToken
};
this._sendPacket(header);
this._storeRequest(header.id, 'init', INIT_TIMEOUT);
}
}, {
key: '_sendUpdate',
value: function _sendUpdate() {
_logger2.default.trace('_sendUpdate');
var header = {
id: _uuid2.default.v4(),
method: 'update',
token: this._activeToken
};
this._sendPacket(header);
this._storeRequest(header.id, 'update', UPDATE_TIMEOUT);
}
}, {
key: '_cancelInit',
value: function _cancelInit() {
_logger2.default.trace('_cancelInit');
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator3.default)(this._activeRequests), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _step$value = (0, _slicedToArray3.default)(_step.value, 2),
id = _step$value[0],
request = _step$value[1];
if (request && request.reqType === 'init') {
clearTimeout(request.timeout);
this._activeRequests.delete(id);
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}, {
key: '_cancelUpdate',
value: function _cancelUpdate() {
_logger2.default.trace('_cancelUpdate');
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = (0, _getIterator3.default)(this._activeRequests), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _step2$value = (0, _slicedToArray3.default)(_step2.value, 2),
id = _step2$value[0],
request = _step2$value[1];
if (request && request.reqType === 'update') {
clearTimeout(request.timeout);
this._activeRequests.delete(id);
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
/**
* Should be called for each message to confirm it received
*/
}, {
key: '_confirmReceiving',
value: function _confirmReceiving(messageHeader) {
_logger2.default.trace('_confirmReceiving');
var header = {
method: 'reply',
id: messageHeader.id,
payload_type: 'application/json', // eslint-disable-line camelcase
status: { code: 200, status: 'OK' }
};
try {
this._sendPacket(header);
} catch (e) {
_logger2.default.debug('failed to confirm packet receiving', e);
}
}
/**
* Prepare binary packet and send it over the network
*/
}, {
key: '_sendPacket',
value: function _sendPacket(header, payload) {
var payloadString = preparePayload(payload);
header.payload_size = byteLength(payloadString); // eslint-disable-line camelcase
var headerString = (0, _stringify2.default)(header) + '\r\n';
var magicString = 'TWILSOCK V3.0 ' + (byteLength(headerString) - 2) + '\r\n';
_logger2.default.debug('send request:', magicString + headerString + payloadString);
var message = stringToUint8Array(magicString + headerString + payloadString);
try {
this._socket.send(message.buffer);
} catch (e) {
_logger2.default.info('failed to send ', header, e);
_logger2.default.info(e.stack);
throw e;
}
}
/**
* Shutdown connection
* @private
*/
}, {
key: '_closeSocket',
value: function _closeSocket() {
_logger2.default.trace('_closeSocket');
if (this._socket) {
this._socket.onopen = null;
this._socket.onclose = null;
this._socket.onerror = null;
this._socket.onmessage = null;
this._socket.close();
}
this._fsm.socketClosed();
}
/**
* Initiate the twilsock connection
* If already connected, it does nothing
*/
}, {
key: 'connect',
value: function connect() {
_logger2.default.trace('connect');
this._fsm.userConnect();
}
/**
* Close twilsock connection
* If already disconnected, it does nothing
*/
}, {
key: 'disconnect',
value: function disconnect() {
var _this5 = this;
_logger2.default.trace('disconnect');
if (this._fsm.is('disconnected')) {
return _promise2.default.resolve();
}
return new _promise2.default(function (resolve) {
_this5._disconnectedPromiseResolve = resolve;
_this5._fsm.userDisconnect();
});
}
/**
* Update fpa token for twilsock connection
*/
}, {
key: 'updateToken',
value: function updateToken() {
_logger2.default.trace('updateToken:', this._config.token);
if (this._fsm.current === 'initialising' || this._fsm.current === 'updating' || this._fsm.current === 'waitSocketClosed' || this._fsm.current === 'waitOffloadSocketClosed') {
_logger2.default.debug('defer updateToken because of', this._fsm.current, 'is in progress');
this._isDeferredUpdate = true;
return;
}
this._isDeferredUpdate = false;
this._activeToken = this._config.token;
this._fsm.userUpdateToken();
}
/**
* Send upstream message
* @returns {String} id of sent message
*/
}, {
key: 'sendUpstreamMessage',
value: function sendUpstreamMessage(address, headers, body) {
var id = _uuid2.default.v4();
var httpRequest = {
host: address.host,
path: address.path,
method: address.method
};
if (address.hasOwnProperty('params')) {
httpRequest.params = address.params;
}
/* eslint-disable camelcase */
var twilsockHeader = {
method: 'message',
id: id,
http_request: httpRequest
};
if (headers) {
twilsockHeader.http_request.headers = headers;
}
if (headers && headers.hasOwnProperty('Content-Type')) {
twilsockHeader.payload_type = headers['Content-Type'];
}
this._sendPacket(twilsockHeader, body);
return id;
/* eslint-enable camelcase */
}
}, {
key: 'send',
value: function send(header, body) {
header.id = header.id || _uuid2.default.v4();
this._sendPacket(header, body);
return header.id;
}
/**
* @private
*/
}, {
key: '_onCloseReceived',
value: function _onCloseReceived(reason) {
_logger2.default.trace('_onCloseReceived');
_logger2.default.info('connection closed by server, reason is', reason);
// Waiting for server close connection. All others events are skipped
if (this._socket) {
this._socket.onopen = null;
this._socket.onerror = null;
this._socket.onmessage = null;
}
}
/**
* @private
*/
}, {
key: '_startWatchdogTimer',
value: function _startWatchdogTimer() {
var _this6 = this;
_logger2.default.trace('_startWatchdogTimer');
this._timestamp = Date.now();
this._watchTimer = setInterval(function () {
if (Date.now() - _this6._timestamp > ACTIVITY_TIMEOUT && _this6._socket) {
_this6._socket.close();
}
}, ACTIVITY_CHECK_INTERVAL);
}
/**
* @private
*/
}, {
key: '_stopWatchdogTimer',
value: function _stopWatchdogTimer() {
_logger2.default.trace('_stopWatchdogTimer');
clearInterval(this._watchTimer);
}
/**
* @private
*/
}, {
key: '_updateActivityTimestamp',
value: function _updateActivityTimestamp() {
_logger2.default.trace('_updateActivityTimestamp');
this._timestamp = Date.now();
}
}]);
return TwilsockChannel;
}(_events2.default);
/**
* Enum for connection state values.
* @readonly
* @enum {number}
*/
exports.default = TwilsockChannel;
TwilsockChannel.state = {
DISCONNECTED: 'disconnected',
CONNECTING: 'connecting',
CONNECTED: 'connected',
DISCONNECTING: 'disconnecting',
ERROR: 'error',
REJECTED: 'rejected'
};
(0, _freeze2.default)(TwilsockChannel.state);
(0, _freeze2.default)(TwilsockChannel);
module.exports = exports['default'];
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./logger":277,"babel-runtime/core-js/get-iterator":32,"babel-runtime/core-js/json/stringify":34,"babel-runtime/core-js/map":35,"babel-runtime/core-js/object/define-properties":39,"babel-runtime/core-js/object/freeze":41,"babel-runtime/core-js/object/get-prototype-of":42,"babel-runtime/core-js/promise":45,"babel-runtime/helpers/classCallCheck":50,"babel-runtime/helpers/createClass":51,"babel-runtime/helpers/inherits":53,"babel-runtime/helpers/possibleConstructorReturn":54,"babel-runtime/helpers/slicedToArray":55,"babel-runtime/helpers/typeof":56,"backoff":58,"events":214,"javascript-state-machine":217,"uuid":283,"ws":70}],280:[function(_dereq_,module,exports){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
},{}],281:[function(_dereq_,module,exports){
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
},{}],282:[function(_dereq_,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = _dereq_('./support/isBuffer');
function objectToString(o) {
return Object.prototype.toString.call(o);
}
function pad(n) {
return n < 10 ? '0' + n.toString(10) : n.toString(10);
}
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'];
// 26 Feb 16:19:34
function timestamp() {
var d = new Date();
var time = [pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds())].join(':');
return [d.getDate(), months[d.getMonth()], time].join(' ');
}
// log is just a thin wrapper to console.log that prepends a timestamp
exports.log = function() {
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
};
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
exports.inherits = _dereq_('inherits');
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
if (!add || !isObject(add)) return origin;
var keys = Object.keys(add);
var i = keys.length;
while (i--) {
origin[keys[i]] = add[keys[i]];
}
return origin;
};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./support/isBuffer":281,"_process":225,"inherits":280}],283:[function(_dereq_,module,exports){
var v1 = _dereq_('./v1');
var v4 = _dereq_('./v4');
var uuid = v4;
uuid.v1 = v1;
uuid.v4 = v4;
module.exports = uuid;
},{"./v1":286,"./v4":287}],284:[function(_dereq_,module,exports){
/**
* Convert array of 16 byte values to UUID string format of the form:
* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
*/
var byteToHex = [];
for (var i = 0; i < 256; ++i) {
byteToHex[i] = (i + 0x100).toString(16).substr(1);
}
function bytesToUuid(buf, offset) {
var i = offset || 0;
var bth = byteToHex;
return bth[buf[i++]] + bth[buf[i++]] +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] +
bth[buf[i++]] + bth[buf[i++]] +
bth[buf[i++]] + bth[buf[i++]];
}
module.exports = bytesToUuid;
},{}],285:[function(_dereq_,module,exports){
(function (global){
// Unique ID creation requires a high quality random # generator. In the
// browser this is a little complicated due to unknown quality of Math.random()
// and inconsistent support for the `crypto` API. We do the best we can via
// feature-detection
var rng;
var crypto = global.crypto || global.msCrypto; // for IE 11
if (crypto && crypto.getRandomValues) {
// WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
var rnds8 = new Uint8Array(16); // eslint-disable-line no-undef
rng = function whatwgRNG() {
crypto.getRandomValues(rnds8);
return rnds8;
};
}
if (!rng) {
// Math.random()-based (RNG)
//
// If all else fails, use Math.random(). It's fast, but is of unspecified
// quality.
var rnds = new Array(16);
rng = function() {
for (var i = 0, r; i < 16; i++) {
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
}
return rnds;
};
}
module.exports = rng;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],286:[function(_dereq_,module,exports){
var rng = _dereq_('./lib/rng');
var bytesToUuid = _dereq_('./lib/bytesToUuid');
// **`v1()` - Generate time-based UUID**
//
// Inspired by https://github.com/LiosK/UUID.js
// and http://docs.python.org/library/uuid.html
// random #'s we need to init node and clockseq
var _seedBytes = rng();
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
var _nodeId = [
_seedBytes[0] | 0x01,
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
];
// Per 4.2.2, randomize (14 bit) clockseq
var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
// Previous uuid creation time
var _lastMSecs = 0, _lastNSecs = 0;
// See https://github.com/broofa/node-uuid for API details
function v1(options, buf, offset) {
var i = buf && offset || 0;
var b = buf || [];
options = options || {};
var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
// Per 4.2.1.2, use count of uuid's generated during the current clock
// cycle to simulate higher resolution clock
var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
// Time since last uuid creation (in msecs)
var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
// Per 4.2.1.2, Bump clockseq on clock regression
if (dt < 0 && options.clockseq === undefined) {
clockseq = clockseq + 1 & 0x3fff;
}
// Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
// time interval
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
nsecs = 0;
}
// Per 4.2.1.2 Throw error if too many uuids are requested
if (nsecs >= 10000) {
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
}
_lastMSecs = msecs;
_lastNSecs = nsecs;
_clockseq = clockseq;
// Per 4.1.4 - Convert from unix epoch to Gregorian epoch
msecs += 12219292800000;
// `time_low`
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
b[i++] = tl >>> 24 & 0xff;
b[i++] = tl >>> 16 & 0xff;
b[i++] = tl >>> 8 & 0xff;
b[i++] = tl & 0xff;
// `time_mid`
var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
b[i++] = tmh >>> 8 & 0xff;
b[i++] = tmh & 0xff;
// `time_high_and_version`
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
b[i++] = tmh >>> 16 & 0xff;
// `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
b[i++] = clockseq >>> 8 | 0x80;
// `clock_seq_low`
b[i++] = clockseq & 0xff;
// `node`
var node = options.node || _nodeId;
for (var n = 0; n < 6; ++n) {
b[i + n] = node[n];
}
return buf ? buf : bytesToUuid(b);
}
module.exports = v1;
},{"./lib/bytesToUuid":284,"./lib/rng":285}],287:[function(_dereq_,module,exports){
var rng = _dereq_('./lib/rng');
var bytesToUuid = _dereq_('./lib/bytesToUuid');
function v4(options, buf, offset) {
var i = buf && offset || 0;
if (typeof(options) == 'string') {
buf = options == 'binary' ? new Array(16) : null;
options = null;
}
options = options || {};
var rnds = options.random || (options.rng || rng)();
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
rnds[6] = (rnds[6] & 0x0f) | 0x40;
rnds[8] = (rnds[8] & 0x3f) | 0x80;
// Copy bytes to buffer, if provided
if (buf) {
for (var ii = 0; ii < 16; ++ii) {
buf[i + ii] = rnds[ii];
}
}
return buf || bytesToUuid(rnds);
}
module.exports = v4;
},{"./lib/bytesToUuid":284,"./lib/rng":285}],288:[function(_dereq_,module,exports){
module.exports = {
h32: _dereq_("./xxhash")
, h64: _dereq_("./xxhash64")
}
},{"./xxhash":289,"./xxhash64":290}],289:[function(_dereq_,module,exports){
(function (Buffer){
/**
xxHash implementation in pure Javascript
Copyright (C) 2013, Pierre Curto
MIT license
*/
var UINT32 = _dereq_('cuint').UINT32
/*
Merged this sequence of method calls as it speeds up
the calculations by a factor of 2
*/
// this.v1.add( other.multiply(PRIME32_2) ).rotl(13).multiply(PRIME32_1);
UINT32.prototype.xxh_update = function (low, high) {
var b00 = PRIME32_2._low
var b16 = PRIME32_2._high
var c16, c00
c00 = low * b00
c16 = c00 >>> 16
c16 += high * b00
c16 &= 0xFFFF // Not required but improves performance
c16 += low * b16
var a00 = this._low + (c00 & 0xFFFF)
var a16 = a00 >>> 16
a16 += this._high + (c16 & 0xFFFF)
var v = (a16 << 16) | (a00 & 0xFFFF)
v = (v << 13) | (v >>> 19)
a00 = v & 0xFFFF
a16 = v >>> 16
b00 = PRIME32_1._low
b16 = PRIME32_1._high
c00 = a00 * b00
c16 = c00 >>> 16
c16 += a16 * b00
c16 &= 0xFFFF // Not required but improves performance
c16 += a00 * b16
this._low = c00 & 0xFFFF
this._high = c16 & 0xFFFF
}
/*
* Constants
*/
var PRIME32_1 = UINT32( '2654435761' )
var PRIME32_2 = UINT32( '2246822519' )
var PRIME32_3 = UINT32( '3266489917' )
var PRIME32_4 = UINT32( '668265263' )
var PRIME32_5 = UINT32( '374761393' )
/**
* Convert string to proper UTF-8 array
* @param str Input string
* @returns {Uint8Array} UTF8 array is returned as uint8 array
*/
function toUTF8Array (str) {
var utf8 = []
for (var i=0, n=str.length; i < n; i++) {
var charcode = str.charCodeAt(i)
if (charcode < 0x80) utf8.push(charcode)
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f))
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f))
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff))
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f))
}
}
return new Uint8Array(utf8)
}
/**
* XXH object used as a constructor or a function
* @constructor
* or
* @param {Object|String} input data
* @param {Number|UINT32} seed
* @return ThisExpression
* or
* @return {UINT32} xxHash
*/
function XXH () {
if (arguments.length == 2)
return new XXH( arguments[1] ).update( arguments[0] ).digest()
if (!(this instanceof XXH))
return new XXH( arguments[0] )
init.call(this, arguments[0])
}
/**
* Initialize the XXH instance with the given seed
* @method init
* @param {Number|Object} seed as a number or an unsigned 32 bits integer
* @return ThisExpression
*/
function init (seed) {
this.seed = seed instanceof UINT32 ? seed.clone() : UINT32(seed)
this.v1 = this.seed.clone().add(PRIME32_1).add(PRIME32_2)
this.v2 = this.seed.clone().add(PRIME32_2)
this.v3 = this.seed.clone()
this.v4 = this.seed.clone().subtract(PRIME32_1)
this.total_len = 0
this.memsize = 0
this.memory = null
return this
}
XXH.prototype.init = init
/**
* Add data to be computed for the XXH hash
* @method update
* @param {String|Buffer|ArrayBuffer} input as a string or nodejs Buffer or ArrayBuffer
* @return ThisExpression
*/
XXH.prototype.update = function (input) {
var isString = typeof input == 'string'
var isArrayBuffer
// Convert all strings to utf-8 first (issue #5)
if (isString) {
input = toUTF8Array(input)
isString = false
isArrayBuffer = true
}
if (typeof ArrayBuffer !== "undefined" && input instanceof ArrayBuffer)
{
isArrayBuffer = true
input = new Uint8Array(input);
}
var p = 0
var len = input.length
var bEnd = p + len
if (len == 0) return this
this.total_len += len
if (this.memsize == 0)
{
if (isString) {
this.memory = ''
} else if (isArrayBuffer) {
this.memory = new Uint8Array(16)
} else {
this.memory = new Buffer(16)
}
}
if (this.memsize + len < 16) // fill in tmp buffer
{
// XXH_memcpy(this.memory + this.memsize, input, len)
if (isString) {
this.memory += input
} else if (isArrayBuffer) {
this.memory.set( input.subarray(0, len), this.memsize )
} else {
input.copy( this.memory, this.memsize, 0, len )
}
this.memsize += len
return this
}
if (this.memsize > 0) // some data left from previous update
{
// XXH_memcpy(this.memory + this.memsize, input, 16-this.memsize);
if (isString) {
this.memory += input.slice(0, 16 - this.memsize)
} else if (isArrayBuffer) {
this.memory.set( input.subarray(0, 16 - this.memsize), this.memsize )
} else {
input.copy( this.memory, this.memsize, 0, 16 - this.memsize )
}
var p32 = 0
if (isString) {
this.v1.xxh_update(
(this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
, (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
)
p32 += 4
this.v2.xxh_update(
(this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
, (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
)
p32 += 4
this.v3.xxh_update(
(this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
, (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
)
p32 += 4
this.v4.xxh_update(
(this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
, (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
)
} else {
this.v1.xxh_update(
(this.memory[p32+1] << 8) | this.memory[p32]
, (this.memory[p32+3] << 8) | this.memory[p32+2]
)
p32 += 4
this.v2.xxh_update(
(this.memory[p32+1] << 8) | this.memory[p32]
, (this.memory[p32+3] << 8) | this.memory[p32+2]
)
p32 += 4
this.v3.xxh_update(
(this.memory[p32+1] << 8) | this.memory[p32]
, (this.memory[p32+3] << 8) | this.memory[p32+2]
)
p32 += 4
this.v4.xxh_update(
(this.memory[p32+1] << 8) | this.memory[p32]
, (this.memory[p32+3] << 8) | this.memory[p32+2]
)
}
p += 16 - this.memsize
this.memsize = 0
if (isString) this.memory = ''
}
if (p <= bEnd - 16)
{
var limit = bEnd - 16
do
{
if (isString) {
this.v1.xxh_update(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
)
p += 4
this.v2.xxh_update(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
)
p += 4
this.v3.xxh_update(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
)
p += 4
this.v4.xxh_update(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
)
} else {
this.v1.xxh_update(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
)
p += 4
this.v2.xxh_update(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
)
p += 4
this.v3.xxh_update(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
)
p += 4
this.v4.xxh_update(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
)
}
p += 4
} while (p <= limit)
}
if (p < bEnd)
{
// XXH_memcpy(this.memory, p, bEnd-p);
if (isString) {
this.memory += input.slice(p)
} else if (isArrayBuffer) {
this.memory.set( input.subarray(p, bEnd), this.memsize )
} else {
input.copy( this.memory, this.memsize, p, bEnd )
}
this.memsize = bEnd - p
}
return this
}
/**
* Finalize the XXH computation. The XXH instance is ready for reuse for the given seed
* @method digest
* @return {UINT32} xxHash
*/
XXH.prototype.digest = function () {
var input = this.memory
var isString = typeof input == 'string'
var p = 0
var bEnd = this.memsize
var h32, h
var u = new UINT32
if (this.total_len >= 16)
{
h32 = this.v1.rotl(1).add( this.v2.rotl(7).add( this.v3.rotl(12).add( this.v4.rotl(18) ) ) )
}
else
{
h32 = this.seed.clone().add( PRIME32_5 )
}
h32.add( u.fromNumber(this.total_len) )
while (p <= bEnd - 4)
{
if (isString) {
u.fromBits(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
)
} else {
u.fromBits(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
)
}
h32
.add( u.multiply(PRIME32_3) )
.rotl(17)
.multiply( PRIME32_4 )
p += 4
}
while (p < bEnd)
{
u.fromBits( isString ? input.charCodeAt(p++) : input[p++], 0 )
h32
.add( u.multiply(PRIME32_5) )
.rotl(11)
.multiply(PRIME32_1)
}
h = h32.clone().shiftRight(15)
h32.xor(h).multiply(PRIME32_2)
h = h32.clone().shiftRight(13)
h32.xor(h).multiply(PRIME32_3)
h = h32.clone().shiftRight(16)
h32.xor(h)
// Reset the state
this.init( this.seed )
return h32
}
module.exports = XXH
}).call(this,_dereq_("buffer").Buffer)
},{"buffer":71,"cuint":209}],290:[function(_dereq_,module,exports){
(function (Buffer){
/**
xxHash64 implementation in pure Javascript
Copyright (C) 2016, Pierre Curto
MIT license
*/
var UINT64 = _dereq_('cuint').UINT64
/*
* Constants
*/
var PRIME64_1 = UINT64( '11400714785074694791' )
var PRIME64_2 = UINT64( '14029467366897019727' )
var PRIME64_3 = UINT64( '1609587929392839161' )
var PRIME64_4 = UINT64( '9650029242287828579' )
var PRIME64_5 = UINT64( '2870177450012600261' )
/**
* Convert string to proper UTF-8 array
* @param str Input string
* @returns {Uint8Array} UTF8 array is returned as uint8 array
*/
function toUTF8Array (str) {
var utf8 = []
for (var i=0, n=str.length; i < n; i++) {
var charcode = str.charCodeAt(i)
if (charcode < 0x80) utf8.push(charcode)
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f))
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f))
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff))
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f))
}
}
return new Uint8Array(utf8)
}
/**
* XXH64 object used as a constructor or a function
* @constructor
* or
* @param {Object|String} input data
* @param {Number|UINT64} seed
* @return ThisExpression
* or
* @return {UINT64} xxHash
*/
function XXH64 () {
if (arguments.length == 2)
return new XXH64( arguments[1] ).update( arguments[0] ).digest()
if (!(this instanceof XXH64))
return new XXH64( arguments[0] )
init.call(this, arguments[0])
}
/**
* Initialize the XXH64 instance with the given seed
* @method init
* @param {Number|Object} seed as a number or an unsigned 32 bits integer
* @return ThisExpression
*/
function init (seed) {
this.seed = seed instanceof UINT64 ? seed.clone() : UINT64(seed)
this.v1 = this.seed.clone().add(PRIME64_1).add(PRIME64_2)
this.v2 = this.seed.clone().add(PRIME64_2)
this.v3 = this.seed.clone()
this.v4 = this.seed.clone().subtract(PRIME64_1)
this.total_len = 0
this.memsize = 0
this.memory = null
return this
}
XXH64.prototype.init = init
/**
* Add data to be computed for the XXH64 hash
* @method update
* @param {String|Buffer|ArrayBuffer} input as a string or nodejs Buffer or ArrayBuffer
* @return ThisExpression
*/
XXH64.prototype.update = function (input) {
var isString = typeof input == 'string'
var isArrayBuffer
// Convert all strings to utf-8 first (issue #5)
if (isString) {
input = toUTF8Array(input)
isString = false
isArrayBuffer = true
}
if (typeof ArrayBuffer !== "undefined" && input instanceof ArrayBuffer)
{
isArrayBuffer = true
input = new Uint8Array(input);
}
var p = 0
var len = input.length
var bEnd = p + len
if (len == 0) return this
this.total_len += len
if (this.memsize == 0)
{
if (isString) {
this.memory = ''
} else if (isArrayBuffer) {
this.memory = new Uint8Array(32)
} else {
this.memory = new Buffer(32)
}
}
if (this.memsize + len < 32) // fill in tmp buffer
{
// XXH64_memcpy(this.memory + this.memsize, input, len)
if (isString) {
this.memory += input
} else if (isArrayBuffer) {
this.memory.set( input.subarray(0, len), this.memsize )
} else {
input.copy( this.memory, this.memsize, 0, len )
}
this.memsize += len
return this
}
if (this.memsize > 0) // some data left from previous update
{
// XXH64_memcpy(this.memory + this.memsize, input, 16-this.memsize);
if (isString) {
this.memory += input.slice(0, 32 - this.memsize)
} else if (isArrayBuffer) {
this.memory.set( input.subarray(0, 32 - this.memsize), this.memsize )
} else {
input.copy( this.memory, this.memsize, 0, 32 - this.memsize )
}
var p64 = 0
if (isString) {
var other
other = UINT64(
(this.memory.charCodeAt(p64+1) << 8) | this.memory.charCodeAt(p64)
, (this.memory.charCodeAt(p64+3) << 8) | this.memory.charCodeAt(p64+2)
, (this.memory.charCodeAt(p64+5) << 8) | this.memory.charCodeAt(p64+4)
, (this.memory.charCodeAt(p64+7) << 8) | this.memory.charCodeAt(p64+6)
)
this.v1.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p64 += 8
other = UINT64(
(this.memory.charCodeAt(p64+1) << 8) | this.memory.charCodeAt(p64)
, (this.memory.charCodeAt(p64+3) << 8) | this.memory.charCodeAt(p64+2)
, (this.memory.charCodeAt(p64+5) << 8) | this.memory.charCodeAt(p64+4)
, (this.memory.charCodeAt(p64+7) << 8) | this.memory.charCodeAt(p64+6)
)
this.v2.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p64 += 8
other = UINT64(
(this.memory.charCodeAt(p64+1) << 8) | this.memory.charCodeAt(p64)
, (this.memory.charCodeAt(p64+3) << 8) | this.memory.charCodeAt(p64+2)
, (this.memory.charCodeAt(p64+5) << 8) | this.memory.charCodeAt(p64+4)
, (this.memory.charCodeAt(p64+7) << 8) | this.memory.charCodeAt(p64+6)
)
this.v3.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p64 += 8
other = UINT64(
(this.memory.charCodeAt(p64+1) << 8) | this.memory.charCodeAt(p64)
, (this.memory.charCodeAt(p64+3) << 8) | this.memory.charCodeAt(p64+2)
, (this.memory.charCodeAt(p64+5) << 8) | this.memory.charCodeAt(p64+4)
, (this.memory.charCodeAt(p64+7) << 8) | this.memory.charCodeAt(p64+6)
)
this.v4.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
} else {
var other
other = UINT64(
(this.memory[p64+1] << 8) | this.memory[p64]
, (this.memory[p64+3] << 8) | this.memory[p64+2]
, (this.memory[p64+5] << 8) | this.memory[p64+4]
, (this.memory[p64+7] << 8) | this.memory[p64+6]
)
this.v1.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p64 += 8
other = UINT64(
(this.memory[p64+1] << 8) | this.memory[p64]
, (this.memory[p64+3] << 8) | this.memory[p64+2]
, (this.memory[p64+5] << 8) | this.memory[p64+4]
, (this.memory[p64+7] << 8) | this.memory[p64+6]
)
this.v2.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p64 += 8
other = UINT64(
(this.memory[p64+1] << 8) | this.memory[p64]
, (this.memory[p64+3] << 8) | this.memory[p64+2]
, (this.memory[p64+5] << 8) | this.memory[p64+4]
, (this.memory[p64+7] << 8) | this.memory[p64+6]
)
this.v3.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p64 += 8
other = UINT64(
(this.memory[p64+1] << 8) | this.memory[p64]
, (this.memory[p64+3] << 8) | this.memory[p64+2]
, (this.memory[p64+5] << 8) | this.memory[p64+4]
, (this.memory[p64+7] << 8) | this.memory[p64+6]
)
this.v4.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
}
p += 32 - this.memsize
this.memsize = 0
if (isString) this.memory = ''
}
if (p <= bEnd - 32)
{
var limit = bEnd - 32
do
{
if (isString) {
var other
other = UINT64(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
, (input.charCodeAt(p+5) << 8) | input.charCodeAt(p+4)
, (input.charCodeAt(p+7) << 8) | input.charCodeAt(p+6)
)
this.v1.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p += 8
other = UINT64(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
, (input.charCodeAt(p+5) << 8) | input.charCodeAt(p+4)
, (input.charCodeAt(p+7) << 8) | input.charCodeAt(p+6)
)
this.v2.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p += 8
other = UINT64(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
, (input.charCodeAt(p+5) << 8) | input.charCodeAt(p+4)
, (input.charCodeAt(p+7) << 8) | input.charCodeAt(p+6)
)
this.v3.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p += 8
other = UINT64(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
, (input.charCodeAt(p+5) << 8) | input.charCodeAt(p+4)
, (input.charCodeAt(p+7) << 8) | input.charCodeAt(p+6)
)
this.v4.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
} else {
var other
other = UINT64(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
, (input[p+5] << 8) | input[p+4]
, (input[p+7] << 8) | input[p+6]
)
this.v1.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p += 8
other = UINT64(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
, (input[p+5] << 8) | input[p+4]
, (input[p+7] << 8) | input[p+6]
)
this.v2.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p += 8
other = UINT64(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
, (input[p+5] << 8) | input[p+4]
, (input[p+7] << 8) | input[p+6]
)
this.v3.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
p += 8
other = UINT64(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
, (input[p+5] << 8) | input[p+4]
, (input[p+7] << 8) | input[p+6]
)
this.v4.add( other.multiply(PRIME64_2) ).rotl(31).multiply(PRIME64_1);
}
p += 8
} while (p <= limit)
}
if (p < bEnd)
{
// XXH64_memcpy(this.memory, p, bEnd-p);
if (isString) {
this.memory += input.slice(p)
} else if (isArrayBuffer) {
this.memory.set( input.subarray(p, bEnd), this.memsize )
} else {
input.copy( this.memory, this.memsize, p, bEnd )
}
this.memsize = bEnd - p
}
return this
}
/**
* Finalize the XXH64 computation. The XXH64 instance is ready for reuse for the given seed
* @method digest
* @return {UINT64} xxHash
*/
XXH64.prototype.digest = function () {
var input = this.memory
var isString = typeof input == 'string'
var p = 0
var bEnd = this.memsize
var h64, h
var u = new UINT64
if (this.total_len >= 32)
{
h64 = this.v1.clone().rotl(1)
h64.add( this.v2.clone().rotl(7) )
h64.add( this.v3.clone().rotl(12) )
h64.add( this.v4.clone().rotl(18) )
h64.xor( this.v1.multiply(PRIME64_2).rotl(31).multiply(PRIME64_1) )
h64.multiply(PRIME64_1).add(PRIME64_4)
h64.xor( this.v2.multiply(PRIME64_2).rotl(31).multiply(PRIME64_1) )
h64.multiply(PRIME64_1).add(PRIME64_4)
h64.xor( this.v3.multiply(PRIME64_2).rotl(31).multiply(PRIME64_1) )
h64.multiply(PRIME64_1).add(PRIME64_4)
h64.xor( this.v4.multiply(PRIME64_2).rotl(31).multiply(PRIME64_1) )
h64.multiply(PRIME64_1).add(PRIME64_4)
}
else
{
h64 = this.seed.clone().add( PRIME64_5 )
}
h64.add( u.fromNumber(this.total_len) )
while (p <= bEnd - 8)
{
if (isString) {
u.fromBits(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
, (input.charCodeAt(p+5) << 8) | input.charCodeAt(p+4)
, (input.charCodeAt(p+7) << 8) | input.charCodeAt(p+6)
)
} else {
u.fromBits(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
, (input[p+5] << 8) | input[p+4]
, (input[p+7] << 8) | input[p+6]
)
}
u.multiply(PRIME64_2).rotl(31).multiply(PRIME64_1)
h64
.xor(u)
.rotl(27)
.multiply( PRIME64_1 )
.add( PRIME64_4 )
p += 8
}
if (p + 4 <= bEnd) {
if (isString) {
u.fromBits(
(input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
, (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
, 0
, 0
)
} else {
u.fromBits(
(input[p+1] << 8) | input[p]
, (input[p+3] << 8) | input[p+2]
, 0
, 0
)
}
h64
.xor( u.multiply(PRIME64_1) )
.rotl(23)
.multiply( PRIME64_2 )
.add( PRIME64_3 )
p += 4
}
while (p < bEnd)
{
u.fromBits( isString ? input.charCodeAt(p++) : input[p++], 0, 0, 0 )
h64
.xor( u.multiply(PRIME64_5) )
.rotl(11)
.multiply(PRIME64_1)
}
h = h64.clone().shiftRight(33)
h64.xor(h).multiply(PRIME64_2)
h = h64.clone().shiftRight(29)
h64.xor(h).multiply(PRIME64_3)
h = h64.clone().shiftRight(32)
h64.xor(h)
// Reset the state
this.init( this.seed )
return h64
}
module.exports = XXH64
}).call(this,_dereq_("buffer").Buffer)
},{"buffer":71,"cuint":209}],291:[function(_dereq_,module,exports){
module.exports={
"name": "twilio-chat",
"version": "1.2.1",
"description": "Twilio Chat service client library",
"main": "lib/index.js",
"browser": "browser/index.js",
"types": "./lib/client.d.ts",
"author": "Twilio",
"license": "MIT",
"dependencies": {
"twilio-mcs-client": "^0.0.4",
"durational": "^1.1.0",
"isomorphic-form-data": "^1.0.0",
"loglevel": "^1.5.0",
"operation-retrier": "^1.3.2",
"platform": "^1.3.4",
"rfc6902": "^1.3.0",
"twilio-ems-client": "^0.2.6",
"twilio-notifications": "^0.4.4",
"twilio-sync": "^0.5.10",
"twilio-transport": "^0.1.4",
"twilsock": "^0.3.5",
"uuid": "^3.1.0"
},
"devDependencies": {
"@types/chai": "^3.4.35",
"@types/chai-as-promised": "0.0.31",
"@types/chai-string": "^1.1.30",
"@types/core-js": "^0.9.41",
"@types/mocha": "^2.2.43",
"@types/node": "^7.0.5",
"@types/sinon": "^2.3.5",
"@types/sinon-chai": "^2.7.27",
"async": "^2.1.5",
"async-test-tools": "^1.0.6",
"babel-eslint": "^7.2.3",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-istanbul": "^4.1.5",
"babel-plugin-transform-async-to-generator": "^6.24.1",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-require": "^1.0.1",
"babel-runtime": "^6.23.0",
"babelify": "^7.3.0",
"browserify": "^14.1.0",
"browserify-replace": "^0.9.0",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"chai-string": "^1.4.0",
"cheerio": "^0.22.0",
"del": "^3.0.0",
"fs": "0.0.1-security",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-derequire": "^2.1.0",
"gulp-insert": "^0.5.0",
"gulp-mocha": "^4.1.0",
"gulp-rename": "^1.2.2",
"gulp-tap": "^1.0.1",
"gulp-tslint": "^8.1.0",
"gulp-typescript": "^3.1.7",
"gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.8",
"gulpclass": "^0.1.2",
"ink-docstrap": "^1.3.0",
"jsdoc": "3.4.3",
"jsdoc-strip-async-await": "^0.1.0",
"karma": "^1.5.0",
"karma-browserify": "^5.1.1",
"karma-browserstack-launcher": "^1.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.2",
"karma-sinon-ie": "^2.0.0",
"loglevel-message-prefix": "^2.0.1",
"mocha.parallel": "^0.15.0",
"nyc": "^11.2.1",
"path": "^0.12.7",
"sinon": "^2.3.2",
"sinon-chai": "^2.14.0",
"ts-node": "^3.0.4",
"tslint": "^5.4.2",
"twilio": "^3.7.0",
"typescript": "^2.5.3",
"uglify-save-license": "^0.4.1",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
},
"engines": {
"node": ">=6"
}
}
},{}]},{},[3])(3)
});