'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = pagedSync;
var _filter = require('lodash/filter');
var _filter2 = _interopRequireDefault(_filter);
var _cloneDeep = require('lodash/cloneDeep');
var _cloneDeep2 = _interopRequireDefault(_cloneDeep);
var _createRequestConfig = require('contentful-sdk-core/create-request-config');
var _createRequestConfig2 = _interopRequireDefault(_createRequestConfig);
var _freezeSys = require('contentful-sdk-core/freeze-sys');
var _freezeSys2 = _interopRequireDefault(_freezeSys);
var _linkGetters = require('./mixins/link-getters');
var _linkGetters2 = _interopRequireDefault(_linkGetters);
var _stringifySafe = require('./mixins/stringify-safe');
var _stringifySafe2 = _interopRequireDefault(_stringifySafe);
var _toPlainObject = require('contentful-sdk-core/mixins/to-plain-object');
var _toPlainObject2 = _interopRequireDefault(_toPlainObject);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @memberof Sync
* @typedef SyncCollection
* @prop {Array<Entities.Entry>} entries - All existing entries on first sync. New and updated entries on subsequent syncs.
* @prop {Array<Entities.Asset>} assets - All existing assets on first sync. New and updated assets on subsequent syncs.
* @prop {Array<Sync.DeletedEntry>} deletedEntries - List of deleted Entries since last sync
* @prop {Array<Sync.DeletedAsset>} deletedAssets - List of deleted Assets since last sync
* @prop {string} nextSyncToken - Token to be sent to the next sync call
* @prop {function(): Object} toPlainObject() - Returns this Sync collection as a plain JS object
* @prop {function(?function=, space=): Object} stringifySafe(replacer,space) - Stringifies the Sync collection, accounting for circular references. Circular references will be replaced with just a Link object, with a <code>circular</code> property set to <code>true</code>. See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">MDN</a> and <a href="https://www.npmjs.com/package/json-stringify-safe">json-stringify-safe</a> for more details on the arguments this method can take.
*/
/**
* Deleted Entries are the same as Entries, but only appear on the sync API.
* @memberof Sync
* @typedef DeletedEntry
* @type Entities.Entry
*/
/**
* Deleted Assets are the same as Assets, but only appear on the sync API.
* @memberof Sync
* @typedef DeletedAsset
* @type Entities.Asset
*/
/**
* This module retrieves all the available pages for a sync operation
* @private
* @param {Object} http - HTTP client
* @param {Object} query - Query object
* @param {boolean} resolveLinks - If links should be resolved
* @return {Promise<SyncCollection>}
*/
function pagedSync(http, query, resolveLinks) {
if (!query || !query.initial && !query.nextSyncToken) {
throw new Error('Please provide one of `initial` or `nextSyncToken` parameters for syncing');
}
if (query && query.content_type && !query.type) {
query.type = 'Entry';
} else if (query && query.content_type && query.type && query.type !== 'Entry') {
throw new Error('When using the `content_type` filter your `type` parameter cannot be different from `Entry`.');
}
if (query.nextSyncToken) {
query.sync_token = query.nextSyncToken;
delete query.initial;
delete query.nextSyncToken;
}
return getSyncPage(http, [], query).then(function (response) {
// clones response.items used in includes because we don't want these to be mutated
if (resolveLinks) {
(0, _linkGetters2.default)(response.items, mapIncludeItems((0, _cloneDeep2.default)(response.items)));
}
// maps response items again after getters are attached
var mappedResponseItems = mapResponseItems(response.items);
mappedResponseItems.nextSyncToken = response.nextSyncToken;
return (0, _freezeSys2.default)((0, _stringifySafe2.default)((0, _toPlainObject2.default)(mappedResponseItems)));
}, function (error) {
throw error.data;
});
}
/**
* @private
* @param {Array<Entities.Entry|Entities.Array|Sync.DeletedEntry|Sync.DeletedAsset>} items
* @return {Object} Entities mapped to an object for each entity type
*/
/**
* See <a href="https://www.contentful.com/developers/docs/concepts/sync/">Synchronization</a> for more information.
* @namespace Sync
*/
function mapResponseItems(items) {
return {
entries: (0, _filter2.default)(items, ['sys.type', 'Entry']),
assets: (0, _filter2.default)(items, ['sys.type', 'Asset']),
deletedEntries: (0, _filter2.default)(items, ['sys.type', 'DeletedEntry']),
deletedAssets: (0, _filter2.default)(items, ['sys.type', 'DeletedAsset'])
};
}
/**
* Creates an object similar to the one retrieved on `includes` from the `entries`
* endpoint, for usage with the link getters mixin
* @private
* @param {Array<Entities.Entry|Entities.Array|Sync.DeletedEntry|Sync.DeletedAsset>} items
* @return {Object}
*/
function mapIncludeItems(items) {
return {
Entry: (0, _filter2.default)(items, ['sys.type', 'Entry']),
Asset: (0, _filter2.default)(items, ['sys.type', 'Asset'])
};
}
/**
* If the response contains a nextPageUrl, extracts the sync token to get the
* next page and calls itself again with that token.
* Otherwise, if the response contains a nextSyncUrl, extracts the sync token
* and returns it.
* On each call of this function, any retrieved items are collected in the
* supplied items array, which gets returned in the end
* @private
* @param {Object} http
* @param {Array<Entities.Entry|Entities.Array|Sync.DeletedEntry|Sync.DeletedAsset>} items
* @param {Object} query
* @return {Promise<{items: Array, nextSyncToken: string}>}
*/
function getSyncPage(http, items, query) {
return http.get('sync', (0, _createRequestConfig2.default)({ query: query })).then(function (response) {
var data = response.data;
items = items.concat(data.items);
if (data.nextPageUrl) {
delete query.initial;
query.sync_token = getToken(data.nextPageUrl);
return getSyncPage(http, items, query);
} else if (data.nextSyncUrl) {
return {
items: items,
nextSyncToken: getToken(data.nextSyncUrl)
};
}
});
}
/**
* Extracts token out of an url
* @private
*/
function getToken(url) {
var urlParts = url.split('?');
return urlParts.length > 0 ? urlParts[1].replace('sync_token=', '') : '';
}