Socket
Socket
Sign inDemoInstall

twilio-sync

Package Overview
Dependencies
Maintainers
2
Versions
608
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

twilio-sync - npm Package Compare versions

Comparing version 0.4.1 to 0.4.2-dev.1

browser/cache.js

101

lib/cache.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _map = require("babel-runtime/core-js/map");
var _map2 = _interopRequireDefault(_map);
var _defineProperties = require("babel-runtime/core-js/object/define-properties");
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var Cache = function () {
function Cache() {
(0, _classCallCheck3.default)(this, Cache);
(0, _defineProperties2.default)(this, {
_items: { value: new _map2.default() }
});
}
(0, _createClass3.default)(Cache, [{
key: "store",
value: function store(key, value) {
/*
let cachedEntity = _items.get(key);
if (!cachedEntity || cachedEntity) {
_items.insert(key, value);
const karibu_1 = require("karibu");
class Entry {
constructor(value, revision) {
this.value = value;
this.revision = revision;
}
get isValid() { return true; }
}
class Tombstone {
constructor(revision) {
this.revision = revision;
}
get isValid() { return false; }
}
class Cache {
constructor() {
this.items = new karibu_1.TreeMap();
}
store(key, value, revision) {
let entry = this.items.get(key);
if (entry && entry.revision > revision) {
if (entry.isValid) {
return entry.value;
}
return null;
}
this.items.set(key, new Entry(value, revision));
return value;
}
*/
return value;
}
}, {
key: "get",
value: function get(key) {
return this._items.get(key) || null;
delete(key, revision) {
let curr = this.items.get(key);
if (!curr || curr.revision < revision) {
this.items.set(key, new Tombstone(revision));
}
}
}]);
return Cache;
}();
isKnown(key, revision) {
let curr = this.items.get(key);
return curr && curr.revision >= revision;
}
get(key) {
let entry = this.items.get(key);
if (entry && entry.isValid) {
return entry.value;
}
return null;
}
has(key) {
let entry = this.items.get(key);
return entry && entry.isValid;
}
}
exports.Cache = Cache;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Cache;
module.exports = exports["default"];

