data-synchronizer
Version:
A versatile library for transferring data across multi-page applications or single page applications.
712 lines (710 loc) • 23.5 kB
JavaScript
require("core-js/modules/es.object.set-prototype-of.js");
require("core-js/modules/es.object.assign.js");
require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.symbol.iterator.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/es.function.name.js");
require("core-js/modules/es.regexp.to-string.js");
require("core-js/modules/web.dom-collections.for-each.js");
require("core-js/modules/es.object.entries.js");
require("core-js/modules/es.object.keys.js");
require("core-js/modules/es.string.starts-with.js");
require("core-js/modules/es.array.map.js");
require("core-js/modules/es.array.from.js");
require("core-js/modules/es.set.js");
require("core-js/modules/es.map.js");
require("core-js/modules/es.array.slice.js");
require("core-js/modules/es.regexp.constructor.js");
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.string.replace.js");
require("core-js/modules/es.string.match.js");
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.string.includes.js");
require("core-js/modules/es.array.find.js");
define(['exports'], function (exports) {
'use strict';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
var _extendStatics = function extendStatics(d, b) {
_extendStatics = Object.setPrototypeOf || {
__proto__: []
} instanceof Array && function (d, b) {
d.__proto__ = b;
} || function (d, b) {
for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
};
return _extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
_extendStatics(d, b);
function __() {
this.constructor = d;
}
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var _assign = function __assign() {
_assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return _assign.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
}
return t;
}
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator,
m = s && o[s],
i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function next() {
if (o && i >= o.length) o = void 0;
return {
value: o && o[i++],
done: !o
};
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o),
r,
ar = [],
e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
} catch (error) {
e = {
error: error
};
} finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
} finally {
if (e) throw e.error;
}
}
return ar;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
var $type$g = 'string';
var to$g = function to$g(value) {
return [$type$g, value];
};
var from$g = function from$g(value) {
return value;
};
var str = [$type$g, from$g, to$g];
var $type$f = 'boolean';
var to$f = function to$f(value) {
return [$type$f, value];
};
var from$f = function from$f(value) {
return value;
};
var bool = [$type$f, from$f, to$f];
var $type$e = 'number';
var to$e = function to$e(value) {
return [$type$e, value.toString()];
};
var from$e = function from$e(value) {
return +value;
};
var num = [$type$e, from$e, to$e];
var $type$d = 'symbol';
var to$d = function to$d(value) {
return [$type$d, value.description];
};
var from$d = function from$d(value) {
return Symbol.for(value);
};
var sym = [$type$d, from$d, to$d];
var $type$c = 'bigint';
var to$c = function to$c(value) {
return [$type$c, value.toString()];
};
var from$c = function from$c(value) {
return BigInt(value);
};
var bi = [$type$c, from$c, to$c];
var $type$b = 'object';
var to$b = function to$b(value) {
var o = {};
Object.entries(value).forEach(function (_a) {
var _b = __read(_a, 2),
key = _b[0],
value = _b[1];
o[key] = toJsonString(value);
});
return [$type$b, o];
};
var from$b = function from$b(value) {
// fix: BroadcastChannel engine, the value will be object type, but localstorage engine it is string type
var o = typeof value === 'string' ? JSON.parse(value) : value;
var r = {};
Object.entries(o).forEach(function (_a) {
var _b = __read(_a, 2),
key = _b[0],
value = _b[1];
// @ts-ignore
var _c = __read(value, 2),
$type = _c[0],
$value = _c[1];
r[key] = formatMap[$type].from($value);
});
return r;
};
var obj = [$type$b, from$b, to$b];
var $type$a = 'null';
var to$a = function to$a(value) {
return [$type$a, '' + value];
};
var from$a = function from$a() {
return null;
};
var nul = [$type$a, from$a, to$a];
var $type$9 = 'function';
var to$9 = function to$9(value) {
return [$type$9, value.toString()];
};
var from$9 = function from$9(value) {
var funcBody = value.startsWith('function') ? value : 'function ' + value;
var func = new Function("return ".concat(funcBody));
return func();
};
var func = [$type$9, from$9, to$9];
var $type$8 = 'array';
var to$8 = function to$8(value) {
var arr = [];
value.forEach(function (item, i) {
arr[i] = toJsonString(item);
});
return [$type$8, arr];
};
var from$8 = function from$8(value) {
var arr = typeof value === 'string' ? JSON.parse(value) : value;
var r = [];
arr.forEach(function (item, i) {
var _a = __read(item, 2),
$type = _a[0],
$value = _a[1];
r[i] = formatMap[$type].from($value);
});
return r;
};
var arr = [$type$8, from$8, to$8];
var $type$7 = 'set';
var to$7 = function to$7(value) {
var arr = Array.from(value).map(function (item) {
return toJsonString(item);
});
return [$type$7, arr];
};
var from$7 = function from$7(value) {
var o = typeof value === 'string' ? JSON.parse(value) : value;
var s = new Set();
o.forEach(function (item) {
var _a = __read(item, 2),
$type = _a[0],
$value = _a[1];
var it = formatMap[$type].from($value);
s.add(it);
});
return s;
};
var se = [$type$7, from$7, to$7];
var $type$6 = 'map';
var to$6 = function to$6(value) {
var e_1, _a;
var entries = value.entries();
// const obj: Record<any, V> = {};
var arr = [];
try {
// 遍历迭代器并输出键值对
for (var entries_1 = __values(entries), entries_1_1 = entries_1.next(); !entries_1_1.done; entries_1_1 = entries_1.next()) {
var _b = __read(entries_1_1.value, 2),
key = _b[0],
value_1 = _b[1];
var k = toJsonString(key);
// @ts-ignore
var v = toJsonString(value_1);
arr.push([k, v]);
}
} catch (e_1_1) {
e_1 = {
error: e_1_1
};
} finally {
try {
if (entries_1_1 && !entries_1_1.done && (_a = entries_1.return)) _a.call(entries_1);
} finally {
if (e_1) throw e_1.error;
}
}
return [$type$6, arr];
};
var from$6 = function from$6(value) {
var o = typeof value === 'string' ? JSON.parse(value) : value;
var m = new Map();
o.forEach(function (_a) {
var _b = __read(_a, 2),
k = _b[0],
v = _b[1];
var _c = __read(k, 2),
$keyType = _c[0],
$keyValue = _c[1];
var _d = __read(v, 2),
$valueType = _d[0],
$valueValue = _d[1];
k = formatMap[$keyType].from($keyValue);
v = formatMap[$valueType].from($valueValue);
m.set(k, v);
});
return m;
};
var ma = [$type$6, from$6, to$6];
var $type$5 = 'date';
var to$5 = function to$5(value) {
return [$type$5, '' + value.getTime()];
};
var from$5 = function from$5(value) {
return new Date(+value);
};
var dat = [$type$5, from$5, to$5];
var $type$4 = 'regexp';
var to$4 = function to$4(value) {
return [$type$4, value.toString()];
};
var from$4 = function from$4(value) {
// 去掉字符串中的前后斜杠
var pattern = value.slice(1, value.lastIndexOf('/')); // 获取模式部分
var flags = value.slice(value.lastIndexOf('/') + 1); // 获取标志部分
// 使用 RegExp 构造函数创建正则表达式
var regex = new RegExp(pattern, flags);
return regex;
};
var reg = [$type$4, from$4, to$4];
var $type$3 = 'undefined';
var to$3 = function to$3() {
return [$type$3, 'undefined'];
};
var from$3 = function from$3() {
return undefined;
};
var und = [$type$3, from$3, to$3];
var $type$2 = 'arrowFunction';
var to$2 = function to$2(value) {
return [$type$2, value.toString()];
};
var from$2 = function from$2(value) {
var arrowFunc = new Function("return ".concat(value));
return arrowFunc();
};
var arrowFunction = [$type$2, from$2, to$2];
var $type$1 = 'asyncfunction';
var to$1 = function to$1(value) {
var funcString = value.toString();
if (!funcString.startsWith('async function')) {
funcString = funcString.replace('async', 'async function');
}
return [$type$1, funcString];
};
var from$1 = function from$1(value) {
var arrowFunc = new Function("return ".concat(value));
return arrowFunc();
};
var asyncFunction = [$type$1, from$1, to$1];
var $type = 'generatorfunction';
var to = function to(value) {
var funcString = value.toString();
if (funcString.startsWith("*")) {
funcString = "function ".concat(funcString);
}
return [$type, funcString.toString()];
};
var from = function from(value) {
var arrowFunc = new Function("return ".concat(value));
return arrowFunc();
};
var generatorFunction = [$type, from, to];
var formatMap = [str, bool, num, sym, bi, obj, nul, func, arr, se, ma, dat, reg, und, arrowFunction, asyncFunction, generatorFunction].reduce(function (cur, next) {
var _a;
var _b = __read(next, 3),
$type = _b[0],
from = _b[1],
to = _b[2];
Object.assign(cur, (_a = {},
// @ts-ignore
_a[$type] = {
from: from,
to: to
}, _a));
return cur;
}, {});
var isSupportBroadcastChannel = ("BroadcastChannel" in window);
var isSupportLocalStorage = ("localStorage" in window);
var isArrowFunction = function isArrowFunction(fn) {
var str = (fn === null || fn === void 0 ? void 0 : fn.toString()) || '';
// 判断函数体是否有花括号
if (str.match(/{[\s\S]*}/)) {
// 将花括号内的函数体去掉
return str.replace(/{[\s\S]*}/, "").includes("=>");
} else {
return true;
}
};
var getType = function getType(v) {
if (v === undefined) {
return "undefined";
} else if (v === null) {
return "null";
} else if (v instanceof Function && isArrowFunction(v)) {
return "arrowFunction";
} else {
return v.constructor.name.toLowerCase();
}
};
var fromJsonStringData = function fromJsonStringData(jsonString) {
var data = JSON.parse(jsonString);
var $payload = data.$payload;
data.$id;
var others = __rest(data, ["$payload", "$id"]);
var o = _assign(_assign({}, others), {
$payload: []
});
var _a = __read($payload, 2),
$type = _a[0],
$value = _a[1];
o["$payload"] = formatMap[$type].from($value);
return o;
};
var toJsonString = function toJsonString(payload) {
var target = formatMap[getType(payload)];
if (target) {
payload = target.to(payload);
}
return payload;
};
var handleData = function handleData(payload, target) {
var $payload = toJsonString(payload);
return {
$origin: location.href,
$payload: $payload,
$target: typeof target === "string" ? target : target === null || target === void 0 ? void 0 : target.source,
$id: generateRandomAlphaNum(16)
};
};
var canInvoke = function canInvoke(text, pattern) {
if (!pattern) return true;
return new RegExp(pattern).test(text);
};
var generateRandomAlphaNum = function generateRandomAlphaNum(len) {
var rdmString = "";
for (; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
return rdmString.substr(0, len);
};
var uniqueArr = function uniqueArr(arr) {
return Array.from(new Set(arr));
};
var ChannelMap = new Map();
var onBroadcastChannelMessage = function onBroadcastChannelMessage(chan, callback) {
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
chan.forEach(function (c) {
var bc = new BroadcastChannel(c);
bc.addEventListener('message', function (event) {
try {
var data = fromJsonStringData(event.data);
var invoke = canInvoke(location.href, data.$target);
if (!invoke) return;
typeof callback === 'function' && callback(data);
} catch (error) {
console.error(error);
}
});
var bcList = ChannelMap.get(c) || [];
bcList.push(bc);
ChannelMap.set(c, bcList);
});
};
var sendBroadcastChannelMessage = function sendBroadcastChannelMessage(chan, o, params) {
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
var jsonData = handleData(o, params);
chan.forEach(function (c) {
var bc = new BroadcastChannel(c);
bc.postMessage(JSON.stringify(jsonData));
var bcList = ChannelMap.get(c) || [];
bcList.push(bc);
ChannelMap.set(c, bcList);
});
};
var onSendBroadcastChannelMessageError = function onSendBroadcastChannelMessageError(chan, callback) {
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
chan.forEach(function (c) {
var bc = new BroadcastChannel(c);
bc.addEventListener('messageerror', function (event) {
typeof callback === 'function' && callback(event);
});
var bcList = ChannelMap.get(c) || [];
bcList.push(bc);
ChannelMap.set(c, bcList);
});
};
var closeBroadcastChannel = function closeBroadcastChannel(chan) {
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
chan.forEach(function (c) {
var bcList = ChannelMap.get(c) || [];
if (!bcList.length) {
throw new Error("the channel named ".concat(chan, " isn't exist"));
}
bcList.forEach(function (bc) {
bc.close();
});
ChannelMap.delete(c);
});
};
var OnSendMessageErrorMap = new Map();
var onLocalStorageMessage = function onLocalStorageMessage(chan, callback) {
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
window.addEventListener("storage", function (event) {
var key = event.key;
if (!chan.includes(key)) return;
try {
var o = fromJsonStringData(event.newValue);
var invoke = canInvoke(location.href, o.$target);
if (!invoke) return;
callback(o);
} catch (error) {
console.error(error);
}
});
};
var sendLocalStorageMessage = function sendLocalStorageMessage(chan, o, params) {
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
var res = handleData(o, params);
var jsonString = JSON.stringify(res);
chan.forEach(function (c) {
try {
window.localStorage.setItem(c, jsonString);
// dispatch event
var event_1 = new StorageEvent("storage", {
key: c,
newValue: jsonString
});
window.dispatchEvent(event_1);
} catch (error) {
var callbacks = OnSendMessageErrorMap.get(c);
(callbacks || []).forEach(function (callback) {
callback(error);
});
}
});
};
var onSendLocalStorageMessageError = function onSendLocalStorageMessageError(chan, callback) {
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
chan.forEach(function (k) {
var fns = OnSendMessageErrorMap.get(k);
if (fns) {
fns.push(callback);
} else {
fns = [callback];
}
OnSendMessageErrorMap.set(k, fns);
});
};
var closeLocalStorage = function closeLocalStorage(chan) {
var setItem = localStorage.setItem;
if (typeof chan === "string") {
chan = [chan];
}
chan = uniqueArr(chan);
localStorage.setItem = function (key, value) {
if (chan.includes(key)) {
return;
}
setItem(key, value);
};
var getItem = localStorage.getItem;
localStorage.getItem = function (key) {
if (chan.includes(key)) {
return;
}
return getItem(key);
};
};
var BaseAdaptor = /** @class */function () {
function BaseAdaptor() {}
return BaseAdaptor;
}();
var LocalStorageAdaptor = /** @class */function (_super) {
__extends(LocalStorageAdaptor, _super);
function LocalStorageAdaptor() {
return _super !== null && _super.apply(this, arguments) || this;
}
LocalStorageAdaptor.prototype.onMessage = function (chan, callback) {
onLocalStorageMessage(chan, callback);
};
LocalStorageAdaptor.prototype.onSendMessageError = function (chan, callback) {
onSendLocalStorageMessageError(chan, callback);
};
LocalStorageAdaptor.prototype.sendMessage = function (chan, o, targets) {
sendLocalStorageMessage(chan, o, targets);
};
LocalStorageAdaptor.prototype.close = function (chan) {
closeLocalStorage(chan);
};
return LocalStorageAdaptor;
}(BaseAdaptor);
var BroadcastChannelAdaptor = /** @class */function (_super) {
__extends(BroadcastChannelAdaptor, _super);
function BroadcastChannelAdaptor() {
return _super !== null && _super.apply(this, arguments) || this;
}
BroadcastChannelAdaptor.prototype.onMessage = function (chan, callback) {
onBroadcastChannelMessage(chan, callback);
};
BroadcastChannelAdaptor.prototype.sendMessage = function (chan, o, targets) {
sendBroadcastChannelMessage(chan, o, targets);
};
BroadcastChannelAdaptor.prototype.onSendMessageError = function (chan, callback) {
onSendBroadcastChannelMessageError(chan, callback);
};
BroadcastChannelAdaptor.prototype.close = function (chan) {
closeBroadcastChannel(chan);
};
return BroadcastChannelAdaptor;
}(BaseAdaptor);
var isSupport$1 = isSupportBroadcastChannel || isSupportLocalStorage;
var DataSynchronizer = /** @class */function () {
function DataSynchronizer(options) {
this.options = {
engine: 'BroadcastChannel'
};
if (!isSupport$1) {
throw new Error("The library doesn't support your browser.");
}
Object.assign(this.options, options);
this.initEngine();
}
DataSynchronizer.prototype.initEngine = function () {
var engine = this.options.engine;
var engineMap = {
BroadcastChannel: BroadcastChannelAdaptor,
LocalStorage: LocalStorageAdaptor
};
this.instance = new engineMap[engine](this.options);
};
DataSynchronizer.prototype.onMessage = function (chan, callback) {
this.instance.onMessage(chan, callback);
};
DataSynchronizer.prototype.sendMessage = function (chan, o, params) {
this.instance.sendMessage(chan, o, params);
};
DataSynchronizer.prototype.onMessageError = function (chan, callback) {
this.instance.onSendMessageError(chan, callback);
};
DataSynchronizer.prototype.close = function (chan) {
this.instance.close(chan);
};
return DataSynchronizer;
}();
var isSupport = isSupportBroadcastChannel || isSupportLocalStorage;
var useDataSynchronizer = function useDataSynchronizer(options) {
if (!isSupport) {
throw new Error("the lib isn't support your browser.");
}
var defaultOptions = {
engine: 'BroadcastChannel'
};
options = Object.assign(defaultOptions, options);
var strategies = [{
engine: 'BroadcastChannel',
support: isSupportBroadcastChannel,
onMessage: onBroadcastChannelMessage,
sendMessage: sendBroadcastChannelMessage,
onSendMessageError: onSendBroadcastChannelMessageError,
close: closeBroadcastChannel
}, {
engine: 'LocalStorage',
support: isSupportLocalStorage,
onMessage: onLocalStorageMessage,
sendMessage: sendLocalStorageMessage,
onSendMessageError: onSendLocalStorageMessageError,
close: closeLocalStorage
}];
var o = strategies.find(function (item) {
return item.engine === options.engine && item.support;
});
var onMessage = function onMessage(chan, callback) {
return o.onMessage(chan, callback);
};
var onMessageError = function onMessageError(chan, callback) {
return o.onSendMessageError(chan, callback);
};
var sendMessage = function sendMessage(chan, value, params) {
return o.sendMessage(chan, value, params);
};
var close = function close(chan) {
return o.close(chan);
};
return {
onMessage: onMessage,
sendMessage: sendMessage,
onMessageError: onMessageError,
close: close
};
};
exports.DataSynchronizer = DataSynchronizer;
exports.useDataSynchronizer = useDataSynchronizer;
});