@lastos/page-spy-react-native
Version:
An SDK of PageSpy for debugging react native app
1,644 lines (1,625 loc) • 210 kB
JavaScript
import { Platform } from 'react-native';
import LocalPromise from 'promise/setimmediate/es6-extensions';
import RejectTracking from 'promise/setimmediate/rejection-tracking';
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function toPropertyKey(t) {
var i = toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
function _defineProperty(obj, key, value) {
key = toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function isBrowser() {
return typeof window === 'object' && typeof document === 'object' && Object.prototype.toString.call(document) === '[object HTMLDocument]';
}
function getRandomId() {
return Math.random().toString(36).slice(2);
}
function getObjectKeys(obj) {
return Object.keys(obj);
}
function toStringTag(value) {
return Object.prototype.toString.call(value);
}
function hasOwnProperty(target, key) {
return Object.prototype.hasOwnProperty.call(target, key);
}
function isString(value) {
return typeof value === 'string';
}
function isNumber(value) {
return typeof value === 'number';
}
function isBigInt(value) {
return toStringTag(value) === '[object BigInt]';
}
function isArray(value) {
return value instanceof Array;
}
function isArrayLike(value) {
if (typeof NodeList === 'function' && NodeList.name === 'NodeList' && value instanceof NodeList) {
return true;
}
if (typeof HTMLCollection === 'function' && HTMLCollection.name === 'HTMLCollection' && value instanceof HTMLCollection) {
return true;
}
return false;
}
function isObjectLike(value) {
return typeof value === 'object' && value !== null;
}
function isPlainObject(value) {
if (!isObjectLike(value) || toStringTag(value) !== '[object Object]') {
return false;
}
return true;
}
function isPrototype(value) {
if (isObjectLike(value) && hasOwnProperty(value, 'constructor') && typeof value.constructor === 'function') {
return true;
}
return false;
}
function isBlob(value) {
return value instanceof Blob;
}
function isArrayBuffer(value) {
return value instanceof ArrayBuffer;
}
function isFormData(value) {
return value instanceof FormData;
}
function isFile(value) {
return value instanceof File;
}
function isHeaders(value) {
return value instanceof Headers;
}
function isURL(value) {
return value instanceof URL;
}
function isClass(obj) {
return typeof obj === 'function' && typeof obj.prototype !== 'undefined';
}
const CN_IDs = ['zh-CN', 'zh-HK', 'zh-TW', 'zh', 'zh-Hans-CN'];
function isCN() {
if (isBrowser()) {
const {
lang
} = document.documentElement;
if (lang) return CN_IDs.some(i => i === lang);
return CN_IDs.some(i => i === navigator.language);
}
return false;
}
function isTypedArray(value) {
return ArrayBuffer.isView(value);
}
const stringify = value => "".concat(value);
const primitive = value => ({
ok: true,
value
});
function makePrimitiveValue(value) {
if (value === undefined) {
return primitive(stringify(value));
}
if (value === null) {
return primitive(value);
}
if (isNumber(value)) {
if (value === -Infinity || value === Infinity || Number.isNaN(value)) {
return primitive(stringify(value));
}
}
if (isBigInt(value)) {
return primitive("".concat(value, "n"));
}
if (typeof value === 'symbol' || typeof value === 'function') {
return primitive(stringify(value.toString()));
}
if (value instanceof Error) {
return primitive(stringify(value.stack));
}
if (value === Object.prototype) {
return {
value: null,
ok: false
};
}
if (!(value instanceof Object || typeof value === 'object')) {
return primitive(value);
}
return {
value,
ok: false
};
}
/**
* convert `symbol / error / undefined / function` type data to readable string content
*/
function stringifyData(data) {
const {
ok,
value
} = makePrimitiveValue(data);
/* c8 ignore next 3 */
if (ok) {
return value;
}
return JSON.stringify(data, (key, val) => makePrimitiveValue(val).value, 2);
}
function getValueType(value) {
if (value === undefined) return 'undefined';
if (value === null) return 'null';
if (isBigInt(value)) return 'bigint';
if (value instanceof Object) {
if (value instanceof Error) return 'error';
// Here we do not use 'instanceof Function' because in some context
// like mini program the Function constructor is overwritten.
if (typeof value === 'function') return 'function';
return 'object';
}
return typeof value;
}
const unproxyConsole = {
...console
};
const psLog = ['log', 'info', 'error', 'warn', 'debug'].reduce((result, method) => {
result[method] = function () {
for (var _len = arguments.length, message = new Array(_len), _key = 0; _key < _len; _key++) {
message[_key] = arguments[_key];
}
console[method]("[PageSpy] [".concat(method.toLocaleUpperCase(), "] "), ...message);
};
result.unproxy[method] = function () {
for (var _len2 = arguments.length, message = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
message[_key2] = arguments[_key2];
}
unproxyConsole[method]("[PageSpy] [".concat(method.toLocaleUpperCase(), "] "), ...message);
};
return result;
}, {
unproxy: {}
});
function getAuthSecret() {
const secret = Math.floor(Math.random() * 1000000);
return String(secret).padStart(6, '0');
}
const formatErrorObj = err => {
if (typeof err !== 'object') return null;
const {
name,
message,
stack
} = Object(err);
if ([name, message, stack].every(Boolean) === false) {
return null;
}
return {
name,
message,
stack
};
};
const blob2base64Async = blob => {
return new Promise((resolve, reject) => {
const fr = new FileReader();
fr.onload = e => {
var _e$target;
resolve((_e$target = e.target) === null || _e$target === void 0 ? void 0 : _e$target.result);
};
/* c8 ignore next 3 */
fr.onerror = () => {
reject(new Error('blob2base64Async: can not convert'));
};
fr.readAsDataURL(blob);
});
};
class Client {
constructor() {
let info = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
// browserName and framework should be overwritten by package implementation\
osType: 'unknown',
osVersion: 'unknown',
browserType: 'unknown',
browserVersion: 'unknown',
framework: 'unknown',
isDevTools: false,
sdk: 'unknown',
sdkVersion: '0.0.0'
};
let
// the raw info from getSystemInfoSync or similar api, will be sent by system plugin
rawInfo = arguments.length > 1 ? arguments[1] : undefined;
_defineProperty(this, "info", void 0);
_defineProperty(this, "rawInfo", void 0);
_defineProperty(this, "plugins", []);
_defineProperty(this, "_name", '');
this.info = info;
this.rawInfo = rawInfo;
}
makeClientInfoMsg() {
const msg = {
sdk: this.info.sdk,
isDevTools: this.info.isDevTools,
ua: this.getName(),
plugins: this.plugins
};
return msg;
}
getName() {
if (!this._name) {
const {
ua,
osType,
osVersion,
browserType,
browserVersion
} = this.info;
this._name = ua || "".concat(osType, "/").concat(osVersion, " ").concat(browserType, "/").concat(browserVersion);
}
return this._name;
}
}
class Atom {
constructor() {
_defineProperty(this, "store", {});
// { __atomId: instanceId }
_defineProperty(this, "instanceStore", {});
}
getStore() {
return this.store;
}
resetStore() {
this.store = {};
}
getInstanceStore() {
return this.instanceStore;
}
resetInstanceStore() {
this.instanceStore = {};
}
transformToAtom(data) {
let serializeData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
const {
value,
ok
} = makePrimitiveValue(data);
const id = getRandomId();
if (ok) {
return {
id,
type: getValueType(data),
value
};
}
if (serializeData) {
try {
return {
id,
type: 'json',
value: JSON.stringify(data)
};
} catch (e) {
// type === 'json' && value === null 作为无法序列化数据时的硬编码
return {
id,
type: 'json',
value: null
};
}
}
return this.add(data);
}
get(id) {
const cacheData = this.store[id];
const instanceId = this.instanceStore[id];
if (!cacheData) return null;
const result = {};
const descriptors = Object.getOwnPropertyDescriptors(cacheData);
Object.keys(descriptors).forEach(key => {
const desc = descriptors[key];
if (hasOwnProperty(desc, 'value')) {
desc.value = this.transformToAtom(desc.value);
}
result[key] = Atom.getAtomOverview({
atomId: getRandomId(),
instanceId,
value: desc
});
});
const extraProps = this.addExtraProperty(id);
return {
...result,
...extraProps
};
}
/* c8 ignore start */
getOrigin(id) {
const value = this.store[id];
if (!value) return null;
return value;
}
/* c8 ignore stop */
add(data) {
let insId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
const id = getRandomId();
let instanceId = id;
// must provide the instance id if the `isPrototype(data)` return true,
// or else will occur panic when access the property along the proto chain
if (isPrototype(data)) {
instanceId = insId;
}
this.store[id] = data;
this.instanceStore[id] = instanceId;
const name = Atom.getSemanticValue(data);
return Atom.getAtomOverview({
atomId: id,
value: name,
instanceId
});
}
static getAtomOverview(_ref) {
let {
instanceId = '',
atomId,
value
} = _ref;
const id = getRandomId();
return {
id,
type: 'atom',
__atomId: atomId,
instanceId,
value
};
}
static getSemanticValue(data) {
if (isPlainObject(data)) {
return 'Object {...}';
}
if (isArray(data)) {
return "Array (".concat(data.length, ")");
}
const constructorName = data.constructor.name;
return constructorName;
}
addExtraProperty(id) {
const data = this.store[id];
const instanceId = this.instanceStore[id];
const result = {};
if (data instanceof String || data instanceof Number || data instanceof Boolean) {
result['[[PrimitiveValue]]'] = this.transformToAtom(data.valueOf());
}
if (data instanceof Set) {
const entries = {};
let index = 0;
for (const v of data) {
entries[index++] = v;
}
entries.size = data.size;
result['[[Entries]]'] = this.transformToAtom(entries);
}
if (data instanceof Map) {
const entries = {};
let index = 0;
for (const [k, v] of data.entries()) {
entries[index++] = {
key: k,
value: v
};
}
entries.size = data.size;
result['[[Entries]]'] = this.transformToAtom(entries);
}
/* c8 ignore next 3 */
if (isArray(data) || isArrayLike(data)) {
result.length = this.transformToAtom(data.length);
}
if (Object.getPrototypeOf(data) !== null) {
result['[[Prototype]]'] = this.add(Object.getPrototypeOf(data), instanceId);
} else {
// eslint-disable-next-line no-underscore-dangle
result.___proto___ = this.transformToAtom(null);
}
return result;
}
}
const atom = new Atom();
const CONNECT = 'connect';
const JOIN = 'join';
const LEAVE = 'leave';
const CLOSE = 'close';
const MESSAGE = 'message';
const BROADCAST = 'broadcast';
const ERROR = 'error';
const PING = 'ping';
const PONG = 'pong';
const UPDATE_ROOM_INFO = 'updateRoomInfo';
var SERVER_MESSAGE_TYPE = /*#__PURE__*/Object.freeze({
__proto__: null,
BROADCAST: BROADCAST,
CLOSE: CLOSE,
CONNECT: CONNECT,
ERROR: ERROR,
JOIN: JOIN,
LEAVE: LEAVE,
MESSAGE: MESSAGE,
PING: PING,
PONG: PONG,
UPDATE_ROOM_INFO: UPDATE_ROOM_INFO
});
function makeMessage(type, data) {
let needId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
const result = {
...(needId && {
id: getRandomId()
}),
...data
};
return {
role: 'client',
type,
data: result
};
}
function makeUnicastMessage(msg, from, to) {
return {
type: MESSAGE,
content: {
data: msg,
from,
to
}
};
}
function makeBroadcastMessage(msg) {
return {
type: BROADCAST,
content: {
data: msg
}
};
}
// fork WebSocket state
var SocketState;
(function (SocketState) {
SocketState[SocketState["CONNECTING"] = 0] = "CONNECTING";
SocketState[SocketState["OPEN"] = 1] = "OPEN";
SocketState[SocketState["CLOSING"] = 2] = "CLOSING";
SocketState[SocketState["CLOSED"] = 3] = "CLOSED";
})(SocketState || (SocketState = {}));
const HEARTBEAT_INTERVAL = 5000;
// The reconnect interval has an initial time of 2000 ms,
// for each failed reconnection attempt, the time will be increased by 1.5x,
// until the attempt number reaches 4, the time will be fixed, which is Math.pow(1.5, 4) * 2000.
// retry interval
const INIT_RETRY_INTERVAL = 2000;
// retry interval time will increase by 1.5x each time.
const RETRY_TIME_INCR = 1.5;
// the time increase pow limit.
const MAX_RETRY_INTERVAL = Math.pow(RETRY_TIME_INCR, 4) * INIT_RETRY_INTERVAL;
// 封装不同平台的 socket
class SocketWrapper {
constructor() {
_defineProperty(this, "events", {
open: [],
close: [],
error: [],
message: []
});
}
emit(event, data) {
this.events[event].forEach(fun => {
fun(data);
});
// for close and error, clear all listeners or they will be called on next socket instance.
if (event === 'close' || event === 'error') {
this.clearListeners();
}
}
onOpen(fun) {
this.events.open.push(fun);
}
onClose(fun) {
this.events.close.push(fun);
}
onError(fun) {
this.events.error.push(fun);
}
onMessage(fun) {
this.events.message.push(fun);
}
clearListeners() {
// clear listeners
Object.entries(this.events).forEach(_ref => {
let [, funs] = _ref;
funs.splice(0);
});
}
}
class SocketStoreBase {
getSocket() {
return this.socketWrapper;
}
updateRoomInfo() {
if (this.getPageSpyConfig) {
var _this$getClient;
const {
project,
title,
unique,
url,
env,
version
} = this.getPageSpyConfig();
const name = (_this$getClient = this.getClient) === null || _this$getClient === void 0 ? void 0 : _this$getClient.call(this).getName();
this.send({
type: UPDATE_ROOM_INFO,
content: {
info: {
name,
group: project,
tags: {
title,
name,
group: project,
unique,
url,
env,
version
}
}
}
}, true);
}
}
// response message filters, to handle some wired messages
constructor() {
_defineProperty(this, "socketUrl", '');
_defineProperty(this, "socketConnection", null);
_defineProperty(this, "debuggerConnection", null);
// ping timer used for send next ping.
// a ping is sent after last msg (normal msg or pong) received.
_defineProperty(this, "pingTimer", null);
// pong timer used for waiting for pong, if pong not received, close the connection
_defineProperty(this, "pongTimer", null);
_defineProperty(this, "retryTimer", null);
// Cache messages only in online mode
_defineProperty(this, "isOffline", false);
// Maximum message length,
// the 0 meant no limitation.
_defineProperty(this, "messageCapacity", 0);
// messages store
_defineProperty(this, "messages", []);
// events center
_defineProperty(this, "events", {
debug: [],
refresh: [],
'atom-detail': [],
'atom-getter': [],
'debugger-online': [],
'database-pagination': [],
'public-data': [],
'harbor-clear': []
});
// initial retry interval.
_defineProperty(this, "retryInterval", INIT_RETRY_INTERVAL);
_defineProperty(this, "connectable", true);
_defineProperty(this, "getPageSpyConfig", null);
_defineProperty(this, "getClient", null);
this.addListener('atom-detail', SocketStoreBase.handleResolveAtom);
this.addListener('atom-getter', SocketStoreBase.handleAtomPropertyGetter);
this.addListener('debugger-online', this.handleFlushBuffer);
}
async init(url) {
try {
var _this$socketWrapper, _this$socketWrapper2, _this$socketWrapper3, _this$socketWrapper4, _this$socketWrapper5;
if (!url) {
throw Error('WebSocket url cannot be empty');
}
this.socketWrapper.clearListeners();
// close existing connection
if (this.socketWrapper.getState() === SocketState.OPEN) {
// make sure the existing connection closed.
// we need to register new handlers immediately.
await new Promise(resolve => {
this.socketWrapper.onClose(() => {
this.socketWrapper.clearListeners();
resolve();
});
this.socketWrapper.close();
});
}
(_this$socketWrapper = this.socketWrapper) === null || _this$socketWrapper === void 0 || _this$socketWrapper.onOpen(() => {
this.connectOnline();
});
// Strictly, the onMessage should be called after onOpen. But for some platform(alipay,)
// this may cause some message losing.
(_this$socketWrapper2 = this.socketWrapper) === null || _this$socketWrapper2 === void 0 || _this$socketWrapper2.onMessage(evt => {
this.handleMessage(evt);
});
(_this$socketWrapper3 = this.socketWrapper) === null || _this$socketWrapper3 === void 0 || _this$socketWrapper3.onClose(() => {
this.connectOffline();
});
(_this$socketWrapper4 = this.socketWrapper) === null || _this$socketWrapper4 === void 0 || _this$socketWrapper4.onError(() => {
// we treat on error the same with on close.
this.connectOffline();
});
this.socketUrl = url;
(_this$socketWrapper5 = this.socketWrapper) === null || _this$socketWrapper5 === void 0 || _this$socketWrapper5.init(url);
} catch (e) {
psLog.error(e.message);
}
}
addListener(type, fn) {
/* c8 ignore next 3 */
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push(fn);
}
removeListener(type, fn) {
/* c8 ignore next 3 */
const fns = this.events[type] || [];
const index = fns.indexOf(fn);
if (index > -1) {
fns.splice(index, 1);
}
}
broadcastMessage(msg) {
let noCache = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
const message = makeBroadcastMessage(msg);
this.send(message, noCache);
}
close() {
var _this$socketWrapper6;
this.connectable = false;
this.clearPing();
(_this$socketWrapper6 = this.socketWrapper) === null || _this$socketWrapper6 === void 0 || _this$socketWrapper6.close();
this.messages = [];
Object.entries(this.events).forEach(_ref2 => {
let [evt, fns] = _ref2;
// 这三个事件的生命周期跟随 socketStore
if (['atom-detail', 'atom-getter', 'debugger-online'].includes(evt)) {
return;
}
fns.splice(0);
});
}
connectOnline() {
this.retryInterval = INIT_RETRY_INTERVAL;
this.updateRoomInfo();
this.ping();
}
connectOffline() {
this.socketConnection = null;
this.debuggerConnection = null;
this.clearPing();
if (this.retryTimer) {
clearTimeout(this.retryTimer);
}
if (!this.connectable) return;
this.retryTimer = setTimeout(() => {
if (this.retryInterval < MAX_RETRY_INTERVAL) {
this.retryInterval *= RETRY_TIME_INCR;
}
this.retryTimer = null;
this.tryReconnect();
}, this.retryInterval);
}
tryReconnect() {
this.init(this.socketUrl);
}
ping() {
if (this.pingTimer) {
clearTimeout(this.pingTimer);
}
if (this.pongTimer) {
clearTimeout(this.pongTimer);
}
/* c8 ignore start */
this.pingTimer = setTimeout(() => {
this.send({
type: 'ping',
content: null
});
this.pingTimer = null;
this.pongTimer = setTimeout(() => {
// lost connection
this.connectOffline();
this.pongTimer = null;
}, HEARTBEAT_INTERVAL);
}, HEARTBEAT_INTERVAL);
/* c8 ignore stop */
}
clearPing() {
if (this.pingTimer) {
clearTimeout(this.pingTimer);
this.pingTimer = null;
}
if (this.pongTimer) {
clearTimeout(this.pongTimer);
this.pongTimer = null;
}
}
handlePong() {
clearTimeout(this.pongTimer);
this.pongTimer = null;
this.ping();
}
// get the data which we expected from nested structure of the message
handleMessage(evt) {
var _this$socketConnectio;
if (SocketStoreBase.messageFilters.length) {
SocketStoreBase.messageFilters.forEach(filter => {
evt = filter(evt);
});
}
const {
CONNECT,
MESSAGE,
ERROR,
JOIN,
PING,
PONG,
LEAVE,
CLOSE,
BROADCAST
} = SERVER_MESSAGE_TYPE;
const result = JSON.parse(evt.data);
const {
type
} = result;
switch (type) {
case CONNECT:
const {
selfConnection,
roomConnections
} = result.content;
this.socketConnection = selfConnection;
this.debuggerConnection = roomConnections.find(i => i.userId === 'Debugger') || null;
break;
case JOIN:
case LEAVE:
const {
connection
} = result.content;
if (connection.userId === 'Debugger') {
if (type === JOIN) {
this.debuggerConnection = connection;
// once connected, send client info
this.sendClientInfo();
} else {
this.debuggerConnection = null;
}
}
break;
case MESSAGE:
const {
data,
from,
to
} = result.content;
if (to.address === ((_this$socketConnectio = this.socketConnection) === null || _this$socketConnectio === void 0 ? void 0 : _this$socketConnectio.address)) {
this.dispatchEvent(data.type, {
source: data,
from,
to
});
}
break;
case CLOSE:
case ERROR:
this.connectOffline();
break;
/* c8 ignore stop */
}
// whatever the type is, we should handle pong
this.handlePong();
}
dispatchEvent(type, data) {
var _this$events$type;
if (['public-data'].includes(type)) {
this.events['public-data'].forEach(fn => {
fn(data);
});
return;
}
(_this$events$type = this.events[type]) === null || _this$events$type === void 0 || _this$events$type.forEach(fn => {
fn.call(this, data, d => {
this.unicastMessage(d, data.from);
});
});
}
unicastMessage(msg, to) {
const message = makeUnicastMessage(msg, this.socketConnection, to);
this.send(message);
}
handleFlushBuffer(message) {
const {
latestId
} = message.source.data;
const msgIndex = this.messages.findIndex(i => i.content.data.data.id === latestId);
/* c8 ignore start */
this.messages.slice(msgIndex + 1).forEach(msg => {
const data = {
type: MESSAGE,
content: {
data: msg.content.data,
from: this.socketConnection,
to: message.from
}
};
this.send(data, true);
});
/* c8 ignore stop */
}
static handleResolveAtom(_ref3, reply) {
let {
source
} = _ref3;
const {
type,
data
} = source;
if (type === 'atom-detail') {
const atomData = atom.get(data) || {};
const msg = makeMessage("atom-detail-".concat(data), atomData, false);
reply(msg);
}
}
static handleAtomPropertyGetter(_ref4, reply) {
let {
source
} = _ref4;
const {
type,
data
} = source;
if (type === 'atom-getter') {
const {
id,
parentId,
key,
instanceId
} = data;
const instance = atom.getOrigin(instanceId);
const current = atom.getOrigin(parentId);
let value = {};
/* c8 ignore start */
if (instance && current) {
var _Object$getOwnPropert;
value = (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(current, key)) === null || _Object$getOwnPropert === void 0 || (_Object$getOwnPropert = _Object$getOwnPropert.get) === null || _Object$getOwnPropert === void 0 ? void 0 : _Object$getOwnPropert.call(instance);
} else {
value = new Error('Getter computed failed');
}
/* c8 ignore stop */
const msg = makeMessage("atom-getter-".concat(id), atom.transformToAtom(value));
reply(msg);
}
}
send(msg) {
let noCache = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
const sendable = this.checkIfSend(msg);
if (sendable) {
/* c8 ignore start */
try {
var _this$socketWrapper7;
const pkMsg = msg;
pkMsg.createdAt = Date.now();
pkMsg.requestId = getRandomId();
const dataString = stringifyData(pkMsg);
(_this$socketWrapper7 = this.socketWrapper) === null || _this$socketWrapper7 === void 0 || _this$socketWrapper7.send(dataString);
} catch (e) {
psLog.error("Incompatible: ".concat(e.message));
this.connectOffline();
}
/* c8 ignore stop */
}
const cacheable = this.checkIfCache(msg, noCache);
if (cacheable) {
if (this.messageCapacity !== 0 && this.messages.length >= this.messageCapacity) {
this.messages.shift();
}
this.messages.push(msg);
}
}
checkIfSend(msg) {
if (this.socketWrapper.getState() !== SocketState.OPEN) return false;
if ([UPDATE_ROOM_INFO, PING].includes(msg.type)) {
return true;
}
if (!this.debuggerConnection) return false;
return true;
}
checkIfCache(msg) {
let noCache = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (this.isOffline || noCache) return false;
if ([MESSAGE, PING].includes(msg.type)) {
return false;
}
return true;
}
sendClientInfo() {
var _this$getClient2;
const clientInfo = (_this$getClient2 = this.getClient) === null || _this$getClient2 === void 0 ? void 0 : _this$getClient2.call(this).makeClientInfoMsg();
this.broadcastMessage({
role: 'client',
type: 'client-info',
data: clientInfo
}, true);
}
}
_defineProperty(SocketStoreBase, "messageFilters", []);
class RNWebSocketWrapper extends SocketWrapper {
constructor() {
super(...arguments);
_defineProperty(this, "socketInstance", null);
}
init(url) {
this.socketInstance = new WebSocket(url);
const eventNames = ['open', 'close', 'error', 'message'];
eventNames.forEach(eventName => {
this.socketInstance.addEventListener(eventName, data => {
this.events[eventName].forEach(cb => {
cb(data);
});
});
});
}
send(data) {
var _this$socketInstance;
(_this$socketInstance = this.socketInstance) === null || _this$socketInstance === void 0 || _this$socketInstance.send(stringifyData(data));
}
close() {
var _this$socketInstance2;
(_this$socketInstance2 = this.socketInstance) === null || _this$socketInstance2 === void 0 || _this$socketInstance2.close();
}
getState() {
var _this$socketInstance3;
return (_this$socketInstance3 = this.socketInstance) === null || _this$socketInstance3 === void 0 ? void 0 : _this$socketInstance3.readyState;
}
}
class RNWebSocketStore extends SocketStoreBase {
// disable lint: this is an abstract method of parent class, so it cannot be static
// eslint-disable-next-line class-methods-use-this
onOffline() {}
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor() {
super();
// websocket instance
_defineProperty(this, "socketWrapper", new RNWebSocketWrapper());
}
}
const socketStore = new RNWebSocketStore();
class ConsolePlugin {
constructor() {
_defineProperty(this, "name", 'ConsolePlugin');
_defineProperty(this, "console", {});
_defineProperty(this, "proxyTypes", ['log', 'info', 'error', 'warn', 'debug']);
_defineProperty(this, "$pageSpyConfig", null);
}
async onInit(_ref) {
let {
config
} = _ref;
if (ConsolePlugin.hasInitd) return;
ConsolePlugin.hasInitd = true;
socketStore.addListener('debug', ConsolePlugin.handleDebugger);
this.$pageSpyConfig = config;
this.init();
}
init() {
const that = this;
this.proxyTypes.forEach(item => {
// Not using globalThis or global, cause "console" exists in any env,
// but global may be blocked.
this.console[item] = console[item] || console.log || (() => {});
Object.defineProperty(console, item, {
value() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
that.printLog({
logType: item,
logs: args,
url: ''
});
},
configurable: true,
enumerable: true,
writable: true
});
});
}
reset() {
this.proxyTypes.forEach(item => {
console[item] = this.console[item];
});
}
onReset() {
this.reset();
ConsolePlugin.hasInitd = false;
}
// run executable code which received from remote and send back the result
static handleDebugger(_ref2, reply) {
let {
source
} = _ref2;
const {
type,
data
} = source;
if (type === 'debug') {
const originMsg = makeMessage('console', {
logType: 'debug-origin',
logs: [{
id: getRandomId(),
type: 'debug-origin',
value: data
}]
});
reply(originMsg);
try {
// eslint-disable-next-line no-new-func, @typescript-eslint/no-implied-eval
const result = new Function("return ".concat(data))();
const evalMsg = makeMessage('console', {
logType: 'debug-eval',
logs: [atom.transformToAtom(result)]
});
reply(evalMsg);
} catch (err) {
const errMsg = makeMessage('console', {
logType: 'error',
logs: [{
type: 'error',
value: err.stack
}]
});
reply(errMsg);
}
}
}
printLog(data) {
if (data.logs && data.logs.length) {
var _this$$pageSpyConfig, _this$$pageSpyConfig2;
const processor = (_this$$pageSpyConfig = this.$pageSpyConfig) === null || _this$$pageSpyConfig === void 0 || (_this$$pageSpyConfig = _this$$pageSpyConfig.dataProcessor) === null || _this$$pageSpyConfig === void 0 ? void 0 : _this$$pageSpyConfig.console;
if (processor) {
this.reset();
const processedByUser = processor(data);
this.init();
if (processedByUser === false) return;
}
this.console[data.logType](...data.logs);
const atomLog = makeMessage('console', {
...data,
time: Date.now(),
logs: data.logs.map(log => {
return atom.transformToAtom(log, false);
})
});
socketStore.broadcastMessage(atomLog);
if (!((_this$$pageSpyConfig2 = this.$pageSpyConfig) !== null && _this$$pageSpyConfig2 !== void 0 && _this$$pageSpyConfig2.serializeData)) {
socketStore.dispatchEvent('public-data', atomLog);
} else {
const serializeLog = {
...atomLog,
data: {
...atomLog.data,
logs: data.logs.map(log => {
return atom.transformToAtom(log, true);
})
}
};
socketStore.dispatchEvent('public-data', serializeLog);
}
}
}
}
_defineProperty(ConsolePlugin, "hasInitd", false);
class RequestItem {
constructor(id) {
_defineProperty(this, "id", '');
_defineProperty(this, "method", '');
_defineProperty(this, "url", '');
_defineProperty(this, "requestType", 'xhr');
_defineProperty(this, "requestHeader", null);
_defineProperty(this, "status", 0);
_defineProperty(this, "statusText", '');
_defineProperty(this, "readyState", 0);
// See: https://github.com/HuolalaTech/page-spy-web/issues/390
_defineProperty(this, "response", '__PLACEHOLDER_RESPONSE_DEFINED_BY_PAGE_SPY__');
_defineProperty(this, "responseReason", null);
// error response reason
_defineProperty(this, "responseType", '');
_defineProperty(this, "responseHeader", null);
_defineProperty(this, "startTime", 0);
_defineProperty(this, "endTime", 0);
_defineProperty(this, "costTime", 0);
/**
* @deprecated please using `requestPayload`
*/
_defineProperty(this, "postData", null);
_defineProperty(this, "requestPayload", null);
_defineProperty(this, "withCredentials", false);
// For EventSource
_defineProperty(this, "lastEventId", '');
this.id = id;
}
}
// File size is not recommended to exceed the MAX_SIZE,
// big size files would result negative performance impact distinctly in local-test.
const MAX_SIZE = 1024 * 1024 * 2;
const Reason = {
EXCEED_SIZE: 'Exceed maximum limit'
};
const PAGE_SPY_WS_ENDPOINT = '/api/v1/ws/room/join';
// Fork XMLHttpRequest status, for usage in platforms other than browser.
var ReqReadyState;
(function (ReqReadyState) {
ReqReadyState[ReqReadyState["UNSENT"] = 0] = "UNSENT";
ReqReadyState[ReqReadyState["OPENED"] = 1] = "OPENED";
ReqReadyState[ReqReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED";
ReqReadyState[ReqReadyState["LOADING"] = 3] = "LOADING";
ReqReadyState[ReqReadyState["DONE"] = 4] = "DONE";
})(ReqReadyState || (ReqReadyState = {}));
const BINARY_FILE_VARIANT = '(file)';
function formatEntries(data) {
const result = [];
let processor = data.next();
while (!processor.done) {
const [key, value] = processor.value;
let variant;
if (isFile(value)) {
variant = BINARY_FILE_VARIANT;
} else {
variant = String(value);
}
result.push([key, variant]);
processor = data.next();
}
return result;
}
class NetworkProxyBase {
constructor(socketStore) {
_defineProperty(this, "socketStore", void 0);
_defineProperty(this, "reqMap", Object.create(null));
this.socketStore = socketStore;
}
getRequestMap() {
return this.reqMap;
}
getRequest(id) {
const req = this.reqMap[id];
return req;
}
removeRequest(id) {
delete this.reqMap[id];
}
createRequest(id) {
if (!id) {
psLog.warn('The "id" is required when init request object');
return false;
}
if (this.reqMap[id]) {
psLog.warn('The request object has been in store, disallow duplicate create');
return false;
}
this.reqMap[id] = new RequestItem(id);
return true;
}
setRequest(id, req) {
if (!id || !req) return false;
this.reqMap[id] = req;
return true;
}
sendRequestItem(id, req) {
var _NetworkProxyBase$dat;
const processedByUser = (_NetworkProxyBase$dat = NetworkProxyBase.dataProcessor) === null || _NetworkProxyBase$dat === void 0 ? void 0 : _NetworkProxyBase$dat.call(NetworkProxyBase, req);
if (processedByUser === false) return;
try {
if (!this.reqMap[id]) {
this.reqMap[id] = req;
}
const message = makeMessage('network', {
...req
}, false);
this.socketStore.dispatchEvent('public-data', message);
this.socketStore.broadcastMessage(message, req.readyState !== ReqReadyState.DONE);
this.deferDeleteRequest(id);
} catch (e) {
psLog.error(e.message);
}
}
deferDeleteRequest(id) {
const req = this.getRequest(id);
if (req && req.readyState === ReqReadyState.DONE) {
setTimeout(() => {
delete this.reqMap[id];
}, 3000);
}
}
}
_defineProperty(NetworkProxyBase, "dataProcessor", void 0);
var util;
(function (util) {
util.assertEqual = val => val;
function assertIs(_arg) {}
util.assertIs = assertIs;
function assertNever(_x) {
throw new Error();
}
util.assertNever = assertNever;
util.arrayToEnum = items => {
const obj = {};
for (const item of items) {
obj[item] = item;
}
return obj;
};
util.getValidEnumValues = obj => {
const validKeys = util.objectKeys(obj).filter(k => typeof obj[obj[k]] !== "number");
const filtered = {};
for (const k of validKeys) {
filtered[k] = obj[k];
}
return util.objectValues(filtered);
};
util.objectValues = obj => {
return util.objectKeys(obj).map(function (e) {
return obj[e];
});
};
util.objectKeys = typeof Object.keys === "function" // eslint-disable-line ban/ban
? obj => Object.keys(obj) // eslint-disable-line ban/ban
: object => {
const keys = [];
for (const key in object) {
if (Object.prototype.hasOwnProperty.call(object, key)) {
keys.push(key);
}
}
return keys;
};
util.find = (arr, checker) => {
for (const item of arr) {
if (checker(item)) return item;
}
return undefined;
};
util.isInteger = typeof Number.isInteger === "function" ? val => Number.isInteger(val) // eslint-disable-line ban/ban
: val => typeof val === "number" && isFinite(val) && Math.floor(val) === val;
function joinValues(array) {
let separator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : " | ";
return array.map(val => typeof val === "string" ? "'".concat(val, "'") : val).join(separator);
}
util.joinValues = joinValues;
util.jsonStringifyReplacer = (_, value) => {
if (typeof value === "bigint") {
return value.toString();
}
return value;
};
})(util || (util = {}));
var objectUtil;
(function (objectUtil) {
objectUtil.mergeShapes = (first, second) => {
return {
...first,
...second // second overwrites first
};
};
})(objectUtil || (objectUtil = {}));
const ZodParsedType = util.arrayToEnum(["string", "nan", "number", "integer", "float", "boolean", "date", "bigint", "symbol", "function", "undefined", "null", "array", "object", "unknown", "promise", "void", "never", "map", "set"]);
const getParsedType = data => {
const t = typeof data;
switch (t) {
case "undefined":
return ZodParsedType.undefined;
case "string":
return ZodParsedType.string;
case "number":
return isNaN(data) ? ZodParsedType.nan : ZodParsedType.number;
case "boolean":
return ZodParsedType.boolean;
case "function":
return ZodParsedType.function;
case "bigint":
return ZodParsedType.bigint;
case "symbol":
return ZodParsedType.symbol;
case "object":
if (Array.isArray(data)) {
return ZodParsedType.array;
}
if (data === null) {
return ZodParsedType.null;
}
if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") {
return ZodParsedType.promise;
}
if (typeof Map !== "undefined" && data instanceof Map) {
return ZodParsedType.map;
}
if (typeof Set !== "undefined" && data instanceof Set) {
return ZodParsedType.set;
}
if (typeof Date !== "undefined" && data instanceof Date) {
return ZodParsedType.date;
}
return ZodParsedType.object;
default:
return ZodParsedType.unknown;
}
};
const ZodIssueCode = util.arrayToEnum(["invalid_type", "invalid_literal", "custom", "invalid_union", "invalid_union_discriminator", "invalid_enum_value", "unrecognized_keys", "invalid_arguments", "invalid_return_type", "invalid_date", "invalid_string", "too_small", "too_big", "invalid_intersection_types", "not_multiple_of", "not_finite"]);
const quotelessJson = obj => {
const json = JSON.stringify(obj, null, 2);
return json.replace(/"([^"]+)":/g, "$1:");
};
class ZodError extends Error {
get errors() {
return this.issues;
}
constructor(issues) {
var _this;
super();
_this = this;
this.issues = [];
this.addIssue = sub => {
this.issues = [...this.issues, sub];
};
this.addIssues = function () {
let subs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
_this.issues = [..._this.issues, ...subs];
};
const actualProto = new.target.prototype;
if (Object.setPrototypeOf) {
// eslint-disable-next-line ban/ban
Object.setPrototypeOf(this, actualProto);
} else {
this.__proto__ = actualProto;
}
this.name = "ZodError";
this.issues = issues;
}
format(_mapper) {
const mapper = _mapper || function (issue) {
return issue.message;
};
const fieldErrors = {
_errors: []
};
const processError = error => {
for (const issue of error.issues) {
if (issue.code === "invalid_union") {
issue.unionErrors.map(processError);
} else if (issue.code === "invalid_return_type") {
processError(issue.returnTypeError);
} else if (issue.code === "invalid_arguments") {
processError(issue.argumentsError);
} else if (issue.path.length === 0) {
fieldErrors._errors.push(mapper(issue));
} else {
let curr = fieldErrors;
let i = 0;
while (i < issue.path.length) {
const el = issue.path[i];
const terminal = i === issue.path.length - 1;
if (!terminal) {
curr[el] = curr[el] || {
_errors: []
};
// if (typeof el === "string") {
// curr[el] = curr[el] || { _errors: [] };
// } else if (typeof el === "number") {
// const errorArray: any = [];
// errorArray._errors = [];
// curr[el] = curr[el] || errorArray;
// }
} else {
curr[el] = curr[el] || {
_errors: []
};
curr[el]._errors.push(mapper(issue));
}
curr = curr[el];
i++;
}
}
}
};
processError(this);
return fieldErrors;
}
static assert(value) {
if (!(value instanceof ZodError)) {
throw new Error("Not a ZodError: ".concat(value));
}
}
toString() {
return this.message;
}
get message() {
return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
}
get isEmpty() {
return this.issues.length === 0;
}
flatten() {
let mapper = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : issue => issue.message;
const fieldErrors = {};
const formErrors = [];
for (const sub of this.issues) {
if (sub.path.length > 0) {
fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || [];
fieldErrors[sub.path[0]].push(mapper(sub));
} else {
formErrors.push(mapper(sub));
}
}
return {
formErrors,
fieldErrors
};
}
get formErrors() {
return this.flatten();
}
}
ZodError.create = issues => {
const error = new ZodError(issues);
return error;
};
const errorMap = (issue, _ctx) => {
let message;
switch (issue.code) {
case ZodIssueCode.invalid_type:
if (issue.received === ZodParsedType.undefined) {
message = "Required";
} else {
message = "Expected ".concat(issue.expected, ", received ").concat(issue.received);
}
break;
case ZodIssueCode.invalid_literal:
message = "Invalid literal value, expected ".concat(JSON.stringify(issue.expected, util.jsonStringifyReplacer));
break;
case ZodIssueCode.unrecognized_keys:
message = "Unrecognized key(s) in object: ".concat(util.joinValues(issue.keys, ", "));
break;
case ZodIssueCode.invalid_union:
message = "Invalid input";
break;
case ZodIssueCode.invalid_union_discriminator:
message = "Invalid discriminator value. Expected ".concat(util.joinValues(issue.options));
break;
case ZodIssueCode.invalid_enum_value:
message = "Invalid enum value. Expected ".concat(util.joinValues(issue.options), ", received '").concat(issue.received, "'");
break;
case ZodIssueCode.invalid_arguments:
message = "Invalid function arguments";
break;
case ZodIssueCode.invalid_return_type:
message = "Invalid function return type";
break;
case ZodIssueCode.invalid_date:
message = "Invalid date";
break;
case ZodIssueCode.invalid_string:
if (typeof issue.validation === "object") {
if ("includes" in issue.validation) {
message = "Invalid input: must include \"".concat(issue.validation.includes, "\"");
if (typeof issue.validation.position === "number") {
message = "".concat(message, " at one or more positions greater than or equal to ").concat(issue.validation.position);
}
} else if ("startsWith" in issue.validation) {
message = "Invalid input: must start with \"".concat(issue.validation.startsWith, "\"");
} else if ("endsWith" in issue.validation) {
message = "Invalid input: must end with \"".concat(issue.validation.endsWith, "\"");
} else {
util.assertNever(issue.validation);
}
} else if (issue.validation !== "regex") {
message = "Invalid ".concat(issue.validation);
} else {
message = "Invalid";
}
break;
case ZodIssueCode.too_small:
if (issue.type === "array") message = "Array must contain ".concat(issue.exact ? "exactly" : issue.inclusive ? "at least" : "more than", " ").concat(issue.minimum, " element(s)");else if (issue.type === "string") message = "String must contain ".concat(issue.exact ? "exactly" : issue.inclusive ? "at least" : "over", " ").concat(issue.minimum, " character(s)");else if (issue.type === "number") message = "Number must be ".concat(issue.exact ? "exactly equal to " : issue.inclusive ? "greater than or equal to " : "greater than ").concat(issue.minimum);else if (issue.type === "date") message = "Date must be ".concat(issue.exact ? "exactly equal to " : issue.inclusive ? "greater than or equal to " : "greater than ").concat(new Date(Number(issue.minimum)));else message = "Invalid input";
break;
case ZodIssueCode.too_big:
if (issue.type === "array") message = "Array must contain ".concat(issue.exact ? "exactly" : issue.inclusive ? "at most" : "less than", " ").concat(issue.maximum, " element(s)");else if (issue.type === "string") message = "String must contain ".concat(issue.exact ? "exactly" : issue.inclusive ? "at most" : "under", " ").concat(issue.maximum, " character(s)");else if (issue.type === "number") message = "Number must be ".concat(issue.exact ? "exactly" : issue.inclusive ? "less than or equal to" : "less than", " ").concat(issue.maximum);else if (issue.type === "bigint") message = "BigInt must be ".concat(issue.exact ? "exactly" : issue.inclusive ? "less than or equal to" : "less than", " ").concat(issue.maximum);else if (issue.type === "date") message = "Date must be ".concat(issue.exact ? "exactly" : issue.inclusive ? "smaller than or equal to" : "smaller than", " ").concat(new Date(Number(issue.maximum)));else message = "Invalid input";
break;
case ZodIssueCode.custom:
message = "Invalid input";
break;
case ZodIssueCode.invalid_intersection_types:
message = "Intersection results could not be merged";
break;
case ZodIssueCode.not_multiple_of:
message = "Number must be a multiple of ".concat(issue.multipleOf);
break;
case ZodIssueCode.not_finite:
message = "Number must be finite";
break;
default:
message = _ctx.defaultError;
util.assertNever(issue);
}
return {
message
};
};
let overrideErrorMap = errorMap;
function setErrorMap(map) {
overrideErrorMap = map;
}
function getErrorMap() {
return overrideErrorMap;
}
const makeIssue = params => {
const {
data,
path,
errorMaps,
issueData
} = params;
const fullPath = [...path, ...(issueData.path || [])];
const fullIssue = {
...issueData,
path: fullPath
};
if (issueData.message !== undefined) {
return {
...issueData,
path: fullPath,
message: issueData.message
};
}
let errorMessage = "";
const maps = errorMaps.filter(m => !!m).slice().reverse();
for (const map of maps) {
errorMessage = map(fullIssue, {
data,
defaultError: errorMessage
}).message;
}
return {
...issueData,
path: fullPath,
message: errorMessage
};
};
const EMPTY_PATH = [];
func