@xysfe/memento-core
Version:
record and replay the web
346 lines (343 loc) • 15.2 kB
JavaScript
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 };