@@ -1,94 +0,38 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _events = require('events');
var _events2 = _interopRequireDefault(_events);
var _jsondiff = require('./jsondiff');
var _jsondiff2 = _interopRequireDefault(_jsondiff);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
const events_1 = require("events");
const rfc6902_1 = require("rfc6902");
/**
* Tracks changes for JS objects and emits appropriate callbacks
*/
var ChangeTracker = function (_EventEmitter) {
(0, _inherits3.default)(ChangeTracker, _EventEmitter);
function ChangeTracker(data) {
(0, _classCallCheck3.default)(this, ChangeTracker);
var _this = (0, _possibleConstructorReturn3.default)(this, (ChangeTracker.__proto__ || (0, _getPrototypeOf2.default)(ChangeTracker)).call(this));
(0, _defineProperties2.default)(_this, {
_pendingListeners: { value: {} },
_data: { value: data || {}, writable: true }
});
['keyAdded', 'keyRemoved', 'keyUpdated'].forEach(function (eventName) {
_this._pendingListeners[eventName] = {};
_this.on(eventName, function (path, value) {
var handlers = _this._pendingListeners[eventName][path] || [];
handlers.forEach(function (handler) {
return handler(value);
class ChangeTracker extends events_1.EventEmitter {
constructor(data) {
super();
['keyAdded', 'keyRemoved', 'keyUpdated'].forEach((eventName) => {
this.pendingListeners[eventName] = {};
this.on(eventName, (path, value) => {
let handlers = this.pendingListeners[eventName][path] || [];
handlers.forEach(handler => handler(value));
this.pendingListeners[eventName][path] = [];
});
});
_this._pendingListeners[eventName][path] = [];
});
});
return _this;
}
/**
* Compare old and new data and fire events if difference found
* @private
*/
(0, _createClass3.default)(ChangeTracker, [{
key: '_traverse',
value: function _traverse(originalData, updatedData) {
var _this2 = this;
var diff = _jsondiff2.default.diff(originalData, updatedData);
diff.forEach(function (row) {
if (row.op === 'add') {
_this2.emit('keyAdded', row.path, row.value);
} else if (row.op === 'replace') {
_this2.emit('keyUpdated', row.path, row.value);
} else if (row.op === 'remove') {
_this2.emit('keyRemoved', row.path);
}
});
}
/**
* Compare old and new data and fire events if difference found
* @private
*/
traverse(originalData, updatedData) {
let diff = rfc6902_1.createPatch(originalData, updatedData);
diff.forEach((row) => {
if (row.op === 'add') {
this.emit('keyAdded', row.path, row.value);
}
else if (row.op === 'replace') {
this.emit('keyUpdated', row.path, row.value);
}
else if (row.op === 'remove') {
this.emit('keyRemoved', row.path);
}
});
}
/**
* Set new data to process

@@ -98,22 +42,15 @@ * @param Object updatedData new data set

*/
}, {
key: 'update',
value: function update(updatedData) {
var originalData = this._data;
this._data = updatedData;
this._traverse(originalData, updatedData);
update(updatedData) {
const originalData = this.data;
this.data = updatedData;
this.traverse(originalData, updatedData);
}
}, {
key: 'addEventHandler',
value: function addEventHandler(eventName, path, handler) {
var handlers = this._pendingListeners[eventName][path] || [];
handlers.push(handler);
this._pendingListeners[eventName][path] = handlers;
addEventHandler(eventName, path, handler) {
const handlers = this.pendingListeners[eventName][path] || [];
handlers.push(handler);
this.pendingListeners[eventName][path] = handlers;
}
}]);
return ChangeTracker;
}(_events2.default);
}
exports.ChangeTracker = ChangeTracker;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = ChangeTracker;
module.exports = exports['default'];

@@ -1,131 +0,53 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _freeze = require('babel-runtime/core-js/object/freeze');
var _freeze2 = _interopRequireDefault(_freeze);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _events = require('events');
var _twilsock = require('twilsock');
var _twilsock2 = _interopRequireDefault(_twilsock);
var _twilioTransport = require('twilio-transport');
var _twilioNotifications = require('twilio-notifications');
var _twilioNotifications2 = _interopRequireDefault(_twilioNotifications);
var _utils = require('./utils');
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _configuration = require('./configuration');
var _configuration2 = _interopRequireDefault(_configuration);
var _subscriptions = require('./subscriptions');
var _subscriptions2 = _interopRequireDefault(_subscriptions);
var _router = require('./router');
var _router2 = _interopRequireDefault(_router);
var _network = require('./network');
var _network2 = _interopRequireDefault(_network);
var _syncdocument = require('./syncdocument');
var _syncdocument2 = _interopRequireDefault(_syncdocument);
var _synclist = require('./synclist');
var _synclist2 = _interopRequireDefault(_synclist);
var _syncmap = require('./syncmap');
var _syncmap2 = _interopRequireDefault(_syncmap);
var _clientInfo = require('./clientInfo');
var _clientInfo2 = _interopRequireDefault(_clientInfo);
var _entitiesCache = require('./entitiesCache');
var _entitiesCache2 = _interopRequireDefault(_entitiesCache);
var _syncerror = require('./syncerror');
var _syncerror2 = _interopRequireDefault(_syncerror);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var SYNC_PRODUCT_ID = 'data_sync';
var SDK_VERSION = require('../package.json').version;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const events_1 = require("events");
const Twilsock = require("twilsock");
const twilio_transport_1 = require("twilio-transport");
const twilio_ems_client_1 = require("twilio-ems-client");
const Notifications = require("twilio-notifications");
const utils_1 = require("./utils");
const logger_1 = require("./logger");
const configuration_1 = require("./configuration");
const subscriptions_1 = require("./subscriptions");
const router_1 = require("./router");
const network_1 = require("./network");
const syncdocument_1 = require("./syncdocument");
const synclist_1 = require("./synclist");
const syncmap_1 = require("./syncmap");
const clientInfo_1 = require("./clientInfo");
const entitiesCache_1 = require("./entitiesCache");
const syncerror_1 = require("./syncerror");
const SYNC_PRODUCT_ID = 'data_sync';
const SDK_VERSION = require('../package.json').version;
function subscribe(subscribable) {
subscribable._subscribe();
return subscribable;
subscribable._subscribe();
return subscribable;
}
function prepareCreatePayload(name, purpose, context, data) {
return {
unique_name: name, // eslint-disable-line camelcase
purpose: purpose,
context: context,
data: data };
function createPayload(name, purpose, context, data) {
return { unique_name: name,
purpose: purpose,
context: context,
data: data };
}
function decompose(arg) {
if (!arg) {
return { id: null };
}
if (typeof arg === 'string') {
return { id: arg };
}
return { id: arg.uniqueName || arg.sid || arg.id,
purpose: arg.purpose,
data: arg.data,
context: arg.context,
mode: arg.mode
};
if (!arg) {
return { id: null, purpose: null, data: null, context: null, mode: null };
}
if (typeof arg === 'string') {
return { id: arg, purpose: null, data: null, context: null, mode: null };
}
return { id: arg.uniqueName || arg.sid || arg.id,
purpose: arg.purpose,
data: arg.data,
context: arg.context,
mode: arg.mode
};
}
/**

@@ -138,131 +60,96 @@ * @class Client

*/
var Client = function (_EventEmitter) {
(0, _inherits3.default)(Client, _EventEmitter);
/*
* @constructor
* @param {string} Token Twilio access token
* @param {Client#ClientOptions} options - Options to customize the Client
*/
function Client(token, options) {
(0, _classCallCheck3.default)(this, Client);
var _this = (0, _possibleConstructorReturn3.default)(this, (Client.__proto__ || (0, _getPrototypeOf2.default)(Client)).call(this));
options = options || {};
if (!token) {
throw new Error('Sync library needs a valid Twilio token to be passed');
class SyncClient extends events_1.EventEmitter {
/*
* @constructor
* @param {string} Token Twilio access token
* @param {Client#ClientOptions} options - Options to customize the Client
*/
constructor(fpaToken, options = {}) {
super();
if (!fpaToken) {
throw new Error('Sync library needs a valid Twilio token to be passed');
}
if (options.hasOwnProperty('logLevel')) {
logger_1.default.setLevel(options.logLevel);
}
let productId = options.productId = options.productId || SYNC_PRODUCT_ID;
let emsClient = options.emsClient = options.emsClient || new twilio_ems_client_1.EmsClient(options);
let twilsock = options.twilsockClient = options.twilsockClient || new Twilsock(fpaToken, options);
let transport = options.transport = options.transport || new twilio_transport_1.Transport(options.twilsockClient);
let notifications = options.notificationsClient = options.notificationsClient || new Notifications(fpaToken, options);
let config = new configuration_1.Configuration(null, options);
let network = new network_1.Network(productId, new clientInfo_1.ClientInfo(SDK_VERSION), config, transport);
this.fpaToken = fpaToken;
emsClient.setToken(fpaToken).then(response => this.services.config.updateToken(response.token));
twilsock.connect();
this.services = { config, twilsock, notifications, network, emsClient, router: null, subscriptions: null };
let subscriptions = new subscriptions_1.Subscriptions(this.services);
let router = new router_1.Router({ config, subscriptions, notifications });
this.services.router = router;
this.services.subscriptions = subscriptions;
this.entities = new entitiesCache_1.EntitiesCache();
notifications.on('connectionStateChanged', () => {
this.emit('connectionStateChanged', this.services.notifications.connectionState);
});
}
if (options.hasOwnProperty('logLevel')) {
_logger2.default.setLevel(options.logLevel);
}
options.productId = options.productId || SYNC_PRODUCT_ID;
var productId = options.productId;
options.twilsockClient = options.twilsockClient || new _twilsock2.default(token, options);
options.transport = options.transport || new _twilioTransport.Transport(options.twilsockClient);
options.notificationsClient = options.notificationsClient || new _twilioNotifications2.default(token, options);
var transport = options.transport;
var notifications = options.notificationsClient;
var config = new _configuration2.default(token, options);
var network = new _network2.default(productId, new _clientInfo2.default(SDK_VERSION), config, transport);
var subscriptions = new _subscriptions2.default(config, network, _twilioTransport.TwilsockUnavailableError);
var router = new _router2.default({ config: config, subscriptions: subscriptions, notifications: notifications });
(0, _defineProperties2.default)(_this, {
_config: { value: config },
_twilsock: { value: options.twilsockClient },
_notifications: { value: notifications },
_network: { value: network },
_router: { value: router },
_subscriptions: { value: subscriptions },
_entities: { value: new _entitiesCache2.default() },
_dependencies: { get: function get() {
return {
config: _this._config,
datasync: _this,
network: _this._network,
router: _this._router
};
/**
* Current version of Sync client.
* @name Client#version
* @type String
* @readonly
*/
static get version() { return SDK_VERSION; }
get connectionState() { return this.services.notifications.connectionState; }
/**
* Returns promise which resolves when library is correctly initialized
* Or throws if initialization is impossible
*/
ensureReady() {
if (this.services.config.token) {
return Promise.resolve(this.services.config.token);
}
},
connectionState: { get: function get() {
return _this._notifications.connectionState;
}, enumerable: true }
});
notifications.on('connectionStateChanged', function () {
_this.emit('connectionStateChanged', _this._notifications.connectionState);
});
return _this;
}
(0, _createClass3.default)(Client, [{
key: '_get',
value: function _get(baseUri, id) {
if (!id) {
return _promise2.default.resolve(null);
}
var uri = new _utils.UriBuilder(baseUri).arg('Deep', true).arg('Id', id).build();
return this._network.get(uri).then(function (response) {
return response.body;
}).then(function (body) {
return body.documents || body.lists || body.maps || [];
}).then(function (objects) {
return objects.length === 0 ? null : objects[0];
});
return new Promise((resolve, reject) => {
this.services.emsClient.once('token', token => {
setTimeout(() => resolve(token), 0);
});
});
}
}, {
key: '_createDocument',
value: function _createDocument(id, purpose, data) {
var payload = prepareCreatePayload(id, purpose, null, data);
return this._network.post(this._config.documentsUri, payload).then(function (response) {
return response.body;
});
_get(baseUri, id) {
return __awaiter(this, void 0, void 0, function* () {
if (!id) {
return null;
}
const uri = new utils_1.UriBuilder(baseUri).arg('Deep', true).arg('Id', id).build();
let response = yield this.services.network.get(uri);
let objects = (response.body.documents || response.body.lists || response.body.maps || []);
return objects.length === 0 ? null : objects[0];
});
}
}, {
key: '_getDocument',
value: function _getDocument(id) {
return this._get(this._config.documentsUri, id);
_createDocument(id, purpose, data) {
let payload = createPayload(id, purpose, null, data);
return this.services.network.post(this.services.config.documentsUri, payload).then(response => response.body);
}
}, {
key: '_createList',
value: function _createList(id, purpose, context) {
var payload = prepareCreatePayload(id, purpose, context);
return this._network.post(this._config.listsUri, payload).then(function (response) {
return response.body;
});
_getDocument(id) {
return this._get(this.services.config.documentsUri, id);
}
}, {
key: '_getList',
value: function _getList(id) {
return this._get(this._config.listsUri, id);
_createList(id, purpose, context) {
let payload = createPayload(id, purpose, context);
return this.services.network.post(this.services.config.listsUri, payload).then(response => response.body);
}
}, {
key: '_createMap',
value: function _createMap(id, purpose, context) {
var payload = prepareCreatePayload(id, purpose, context);
return this._network.post(this._config.mapsUri, payload).then(function (response) {
return response.body;
});
_getList(id) {
return this._get(this.services.config.listsUri, id);
}
}, {
key: '_getMap',
value: function _getMap(id) {
return this._get(this._config.mapsUri, id);
_createMap(id, purpose, context) {
let payload = createPayload(id, purpose, context);
return this.services.network.post(this.services.config.mapsUri, payload).then(response => response.body);
}
}, {
key: '_getCached',
value: function _getCached(id, type) {
var cached = this._entities.get(id, type);
return cached ? _promise2.default.resolve(cached._subscribe()) : null;
_getMap(id) {
return this._get(this.services.config.mapsUri, id);
}
getCached(id, type) {
return this.entities.get(id, type) || null;
}
removeFromCache(sid) {
this.entities.remove(sid);
}
/**

@@ -274,28 +161,21 @@ * Open a SyncDocument by identifier, or create one if none exists

*/
}, {
key: 'document',
value: function document(arg) {
var _this2 = this;
var _decompose = decompose(arg),
id = _decompose.id,
purpose = _decompose.purpose,
data = _decompose.data,
mode = _decompose.mode;
return this._getCached(id, 'doc') || this._getDocument(id).then(function (body) {
if (body) {
return body;
} else if (mode !== 'open') {
return _this2._createDocument(id, purpose, data);
}
throw new _syncerror2.default('Not found', 404);
}).then(function (body) {
return new _syncdocument2.default(_this2._dependencies, body);
}).then(function (entity) {
return _this2._entities.store(entity);
}).then(subscribe);
document(arg) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureReady();
let { id, purpose, data, mode } = decompose(arg);
return this.getCached(id, 'document') || this._getDocument(id)
.then(body => {
if (body) {
return body;
}
else if (mode !== 'open') {
return this._createDocument(id, purpose, data);
}
throw new syncerror_1.default('Not found', 404);
})
.then(body => new syncdocument_1.SyncDocument(this.services, body, sid => this.removeFromCache(sid)))
.then(entity => this.entities.store(entity))
.then(subscribe);
});
}
/**

@@ -307,28 +187,21 @@ * Open a Map by identifier, or create one if none exists

*/
}, {
key: 'map',
value: function map(arg) {
var _this3 = this;
var _decompose2 = decompose(arg),
id = _decompose2.id,
purpose = _decompose2.purpose,
context = _decompose2.context,
mode = _decompose2.mode;
return this._getCached(id, 'map') || this._getMap(id).then(function (body) {
if (body) {
return body;
} else if (mode !== 'open') {
return _this3._createMap(id, purpose, context);
}
throw new _syncerror2.default('Not found', 404);
}).then(function (body) {
return new _syncmap2.default(_this3._dependencies, body);
}).then(function (entity) {
return _this3._entities.store(entity);
}).then(subscribe);
map(arg) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureReady();
let { id, purpose, context, mode } = decompose(arg);
return this.getCached(id, 'map') || this._getMap(id)
.then(body => {
if (body) {
return body;
}
else if (mode !== 'open') {
return this._createMap(id, purpose, context);
}
throw new syncerror_1.default('Not found', 404);
})
.then(body => new syncmap_1.SyncMap(this.services, body, sid => this.removeFromCache(sid)))
.then(entity => this.entities.store(entity))
.then(subscribe);
});
}
/**

@@ -340,28 +213,21 @@ * Open a List by identifier, or create one if none exists

*/
}, {
key: 'list',
value: function list(arg) {
var _this4 = this;
var _decompose3 = decompose(arg),
id = _decompose3.id,
purpose = _decompose3.purpose,
context = _decompose3.context,
mode = _decompose3.mode;
return this._getCached(id, 'list') || this._getList(id).then(function (body) {
if (body) {
return body;
} else if (mode !== 'open') {
return _this4._createList(id, purpose, context);
}
throw new _syncerror2.default('Not found', 404);
}).then(function (body) {
return new _synclist2.default(_this4._dependencies, body);
}).then(function (entity) {
return _this4._entities.store(entity);
}).then(subscribe);
list(arg) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureReady();
let { id, purpose, context, mode } = decompose(arg);
return this.getCached(id, 'list') || this._getList(id)
.then(body => {
if (body) {
return body;
}
else if (mode !== 'open') {
return this._createList(id, purpose, context);
}
throw new syncerror_1.default('Not found', 404);
})
.then(body => new synclist_1.SyncList(this.services, body, sid => this.removeFromCache(sid)))
.then(entity => this.entities.store(entity))
.then(subscribe);
});
}
/**

@@ -373,10 +239,8 @@ * Gracefully shutdown the libray

*/
}, {
key: 'shutdown',
value: function shutdown() {
this._subscriptions.shutdown();
this._twilsock.disconnect().then(function () {});
shutdown() {
return __awaiter(this, void 0, void 0, function* () {
yield this.services.subscriptions.shutdown();
yield this.services.twilsock.disconnect();
});
}
/**

@@ -388,50 +252,18 @@ * Set new auth token

*/
}, {
key: 'updateToken',
value: function updateToken(token) {
return _promise2.default.all([this._config.updateToken(token), this._notifications.updateToken(token), this._twilsock.updateToken(token)]).then(function () {});
updateToken(fpaToken) {
return __awaiter(this, void 0, void 0, function* () {
this.fpaToken = fpaToken;
yield Promise.all([
this.services.config.updateToken(fpaToken),
this.services.notifications.updateToken(fpaToken),
this.services.twilsock.updateToken(fpaToken)
]);
});
}
}]);
return Client;
}(_events.EventEmitter);
}
exports.SyncClient = SyncClient;
exports.Client = SyncClient;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = SyncClient;
/**
* Current version of Sync client.
* @name Client#version
* @type String
* @readonly
*/
(0, _defineProperties2.default)(Client, {
version: {
enumerable: true,
value: SDK_VERSION
}
});
/**
* Service connection state
* @alias Client#connectionState
* @readonly
* @enum {String}
*/
Client.connectionState = {
/** Client is offline and no connection attempt in process. */
DISCONNECTED: 'disconnected',
/** Client is offline and connection attempt is in process. */
CONNECTING: 'connecting',
/** Client is online and ready. */
CONNECTED: 'connected',
/** Client connection is in the erroneous state. */
ERROR: 'error',
/** Client connection is denied because of invalid token */
DENIED: 'denied'
};
(0, _freeze2.default)(Client.connectionState);
exports.default = Client;
/**
* These options can be passed to Client constructor

@@ -442,3 +274,2 @@ * @typedef {Object} Client#ClientOptions

*/
/**

@@ -449,3 +280,1 @@ * Fired when connection state has been changed.

*/
module.exports = exports['default'];

@@ -1,24 +0,15 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
"use strict";
const platform = require("platform");
class ClientInfo {
constructor(version) {
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;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = ClientInfo;
var _platform = require('platform');
var _platform2 = _interopRequireDefault(_platform);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ClientInfo(version) {
return {
sdk: 'js',
sdkVer: version,
os: _platform2.default.os.family,
osVer: _platform2.default.os.version,
pl: _platform2.default.name,
plVer: _platform2.default.version
};
}
module.exports = exports['default'];

@@ -1,81 +0,35 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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';
"use strict";
const CDS_URI = 'https://cds.twilio.com';
const SUBSCRIPTIONS_PATH = '/v4/Subscriptions';
const MAPS_PATH = '/v3/Maps';
const LISTS_PATH = '/v3/Lists';
const DOCUMENTS_PATH = '/v3/Documents';
/**
* @param {String} token - authentication token
*
* @class Configuration
* @classdesc Settings container for the DataSync library
* Settings container for Sync library
*/
var Configuration = function () {
function Configuration(token, options) {
var _this = this;
(0, _classCallCheck3.default)(this, Configuration);
options = (options || {}).DataSync || {};
var baseUri = options.cdsUri || CDS_URI;
var settings = {
subscriptionsUri: baseUri + SUBSCRIPTIONS_PATH,
documentsUri: baseUri + DOCUMENTS_PATH,
listsUri: baseUri + LISTS_PATH,
mapsUri: baseUri + MAPS_PATH
};
(0, _defineProperties2.default)(this, {
_token: { value: token, writable: true },
token: { enumerable: true, get: function get() {
return _this._token;
} },
subscriptionsUri: { enumerable: true, get: function get() {
return settings.subscriptionsUri;
} },
documentsUri: { enumerable: true, get: function get() {
return settings.documentsUri;
} },
listsUri: { enumerable: true, get: function get() {
return settings.listsUri;
} },
mapsUri: { enumerable: true, get: function get() {
return settings.mapsUri;
} }
});
}
(0, _createClass3.default)(Configuration, [{
key: 'updateToken',
value: function updateToken(token) {
this._token = token;
class Configuration {
/**
* @param {String} token - authentication token
*/
constructor(token, options) {
options = (options || {}).DataSync || {};
const 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
};
}
}]);
return Configuration;
}();
exports.default = Configuration;
module.exports = exports['default'];
get token() { return this._token; }
get subscriptionsUri() { return this.settings.subscriptionsUri; }
get documentsUri() { return this.settings.documentsUri; }
get listsUri() { return this.settings.listsUri; }
get mapsUri() { return this.settings.mapsUri; }
get backoffConfig() { return this.settings.backoffConfig || {}; }
updateToken(token) {
this._token = token;
}
}
exports.Configuration = Configuration;

@@ -1,25 +0,2 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _map = require('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
/**

@@ -29,42 +6,35 @@ * Container for entities which are known by the client

*/
var EntitiesCache = function () {
function EntitiesCache() {
(0, _classCallCheck3.default)(this, EntitiesCache);
(0, _defineProperties2.default)(this, {
_names: { value: new _map2.default() },
_entities: { value: 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;
class EntitiesCache {
constructor() {
this.names = new Map();
this.entities = new Map();
}
}, {
key: 'get',
value: function get(id, type) {
return this._entities.get(id) || this._getResolved(id, type) || null;
store(entity) {
let 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;
getResolved(id, type) {
let resolvedSid = this.names.get(type + '::' + id);
return resolvedSid ? this.entities.get(resolvedSid) : null;
}
}]);
return EntitiesCache;
}();
exports.default = EntitiesCache;
module.exports = exports['default'];
get(id, type) {
return this.entities.get(id) || this.getResolved(id, type) || null;
}
remove(sid) {
let cached = this.entities.get(sid);
if (cached) {
this.entities.delete(sid);
if (cached.uniqueName) {
this.names.delete(cached.type + '::' + cached.uniqueName);
}
}
}
}
exports.EntitiesCache = EntitiesCache;

@@ -1,105 +0,36 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _events = require('events');
var _events2 = _interopRequireDefault(_events);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Base class for all Sync entity types
*/
var Entity = function (_EventEmitter) {
(0, _inherits3.default)(Entity, _EventEmitter);
function Entity(deps) {
(0, _classCallCheck3.default)(this, Entity);
var _this = (0, _possibleConstructorReturn3.default)(this, (Entity.__proto__ || (0, _getPrototypeOf2.default)(Entity)).call(this));
(0, _defineProperties2.default)(_this, {
_deps: { value: deps }
});
return _this;
}
/**
* Subscribe to changes of data entity
* @private
*/
(0, _createClass3.default)(Entity, [{
key: '_subscribe',
value: function _subscribe() {
this._deps.router.subscribe(this.sid, this);
return this;
"use strict";
const events_1 = require("events");
class SyncEntity extends events_1.EventEmitter {
constructor(services) {
super();
this.services = services;
}
reportFailure(err) {
this.emit('failure', err);
}
/**
* Unsubscribe from changes of current data entity
* Subscribe to changes of data entity
* @private
*/
}, {
key: '_unsubscribe',
value: function _unsubscribe() {
this._deps.router.unsubscribe(this.sid);
return this;
_subscribe() {
this.services.router.subscribe(this.sid, this);
return this;
}
/**
* Report an error, which is occured during internal processes
* Unsubscribe from changes of current data entity
* @private
*/
}, {
key: '_reportFailure',
value: function _reportFailure(err) {
this.emit('error', err);
_unsubscribe() {
this.services.router.unsubscribe(this.sid, this);
return this;
}
/**
* Closes current entity
* Remove server subscription, local cache, and other related stuff
* @public
*/
}, {
key: 'close',
value: function close() {
this._unsubscribe();
close() {
this._unsubscribe();
}
}]);
return Entity;
}(_events2.default);
exports.default = Entity;
module.exports = exports['default'];
}
exports.SyncEntity = SyncEntity;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = SyncEntity;

@@ -1,14 +0,5 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _client = require('./client');
var _client2 = _interopRequireDefault(_client);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = _client2.default;
module.exports = exports['default'];
"use strict";
const client_1 = require("./client");
exports.SyncClient = client_1.SyncClient;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = client_1.SyncClient;
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperties = require("babel-runtime/core-js/object/define-properties");
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**

@@ -29,57 +10,40 @@ * @class

*/
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) {
var _this = this;
(0, _classCallCheck3.default)(this, ListItem);
(0, _defineProperties2.default)(this, {
_data: { value: data },
_index: { value: data.index, writable: false },
_uri: { value: data.uri, writable: false },
_value: { value: data.value, writable: true },
_revision: { value: data.revision, writable: true },
_lastEventId: { value: data.eventId, writable: true },
index: { enumerable: true,
get: function get() {
return _this._index;
} },
value: { enumerable: true,
get: function get() {
return _this._value;
} }
});
}
/**
* Update item data
* @param {Number} EventId Update event id
* @param {String} Revision Updated item revision
* @param {Object} Value Updated item data
* @private
*/
(0, _createClass3.default)(ListItem, [{
key: "_update",
value: function _update(eventId, revision, value) {
this._lastEventId = eventId;
this._revision = revision;
this._value = value;
return this;
class ListItem {
/**
* @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
*/
constructor(data) {
this.data = data;
}
}]);
return ListItem;
}();
get uri() { return this.data.uri; }
;
get revision() { return this.data.revision; }
;
get lastEventId() { return this.data.lastEventId; }
;
get index() { return this.data.index; }
;
get value() { return this.data.value; }
;
/**
* Update item data
* @param {Number} EventId Update event id
* @param {String} Revision Updated item revision
* @param {Object} Value Updated item data
* @private
*/
update(eventId, revision, value) {
this.data.lastEventId = eventId;
this.data.revision = revision;
this.data.value = value;
return this;
}
}
exports.ListItem = ListItem;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = ListItem;
module.exports = exports["default"];

@@ -1,42 +0,14 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _from = require('babel-runtime/core-js/array/from');
var _from2 = _interopRequireDefault(_from);
var _loglevel = require('loglevel');
var _loglevel2 = _interopRequireDefault(_loglevel);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
const log = require("loglevel");
function prepareLine(prefix, args) {
return [prefix].concat((0, _from2.default)(args));
return [prefix].concat(Array.from(args));
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = {
setLevel: function setLevel(level) {
_loglevel2.default.setLevel(level);
},
trace: function trace() {
_loglevel2.default.trace.apply(null, prepareLine('Sync T:', arguments));
},
debug: function debug() {
_loglevel2.default.debug.apply(null, prepareLine('Sync D:', arguments));
},
info: function info() {
_loglevel2.default.info.apply(null, prepareLine('Sync I:', arguments));
},
warn: function warn() {
_loglevel2.default.warn.apply(null, prepareLine('Sync W:', arguments));
},
error: function error() {
_loglevel2.default.error.apply(null, prepareLine('Sync E:', arguments));
}
setLevel: function (level) { log.setLevel(level); },
trace: function (...args) { log.trace.apply(null, prepareLine('Sync T:', args)); },
debug: function (...args) { log.debug.apply(null, prepareLine('Sync D:', args)); },
info: function (...args) { log.info.apply(null, prepareLine('Sync I:', args)); },
warn: function (...args) { log.warn.apply(null, prepareLine('Sync W:', args)); },
error: function (...args) { log.error.apply(null, prepareLine('Sync E:', args)); }
};
module.exports = exports['default'];
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperties = require("babel-runtime/core-js/object/define-properties");
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**

@@ -29,57 +10,40 @@ * @class

*/
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(data) {
var _this = this;
(0, _classCallCheck3.default)(this, MapItem);
(0, _defineProperties2.default)(this, {
_data: { value: data },
_key: { value: data.key, writable: false },
_uri: { value: data.uri, writable: false },
_value: { value: data.value, writable: true },
_revision: { value: data.revision, writable: true },
_lastEventId: { value: data.eventId, writable: true },
key: { enumerable: true,
get: function get() {
return _this._key;
} },
value: { enumerable: true,
get: function get() {
return _this._value;
} }
});
}
/**
* Update item data
* @param {Number} EventId Update event id
* @param {String} Revision Updated item revision
* @param {Object} Value Updated item data
* @private
*/
(0, _createClass3.default)(MapItem, [{
key: "_update",
value: function _update(eventId, revision, value) {
this._lastEventId = eventId;
this._revision = revision;
this._value = value;
return this;
class MapItem {
/**
* @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
*/
constructor(data) {
this.data = data;
}
}]);
return MapItem;
}();
get uri() { return this.data.uri; }
;
get revision() { return this.data.revision; }
;
get lastEventId() { return this.data.lastEventId; }
;
get key() { return this.data.key; }
;
get value() { return this.data.value; }
;
/**
* Update item data
* @param {Number} EventId Update event id
* @param {String} Revision Updated item revision
* @param {Object} Value Updated item data
* @private
*/
update(eventId, revision, value) {
this.data.lastEventId = eventId;
this.data.revision = revision;
this.data.value = value;
return this;
}
}
exports.MapItem = MapItem;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = MapItem;
module.exports = exports["default"];

@@ -1,150 +0,65 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _freeze = require('babel-runtime/core-js/object/freeze');
var _freeze2 = _interopRequireDefault(_freeze);
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _uuid = require('uuid');
var _uuid2 = _interopRequireDefault(_uuid);
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
const uuid = require("uuid");
const logger_1 = require("./logger");
const syncerror_1 = require("./syncerror");
function mapTransportError(transportError) {
if (transportError.status === 429) {
throw new syncerror_1.SyncError(transportError.body.message, 429);
}
else {
throw transportError;
}
}
/**
* @class Network
* @classdesc Separates network operations to make it possible to add some optimization/caching strategies
* @classdesc Incapsulates network operations to make it possible to add some optimization/caching strategies
*/
var Network = function () {
function Network(productId, clientInfo, config, transport) {
var _this = this;
(0, _classCallCheck3.default)(this, Network);
(0, _defineProperties2.default)(this, {
_config: { value: config },
_transport: { value: transport },
_headers: { get: function get() {
return {
class Network {
constructor(productId, clientInfo, config, transport) {
this.productId = productId;
this.clientInfo = clientInfo;
this.config = config;
this.transport = transport;
}
createHeaders() {
return {
'Content-Type': 'application/json',
'Twilio-Sync-Client-Info': (0, _stringify2.default)(clientInfo),
'Twilio-Request-Id': 'RQ' + _uuid2.default.v4().replace(/-/g, ''),
'X-Twilio-Product-Id': productId,
'X-Twilio-Token': _this._config.token
};
}
}
});
}
/**
* Make a GET request by given URI
* @param {string} uri is the target of the HTTP fetch.
* @param {boolean} forceTwilsock instructs (iff true) the transport layer to execute this request
* only when a Twilsock connection is avaliable. A request made at any other time will throw
* the exception of the Twilsock library in use.
* @Returns Promise<Response> Result of successful get request
*/
(0, _createClass3.default)(Network, [{
key: 'get',
value: function get(uri) {
var forceTwilsock = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
_logger2.default.debug('GET', uri, 'ID:', this._headers['Twilio-Request-Id']);
return this._transport.get(uri, this._headers, forceTwilsock);
'Twilio-Sync-Client-Info': JSON.stringify(this.clientInfo),
'Twilio-Request-Id': 'RQ' + uuid.v4().replace(/-/g, ''),
'X-Twilio-Product-Id': this.productId,
'X-Twilio-Token': this.config.token
};
}
/**
* Make a POST request to the given URI.
* @param {string} uri is the target of the HTTP fetch.
* @param {boolean} forceTwilsock instructs (iff true) the transport layer to execute this request
* only when a Twilsock connection is avaliable. A request made at any other time will throw
* the exception of the Twilsock library in use.
* Make a GET request by given URI
* @Returns Promise<Response> Result of successful get request
*/
}, {
key: 'post',
value: function post(uri, body, revision) {
var forceTwilsock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var headers = this._headers;
if (typeof revision !== 'undefined') {
headers['If-Match'] = revision;
}
_logger2.default.debug('POST', uri, 'ID:', this._headers['Twilio-Request-Id']);
return this._transport.post(uri, headers, body, forceTwilsock);
get(uri) {
let headers = this.createHeaders();
logger_1.default.debug('GET', uri, 'ID:', headers['Twilio-Request-Id']);
return this.transport.get(uri, headers).catch(mapTransportError);
}
/**
* Make a PUT request to the given URI.
* @param {string} uri is the target of the HTTP fetch.
* @param {boolean} forceTwilsock instructs (iff true) the transport layer to execute this request
* only when a Twilsock connection is avaliable. A request made at any other time will throw
* the exception of the Twilsock library in use.
*/
}, {
key: 'put',
value: function put(uri, body, revision) {
var forceTwilsock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var headers = this._headers;
if (typeof revision !== 'undefined') {
headers['If-Match'] = revision;
}
_logger2.default.debug('PUT', uri, 'ID:', this._headers['Twilio-Request-Id']);
return this._transport.put(uri, headers, body, forceTwilsock);
post(uri, body, revision, twilsockOnly) {
let headers = this.createHeaders();
if (typeof revision !== 'undefined') {
headers['If-Match'] = revision;
}
logger_1.default.debug('POST', uri, 'ID:', headers['Twilio-Request-Id']);
return this.transport.post(uri, headers, body, twilsockOnly).catch(mapTransportError);
}
/**
* Make a DELETE request to the given URI.
* @param {string} uri is the target of the HTTP fetch.
* @param {boolean} forceTwilsock instructs (iff true) the transport layer to execute this request
* only when a Twilsock connection is avaliable. A request made at any other time will throw
* the exception of the Twilsock library in use.
*/
}, {
key: 'delete',
value: function _delete(uri) {
var forceTwilsock = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
_logger2.default.debug('DELETE', uri, 'ID:', this._headers['Twilio-Request-Id']);
return this._transport.delete(uri, this._headers, forceTwilsock);
put(uri, body, revision) {
let headers = this.createHeaders();
if (typeof revision !== 'undefined') {
headers['If-Match'] = revision;
}
logger_1.default.debug('PUT', uri, 'ID:', headers['Twilio-Request-Id']);
return this.transport.put(uri, headers, body).catch(mapTransportError);
}
}]);
return Network;
}();
delete(uri) {
let headers = this.createHeaders();
logger_1.default.debug('DELETE', uri, 'ID:', headers['Twilio-Request-Id']);
return this.transport.delete(uri, headers).catch(mapTransportError);
}
}
exports.Network = Network;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Network;
(0, _freeze2.default)(Network);
module.exports = exports['default'];

@@ -1,25 +0,10 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**

@@ -33,38 +18,33 @@ * @class Paginator

*/
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);
(0, _defineProperties2.default)(this, {
prevToken: { value: prevToken },
nextToken: { value: nextToken },
source: { value: source },
hasNextPage: { value: !!nextToken, enumerable: true },
hasPrevPage: { value: !!prevToken, enumerable: true },
items: { get: function get() {
return items;
}, enumerable: true }
});
}
/**
* Request next page.
* Does not modify existing object
* @return {Promise<Paginator>}
*/
(0, _createClass3.default)(Paginator, [{
key: 'nextPage',
value: function nextPage() {
return this.hasNextPage ? this.source(this.nextToken) : _promise2.default.reject(new Error('No next page'));
class Paginator {
/*
* @constructor
* @param {Array} items Array of element for current page
* @param {Object} params
* @private
*/
constructor(items, source, prevToken, nextToken) {
this.prevToken = prevToken;
this.nextToken = nextToken;
this.items = items;
this.source = source;
}
get hasNextPage() { return !!this.nextToken; }
;
get hasPrevPage() { return !!this.prevToken; }
;
/**
* Request next page.
* Does not modify existing object
* @return {Promise<Paginator>}
*/
nextPage() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.hasNextPage) {
throw new Error('No next page');
}
return this.source(this.nextToken);
});
}
/**
* Request previous page.

@@ -74,13 +54,13 @@ * Does not modify existing object

*/
}, {
key: 'prevPage',
value: function prevPage() {
return this.hasPrevPage ? this.source(this.prevToken) : _promise2.default.reject(new Error('No previous page'));
prevPage() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.hasPrevPage) {
throw new Error('No previous page');
}
return this.source(this.prevToken);
});
}
}]);
return Paginator;
}();
}
exports.Paginator = Paginator;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Paginator;
module.exports = exports['default'];
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _freeze = require("babel-runtime/core-js/object/freeze");
var _freeze2 = _interopRequireDefault(_freeze);
var _promise = require("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var _defineProperties = require("babel-runtime/core-js/object/define-properties");
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var RetryingQueue = function () {
function RetryingQueue() {
(0, _classCallCheck3.default)(this, RetryingQueue);
(0, _defineProperties2.default)(this, {
_queue: { value: [] },
_isActive: { value: false, writable: true }
});
}
(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);
}
class RetryingQueue {
constructor() {
this.queue = new Array();
this.isActive = false;
}
}, {
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);
wakeupQueue() {
if (!this.isActive && this.queue.length > 0) {
this.isActive = true;
setTimeout(() => this.executeTask(this.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 result;
}).then(function (result) {
return _this4._pickSame(result);
}).catch(task.reject);
} else {
throw error;
}
} catch (e) {
task.reject(error);
pickNext() {
this.queue.shift();
if (this.queue.length === 0) {
this.isActive = false;
return;
}
});
setTimeout(() => this.executeTask(this.queue[0]), 0);
}
}, {
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
pickSame(arg) {
this.queue[0].arg = arg;
setTimeout(() => this.executeTask(this.queue[0]), 0);
}
executeTask(task) {
task.task(task.context, task.arg).then(result => {
this.pickNext();
task.resolve(result);
}).catch((error) => {
try {
if (task.handle) {
task.handle(error)
.then(result => this.pickSame(result))
.catch(task.reject);
}
else {
throw error;
}
}
catch (e) {
task.reject(error);
}
});
_this5._wakeupQueue();
});
}
}]);
return RetryingQueue;
}();
add(task, context, arg, errorHandler) {
return new Promise((resolve, reject) => {
this.queue.push({
task: task,
context: context,
arg: arg,
handle: errorHandler,
resolve: resolve,
reject: reject
});
this.wakeupQueue();
});
}
}
exports.RetryingQueue = RetryingQueue;
Object.freeze(RetryingQueue);
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = RetryingQueue;
(0, _freeze2.default)(RetryingQueue);
module.exports = exports["default"];

@@ -1,34 +0,15 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var COREDATA_DOCUMENT_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.document';
var COREDATA_LIST_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.list';
var COREDATA_MAP_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.map';
var SYNC_NOTIFICATION_TYPE = 'twilio.sync.event';
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const logger_1 = require("./logger");
const SYNC_DOCUMENT_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.document';
const SYNC_LIST_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.list';
const SYNC_MAP_NOTIFICATION_TYPE = 'com.twilio.rtd.cds.map';
const SYNC_NOTIFICATION_TYPE = 'twilio.sync.event';
/**

@@ -38,65 +19,43 @@ * @class Router

*/
var Router = function () {
function Router(params) {
var _this = this;
(0, _classCallCheck3.default)(this, Router);
(0, _defineProperties2.default)(this, {
_config: { value: params.config },
_subscriptions: { value: params.subscriptions },
_notifications: { value: params.notifications }
});
this._notifications.subscribe(COREDATA_DOCUMENT_NOTIFICATION_TYPE);
this._notifications.subscribe(COREDATA_LIST_NOTIFICATION_TYPE);
this._notifications.subscribe(COREDATA_MAP_NOTIFICATION_TYPE);
this._notifications.subscribe(SYNC_NOTIFICATION_TYPE);
this._notifications.on('message', this.onMessage.bind(this));
this._notifications.on('transportReady', function (state) {
if (state) {
_this.onConnected();
}
});
}
/**
* 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) {
// As it happens, all message types are intended for the Subscriptions manager.
//
_logger2.default.trace('Notification type:', type, 'content:', message);
this._subscriptions.acceptMessage(message);
class Router {
constructor(params) {
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);
console.log('Scheduled registration');
this.notifications.on('message', message => this.onMessage.bind(this));
this.notifications.on('transportReady', state => { if (state) {
this.onConnected();
} });
}
/**
* Entry point for all incoming messages
* @param {String} type - Type of incoming message
* @param {Object} message - Message to route
*/
onMessage(type, message) {
console.log('Message arrived!');
logger_1.default.trace('Notification type:', type, 'content:', message);
this.subscriptions.acceptMessage(message);
}
/**
* Subscribe for events
*/
}, {
key: 'subscribe',
value: function subscribe(sid, entity) {
this._subscriptions.add(sid, entity);
return _promise2.default.resolve(entity);
subscribe(sid, entity) {
return __awaiter(this, void 0, void 0, function* () {
yield this.subscriptions.add(sid, entity);
});
}
/**
* Unsubscribe from events
*/
}, {
key: 'unsubscribe',
value: function unsubscribe(sid) {
return this._subscriptions.remove(sid);
unsubscribe(sid, entity) {
return __awaiter(this, void 0, void 0, function* () {
yield this.subscriptions.remove(sid);
});
}
/**

@@ -106,13 +65,9 @@ * Handle transport establishing event

*/
}, {
key: 'onConnected',
value: function onConnected() {
this._subscriptions.poke();
onConnected() {
console.log('ON CONNECTED!');
this.subscriptions.poke();
}
}]);
return Router;
}();
}
exports.Router = Router;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Router;
module.exports = exports['default'];

@@ -1,51 +0,16 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _map = require('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _backoff = require('backoff');
var _backoff2 = _interopRequireDefault(_backoff);
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _syncerror = require('./syncerror');
var _syncerror2 = _interopRequireDefault(_syncerror);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var MAX_BATCH_SIZE = 1000;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/* eslint-disable key-spacing */
const Backoff = require("backoff");
const logger_1 = require("./logger");
const syncerror_1 = require("./syncerror");
const twilio_transport_1 = require("twilio-transport");
const MAX_BATCH_SIZE = 1000;
/**

@@ -55,42 +20,18 @@ * A data container used by the Subscriptions class to track subscribed entities' local

*/
/* eslint-disable key-spacing */
var SubscribedEntity = function () {
function SubscribedEntity(entity) {
var _this = this;
(0, _classCallCheck3.default)(this, SubscribedEntity);
(0, _defineProperties2.default)(this, {
sid: { get: function get() {
return entity.sid;
} },
type: { get: function get() {
return entity.type;
} },
lastEventId: { get: function get() {
return entity.lastEventId;
} },
localObject: { value: entity },
correlationId: { value: null, writable: true },
pendingPokeTimer: { value: null, writable: true },
rejectedWithError: { value: false, writable: true },
isInTransition: { get: function get() {
return _this.correlationId !== null;
} }
});
}
(0, _createClass3.default)(SubscribedEntity, [{
key: 'markAsFailed',
value: function markAsFailed(error) {
this.rejectedWithError = error;
class SubscribedEntity {
constructor(entity) {
this.localObject = entity;
this.correlationId = null;
}
}]);
return SubscribedEntity;
}();
get sid() { return this.localObject.sid; }
;
get type() { return this.localObject.type; }
;
get lastEventId() { return this.localObject.lastEventId; }
;
get isInTransition() { return this.correlationId !== null; }
markAsFailed(error) {
this.rejectedWithError = error;
}
}
/**

@@ -102,304 +43,158 @@ * @class Subscriptions

*/
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(config, network, TwilsockUnvailableErrorType) {
var _this2 = this;
(0, _classCallCheck3.default)(this, Subscriptions);
function createBackoff() {
var defaultBackoffConfig = {
randomisationFactor: 0.2,
initialDelay: 100,
maxDelay: 2 * 60 * 1000
};
return _backoff2.default.exponential((0, _extends3.default)(defaultBackoffConfig, config.backoffConfig || {}));
}
(0, _defineProperties2.default)(this, {
_ExceptionOnTwilsockUnavailable: { value: TwilsockUnvailableErrorType, writable: false },
_config: { value: config },
_network: { value: network },
_backoff: { value: createBackoff() },
// This is always the full set of subscribables (SubscribedEntity instances) intended by
// the client. At any point, whatever the state of these subscriptions on the server, this
// is the intent of the user to which the SDK must converge.
_subscriptions: { value: new _map2.default() },
// This includes the set of subscribables (SubscribedEntity instances) for whom a request
// has been dispatched (whether or not this particular request ultimately succeeds) to
// establish a live subscription. Entities are removed when the corresponding "cancel"
// request is dispatched.
_persisted: { value: new _map2.default() }
});
// 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 = _this2._getSubscriptionUpdateBatch(),
action = _getSubscriptionUpdat.action,
subscriptionRequests = _getSubscriptionUpdat.subscriptions;
if (action) {
_this2._applyNewSubscriptionUpdateBatch(action, subscriptionRequests);
} else {
_this2._backoff.reset();
_logger2.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;
}
class Subscriptions {
/**
* @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.
*/
constructor(services) {
this.services = services;
this.subscriptions = new Map();
this.persisted = new Map();
const defaultBackoffConfig = {
randomisationFactor: 0.2,
initialDelay: 100,
maxDelay: 2 * 60 * 1000
};
this.backoff = Backoff.exponential(Object.assign(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', () => {
let { action: action, subscriptions: subscriptionRequests } = this.getSubscriptionUpdateBatch();
if (action) {
this.applyNewSubscriptionUpdateBatch(action, subscriptionRequests);
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
else {
this.backoff.reset();
logger_1.default.info('All subscriptions resolved.');
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
});
}
getSubscriptionUpdateBatch() {
function substract(these, those, ignoreCurrentOp, limit) {
let result = [];
for (let [thisKey, thisValue] of these) {
const otherValue = those.get(thisKey);
if (!otherValue && (ignoreCurrentOp || !thisValue.isInTransition) && !thisValue.rejectedWithError) {
result.push(thisValue);
if (limit && result.length >= limit) {
break;
}
}
}
}
return result;
}
return result;
}
var listToAdd = substract(this._subscriptions, this._persisted, false, MAX_BATCH_SIZE).map(function (x) {
return new SubscribedEntity(x);
});
if (listToAdd.length > 0) {
return { action: 'establish', subscriptions: listToAdd };
}
var listToRemove = substract(this._persisted, this._subscriptions, true, MAX_BATCH_SIZE);
if (listToRemove.length > 0) {
return { action: 'cancel', subscriptions: listToRemove };
}
return {};
let listToAdd = substract(this.subscriptions, this.persisted, false, MAX_BATCH_SIZE)
.map(x => new SubscribedEntity(x));
if (listToAdd.length > 0) {
return { action: 'establish', subscriptions: listToAdd };
}
let listToRemove = substract(this.persisted, this.subscriptions, true, MAX_BATCH_SIZE);
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) {
var _this3 = this;
// Keeping in mind that events may begin flowing _before_ we receive the response
requests = this._processLocalActions(action, requests);
var correlationId = new Date().getTime();
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = (0, _getIterator3.default)(requests), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var subscribed = _step2.value;
this._recordActionAttemptOn(subscribed, action, correlationId);
}
// Send this batch to the service
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
persist() {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
this.backoff.backoff();
}
}
this._request(action, correlationId, requests.map(function (object) {
return {
object_sid: object.sid, // eslint-disable-line camelcase
object_type: object.type, // eslint-disable-line camelcase
last_event_id: action === 'establish' ? object.lastEventId : undefined // eslint-disable-line no-undefined, camelcase
};
})).then(function (response) {
if (action === 'establish') {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = (0, _getIterator3.default)(requests), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var subscribed = _step3.value;
if (subscribed.correlationId === correlationId) {
_this3._beginReplayTimeout(response.body.estimated_delivery_in_ms, subscribed, action, correlationId);
}
catch (e) { } // eslint-disable-line no-empty
}
applyNewSubscriptionUpdateBatch(action, requests) {
return __awaiter(this, void 0, void 0, function* () {
// Keeping in mind that events may begin flowing _before_ we receive the response
requests = this.processLocalActions(action, requests);
const correlationId = new Date().getTime();
for (const subscribed of requests) {
this.recordActionAttemptOn(subscribed, action, correlationId);
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
// Send this batch to the service
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
console.log('POKE: so post', requests.map(x => `{ sid: ${x.sid}, type: ${x.type} }`));
let response = yield this.request(action, correlationId, requests.map(object => ({
object_sid: object.sid,
object_type: object.type,
last_event_id: action === 'establish' ? object.lastEventId : undefined // eslint-disable-line no-undefined, camelcase
})));
console.log('-- OK');
if (action === 'establish') {
for (const subscribed of requests) {
if (subscribed.correlationId === correlationId) {
this.beginReplayTimeout(response.body.estimated_delivery_in_ms, subscribed, action, correlationId);
}
}
}
this.backoff.reset();
}
}
catch (e) {
for (const attemptedSubscription of requests) {
this.recordActionFailureOn(attemptedSubscription, action);
}
if (e instanceof twilio_transport_1.TwilsockUnavailableError) {
logger_1.default.debug(`Twilsock connection (required for subscription) not ready (c:${correlationId}); waiting…`);
this.backoff.reset();
}
else {
logger_1.default.debug(`Failed an attempt to ${action} subscriptions (c:${correlationId}); retrying`, e);
this.backoff.backoff(e);
}
}
});
}
processLocalActions(action, requests) {
if (action === 'cancel') {
return requests.filter(request => !request.rejectedWithError);
}
_this3._backoff.reset();
}).catch(function (e) {
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = (0, _getIterator3.default)(requests), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var attemptedSubscription = _step4.value;
_this3._recordActionFailureOn(attemptedSubscription, action);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
return requests;
}
recordActionAttemptOn(attemptedSubscription, action, correlationId) {
if (action === 'establish') {
this.persisted.set(attemptedSubscription.sid, attemptedSubscription);
attemptedSubscription.correlationId = correlationId;
}
else {
let persistedSubscription = this.persisted.get(attemptedSubscription.sid);
if (persistedSubscription) {
persistedSubscription.correlationId = null;
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
if (e instanceof _this3._ExceptionOnTwilsockUnavailable) {
_logger2.default.debug('Twilsock connection (required for subscription) not ready (c:' + correlationId + '); waiting\u2026');
_this3._backoff.reset();
} else {
_logger2.default.debug('Failed an attempt to ' + action + ' subscriptions (c:' + correlationId + '); retrying', e);
_this3._backoff.backoff(e);
}
recordActionFailureOn(attemptedSubscription, action) {
attemptedSubscription.correlationId = null;
if (action === 'establish') {
this.persisted.delete(attemptedSubscription.sid);
}
});
}
}, {
key: '_processLocalActions',
value: function _processLocalActions(action, requests) {
if (action === 'cancel') {
return requests.filter(function (request) {
return !request.rejectedWithError;
});
}
return requests;
request(action, correlationId, requests) {
logger_1.default.debug(`Attempting '${action}' request (c:${correlationId}):`, requests);
/* eslint-disable camelcase */
const requestBody = {
event_protocol_version: 3,
action,
correlation_id: correlationId,
requests
};
/* eslint-enable camelcase */
return this.services.network.post(this.services.config.subscriptionsUri, requestBody, null, true);
}
}, {
key: '_recordActionAttemptOn',
value: function _recordActionAttemptOn(attemptedSubscription, action, correlationId) {
if (action === 'establish') {
this._persisted.set(attemptedSubscription.sid, attemptedSubscription);
attemptedSubscription.correlationId = correlationId;
} else {
// cancel
var persistedSubscription = this._persisted.get(attemptedSubscription.sid);
if (persistedSubscription) {
persistedSubscription.correlationId = null;
beginReplayTimeout(timeout, subscription, action, failingCorrelationId) {
let isNumeric = !isNaN(parseFloat(timeout)) && isFinite(timeout);
let isValidTimeout = isNumeric && timeout > 0;
if (isValidTimeout) {
subscription.pendingPokeTimer = setTimeout(() => {
if (subscription.correlationId === failingCorrelationId) {
logger_1.default.debug(`Attempt to ${action} ${subscription.sid} (c:${failingCorrelationId}) timed out without confirmation; trying again.`);
subscription.correlationId = null;
this.persisted.delete(subscription.sid);
this.persist();
}
}, timeout);
}
}
}
}, {
key: '_recordActionFailureOn',
value: function _recordActionFailureOn(attemptedSubscription, action) {
attemptedSubscription.correlationId = null;
if (action === 'establish') {
this._persisted.delete(attemptedSubscription.sid);
}
}
/**
* @private
*/
}, {
key: '_request',
value: function _request(action, correlationId, requests) {
_logger2.default.debug('Attempting \'' + action + '\' request (c:' + correlationId + '):', requests);
/* eslint-disable camelcase */
var requestBody = {
event_protocol_version: 3,
action: action,
correlation_id: correlationId,
requests: requests
};
/* eslint-enable camelcase */
return this._network.post(this._config.subscriptionsUri, requestBody, null, true);
}
}, {
key: '_beginReplayTimeout',
value: function _beginReplayTimeout(timeout, subscription, action, failingCorrelationId) {
var _this4 = this;
var isNumeric = !isNaN(parseFloat(timeout)) && isFinite(timeout);
var isValidTimeout = isNumeric && timeout > 0;
if (isValidTimeout) {
subscription.pendingPokeTimer = setTimeout(function () {
if (subscription.correlationId === failingCorrelationId) {
_logger2.default.debug('Attempt to ' + action + ' ' + subscription.sid + ' (c:' + failingCorrelationId + ') timed out without confirmation; trying again.');
subscription.correlationId = null;
_this4._persisted.delete(subscription.sid);
_this4._persist();
}
}, timeout);
}
}
/**
* Establishes intent to be subscribed to this entity. That subscription will be effected

@@ -416,18 +211,13 @@ * asynchronously.

*/
}, {
key: 'add',
value: function add(sid, entity) {
_logger2.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, entity);
this._persist();
add(sid, entity) {
logger_1.default.debug(`Establishing intent to subscribe to ${sid}`);
const 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, entity);
this.persist();
}
/**

@@ -444,13 +234,9 @@ * Establishes the caller's intent to no longer be subscribed to this entity. Following this

*/
}, {
key: 'remove',
value: function remove(sid) {
_logger2.default.debug('Establishing intent to unsubscribe from ' + sid);
var removed = this._subscriptions.delete(sid);
if (removed) {
this._persist();
}
remove(sid) {
logger_1.default.debug(`Establishing intent to unsubscribe from ${sid}`);
const removed = this.subscriptions.delete(sid);
if (removed) {
this.persist();
}
}
/**

@@ -464,106 +250,101 @@ * The point of ingestion for remote incoming messages (e.g. new data was written to a map

*/
}, {
key: 'acceptMessage',
value: function acceptMessage(message) {
_logger2.default.trace('Subscriptions received', message);
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)_/) || {}).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 return undefined; // eslint-disable-line no-undefined
};
this._applyEventToSubscribedEntity(typedSid(), message);
}
break;
default:
_logger2.default.debug('Dropping unknown message type ' + message.event_type);
break;
}
acceptMessage(message) {
logger_1.default.trace('Subscriptions received', message);
console.log('Subscriptions received', message);
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)_/) || {}).input:
{
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
return undefined; // eslint-disable-line no-undefined
}
;
this.applyEventToSubscribedEntity(typedSid(), message);
}
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.correlationId === correlationId) {
if (message.replay_status === 'interrupted') {
_logger2.default.debug('Event Replay for subscription to ' + sid + ' (c:' + correlationId + ') interrupted; continuing eagerly.');
clearTimeout(subscriptionIntent.pendingPokeTimer);
subscriptionIntent.pendingPokeTimer = null;
subscriptionIntent.correlationId = null;
this._persisted.delete(subscriptionIntent.sid);
this._backoff.reset();
} else if (message.replay_status === 'completed') {
_logger2.default.debug('Event Replay for subscription to ' + sid + ' (c:' + correlationId + ') completed. Subscription is ready.');
clearTimeout(subscriptionIntent.pendingPokeTimer);
subscriptionIntent.pendingPokeTimer = null;
subscriptionIntent.correlationId = null;
this._persisted.set(message.object_sid, subscriptionIntent);
this._backoff.reset();
applySubscriptionEstablishedMessage(message, correlationId) {
const sid = message.object_sid;
let subscriptionIntent = this.persisted.get(message.object_sid);
if (subscriptionIntent && subscriptionIntent.correlationId === correlationId) {
if (message.replay_status === 'interrupted') {
logger_1.default.debug(`Event Replay for subscription to ${sid} (c:${correlationId}) interrupted; continuing eagerly.`);
clearTimeout(subscriptionIntent.pendingPokeTimer);
subscriptionIntent.pendingPokeTimer = null;
subscriptionIntent.correlationId = 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.`);
clearTimeout(subscriptionIntent.pendingPokeTimer);
subscriptionIntent.pendingPokeTimer = null;
subscriptionIntent.correlationId = null;
this.persisted.set(message.object_sid, subscriptionIntent);
this.backoff.reset();
}
}
} else {
_logger2.default.debug('Late message for ' + message.object_sid + ' (c:' + correlationId + ') dropped.');
}
this._persist();
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.correlationId === correlationId) {
clearTimeout(persistedSubscription.pendingPokeTimer);
persistedSubscription.pendingPokeTimer = null;
persistedSubscription.correlationId = null;
this._persisted.delete(message.object_sid);
} else {
_logger2.default.debug('Late message for ' + message.object_sid + ' (c:' + correlationId + ') dropped.');
}
this._persist();
applySubscriptionCancelledMessage(message, correlationId) {
let persistedSubscription = this.persisted.get(message.object_sid);
if (persistedSubscription && persistedSubscription.correlationId === correlationId) {
clearTimeout(persistedSubscription.pendingPokeTimer);
persistedSubscription.pendingPokeTimer = null;
persistedSubscription.correlationId = null;
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.correlationId === correlationId) {
subscription.markAsFailed(message.error);
_logger2.default.error('Failed to subscribe on ' + subscription.sid, message.error);
subscriptionIntent._reportFailure(new _syncerror2.default('Failed to subscribe on service events'));
applySubscriptionFailedMessage(message, correlationId) {
const sid = message.object_sid;
let subscriptionIntent = this.subscriptions.get(sid);
let subscription = this.persisted.get(sid);
if (subscriptionIntent && subscription) {
if (subscription.correlationId === correlationId) {
subscription.markAsFailed(message.error);
logger_1.default.error(`Failed to subscribe on ${subscription.sid}`, message.error);
subscriptionIntent.reportFailure(new syncerror_1.SyncError('Failed to subscribe on service events'));
}
}
} else if (!subscriptionIntent && subscription) {
this._persisted.delete(sid);
}
this._persist();
else if (!subscriptionIntent && subscription) {
this.persisted.delete(sid);
}
this.persist();
}
}, {
key: '_applyEventToSubscribedEntity',
value: function _applyEventToSubscribedEntity(sid, message) {
var subscriptionIntent = sid ? this._subscriptions.get(sid) : null;
if (subscriptionIntent) {
message.event.type = message.event_type;
subscriptionIntent._update(message.event, true);
} else {
_logger2.default.debug('Message dropped for SID \'' + sid + '\', for which there is no subscription.');
}
applyEventToSubscribedEntity(sid, message) {
let subscriptionIntent = sid ? this.subscriptions.get(sid) : null;
if (subscriptionIntent) {
message.event.type = message.event_type;
subscriptionIntent._update(message.event);
}
else {
logger_1.default.debug(`Message dropped for SID '${sid}', for which there is no subscription.`);
}
}
/**

@@ -576,88 +357,30 @@ * Prompts a playback of any missed changes made to any subscribed object. This method

*/
}, {
key: 'poke',
value: function poke() {
_logger2.default.info('Triggering event replay for all subscriptions.');
var failedSubscriptions = [];
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = (0, _getIterator3.default)(this._persisted), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var _step5$value = (0, _slicedToArray3.default)(_step5.value, 2),
_ = _step5$value[0],
it = _step5$value[1];
// eslint-disable-line no-unused-vars
clearTimeout(it.pendingPokeTimer);
it.pendingPokeTimer = null;
it.correlationId = null;
if (it.rejectedWithError) {
failedSubscriptions.push(it);
}
poke() {
logger_1.default.info('Triggering event replay for all subscriptions.');
let failedSubscriptions = [];
for (const [_, it] of this.persisted) {
clearTimeout(it.pendingPokeTimer);
it.pendingPokeTimer = null;
it.correlationId = null;
if (it.rejectedWithError) {
failedSubscriptions.push(it);
}
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
console.log(`POKE: have ${this.persisted.size}, where ${failedSubscriptions.length} are failed`);
this.persisted.clear();
for (let it of failedSubscriptions) {
this.persisted.set(it.sid, it);
}
}
this._persisted.clear();
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = (0, _getIterator3.default)(failedSubscriptions), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var it = _step6.value;
this._persisted.set(it.sid, it);
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
this._persist();
this.persist();
}
/**
* Stops all communication, clears any subscription intent, and returns.
*/
}, {
key: 'shutdown',
value: function shutdown() {
this._backoff.reset();
this._subscriptions.clear();
shutdown() {
this.backoff.reset();
this.subscriptions.clear();
}
}]);
return Subscriptions;
}();
}
exports.Subscriptions = Subscriptions;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Subscriptions;
module.exports = exports['default'];

@@ -1,53 +0,14 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _entity = require('./entity');
var _entity2 = _interopRequireDefault(_entity);
var _jsondiff = require('./jsondiff');
var _jsondiff2 = _interopRequireDefault(_jsondiff);
var _retryingqueue = require('./retryingqueue');
var _retryingqueue2 = _interopRequireDefault(_retryingqueue);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const logger_1 = require("./logger");
const entity_1 = require("./entity");
const rfc6902_1 = require("rfc6902");
const retryingqueue_1 = require("./retryingqueue");
/**

@@ -67,70 +28,27 @@ * @class

*/
var SyncDocument = function (_SyncEntity) {
(0, _inherits3.default)(SyncDocument, _SyncEntity);
/**
* @constructor
* @private
*/
function SyncDocument(params, descriptor) {
(0, _classCallCheck3.default)(this, SyncDocument);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncDocument.__proto__ || (0, _getPrototypeOf2.default)(SyncDocument)).call(this, params));
(0, _defineProperties2.default)(_this, {
_config: { value: params.config },
_datasync: { value: params.datasync },
_network: { value: params.network },
_router: { value: params.router },
_updateQueue: { value: new _retryingqueue2.default() },
_pendingListeners: { value: {} },
_descriptor: { value: descriptor },
_sid: { value: descriptor.sid },
_revision: { value: descriptor.revision, writable: true },
_lastEventId: { value: descriptor.last_event_id, writable: true },
_data: { value: descriptor.data || {}, writable: true },
uri: { get: function get() {
return _this._descriptor.url;
} },
sid: { enumerable: true, get: function get() {
return _this._sid;
} },
value: { enumerable: true, get: function get() {
return _this._data;
} },
uniqueName: { enumerable: true, get: function get() {
return _this._descriptor.unique_name || null;
} }
});
_this._initialize();
return _this;
}
(0, _createClass3.default)(SyncDocument, [{
key: '_initialize',
class SyncDocument extends entity_1.SyncEntity {
/**
* @constructor
* @private
*/
value: function _initialize() {
var _this2 = this;
['keyAdded', 'keyRemoved', 'keyUpdated', 'keyAddedRemotely', 'keyRemovedRemotely', 'keyUpdatedRemotely'].forEach(function (eventName) {
_this2._pendingListeners[eventName] = {};
_this2.on(eventName, function (path, data) {
var handlers = _this2._pendingListeners[eventName][path] || [];
handlers.forEach(function (handler) {
handler(data);
});
_this2._pendingListeners[eventName][path] = [];
});
});
constructor(services, descriptor, onRemoveDocument) {
super(services);
this.actionQueue = new retryingqueue_1.RetryingQueue();
this.descriptor = descriptor;
this.onRemoveDocument = onRemoveDocument;
}
get uri() { return this.descriptor.url; }
;
get revision() { return this.descriptor.revision; }
;
get lastEventId() { return this.descriptor.last_event_id; }
;
get sid() { return this.descriptor.sid; }
;
get value() { return this.descriptor.data; }
;
get uniqueName() { return this.descriptor.unique_name || null; }
;
static get type() { return 'document'; }
get type() { return 'document'; }
/**

@@ -140,24 +58,19 @@ * Update data entity with new data

*/
}, {
key: '_update',
value: function _update(update) {
switch (update.type) {
case 'document_updated':
if (update.id > this._lastEventId) {
var originalData = this._data;
this._lastEventId = update.id;
this._revision = update.document_revision;
this._data = update.document_data;
this._traverse(originalData, update.document_data, false);
this.emit('updated', update.document_data, false);
this.emit('updatedRemotely', update.document_data);
}
break;
case 'document_removed':
this.emit('removed', false);
this.emit('removedRemotely');
}
_update(update) {
switch (update.type) {
case 'document_updated':
if (update.id > this.lastEventId) {
let 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);
}
break;
case 'document_removed':
this.onRemoved(false);
}
}
/**

@@ -167,29 +80,25 @@ * Calculate diff between old and new data

*/
}, {
key: '_traverse',
value: function _traverse(originalData, updatedData, isLocalEvent) {
var _this3 = this;
var diff = _jsondiff2.default.diff(originalData, updatedData);
diff.forEach(function (row) {
if (row.op === 'add') {
_this3.emit('keyAdded', row.path, row.value, isLocalEvent);
if (!isLocalEvent) {
_this3.emit('keyAddedRemotely', row.path, row.value);
}
} else if (row.op === 'replace') {
_this3.emit('keyUpdated', row.path, row.value, isLocalEvent);
if (!isLocalEvent) {
_this3.emit('keyUpdatedRemotely', row.path, row.value);
}
} else if (row.op === 'remove') {
_this3.emit('keyRemoved', row.path, isLocalEvent);
if (!isLocalEvent) {
_this3.emit('keyRemovedRemotely', row.path);
}
}
});
traverse(originalData, updatedData, isLocalEvent) {
let diff = rfc6902_1.createPatch(originalData, updatedData);
diff.forEach((row) => {
if (row.op === 'add') {
this.emit('keyAdded', row.path, row.value, isLocalEvent);
if (!isLocalEvent) {
this.emit('keyAddedRemotely', row.path, row.value);
}
}
else if (row.op === 'replace') {
this.emit('keyUpdated', row.path, row.value, isLocalEvent);
if (!isLocalEvent) {
this.emit('keyUpdatedRemotely', row.path, row.value);
}
}
else if (row.op === 'remove') {
this.emit('keyRemoved', row.path, isLocalEvent);
if (!isLocalEvent) {
this.emit('keyRemovedRemotely', row.path);
}
}
});
}
/**

@@ -200,9 +109,6 @@ * @returns {Object} Internal data of entity

*/
}, {
key: 'get',
value: function get(path) {
return !path ? this._data : this._value(path);
get(path) {
// return !path ? this.value : this.value(path);
return this.value;
}
/**

@@ -215,59 +121,42 @@ * Set new value for the document

*/
}, {
key: 'set',
value: function set(value, conditional) {
return this._actualSet(value, conditional ? function () {
throw new Error('Revision mismatch');
} : null);
set(value, conditional) {
return this._actualSet(value, conditional ? () => { throw new Error('Revision mismatch'); }
: null);
}
/**
* @private
*/
}, {
key: '_actualSet',
value: function _actualSet(data, conflictResolver) {
var _this4 = this;
var resolver = void 0;
var arg = { data: data };
if (conflictResolver) {
arg.revision = this._revision;
resolver = function resolver(err) {
if (err.status === 412) {
return _this4._softSync().then(function () {
return {
revision: _this4._revision,
data: conflictResolver(_this4._data, data)
};
_actualSet(data, conflictResolver) {
let resolver;
let arg = { data,
revision: (conflictResolver ? this.revision : undefined) };
if (conflictResolver) {
resolver = (err) => __awaiter(this, void 0, void 0, function* () {
if (err.status === 412) {
yield this.softSync();
return { revision: this.revision,
data: conflictResolver(this.value, data) };
}
throw err;
});
}
throw err;
};
}
return this._updateQueue.add(this._set.bind(this), this.uri, arg, resolver).then(function (result) {
_this4._revision = result.revision;
_this4._data = result.data;
return data;
}).then(function (_data) {
_this4.emit('updated', _data, true);
});
}
return this.actionQueue
.add(this._set.bind(this), this.uri, arg, resolver)
.then(result => {
this.descriptor.revision = result.revision;
this.descriptor.data = result.data;
this.emit('updated', this.value, true);
return this.value;
});
}
/**
* @param {Document~Mutator} mutator Function to apply to current data in order to modify it.
* Can be called multiple times if same data modified remotely at the same time.
* @return {Promise}
* @return {Promise<Object>}
*/
}, {
key: 'mutate',
value: function mutate(mutator) {
return this._actualSet(mutator(this._data), mutator);
mutate(mutator) {
return __awaiter(this, void 0, void 0, function* () {
return this._actualSet(mutator(this.value), mutator);
});
}
/**

@@ -277,20 +166,11 @@ * @param {Object} update Set of fields to update

*/
}, {
key: 'update',
value: function update(obj) {
return this.mutate(function (remote) {
(0, _extends3.default)(remote, obj);
return remote;
});
update(obj) {
return this.mutate(remote => Object.assign(remote, obj));
}
}, {
key: '_set',
value: function _set(context, param) {
return this._network.post(this.uri, { data: param.data }, param.revision).then(function (response) {
var revision = response.body.revision;
return { revision: revision, data: param.data };
});
_set(context, param) {
return __awaiter(this, void 0, void 0, function* () {
let response = yield this.services.network.post(this.uri, { data: param.data }, param.revision);
return { revision: response.body.revision, data: param.data };
});
}
/**

@@ -300,45 +180,21 @@ * Get new data from server

*/
}, {
key: '_softSync',
value: function _softSync() {
var _this5 = this;
return this._network.get(this.uri).then(function (response) {
_this5._update({ type: 'document_updated',
id: response.body.last_event_id,
document_revision: response.body.revision, // eslint-disable-line camelcase
document_data: response.body.data }); // eslint-disable-line camelcase
return _this5;
});
softSync() {
return this.services.network.get(this.uri)
.then(response => {
this._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 this;
})
.catch(err => {
if (err.status === 404) {
this.onRemoved(false);
}
else {
logger_1.default.error(`Can't get updates for ${this.sid}:`, err);
}
});
}
/**
* Download new data from service and overwrite local changes
* Won't fire any events and callbacks about changes
* @private
*/
}, {
key: '_forceSync',
value: function _forceSync() {
var _this6 = this;
return this._network.get(this.uri).then(function (response) {
_this6._revision = response.body.revision;
_this6._data = response.body.data;
return _this6;
}).catch(function (reason) {
_logger2.default.error('Failed to get entity:', reason);
});
}
}, {
key: 'addEventHandler',
value: function addEventHandler(eventName, path, handler) {
var handlers = this._pendingListeners[eventName][path] || [];
handlers.push(handler);
this._pendingListeners[eventName][path] = handlers;
}
/**
* Get value by given path

@@ -348,24 +204,24 @@ * @param {string} path JSON path

*/
}, {
key: '_value',
value: function _value(path) {
var _this7 = this;
var result = void 0;
/*
_value(path) {
let result;
try {
(function () {
var pathArr = path.replace(/^\/|\/$/gm, '').split('/');
var obj = _this7.data;
pathArr.forEach(function (el) {
obj = obj[el];
});
result = obj;
})();
let pathArr = path.replace(/^\/|\/$/gm, '').split('/');
let obj = this.data;
pathArr.forEach((el) => { obj = obj[el]; });
result = obj;
} catch (e) {
_logger2.default.warn('Failed to get value:', e);
log.warn('Failed to get value:', e);
}
return result;
}
*/
onRemoved(locally) {
this._unsubscribe();
// Should also do some cleanup here
this.emit('removed', locally);
if (!locally) {
this.emit('removedRemotely');
}
}
/**

@@ -376,28 +232,13 @@ * Removes document from service

*/
}, {
key: 'removeDocument',
value: function removeDocument() {
var _this8 = this;
return this._network.delete(this.uri).then(function () {
_this8.emit('removed', true);
});
removeDocument() {
return __awaiter(this, void 0, void 0, function* () {
this.onRemoveDocument(this.sid);
yield this.services.network.delete(this.uri);
this.onRemoved(true);
});
}
}, {
key: 'type',
get: function get() {
return 'document';
}
}, {
key: 'lastEventId',
get: function get() {
return this._lastEventId;
}
}]);
return SyncDocument;
}(_entity2.default);
}
exports.SyncDocument = SyncDocument;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = SyncDocument;
/**

@@ -409,3 +250,2 @@ * Applies a transformation to the document value

*/
/**

@@ -416,3 +256,2 @@ * Fired when document value changed

*/
/**

@@ -423,3 +262,2 @@ * Fired when document value changed remotely

*/
/**

@@ -429,3 +267,2 @@ * Fired when document removed from server

*/
/**

@@ -435,3 +272,1 @@ * Fired when document removed from server remotely

*/
module.exports = exports['default'];
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperties = require("babel-runtime/core-js/object/define-properties");
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = require("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var SyncError = function (_Error) {
(0, _inherits3.default)(SyncError, _Error);
function SyncError(message, code) {
(0, _classCallCheck3.default)(this, SyncError);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncError.__proto__ || (0, _getPrototypeOf2.default)(SyncError)).call(this));
(0, _defineProperties2.default)(_this, {
name: { value: _this.constructor.name, enumerable: true },
message: { value: message, enumerable: true },
code: { value: code, enumerable: true }
});
return _this;
}
return SyncError;
}(Error);
/**
* Generic SyncLibrary error class
*/
class SyncError extends Error {
constructor(message, status = 0) {
super();
this.name = this.constructor.name;
this.message = message;
this.status = status;
}
}
exports.SyncError = SyncError;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = SyncError;
module.exports = exports["default"];

@@ -1,71 +0,17 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _map = require('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _utils = require('./utils');
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _entity = require('./entity');
var _entity2 = _interopRequireDefault(_entity);
var _retryingqueue = require('./retryingqueue');
var _retryingqueue2 = _interopRequireDefault(_retryingqueue);
var _listitem = require('./listitem');
var _listitem2 = _interopRequireDefault(_listitem);
var _paginator = require('./paginator');
var _paginator2 = _interopRequireDefault(_paginator);
var _cache = require('./cache');
var _cache2 = _interopRequireDefault(_cache);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const utils_1 = require("./utils");
const logger_1 = require("./logger");
const entity_1 = require("./entity");
const retryingqueue_1 = require("./retryingqueue");
const listitem_1 = require("./listitem");
const paginator_1 = require("./paginator");
const cache_1 = require("./cache");
/**

@@ -86,83 +32,56 @@ * @alias List

*/
var SyncList = function (_SyncEntity) {
(0, _inherits3.default)(SyncList, _SyncEntity);
/**
* @private
*/
function SyncList(deps, descriptor) {
(0, _classCallCheck3.default)(this, SyncList);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncList.__proto__ || (0, _getPrototypeOf2.default)(SyncList)).call(this, deps));
(0, _defineProperties2.default)(_this, {
_config: { value: deps.config, writable: false },
_deps: { value: deps, writable: false },
_descriptor: { value: descriptor },
_tombstones: { value: new _map2.default() },
_updateQueue: { value: new _retryingqueue2.default() },
_cache: { value: new _cache2.default() },
_links: { get: function get() {
return _this._descriptor.links;
} },
_context: { writable: true },
_revision: { value: descriptor.revision, writable: true },
_lastEventId: { value: descriptor.last_event_id, writable: true },
_items: { value: new _map2.default() },
uri: { get: function get() {
return _this._descriptor.url;
} },
sid: { enumerable: true, get: function get() {
return _this._descriptor.sid;
} },
uniqueName: { enumerable: true, get: function get() {
return _this._descriptor.unique_name || null;
} }
});
return _this;
}
(0, _createClass3.default)(SyncList, [{
key: '__set',
value: function __set(location, param) {
return this._deps.network.post(location, { data: param.data }, param.revision).then(function (response) {
var result = response.body;
result.data = param.data;
return result;
});
class SyncList extends entity_1.SyncEntity {
/**
* @private
*/
constructor(services, descriptor, onRemoveList) {
super(services);
this.actionQueue = new retryingqueue_1.RetryingQueue();
this.cache = new cache_1.Cache();
this.descriptor = descriptor;
this.onRemoveList = onRemoveList;
}
}, {
key: '_set',
value: function _set(item, value, resolver) {
var _this2 = this;
if (!resolver) {
return this._deps.network.post(item._uri, { data: value }).then(function (result) {
return item._update(result.body.last_event_id, result.body.revision, value);
get uri() { return this.descriptor.url; }
;
get revision() { return this.descriptor.revision; }
;
get lastEventId() { return this.descriptor.last_event_id; }
;
get links() { return this.descriptor.links; }
;
get sid() { return this.descriptor.sid; }
;
get uniqueName() { return this.descriptor.unique_name || null; }
;
static get type() { return 'list'; }
get type() { return 'list'; }
__set(location, param) {
return __awaiter(this, void 0, void 0, function* () {
let response = yield this.services.network.post(location, { data: param.data }, param.revision);
response.body.data = param.data;
return response.body;
});
}
var _resolver = function _resolver(err) {
if (err.status === 412) {
return _this2._softSync().then(function () {
return _this2.get(item.index);
}).then(function (result) {
return {
revision: result._revision,
data: resolver(result.value, value)
}
_set(item, value, resolver) {
return __awaiter(this, void 0, void 0, function* () {
if (!resolver) {
let result = yield this.services.network.post(item.uri, { data: value });
return item.update(result.body.last_event_id, result.body.revision, value);
}
let _resolver = (err) => {
if (err.status === 412) {
return this.queryEvents()
.then(() => this.get(item.index))
.then(result => ({
revision: result.revision,
data: resolver(result.value, value)
}));
}
throw err;
};
});
}
throw err;
};
return this._updateQueue.add(this.__set.bind(this), item._uri, { revision: item._revision, data: value }, _resolver).then(function (result) {
return item._update(result.last_event_id, result.revision, result.data);
});
return this.actionQueue
.add(this.__set.bind(this), item.uri, { revision: item.revision, data: value }, _resolver)
.then(result => item.update(result.last_event_id, result.revision, result.data));
});
}
/**

@@ -173,30 +92,15 @@ * Add element to the List

*/
}, {
key: 'push',
value: function push(value) {
var _this3 = this;
return this._deps.network.post(this._links.items, { data: value }).then(function (response) {
var item = new _listitem2.default({ index: Number(response.body.index),
revision: response.body.revision,
eventId: response.body.last_event_id,
uri: response.body.url,
value: value });
if (!_this3._items.has(item.index)) {
_this3._items.set(item.index, item);
} else {
var localItem = _this3._items.get(item.index);
if (localItem._lastEventId < item.last_event_id) {
localItem._update(item._lastEventId, item._revision, item.value);
}
item = localItem;
}
_this3.emit('itemAdded', item, true);
return item;
});
push(value) {
return __awaiter(this, void 0, void 0, function* () {
let response = yield this.services.network.post(this.links.items, { data: value });
let index = Number(response.body.index);
let 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 item;
});
}
/**

@@ -206,32 +110,19 @@ * Update existing item in a List

* @param {Object} value - value to set
* @param {Boolean} [conditional=false] Check for remote modification when updating.
* If true, promise will be rejected if value was remotely modified
* @returns {Promise<Item>} - A new element
*/
}, {
key: 'set',
value: function set(index, value, conditional) {
return this._actualSet(index, value, conditional ? function () {
throw new Error('Revision mismatch');
} : null);
set(index, value) {
return this._actualSet(index, value);
}
/**
* @private
*/
}, {
key: '_actualSet',
value: function _actualSet(index, value, resolver) {
var _this4 = this;
return this.get(index).then(function (item) {
return _this4._set(item, value, resolver);
}).then(function (item) {
_this4.emit('itemUpdated', item, true);
return item;
});
_actualSet(index, value, resolver) {
return __awaiter(this, void 0, void 0, function* () {
let item = yield this.get(index);
item = yield this._set(item, value, resolver);
this.emit('itemUpdated', item, true);
return item;
});
}
/**

@@ -244,13 +135,8 @@ * Updates the existing item value

*/
}, {
key: 'mutate',
value: function mutate(index, mutator) {
var _this5 = this;
return this.get(index).then(function (item) {
return _this5._actualSet(index, mutator(item.value), mutator);
});
mutate(index, mutator) {
return __awaiter(this, void 0, void 0, function* () {
let item = yield this.get(index);
return this._actualSet(index, mutator(item.value), mutator);
});
}
/**

@@ -261,12 +147,7 @@ * @param {Number} Index Item key

*/
}, {
key: 'update',
value: function update(index, obj) {
return this.mutate(index, function (remote) {
(0, _extends3.default)(remote, obj);
return remote;
});
update(index, obj) {
return __awaiter(this, void 0, void 0, function* () {
return this.mutate(index, remote => Object.assign(remote, obj));
});
}
/**

@@ -277,16 +158,10 @@ * Remove List item by index

*/
}, {
key: 'remove',
value: function remove(index) {
var _this6 = this;
return this.get(index).then(function (item) {
return _this6._deps.network.delete(item._uri);
}).then(function () {
_this6._items.delete(index);
_this6.emit('itemRemoved', index, true);
});
remove(index) {
return __awaiter(this, void 0, void 0, function* () {
let item = yield this.get(index);
yield this.services.network.delete(item.uri);
this.cache.delete(index, item.lastEventId);
this.emit('itemRemoved', index, true);
});
}
/**

@@ -297,22 +172,15 @@ * Retrieve item by index

*/
}, {
key: 'get',
value: function get(index) {
var _this7 = this;
var cachedItem = this._cache.get(index);
if (cachedItem) {
return _promise2.default.resolve(cachedItem);
}
return this._queryItems({ index: index }).then(function (result) {
if (result.items.length < 1) {
throw new Error('No item with index ' + index + ' found');
}
return _this7._cache.store(index, result.items[0]);
});
get(index) {
return __awaiter(this, void 0, void 0, function* () {
let cachedItem = this.cache.get(index);
if (cachedItem) {
return cachedItem;
}
let result = yield this.queryItems({ index });
if (result.items.length < 1) {
throw new Error('No item with index ' + index + ' found');
}
return this.cache.store(index, result.items[0], result.items[0].lastEventId);
});
}
/**

@@ -322,16 +190,9 @@ * Query events from servie and apply changes to the List

*/
}, {
key: '_queryEvents',
value: function _queryEvents() {
var _this8 = this;
var uri = this._links.events + '?From=' + (this._lastEventId + 1) + '&PageSize=100';
return this._deps.network.get(uri).then(function (response) {
return response.body.events.forEach(function (event) {
return _this8._update(event);
queryEvents() {
return __awaiter(this, void 0, void 0, function* () {
const uri = `${this.links.events}?From=${(this.lastEventId + 1)}&PageSize=100`;
let response = yield this.services.network.get(uri);
response.body.events.forEach(ev => this._update(ev));
});
});
}
/**

@@ -341,35 +202,22 @@ * Query items from the List

*/
}, {
key: '_queryItems',
value: function _queryItems(arg) {
var _this9 = this;
arg = arg || {};
var uri = new _utils.UriBuilder(this._links.items).arg('From', arg.from).arg('PageSize', arg.limit).arg('Index', arg.index).arg('PageToken', arg.pageToken).arg('Order', arg.order).build();
return this._deps.network.get(uri).then(function (response) {
var items = response.body.items.map(function (el) {
return new _listitem2.default({ index: Number(el.index),
uri: el.url,
revision: el.revision,
eventId: el.last_event_id,
value: el.data });
queryItems(arg) {
return __awaiter(this, void 0, void 0, function* () {
arg = arg || {};
const url = new utils_1.UriBuilder(this.links.items)
.arg('From', arg.from)
.arg('PageSize', arg.limit)
.arg('Index', arg.index)
.arg('PageToken', arg.pageToken)
.arg('Order', arg.order)
.build();
let response = yield this.services.network.get(url);
let items = response.body.items.map(el => this.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));
let meta = response.body.meta;
return new paginator_1.Paginator(items, pageToken => this.queryItems({ pageToken }), meta.previous_token, meta.next_token);
});
items.forEach(function (item, idx) {
var knownItem = _this9._items.get(item.index);
if (!knownItem) {
_this9._items.set(item.index, item);
} else {
items[idx] = knownItem;
}
});
var meta = response.body.meta;
return new _paginator2.default(items, function (pageToken) {
return _this9._queryItems({ pageToken: pageToken });
}, meta.previous_token, meta.next_token);
});
}
/**

@@ -384,12 +232,10 @@ * Query items from List

*/
}, {
key: 'getItems',
value: function getItems(args) {
args = args || {};
args.limit = args.pageSize || args.limit || 50;
args.order = args.order || 'asc';
return this._queryItems(args);
getItems(args) {
return __awaiter(this, void 0, void 0, function* () {
args = args || {};
args.limit = args.pageSize || args.limit || 50;
args.order = args.order || 'asc';
return this.queryItems(args);
});
}
/**

@@ -399,36 +245,29 @@ * @return {Promise<Object>} Context of List

*/
}, {
key: 'getContext',
value: function getContext() {
var _this10 = this;
if (typeof this._context !== 'undefined') {
return _promise2.default.resolve(this._context);
}
return this._deps.network.get(this._links.context).then(function (response) {
_this10._context = response.body.data;
return _this10._context;
});
getContext() {
return __awaiter(this, void 0, void 0, function* () {
if (this.context) {
return this.context;
}
let response = yield this.services.network.get(this.links.context);
this.context = response.body.data;
return this.context;
});
}
/**
* @private
*/
}, {
key: 'updateContext',
value: function updateContext(context) {
var _this11 = this;
return this._deps.network.post(this._links.context, { data: context }).then(function () {
_this11._context = context;
_this11.emit('contextUpdated', context, true);
}).catch(function (err) {
_logger2.default.error('Failed to update context', err);
throw err;
});
updateContext(context) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield this.services.network.post(this.links.context, { data: context });
this.context = context;
this.emit('contextUpdated', context, true);
return this;
}
catch (err) {
logger_1.default.error('Failed to update context', err);
throw err;
}
});
}
/**

@@ -439,13 +278,17 @@ * Remove list from service. It will be impossible to restore it.

*/
}, {
key: 'removeList',
value: function removeList() {
var _this12 = this;
return this._deps.network.delete(this.uri).then(function () {
_this12.emit('collectionRemoved', true);
});
removeList() {
return __awaiter(this, void 0, void 0, function* () {
this.onRemoveList(this.sid);
yield this.services.network.delete(this.uri);
this._onRemoved(true);
});
}
_onRemoved(locally) {
this._unsubscribe();
// Should also do some cleanup here
this.emit('collectionRemoved', locally);
if (!locally) {
this.emit('collectionRemovedRemotely');
}
}
/**

@@ -456,66 +299,58 @@ * Force to check for modifications on server

*/
}, {
key: '_softSync',
value: function _softSync() {
return this._queryEvents();
softSync() {
return __awaiter(this, void 0, void 0, function* () {
try {
yield this.queryEvents();
}
catch (err) {
if (err.status === 404) {
this._onRemoved(false);
}
else {
logger_1.default.error(`Can't get updates for ${this.sid}:`, err);
}
}
});
}
}, {
key: '_shouldIgnoreEvent',
value: function _shouldIgnoreEvent(key, eventId) {
return (this._tombstones.get(key) || -1) >= eventId;
shouldIgnoreEvent(key, eventId) {
return this.cache.isKnown(key, eventId);
}
/**
* Handle update event
*
* @param {Object} update
* @param {Boolean} reliable Caller should point if transport reliable or not
* For reliable transport it will advance lastEventId even if gaps in events were found
*
* Handle update, which came from the server
* @private
*/
}, {
key: '_update',
value: function _update(update, reliableTransport) {
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);
}
break;
case 'list_context_updated':
{
this._handleContextUpdate(update.context_data, update.id);
}
break;
case 'list_removed':
{
this.emit('collectionRemoved', false);
this.emit('collectionRemovedRemotely');
}
break;
}
this._revision = update.list_revision;
var updateHasNoGap = update.id - this._lastEventId === 1;
var shouldAdvance = this._lastEventId < update.id && (reliableTransport || updateHasNoGap);
if (shouldAdvance) {
this._lastEventId = update.id;
}
_update(update) {
const 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);
}
break;
case 'list_context_updated':
{
this._handleContextUpdate(update.context_data, update.id);
}
break;
case 'list_removed':
{
this._onRemoved(false);
}
break;
}
if (this.lastEventId < update.id) {
this.descriptor.revision = update.list_revision;
this.descriptor.last_event_id = update.id;
}
}
/**

@@ -525,14 +360,10 @@ * Handle item insertion event, coming from server

*/
}, {
key: '_handleItemAdded',
value: function _handleItemAdded(index, uri, eventId, revision, value) {
if (!this._items.has(index) && !this._shouldIgnoreEvent(index, eventId)) {
var item = new _listitem2.default({ index: index, uri: uri, eventId: eventId, revision: revision, value: value });
this._items.set(index, item);
this.emit('itemAdded', item, false);
this.emit('itemAddedRemotely', item);
}
_handleItemAdded(index, uri, eventId, revision, value) {
if (!this.cache.isKnown(index, eventId)) {
let item = new listitem_1.ListItem({ index, uri, lastEventId: eventId, revision, value });
this.cache.store(index, item, eventId);
this.emit('itemAdded', item, false);
this.emit('itemAddedRemotely', item);
}
}
/**

@@ -542,60 +373,32 @@ * Handle new value of item, coming from server

*/
}, {
key: '_handleItemUpdated',
value: function _handleItemUpdated(index, uri, eventId, revision, value) {
var item = this._items.get(index);
if (!item && !this._shouldIgnoreEvent(index, eventId)) {
item = new _listitem2.default({ index: index, uri: uri, eventId: eventId, revision: revision, value: value });
this._items.set(index, item);
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);
}
_handleItemUpdated(index, uri, eventId, revision, value) {
let item = this.cache.get(index);
if (!item && !this.shouldIgnoreEvent(index, eventId)) {
item = this.cache.store(index, new listitem_1.ListItem({ index, uri, lastEventId: eventId, revision, 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);
}
}
/**
* @private
*/
}, {
key: '_handleItemRemoved',
value: function _handleItemRemoved(index, eventId) {
if (this._items.has(index)) {
this._items.delete(index);
}
this._tombstones.set(index, eventId);
this.emit('itemRemoved', index, false);
this.emit('itemRemovedRemotely', index);
_handleItemRemoved(index, eventId) {
this.cache.delete(index, eventId);
this.emit('itemRemoved', index, false);
this.emit('itemRemovedRemotely', index);
}
}, {
key: '_handleContextUpdate',
value: function _handleContextUpdate(data, eventId) {
if (this._lastEventId < eventId) {
this._context = data;
this.emit('contextUpdated', data, false);
this.emit('contextUpdatedRemotely', data);
}
_handleContextUpdate(data, eventId) {
if (this.lastEventId < eventId) {
this.context = data;
this.emit('contextUpdated', data, false);
this.emit('contextUpdatedRemotely', data);
}
}
}, {
key: 'type',
get: function get() {
return 'list';
}
}, {
key: 'lastEventId',
get: function get() {
return this._lastEventId;
}
}]);
return SyncList;
}(_entity2.default);
}
exports.SyncList = SyncList;
Object.defineProperty(exports, "__esModule", { value: true });
// export { SyncList, ListDescriptor, Mutator };
exports.default = SyncList;
/**

@@ -607,3 +410,2 @@ * Applies a transformation to the item value

*/
/**

@@ -614,3 +416,2 @@ * Fired when item is added to the List

*/
/**

@@ -621,3 +422,2 @@ * Fired when item is added to List by remote actor

*/
/**

@@ -628,3 +428,2 @@ * Fired when item is updated

*/
/**

@@ -635,3 +434,2 @@ * Fired when item is updated by remote actor

*/
/**

@@ -642,3 +440,2 @@ * Fired when item is removed from the List

*/
/**

@@ -649,3 +446,2 @@ * Fired when item is removed from the List by remote actor

*/
/**

@@ -655,3 +451,2 @@ * Fired when List is removed from server

*/
/**

@@ -661,3 +456,1 @@ * Fired when List is removed from server by remote actor

*/
module.exports = exports['default'];

@@ -1,67 +0,17 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _map = require('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _utils = require('./utils');
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _entity = require('./entity');
var _entity2 = _interopRequireDefault(_entity);
var _retryingqueue = require('./retryingqueue');
var _retryingqueue2 = _interopRequireDefault(_retryingqueue);
var _mapitem = require('./mapitem');
var _mapitem2 = _interopRequireDefault(_mapitem);
var _paginator = require('./paginator');
var _paginator2 = _interopRequireDefault(_paginator);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const utils_1 = require("./utils");
const logger_1 = require("./logger");
const entity_1 = require("./entity");
const retryingqueue_1 = require("./retryingqueue");
const mapitem_1 = require("./mapitem");
const paginator_1 = require("./paginator");
const cache_1 = require("./cache");
/**

@@ -83,67 +33,41 @@ * @class

*/
var SyncMap = function (_SyncEntity) {
(0, _inherits3.default)(SyncMap, _SyncEntity);
/**
* @constructor
* @private
*/
function SyncMap(deps, descriptor) {
(0, _classCallCheck3.default)(this, SyncMap);
var _this = (0, _possibleConstructorReturn3.default)(this, (SyncMap.__proto__ || (0, _getPrototypeOf2.default)(SyncMap)).call(this, deps));
var cacheState = {
ensured: false
};
(0, _defineProperties2.default)(_this, {
_descriptor: { value: descriptor },
_cacheState: { value: cacheState },
_tombstones: { value: new _map2.default() },
_updateQueue: { value: new _retryingqueue2.default() },
_links: { get: function get() {
return _this._descriptor.links;
} },
_revision: { value: descriptor.revision, writable: true },
_lastEventId: { value: descriptor.last_event_id, writable: true },
_context: { writable: true },
_items: { value: new _map2.default() },
uri: { get: function get() {
return _this._descriptor.url;
} },
sid: { enumerable: true, get: function get() {
return _this._descriptor.sid;
} },
uniqueName: { enumerable: true, get: function get() {
return _this._descriptor.unique_name || null;
} }
});
return _this;
}
(0, _createClass3.default)(SyncMap, [{
key: '_get',
value: function _get(key) {
return this._query({ key: key }).then(function (result) {
if (result.items.length < 1) {
throw new Error('No item with key ' + key + ' found');
}
return result.items[0];
});
class SyncMap extends entity_1.SyncEntity {
/**
* @private
*/
constructor(services, descriptor, onRemoveMap) {
super(services);
this.actionQueue = new retryingqueue_1.RetryingQueue();
this.cache = new cache_1.Cache();
this.descriptor = descriptor;
this.onRemoveMap = onRemoveMap;
}
}, {
key: '__set',
value: function __set(location, param) {
return this._deps.network.post(location, { data: param.data }, param.revision).then(function (response) {
response = response.body;
response.data = param.data;
return response;
});
get uri() { return this.descriptor.url; }
;
get links() { return this.descriptor.links; }
;
get revision() { return this.descriptor.revision; }
;
get lastEventId() { return this.descriptor.last_event_id; }
;
get sid() { return this.descriptor.sid; }
get uniqueName() { return this.descriptor.unique_name || null; }
static get type() { return 'map'; }
get type() { return 'map'; }
_get(key) {
return this.queryItems({ key: key }).then(result => {
if (result.items.length < 1) {
throw new Error('No item with key ' + key + ' found');
}
return result.items[0];
});
}
__set(location, param) {
return this.services.network.post(location, { data: param.data }, param.revision)
.then(response => {
response = response.body;
response.data = param.data;
return response;
});
}
/**

@@ -153,31 +77,22 @@ * Update known existing element

*/
}, {
key: '_set',
value: function _set(location, keyValue, resolver) {
var _this2 = this;
if (!resolver) {
return this.__set(location, { data: keyValue.data });
}
var _resolver = function _resolver(err) {
if (err.status === 412) {
return _this2._softSync().then(function () {
return _this2.get(keyValue.key);
}).then(function (item) {
return {
revision: item._revision,
data: resolver(item.value, keyValue.data)
};
});
}
throw err;
};
return this._updateQueue.add(this.__set.bind(this), location, { revision: keyValue.revision, data: keyValue.data }, _resolver).then(function (result) {
return result;
});
_set(location, keyValue, resolver) {
return __awaiter(this, void 0, void 0, function* () {
if (!resolver) {
return this.__set(location, { data: keyValue.data });
}
let _resolver = (err) => __awaiter(this, void 0, void 0, function* () {
if (err.status === 412) {
yield this.queryEvents();
let item = yield this.get(keyValue.key);
return {
revision: item.revision,
data: resolver(item.value, keyValue.data)
};
}
throw err;
});
return this.actionQueue
.add(this.__set.bind(this), location, { revision: keyValue.revision, data: keyValue.data }, _resolver);
});
}
/**

@@ -187,37 +102,28 @@ * Create element or update if already existing

*/
}, {
key: '_tryAddOrUpdate',
value: function _tryAddOrUpdate(uri, keyValue, resolver) {
var _this3 = this;
return new _promise2.default(function (resolve, reject) {
_this3._deps.network.post(uri, keyValue).then(function (response) {
response.body.data = keyValue.data;
response.body._isLocallyAdded = true; // TODO: Hack, remove me
resolve(response.body);
}).catch(function (err) {
if (err.status !== 409) {
reject(err);
return;
}
var location = err.body.links.item;
if (!resolver) {
_this3._set(location, keyValue, resolver).then(resolve).catch(reject);
} else {
_this3._deps.network.get(location).then(function (result) {
return {
key: result.key,
revision: result.revision,
data: resolver(result.value, keyValue.data)
};
}).then(function (item) {
return _this3._set(location, item, resolver);
}).then(resolve).catch(reject);
}
_tryAddOrUpdate(uri, keyValue, resolver) {
return __awaiter(this, void 0, void 0, function* () {
try {
let response = yield this.services.network.post(uri, keyValue);
response.body.data = keyValue.data;
return { added: true, value: response.body };
}
catch (err) {
if (err.status !== 409) {
throw err;
}
const location = err.body.links.item;
if (!resolver) {
let value = yield this._set(location, keyValue, resolver);
return { added: false, value: value };
}
else {
let response = yield this.services.network.get(location);
let value = yield this._set(location, { key: response.key,
revision: response.revision,
data: keyValue }, resolver);
return { added: false, value: value };
}
}
});
});
}
/**

@@ -227,19 +133,16 @@ * Query events from servie and apply changes to the collection

*/
}, {
key: '_queryEvents',
value: function _queryEvents() {
var _this4 = this;
var uri = this._links.events + '?From=' + (this._lastEventId + 1) + '&PageSize=100';
return this._deps.network.get(uri).then(function (response) {
return response.body.events.forEach(function (event) {
return _this4._update(event);
queryEvents() {
return __awaiter(this, void 0, void 0, function* () {
try {
const uri = `${this.descriptor.links.events}?From=${(this.lastEventId + 1)}&PageSize=100`;
let response = yield this.services.network.get(uri);
response.body.events.forEach(ev => this._update(ev));
}
catch (e) {
logger_1.default.error('Failed to fetch events:', e);
throw e;
}
;
});
}).catch(function (e) {
_logger2.default.error('Failed to fetch events:', e);
throw e;
});
}
/**

@@ -249,18 +152,12 @@ * @return Promise<Object> Context of collection

*/
}, {
key: 'getContext',
value: function getContext() {
var _this5 = this;
if (typeof this._context !== 'undefined') {
return _promise2.default.resolve(this._context);
}
return this._deps.network.get(this._links.context).then(function (response) {
_this5._context = response.body.data;
return _this5._context;
});
getContext() {
return __awaiter(this, void 0, void 0, function* () {
if (typeof this.context !== 'undefined') {
return this.context;
}
let response = yield this.services.network.get(this.links.context);
this.context = response.body.data;
return this.context;
});
}
/**

@@ -271,14 +168,9 @@ * @param context {Object} New context value

*/
}, {
key: 'updateContext',
value: function updateContext(context) {
var _this6 = this;
return this._deps.network.post(this._links.context, { data: context }).then(function () {
_this6._context = context;
_this6.emit('contextUpdated', context, true);
});
updateContext(context) {
return __awaiter(this, void 0, void 0, function* () {
yield this.services.network.post(this.links.context, { data: context });
this.context = context;
this.emit('contextUpdated', context, true);
});
}
/**

@@ -288,67 +180,43 @@ * Set key and value pair in map

* @param {Object} value Value to set
* @param {Boolean} [conditional=false] Check for remote modification when updating.
* If true, promise will be rejected if value was remotely modified
* @returns {Promise<Item>}
* @public
*/
}, {
key: 'set',
value: function set(key, value, conditional) {
return this._actualSet(key, value, conditional ? function () {
throw new Error('Revision mismatch');
} : null);
set(key, value) {
return this._actualSet(key, value);
}
/**
* @private
*/
}, {
key: '_actualSet',
value: function _actualSet(key, value, resolver) {
var _this7 = this;
var item = this._items.get(key);
if (item) {
var arg = { key: key, data: value };
if (resolver) {
arg.revision = item._revision;
}
return this._set(item._uri, arg, resolver).then(function (response) {
item._update(response.last_event_id, response.revision, response.data);
_this7.emit('itemUpdated', item, true);
return item;
_actualSet(key, value, resolver) {
return __awaiter(this, void 0, void 0, function* () {
let item = this.cache.get(key);
if (item) {
let arg = { key: key, data: value, revision: item.revision || undefined };
let response = yield this._set(item.uri, arg, resolver);
item.update(response.last_event_id, response.revision, response.data);
this.emit('itemUpdated', item, true);
return item;
}
let { added, value: result } = yield this._tryAddOrUpdate(this.links.items, { key: key, data: value }, resolver);
let descriptor = { key: result.key,
revision: result.revision,
lastEventId: result.last_event_id,
uri: result.url,
value: result.data };
item = yield this.cache.get(key);
if (item && descriptor.lastEventId > item.lastEventId) {
item.update(descriptor.lastEventId, descriptor.revision, descriptor.value);
}
else if (!item) {
item = this.cache.store(key, new mapitem_1.MapItem(descriptor), descriptor.lastEventId);
if (added) {
this.emit('itemAdded', item, true);
}
else {
this.emit('itemUpdated', item, true);
}
}
return item;
});
}
return this._tryAddOrUpdate(this._links.items, { key: key, data: value }, resolver).then(function (result) {
return {
_isLocallyAdded: result._isLocallyAdded, // TODO: hack, remove me
key: result.key,
revision: result.revision,
eventId: result.last_event_id,
uri: result.url,
value: result.data
};
}).then(function (descriptor) {
item = _this7._items.get(key);
if (item && descriptor.eventId > item._lastEventId) {
item._update(descriptor.eventId, descriptor.revision, descriptor.value);
} else if (!item) {
item = new _mapitem2.default(descriptor);
_this7._items.set(key, item);
if (descriptor._isLocallyAdded) {
// TODO: hack, remove me
_this7.emit('itemAdded', item, true);
} else {
_this7.emit('itemUpdated', item, true);
}
}
return item;
});
}
/**

@@ -359,39 +227,25 @@ * @param {String} key String identifier of entity in a map

*/
}, {
key: 'get',
value: function get(key) {
if (this._items.has(key)) {
return _promise2.default.resolve(this._items.get(key));
}
return this._query({ key: key }).then(function (result) {
if (result.items.length < 1) {
throw new Error('No item with key ' + key + ' found');
}
return result.items[0];
});
get(key) {
return __awaiter(this, void 0, void 0, function* () {
if (this.cache.has(key)) {
return this.cache.get(key);
}
let result = yield this.queryItems({ key: key });
if (result.items.length < 1) {
throw new Error('No item with key ' + key + ' found');
}
return result.items[0];
});
}
/**
* @param {String} Key Item key
* @param {Map~Mutator} Mutator Function performing value mutation
* @return {Promise<Item>}
*/
}, {
key: 'mutate',
value: function mutate(key, mutator) {
var _this8 = this;
return new _promise2.default(function (resolve) {
return _this8.get(key).then(function (item) {
return resolve(item.value);
}).catch(function () {
return resolve({});
mutate(key, mutator) {
return __awaiter(this, void 0, void 0, function* () {
let value = yield this.get(key).then(item => item.value).catch(() => ({}));
return this._actualSet(key, mutator(value), mutator);
});
}).then(function (value) {
return _this8._actualSet(key, mutator(value), mutator);
});
}
/**

@@ -402,12 +256,7 @@ * @param {String} key Item key

*/
}, {
key: 'update',
value: function update(key, obj) {
return this.mutate(key, function (remote) {
(0, _extends3.default)(remote, obj);
return remote;
});
update(key, obj) {
return __awaiter(this, void 0, void 0, function* () {
return this.mutate(key, remote => Object.assign(remote, obj));
});
}
/**

@@ -417,55 +266,36 @@ * Delete an entity by given key

*/
}, {
key: 'remove',
value: function remove(key) {
var _this9 = this;
if (typeof key === 'undefined') {
throw new Error('Key argument is invalid');
}
return this.get(key).then(function (item) {
return _this9._deps.network.delete(item._uri);
}).then(function () {
_this9._items.delete(key);
_this9.emit('itemRemoved', key, true);
});
remove(key) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof key === 'undefined') {
throw new Error('Key argument is invalid');
}
let item = yield this.get(key);
yield this.services.network.delete(item.uri);
this.cache.delete(key, item.lastEventId);
this.emit('itemRemoved', key, true);
});
}
/**
* @private
*/
}, {
key: '_query',
value: function _query(args) {
var _this10 = this;
args = args || {};
var uri = new _utils.UriBuilder(this._links.items).arg('From', args.from).arg('PageSize', args.limit).arg('Key', args.key).arg('PageToken', args.pageToken).arg('Order', args.order).build();
return this._deps.network.get(uri).then(function (result) {
var items = result.body.items.map(function (el) {
return new _mapitem2.default({ key: el.key,
uri: el.url,
revision: el.revision,
eventId: el.last_event_id,
value: el.data });
queryItems(args) {
return __awaiter(this, void 0, void 0, function* () {
args = args || {};
const uri = new utils_1.UriBuilder(this.links.items)
.arg('From', args.from)
.arg('PageSize', args.limit)
.arg('Key', args.key)
.arg('PageToken', args.pageToken)
.arg('Order', args.order)
.build();
let response = yield this.services.network.get(uri);
let items = response.body.items.map(el => this.cache.store(el.key, new mapitem_1.MapItem({ key: el.key,
uri: el.url,
revision: el.revision,
lastEventId: el.last_event_id,
value: el.data }), el.last_event_id));
const meta = response.body.meta;
return new paginator_1.Paginator(items, pageToken => this.queryItems({ pageToken }), meta.previous_token, meta.next_token);
});
items.forEach(function (item, idx) {
var knownItem = _this10._items.get(item.key);
if (!knownItem) {
_this10._items.set(item.key, item);
} else {
items[idx] = knownItem;
}
});
var meta = result.body.meta;
return new _paginator2.default(items, function (pageToken) {
return _this10._query({ pageToken: pageToken });
}, meta.previous_token, meta.next_token);
});
}
/**

@@ -480,12 +310,10 @@ * Get a list of items from the Map

*/
}, {
key: 'getItems',
value: function getItems(args) {
args = args || {};
args.limit = args.pageSize || args.limit || 50;
args.order = args.order || 'asc';
return this._query(args);
getItems(args) {
return __awaiter(this, void 0, void 0, function* () {
args = args || {};
args.limit = args.pageSize || args.limit || 50;
args.order = args.order || 'asc';
return this.queryItems(args);
});
}
/**

@@ -502,9 +330,17 @@ * Synchronizes object with state on a server

*/
}, {
key: '_softSync',
value: function _softSync() {
return this._queryEvents();
softSync() {
return __awaiter(this, void 0, void 0, function* () {
try {
yield this.queryEvents();
}
catch (err) {
if (err.status === 404) {
this.onRemoved(false);
}
else {
logger_1.default.error(`Can't get updates for ${this.sid}:`, err);
}
}
});
}
/**

@@ -517,48 +353,30 @@ * Enumerate through all of maps items

*/
}, {
key: 'forEach',
value: function forEach(handler) {
var _this11 = this;
return new _promise2.default(function (resolve, reject) {
if (_this11._cacheState.ensured) {
_this11._items.forEach(handler);
resolve();
} else {
(function () {
var firstPageQueryArgs = {
order: 'asc',
limit: 50
};
var getFirstPage = function getFirstPage() {
return _this11._query(firstPageQueryArgs);
};
var handleEnd = function handleEnd() {
_this11._cacheState.ensured = true;
forEach(handler) {
return new Promise((reject) => {
/*
if (this._cacheState.ensured) {
this.items.forEach(handler);
resolve();
};
_this11._processPage(getFirstPage, handler, handleEnd).catch(reject);
})();
}
});
} else {
let firstPageQueryArgs = {
order: 'asc',
limit: 50
};
let getFirstPage = () => this._query(firstPageQueryArgs);
let handleEnd = () => {
this._cacheState.ensured = true;
resolve();
};
this._processPage(getFirstPage, handler, handleEnd).catch(reject);
}
*/
reject(new Error('Not implemented'));
});
}
/**
* @private
*/
}, {
key: '_processPage',
value: function _processPage(getPage, handleElement, handleEnd) {
var _this12 = this;
return getPage().then(function (page) {
page.items.forEach(function (el) {
return handleElement(el);
});
/*
private _processPage(getPage :any, handleElement :any, handleEnd :any) : Promise<Paginator<Item>> {
return getPage().then(page => {
page.items.forEach(el => handleElement(el));
if (page.hasNextPage) {
setTimeout(function () {
return _this12._processPage(page.nextPage.bind(page), handleElement, handleEnd);
});
setTimeout(() => this._processPage(page.nextPage.bind(page), handleElement, handleEnd));
} else {

@@ -569,59 +387,43 @@ handleEnd();

}
}, {
key: '_shouldIgnoreEvent',
value: function _shouldIgnoreEvent(key, eventId) {
return (this._tombstones.get(key) || -1) >= eventId;
*/
shouldIgnoreEvent(key, eventId) {
return this.cache.isKnown(key, eventId);
}
/**
* Handle update event
*
* @param {Object} update
* @param {Boolean} reliable Caller should point if transport reliable or not
* For reliable transport it will advance lastEventId even if gaps in events were found
*
* Handle update from the server
* @private
*/
}, {
key: '_update',
value: function _update(update, reliableTransport) {
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);
}
break;
case 'map_context_updated':
{
this._handleContextUpdate(update.context_data, update.id);
}
break;
case 'map_removed':
{
this.emit('collectionRemoved', false);
this.emit('collectionRemovedRemotely');
}
break;
}
this._revision = update.map_revision;
var updateHasNoGap = update.id - this._lastEventId === 1;
var shouldAdvance = this._lastEventId < update.id && (reliableTransport || updateHasNoGap);
if (shouldAdvance) {
this._lastEventId = update.id;
}
_update(update) {
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);
}
break;
case 'map_context_updated':
{
this._handleContextUpdate(update.context_data, update.id);
}
break;
case 'map_removed':
{
this.onRemoved(false);
}
break;
}
if (this.lastEventId < update.id) {
this.descriptor.revision = update.map_revision;
this.descriptor.last_event_id = update.id;
}
}
/**

@@ -631,15 +433,10 @@ * Handle entity insertion event, coming from server

*/
}, {
key: '_handleItemAdded',
value: function _handleItemAdded(key, uri, eventId, revision, value) {
if (!this._items.has(key) && !this._shouldIgnoreEvent(key, eventId)) {
var item = new _mapitem2.default({ key: key, uri: uri, eventId: eventId, revision: revision, value: value });
this._tombstones.delete(key);
this._items.set(key, item);
this.emit('itemAdded', item, false);
this.emit('itemAddedRemotely', item);
}
_handleItemAdded(key, uri, eventId, revision, value) {
if (!this.cache.has(key) && !this.shouldIgnoreEvent(key, eventId)) {
let item = new mapitem_1.MapItem({ key, uri, lastEventId: eventId, revision, value });
this.cache.store(key, item, eventId);
this.emit('itemAdded', item, false);
this.emit('itemAddedRemotely', item);
}
}
/**

@@ -649,46 +446,39 @@ * Handle new value of entity, coming from server

*/
}, {
key: '_handleItemUpdated',
value: function _handleItemUpdated(key, uri, eventId, revision, value) {
var item = this._items.get(key);
if (!item && !this._shouldIgnoreEvent(key, eventId)) {
item = new _mapitem2.default({ key: key, uri: uri, eventId: eventId, revision: revision, value: value });
this._items.set(key, item);
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);
}
_handleItemUpdated(key, uri, eventId, revision, value) {
let item = this.cache.get(key);
if (!item && !this.shouldIgnoreEvent(key, eventId)) {
item = new mapitem_1.MapItem({ key, uri, lastEventId: eventId, revision, 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) {
if (this._items.has(key)) {
this._items.delete(key);
}
this._tombstones.set(key, eventId);
this.emit('itemRemoved', key, false);
this.emit('itemRemovedRemotely', key, false);
_handleItemRemoved(key, eventId) {
this.cache.delete(key, eventId);
this.emit('itemRemoved', key, false);
this.emit('itemRemovedRemotely', key, false);
}
}, {
key: '_handleContextUpdate',
value: function _handleContextUpdate(data, eventId) {
if (this._lastEventId < eventId) {
this._context = data;
this.emit('contextUpdated', data, false);
this.emit('contextUpdatedRemotely', data);
}
_handleContextUpdate(data, eventId) {
if (this.lastEventId < eventId) {
this.context = data;
this.emit('contextUpdated', data, false);
this.emit('contextUpdatedRemotely', data);
}
}
onRemoved(locally) {
this._unsubscribe();
// Should also do some cleanup here
this.emit('collectionRemoved', locally);
if (!locally) {
this.emit('collectionRemovedRemotely');
}
}
/**

@@ -699,28 +489,14 @@ * Delete map from server. It will be impossible to restore it.

*/
}, {
key: 'removeMap',
value: function removeMap() {
var _this13 = this;
return this._deps.network.delete(this.uri).then(function () {
_this13.emit('collectionRemoved', true);
});
removeMap() {
return __awaiter(this, void 0, void 0, function* () {
this.onRemoveMap(this.sid);
yield this.services.network.delete(this.uri);
this.onRemoved(true);
});
}
}, {
key: 'type',
get: function get() {
return 'map';
}
}, {
key: 'lastEventId',
get: function get() {
return this._lastEventId;
}
}]);
return SyncMap;
}(_entity2.default);
}
exports.SyncMap = SyncMap;
Object.defineProperty(exports, "__esModule", { value: true });
// export { SyncMap, MapDescriptor, Mutator };
exports.default = SyncMap;
/**

@@ -732,3 +508,2 @@ * Applies a transformation to the item value

*/
/**

@@ -739,9 +514,7 @@ * Fired when item is added to the Map

*/
/**
* Fired when item is added to the Map by remote actor
* @event Map#itemAdded
* @event Map#itemAddedRemotely
* @type {Item} Added item
*/
/**

@@ -752,3 +525,2 @@ * Fired when item is updated

*/
/**

@@ -759,3 +531,2 @@ * Fired when item is updated by remote actor

*/
/**

@@ -766,3 +537,2 @@ * Fired when item is removed from the Map

*/
/**

@@ -773,3 +543,2 @@ * Fired when item is removed from the Map by remote actor

*/
/**

@@ -779,3 +548,2 @@ * Fired when Map is removed from server

*/
/**

@@ -785,3 +553,1 @@ * Fired when Map is removed from server by remote actor

*/
module.exports = exports['default'];

@@ -1,26 +0,2 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UriBuilder = exports.deepClone = undefined;
var _defineProperties = require('babel-runtime/core-js/object/define-properties');
var _defineProperties2 = _interopRequireDefault(_defineProperties);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
"use strict";
/**

@@ -33,37 +9,27 @@ * Deep-clone an object. Note that this does not work on object containing

function deepClone(obj) {
return JSON.parse((0, _stringify2.default)(obj));
return JSON.parse(JSON.stringify(obj));
}
exports.deepClone = deepClone;
/**
* Construct URI with query parameters
*/
var UriBuilder = function () {
function UriBuilder(base) {
(0, _classCallCheck3.default)(this, UriBuilder);
(0, _defineProperties2.default)(this, {
base: { value: base },
args: { value: [] }
});
}
(0, _createClass3.default)(UriBuilder, [{
key: 'arg',
value: function arg(name, value) {
if (typeof value !== 'undefined') {
this.args.push(name + '=' + encodeURIComponent(value));
}
return this;
class UriBuilder {
constructor(base) {
this.base = base;
this.args = new Array();
}
}, {
key: 'build',
value: function build() {
return this.args.length === 0 ? this.base : this.base + '?' + this.args.join('&');
arg(name, value) {
if (typeof value !== 'undefined') {
this.args.push(name + '=' + encodeURIComponent(value));
}
return this;
}
}]);
return UriBuilder;
}();
exports.deepClone = deepClone;
exports.UriBuilder = UriBuilder;
;
build() {
return this.args.length === 0
? this.base
: this.base + '?' + this.args.join('&');
}
;
}
exports.UriBuilder = UriBuilder;
{
"name": "twilio-sync",
"version": "0.4.1",
"version": "0.4.2-dev.1",
"description": "Twilio Sync client library",
"main": "lib/index.js",
"directories": {
"test": "test"
},
"browser": "browser/index.js",
"scripts": {
"test": "gulp unit-test",
"prepublish": "node_modules/babel-cli/bin/babel.js src --out-dir lib"
"prepublish": "gulp build"
},

@@ -16,32 +14,42 @@ "author": "Twilio",

"dependencies": {
"babel-runtime": "^6.11.6",
"babel-runtime": "^6.20.0",
"karibu": "^1.0.0",
"loglevel": "^1.4.1",
"platform": "^1.3.1",
"twilio-notifications": "^0.2.0",
"platform": "^1.3.3",
"rfc6902": "^1.2.2",
"twilio-ems-client": "^0.1.5-dev.2",
"twilio-notifications": "^0.3.0-dev.1",
"twilio-transport": "^0.1.1",
"twilsock": "^0.2.0",
"uuid": "^2.0.2"
"twilsock": "^0.2.1",
"uuid": "^3.0.1"
},
"devDependencies": {
"async-test-tools": "^1.0.2",
"babel-cli": "^6.14.0",
"babel-eslint": "^7.0.0",
"@types/chai": "^3.4.34",
"@types/chai-as-promised": "0.0.29",
"@types/loglevel": "^1.4.29",
"@types/mocha": "^2.2.36",
"@types/node": "^6.0.58",
"@types/sinon": "^1.16.34",
"@types/sinon-as-promised": "^4.0.5",
"@types/sinon-chai": "^2.7.27",
"async-test-tools": "^1.0.6",
"babel-cli": "^6.18.0",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-object-assign": "^6.8.0",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.9.0",
"babel-preset-es2015": "^6.18.0",
"babelify": "^7.3.0",
"backoff": "^2.5.0",
"browserify": "^13.1.0",
"browserify": "^13.3.0",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"cheerio": "^0.22.0",
"del": "^2.2.1",
"del": "^2.2.2",
"event-to-promise": "^0.7.0",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-derequire": "^2.1.0",
"gulp-eslint": "^3.0.1",
"gulp-exit": "0.0.2",
"gulp-insert": "^0.5.0",
"gulp-istanbul": "^1.0.0",
"gulp-istanbul": "^1.1.1",
"gulp-mocha": "^3.0.1",

@@ -51,17 +59,28 @@ "gulp-rename": "^1.2.2",

"gulp-tap": "^0.1.3",
"gulp-tslint": "^7.0.1",
"gulp-typescript": "^3.1.4",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.7",
"ink-docstrap": "^1.2.1",
"gulp-util": "^3.0.8",
"ink-docstrap": "^1.3.0",
"isparta": "^4.0.0",
"jsdoc": "^3.4.0",
"jsonwebtoken": "^7.1.6",
"jsdoc": "^3.4.3",
"jsonwebtoken": "^7.2.1",
"karma": "^1.3.0",
"karma-browserify": "^5.1.0",
"karma-browserstack-launcher": "^1.1.1",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.1",
"run-sequence": "^1.2.2",
"sinon": "^1.17.5",
"sinon": "^1.17.7",
"sinon-as-promised": "^4.0.2",
"sinon-chai": "^2.8.0",
"ts-node": "^2.0.0",
"tslint": "^4.3.1",
"twilio": "^3.3.0-edge",
"typescript": "^2.1.4",
"underscore": "^1.8.3",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.8.0"
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc