@analytics/remote-storage-utils
Version:
Storage utilities for cross domain localStorage access, with permissions
277 lines (231 loc) • 10.3 kB
JavaScript
import { CrossStorageClient } from 'cross-storage';
export { CrossStorageClient, CrossStorageHub } from 'cross-storage';
import { isBrowser, isUndefined, isObject } from '@analytics/type-utils';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
/**
* Constructs a new cross storage client
* @param {string} url The url to a cross storage hub
* @param {object} [opts] An optional object containing additional options
* @param {object} [opts.timeout] timeout
* @param {object} [opts.frameId] frameId
* @example
* const storage = new RemoteStorage('https://example.com/storage.html')
* @example
* const storage = new RemoteStorage('https://example.com/storage.html', {
* timeout: 5000,
* frameId: 'storageFrame'
* })
**/
var RemoteStorage = /*#__PURE__*/function () {
function RemoteStorage(url, opts) {
_classCallCheck(this, RemoteStorage);
if (isBrowser) this.storage = new CrossStorageClient(url, opts);
}
_createClass(RemoteStorage, [{
key: "getItem",
value: function getItem(keys) {
return getRemoteItem(keys, this.storage);
}
}, {
key: "setItem",
value: function setItem(key, value) {
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return setRemoteItem(key, value, opts, this.storage);
}
}]);
return RemoteStorage;
}();
function getRemoteItem(_x, _x2) {
return _getRemoteItem.apply(this, arguments);
}
function _getRemoteItem() {
_getRemoteItem = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(keys, instance) {
var remoteKeys, promises;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
remoteKeys = Array.isArray(keys) ? keys : [keys];
promises = remoteKeys.map(function (name) {
return getRemoteItemRaw(name, instance);
});
return _context.abrupt("return", Promise.all(promises).then(function (values) {
return values.map(function (val) {
return safeParse(val);
});
}).then(function (data) {
// If singular return single value
if (data.length === 1) {
return data[0];
} // Else return mapped keys
// Else return mapped keys
return remoteKeys.reduce(function (acc, curr, i) {
acc[curr] = data[i];
return acc;
}, {});
}));
case 3:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return _getRemoteItem.apply(this, arguments);
}
function formatArgs(key, value) {
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var instance = arguments.length > 3 ? arguments[3] : undefined;
var storage = opts._id ? opts : instance;
if (isObject(key)) {
return _objectSpread(_objectSpread({}, key), {}, {
storage: isObject(value) && value._id ? value : storage
});
}
var options = !opts._id ? opts : {};
return _objectSpread({
key: key,
value: value,
storage: storage
}, options);
}
/**
* setRemoteItem
* @param {string} storageKey - localStorage key
* @param {string} storageValue - localStorage value
* @param {[function]} resolve - custom resolver function if value already set
* @param {[functiontype]} instance [description]
*/
function setRemoteItem(_x3, _x4) {
return _setRemoteItem.apply(this, arguments);
}
/**
* Get value from remote storage
* @param {String} key - localStorage key
* @return {Promise} - resolved value
*/
function _setRemoteItem() {
_setRemoteItem = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(storageKey, storageValue) {
var opts,
instance,
_formatArgs,
key,
value,
resolve,
storage,
remoteValueRaw,
remoteParsed,
localParsed,
newValue,
_args2 = arguments;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
opts = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : {};
instance = _args2.length > 3 ? _args2[3] : undefined;
_formatArgs = formatArgs(storageKey, storageValue, opts, instance), key = _formatArgs.key, value = _formatArgs.value, resolve = _formatArgs.resolve, storage = _formatArgs.storage;
/*
console.log('key', key)
console.log('value', value)
console.log('resolve', resolve)
console.log('storageInstance', storageInstance)
/**/
/* No conflict resolver, set remote item */
if (resolve) {
_context2.next = 5;
break;
}
return _context2.abrupt("return", setRemoteItemRaw(key, value, storage));
case 5:
_context2.next = 7;
return getRemoteItemRaw(key, storage);
case 7:
remoteValueRaw = _context2.sent;
if (remoteValueRaw) {
_context2.next = 10;
break;
}
return _context2.abrupt("return", setRemoteItemRaw(key, value, storage));
case 10:
/* Remote value found, parse it and run resolver function */
remoteParsed = safeParse(remoteValueRaw);
localParsed = safeParse(value);
_context2.next = 14;
return resolve({
key: key,
local: localParsed,
localRaw: value,
remote: remoteParsed,
remoteRaw: remoteValueRaw,
isEqual: value === remoteValueRaw || localParsed === remoteParsed
});
case 14:
newValue = _context2.sent;
return _context2.abrupt("return", setRemoteItemRaw(key, newValue, storage));
case 16:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
return _setRemoteItem.apply(this, arguments);
}
function getRemoteItemRaw(key, instance) {
if (!isBrowser) return;
return instance.onConnect().then(function () {
return instance.get(key);
}) // Swallow errors. @TODO make option
["catch"](function (e) {});
}
/**
* Set value on remote storage
* @param {String} key - localStorage key
* @param {String} value - localStorage value
* @return {Promise}
*/
function setRemoteItemRaw(_x5, _x6, _x7) {
return _setRemoteItemRaw.apply(this, arguments);
}
function _setRemoteItemRaw() {
_setRemoteItemRaw = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(key, value, instance) {
return regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
if (!(isUndefined(value) || !isBrowser)) {
_context3.next = 2;
break;
}
return _context3.abrupt("return");
case 2:
return _context3.abrupt("return", instance.onConnect().then(function () {
return instance.set(key, value);
}) // Swallow errors. @TODO make option
["catch"](function (e) {}));
case 3:
case "end":
return _context3.stop();
}
}
}, _callee3);
}));
return _setRemoteItemRaw.apply(this, arguments);
}
function safeParse(val) {
if (isUndefined(val)) return;
try {
return JSON.parse(val);
} catch (e) {
return JSON.parse("\"".concat(val, "\""));
}
}
export { RemoteStorage, getRemoteItem, getRemoteItemRaw, setRemoteItem, setRemoteItemRaw };