UNPKG

@xysfe/memento-core

Version:

record and replay the web

346 lines (343 loc) 15.2 kB
import { __assign, __values, __read } from '../../node_modules/tslib/tslib.es6.js'; import { snapshot } from '../../node_modules/@xysfe/memento-snapshot/es/memento-snapshot.js'; import initObservers, { initOtherObserver } from './observer.js'; import XFix, { CHANGE_STATE_EVENT } from './xfix.js'; import { polyfill, mirror, on, getWindowWidth, getWindowHeight } from '../utils.js'; import { EventType, OtherSource, IncrementalSource } from '../types.js'; import { CanvasManager } from './observers/canvas/canvas-manager.js'; function wrapEvent(e) { return __assign(__assign({}, e), { timestamp: e.timestamp || Date.now() }); } function disposeMousemovePosition(positions, ignoreMousemove) { if (!ignoreMousemove) { return positions; } return positions.map(function (item) { return __assign(__assign({}, item), { x: -40, y: -40 }); }); } function disposeMouseInteraction(d, ignoreMousemove) { if (ignoreMousemove) { d.x = -40; d.y = -40; } return { type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.MouseInteraction }, d) }; } var wrappedEmit; function takeFullSnapshot(options, isCheckout, tag) { var _a, _b, _c, _d; if (options === void 0) { options = {}; } if (isCheckout === void 0) { isCheckout = false; } var emit = options.emit, _e = options.blockClass, blockClass = _e === void 0 ? 'mem-block' : _e; options.ignoreClass; var _g = options.inlineStylesheet, inlineStylesheet = _g === void 0 ? true : _g, _h = options.maskAllInputs, maskAllInputs = _h === void 0 ? false : _h, _j = options.blockElements, blockElements = _j === void 0 ? [] : _j, _k = options.recordCanvas, recordCanvas = _k === void 0 ? false : _k; options.ignoreMousemove; if (!wrappedEmit) { throw new Error('please take full snapshot after start recording'); } wrappedEmit(wrapEvent({ type: EventType.Meta, data: { href: window.location.href, width: getWindowWidth(), height: getWindowHeight(), ratio: window.devicePixelRatio || 1, }, }), isCheckout); var _m = __read(snapshot(document, blockClass, inlineStylesheet, maskAllInputs, blockElements, recordCanvas), 2), node = _m[0], idNodeMap = _m[1]; if (!node) { return console.warn('Failed to snapshot the document'); } mirror.map = idNodeMap; var data = { type: EventType.FullSnapshot, data: { href: window.location.href, width: getWindowWidth(), height: getWindowHeight(), ratio: window.devicePixelRatio || 1, node: node, initialOffset: { left: window.pageXOffset !== undefined ? window.pageXOffset : (document === null || document === void 0 ? void 0 : document.documentElement.scrollLeft) || ((_b = (_a = document === null || document === void 0 ? void 0 : document.body) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.scrollLeft) || (document === null || document === void 0 ? void 0 : document.body.scrollLeft) || 0, top: window.pageYOffset !== undefined ? window.pageYOffset : (document === null || document === void 0 ? void 0 : document.documentElement.scrollTop) || ((_d = (_c = document === null || document === void 0 ? void 0 : document.body) === null || _c === void 0 ? void 0 : _c.parentElement) === null || _d === void 0 ? void 0 : _d.scrollTop) || (document === null || document === void 0 ? void 0 : document.body.scrollTop) || 0, }, }, }; if (tag) { data.tag = tag; } var event = wrapEvent(data); wrappedEmit(event); if (emit) { emit(event, isCheckout); } } function record(options) { if (options === void 0) { options = {}; } var emit = options.emit, checkoutEveryNms = options.checkoutEveryNms, checkoutEveryNth = options.checkoutEveryNth, _a = options.blockClass, blockClass = _a === void 0 ? 'mem-block' : _a, _b = options.ignoreClass, ignoreClass = _b === void 0 ? 'mem-ignore' : _b, asyncClass = options.asyncClass, _c = options.blockElements, blockElements = _c === void 0 ? [] : _c, _d = options.inlineStylesheet, inlineStylesheet = _d === void 0 ? true : _d, maskAllInputs = options.maskAllInputs, _maskInputOptions = options.maskInputOptions, hooks = options.hooks, packFn = options.packFn, _e = options.sampling, sampling = _e === void 0 ? {} : _e, mousemoveWait = options.mousemoveWait, _f = options.recordCanvas, recordCanvas = _f === void 0 ? false : _f, _g = options.ignoreMousemove, ignoreMousemove = _g === void 0 ? false : _g, _h = options.onlyRecordFullSnapshot, onlyRecordFullSnapshot = _h === void 0 ? false : _h; if (!emit) { throw new Error('emit function is required'); } if (mousemoveWait !== undefined && sampling.mousemove === undefined) { sampling.mousemove = mousemoveWait; } var maskInputOptions = maskAllInputs === true ? { color: true, date: true, 'datetime-local': true, email: true, month: true, number: true, range: true, search: true, tel: true, text: true, time: true, url: true, week: true, textarea: true, select: true, } : _maskInputOptions !== undefined ? _maskInputOptions : {}; polyfill(); var lastFullSnapshotEvent; var incrementalSnapshotCount = 0; var opt = __assign(__assign({}, options), { emit: function () { } }); wrappedEmit = function (e, isCheckout) { emit((packFn ? packFn(e) : e), isCheckout); if (e.type === EventType.FullSnapshot) { lastFullSnapshotEvent = e; incrementalSnapshotCount = 0; } else if (e.type === EventType.IncrementalSnapshot) { incrementalSnapshotCount++; var exceedCount = checkoutEveryNth && incrementalSnapshotCount >= checkoutEveryNth; var exceedTime = checkoutEveryNms && e.timestamp - lastFullSnapshotEvent.timestamp > checkoutEveryNms; if (exceedCount || exceedTime) { takeFullSnapshot(opt, true); } } }; var wrappedCanvasMutationEmit = function (p) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.CanvasMutation }, p), })); }; var canvasManager = new CanvasManager({ recordCanvas: recordCanvas, mutationCb: wrappedCanvasMutationEmit, win: window, blockClass: blockClass, mirror: mirror, sampling: sampling.canvas, }); try { XFix.getInstance(); var handlers_1 = []; var url_1 = window.location.href; var pageChange_1 = function (force) { if (force || url_1 !== window.location.href) { url_1 = window.location.href; wrappedEmit(wrapEvent({ type: EventType.PageChange, data: { url: url_1, }, })); } }; var checkPageChange = function () { pageChange_1(false); }; if (!onlyRecordFullSnapshot) { handlers_1.push(on(CHANGE_STATE_EVENT, checkPageChange, window)); handlers_1.push(on('hashchange', checkPageChange, window)); handlers_1.push(on('popstate', checkPageChange, window)); handlers_1.push(on('pageshow', function (event) { if (event.persisted) { pageChange_1(true); } }, window)); } var delayEvents_1 = []; var hasInited_1 = false; if (!onlyRecordFullSnapshot) { handlers_1.push(initOtherObserver({ consoleCb: function (c) { var eventData = { type: EventType.Other, data: { source: OtherSource.Console, sourceData: c, }, }; if (hasInited_1) { wrappedEmit(wrapEvent(eventData)); } else { delayEvents_1.push(eventData); } }, networkCb: function (n) { var eventData = { type: EventType.Other, data: { source: OtherSource.Network, sourceData: n, }, }; if (hasInited_1) { wrappedEmit(wrapEvent(eventData)); } else { delayEvents_1.push(eventData); } }, }, hooks)); } handlers_1.push(on('DOMContentLoaded', function () { wrappedEmit(wrapEvent({ type: EventType.DomContentLoaded, data: {}, })); })); var init_1 = function () { var e_1, _a; takeFullSnapshot(opt); try { for (var delayEvents_2 = __values(delayEvents_1), delayEvents_2_1 = delayEvents_2.next(); !delayEvents_2_1.done; delayEvents_2_1 = delayEvents_2.next()) { var eventData = delayEvents_2_1.value; wrappedEmit(wrapEvent(eventData)); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (delayEvents_2_1 && !delayEvents_2_1.done && (_a = delayEvents_2.return)) _a.call(delayEvents_2); } finally { if (e_1) throw e_1.error; } } hasInited_1 = true; delayEvents_1 = []; if (!onlyRecordFullSnapshot) { handlers_1.push(initObservers({ mutationCb: function (m) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.Mutation }, m), })); }, mousemoveCb: function (positions, source) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: { source: source, positions: disposeMousemovePosition(positions, ignoreMousemove), }, })); }, mouseInteractionCb: function (d) { return wrappedEmit(wrapEvent(disposeMouseInteraction(d, ignoreMousemove))); }, scrollCb: function (p) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.Scroll }, p), })); }, viewportResizeCb: function (d) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.ViewportResize }, d), })); }, inputCb: function (v) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.Input }, v), })); }, mediaInteractionCb: function (p) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.MediaInteraction }, p), })); }, canvasMutationCb: wrappedCanvasMutationEmit, styleSheetRuleCb: function (r) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.StyleSheetRule }, r), })); }, userDefinedEventCb: function (p) { return wrappedEmit(wrapEvent({ type: EventType.IncrementalSnapshot, data: __assign({ source: IncrementalSource.UserDefinedEvent }, p), })); }, blockClass: blockClass, blockElements: blockElements, ignoreClass: ignoreClass, asyncClass: asyncClass, maskInputOptions: maskInputOptions, inlineStylesheet: inlineStylesheet, sampling: sampling, recordCanvas: recordCanvas, canvasManager: canvasManager }, hooks)); } }; if (document.readyState === 'interactive' || document.readyState === 'complete') { init_1(); } else { handlers_1.push(on('load', function () { wrappedEmit(wrapEvent({ type: EventType.Load, data: {}, })); init_1(); }, window)); } return function () { handlers_1.forEach(function (h) { return h(); }); }; } catch (error) { console.warn(error); } } record.addCustomEvent = function (tag, payload) { if (!wrappedEmit) { throw new Error('please add custom event after start recording'); } wrappedEmit(wrapEvent({ type: EventType.Custom, data: { tag: tag, payload: payload, }, })); }; record.takeFullSnapshot = function (options, tag) { if (options === void 0) { options = {}; } if (!wrappedEmit) { return; } takeFullSnapshot(options, false, tag); }; export { record as default };