UNPKG

@lastos/page-spy-react-native

Version:

An SDK of PageSpy for debugging react native app

1,644 lines (1,625 loc) 210 kB
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