global string dictionary support (#2652)

* making new msg type, support on frontend and tracker

* finish adding support for new dictionary for ui

* update branch
This commit is contained in:
Delirium 2024-10-30 15:31:26 +01:00 committed by GitHub
parent 6b9bbf570a
commit fdefe31cf3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 940 additions and 502 deletions

View file

@ -10,5 +10,5 @@ func IsMobileType(id int) bool {
}
func IsDOMType(id int) bool {
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id
}

View file

@ -2,119 +2,121 @@
package messages
const (
MsgTimestamp = 0
MsgSessionStart = 1
MsgSessionEndDeprecated = 3
MsgSetPageLocationDeprecated = 4
MsgSetViewportSize = 5
MsgSetViewportScroll = 6
MsgCreateDocument = 7
MsgCreateElementNode = 8
MsgCreateTextNode = 9
MsgMoveNode = 10
MsgRemoveNode = 11
MsgSetNodeAttribute = 12
MsgRemoveNodeAttribute = 13
MsgSetNodeData = 14
MsgSetCSSData = 15
MsgSetNodeScroll = 16
MsgSetInputTarget = 17
MsgSetInputValue = 18
MsgSetInputChecked = 19
MsgMouseMove = 20
MsgNetworkRequestDeprecated = 21
MsgConsoleLog = 22
MsgPageLoadTiming = 23
MsgPageRenderTiming = 24
MsgJSExceptionDeprecated = 25
MsgIntegrationEvent = 26
MsgCustomEvent = 27
MsgUserID = 28
MsgUserAnonymousID = 29
MsgMetadata = 30
MsgPageEventDeprecated = 31
MsgInputEvent = 32
MsgPageEvent = 33
MsgCSSInsertRule = 37
MsgCSSDeleteRule = 38
MsgFetch = 39
MsgProfiler = 40
MsgOTable = 41
MsgStateAction = 42
MsgReduxDeprecated = 44
MsgVuex = 45
MsgMobX = 46
MsgNgRx = 47
MsgGraphQLDeprecated = 48
MsgPerformanceTrack = 49
MsgStringDict = 50
MsgSetNodeAttributeDict = 51
MsgResourceTimingDeprecated = 53
MsgConnectionInformation = 54
MsgSetPageVisibility = 55
MsgPerformanceTrackAggr = 56
MsgLoadFontFace = 57
MsgSetNodeFocus = 58
MsgLongTask = 59
MsgSetNodeAttributeURLBased = 60
MsgSetCSSDataURLBased = 61
MsgIssueEventDeprecated = 62
MsgTechnicalInfo = 63
MsgCustomIssue = 64
MsgAssetCache = 66
MsgCSSInsertRuleURLBased = 67
MsgMouseClick = 68
MsgMouseClickDeprecated = 69
MsgCreateIFrameDocument = 70
MsgAdoptedSSReplaceURLBased = 71
MsgAdoptedSSReplace = 72
MsgAdoptedSSInsertRuleURLBased = 73
MsgAdoptedSSInsertRule = 74
MsgAdoptedSSDeleteRule = 75
MsgAdoptedSSAddOwner = 76
MsgAdoptedSSRemoveOwner = 77
MsgJSException = 78
MsgZustand = 79
MsgBatchMeta = 80
MsgBatchMetadata = 81
MsgPartitionedMessage = 82
MsgNetworkRequest = 83
MsgWSChannel = 84
MsgInputChange = 112
MsgSelectionChange = 113
MsgMouseThrashing = 114
MsgUnbindNodes = 115
MsgResourceTiming = 116
MsgTabChange = 117
MsgTabData = 118
MsgCanvasNode = 119
MsgTagTrigger = 120
MsgRedux = 121
MsgSetPageLocation = 122
MsgGraphQL = 123
MsgWebVitals = 124
MsgIssueEvent = 125
MsgSessionEnd = 126
MsgSessionSearch = 127
MsgMobileSessionStart = 90
MsgMobileSessionEnd = 91
MsgMobileMetadata = 92
MsgMobileEvent = 93
MsgMobileUserID = 94
MsgMobileUserAnonymousID = 95
MsgMobileScreenChanges = 96
MsgMobileCrash = 97
MsgMobileViewComponentEvent = 98
MsgMobileClickEvent = 100
MsgMobileInputEvent = 101
MsgMobilePerformanceEvent = 102
MsgMobileLog = 103
MsgMobileInternalError = 104
MsgMobileNetworkCall = 105
MsgMobileSwipeEvent = 106
MsgMobileBatchMeta = 107
MsgMobilePerformanceAggregated = 110
MsgMobileIssueEvent = 111
MsgTimestamp = 0
MsgSessionStart = 1
MsgSessionEndDeprecated = 3
MsgSetPageLocationDeprecated = 4
MsgSetViewportSize = 5
MsgSetViewportScroll = 6
MsgCreateDocument = 7
MsgCreateElementNode = 8
MsgCreateTextNode = 9
MsgMoveNode = 10
MsgRemoveNode = 11
MsgSetNodeAttribute = 12
MsgRemoveNodeAttribute = 13
MsgSetNodeData = 14
MsgSetCSSData = 15
MsgSetNodeScroll = 16
MsgSetInputTarget = 17
MsgSetInputValue = 18
MsgSetInputChecked = 19
MsgMouseMove = 20
MsgNetworkRequestDeprecated = 21
MsgConsoleLog = 22
MsgPageLoadTiming = 23
MsgPageRenderTiming = 24
MsgJSExceptionDeprecated = 25
MsgIntegrationEvent = 26
MsgCustomEvent = 27
MsgUserID = 28
MsgUserAnonymousID = 29
MsgMetadata = 30
MsgPageEventDeprecated = 31
MsgInputEvent = 32
MsgPageEvent = 33
MsgCSSInsertRule = 37
MsgCSSDeleteRule = 38
MsgFetch = 39
MsgProfiler = 40
MsgOTable = 41
MsgStateAction = 42
MsgReduxDeprecated = 44
MsgVuex = 45
MsgMobX = 46
MsgNgRx = 47
MsgGraphQLDeprecated = 48
MsgPerformanceTrack = 49
MsgStringDictDeprecated = 50
MsgSetNodeAttributeDictDeprecated = 51
MsgStringDict = 43
MsgSetNodeAttributeDict = 52
MsgResourceTimingDeprecated = 53
MsgConnectionInformation = 54
MsgSetPageVisibility = 55
MsgPerformanceTrackAggr = 56
MsgLoadFontFace = 57
MsgSetNodeFocus = 58
MsgLongTask = 59
MsgSetNodeAttributeURLBased = 60
MsgSetCSSDataURLBased = 61
MsgIssueEventDeprecated = 62
MsgTechnicalInfo = 63
MsgCustomIssue = 64
MsgAssetCache = 66
MsgCSSInsertRuleURLBased = 67
MsgMouseClick = 68
MsgMouseClickDeprecated = 69
MsgCreateIFrameDocument = 70
MsgAdoptedSSReplaceURLBased = 71
MsgAdoptedSSReplace = 72
MsgAdoptedSSInsertRuleURLBased = 73
MsgAdoptedSSInsertRule = 74
MsgAdoptedSSDeleteRule = 75
MsgAdoptedSSAddOwner = 76
MsgAdoptedSSRemoveOwner = 77
MsgJSException = 78
MsgZustand = 79
MsgBatchMeta = 80
MsgBatchMetadata = 81
MsgPartitionedMessage = 82
MsgNetworkRequest = 83
MsgWSChannel = 84
MsgInputChange = 112
MsgSelectionChange = 113
MsgMouseThrashing = 114
MsgUnbindNodes = 115
MsgResourceTiming = 116
MsgTabChange = 117
MsgTabData = 118
MsgCanvasNode = 119
MsgTagTrigger = 120
MsgRedux = 121
MsgSetPageLocation = 122
MsgGraphQL = 123
MsgWebVitals = 124
MsgIssueEvent = 125
MsgSessionEnd = 126
MsgSessionSearch = 127
MsgMobileSessionStart = 90
MsgMobileSessionEnd = 91
MsgMobileMetadata = 92
MsgMobileEvent = 93
MsgMobileUserID = 94
MsgMobileUserAnonymousID = 95
MsgMobileScreenChanges = 96
MsgMobileCrash = 97
MsgMobileViewComponentEvent = 98
MsgMobileClickEvent = 100
MsgMobileInputEvent = 101
MsgMobilePerformanceEvent = 102
MsgMobileLog = 103
MsgMobileInternalError = 104
MsgMobileNetworkCall = 105
MsgMobileSwipeEvent = 106
MsgMobileBatchMeta = 107
MsgMobilePerformanceAggregated = 110
MsgMobileIssueEvent = 111
)
type Timestamp struct {
@ -1317,13 +1319,13 @@ func (msg *PerformanceTrack) TypeID() int {
return 49
}
type StringDict struct {
type StringDictDeprecated struct {
message
Key uint64
Value string
}
func (msg *StringDict) Encode() []byte {
func (msg *StringDictDeprecated) Encode() []byte {
buf := make([]byte, 21+len(msg.Value))
buf[0] = 50
p := 1
@ -1332,22 +1334,22 @@ func (msg *StringDict) Encode() []byte {
return buf[:p]
}
func (msg *StringDict) Decode() Message {
func (msg *StringDictDeprecated) Decode() Message {
return msg
}
func (msg *StringDict) TypeID() int {
func (msg *StringDictDeprecated) TypeID() int {
return 50
}
type SetNodeAttributeDict struct {
type SetNodeAttributeDictDeprecated struct {
message
ID uint64
NameKey uint64
ValueKey uint64
}
func (msg *SetNodeAttributeDict) Encode() []byte {
func (msg *SetNodeAttributeDictDeprecated) Encode() []byte {
buf := make([]byte, 31)
buf[0] = 51
p := 1
@ -1357,12 +1359,60 @@ func (msg *SetNodeAttributeDict) Encode() []byte {
return buf[:p]
}
func (msg *SetNodeAttributeDictDeprecated) Decode() Message {
return msg
}
func (msg *SetNodeAttributeDictDeprecated) TypeID() int {
return 51
}
type StringDict struct {
message
Key string
Value string
}
func (msg *StringDict) Encode() []byte {
buf := make([]byte, 21+len(msg.Key)+len(msg.Value))
buf[0] = 43
p := 1
p = WriteString(msg.Key, buf, p)
p = WriteString(msg.Value, buf, p)
return buf[:p]
}
func (msg *StringDict) Decode() Message {
return msg
}
func (msg *StringDict) TypeID() int {
return 43
}
type SetNodeAttributeDict struct {
message
ID uint64
Name string
Value string
}
func (msg *SetNodeAttributeDict) Encode() []byte {
buf := make([]byte, 31+len(msg.Name)+len(msg.Value))
buf[0] = 52
p := 1
p = WriteUint(msg.ID, buf, p)
p = WriteString(msg.Name, buf, p)
p = WriteString(msg.Value, buf, p)
return buf[:p]
}
func (msg *SetNodeAttributeDict) Decode() Message {
return msg
}
func (msg *SetNodeAttributeDict) TypeID() int {
return 51
return 52
}
type ResourceTimingDeprecated struct {

View file

@ -792,10 +792,37 @@ func DecodePerformanceTrack(reader BytesReader) (Message, error) {
return msg, err
}
func DecodeStringDictDeprecated(reader BytesReader) (Message, error) {
var err error = nil
msg := &StringDictDeprecated{}
if msg.Key, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.Value, err = reader.ReadString(); err != nil {
return nil, err
}
return msg, err
}
func DecodeSetNodeAttributeDictDeprecated(reader BytesReader) (Message, error) {
var err error = nil
msg := &SetNodeAttributeDictDeprecated{}
if msg.ID, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.NameKey, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.ValueKey, err = reader.ReadUint(); err != nil {
return nil, err
}
return msg, err
}
func DecodeStringDict(reader BytesReader) (Message, error) {
var err error = nil
msg := &StringDict{}
if msg.Key, err = reader.ReadUint(); err != nil {
if msg.Key, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.Value, err = reader.ReadString(); err != nil {
@ -810,10 +837,10 @@ func DecodeSetNodeAttributeDict(reader BytesReader) (Message, error) {
if msg.ID, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.NameKey, err = reader.ReadUint(); err != nil {
if msg.Name, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.ValueKey, err = reader.ReadUint(); err != nil {
if msg.Value, err = reader.ReadString(); err != nil {
return nil, err
}
return msg, err
@ -2121,8 +2148,12 @@ func ReadMessage(t uint64, reader BytesReader) (Message, error) {
case 49:
return DecodePerformanceTrack(reader)
case 50:
return DecodeStringDict(reader)
return DecodeStringDictDeprecated(reader)
case 51:
return DecodeSetNodeAttributeDictDeprecated(reader)
case 43:
return DecodeStringDict(reader)
case 52:
return DecodeSetNodeAttributeDict(reader)
case 53:
return DecodeResourceTimingDeprecated(reader)

View file

@ -449,7 +449,7 @@ class PerformanceTrack(Message):
self.used_js_heap_size = used_js_heap_size
class StringDict(Message):
class StringDictDeprecated(Message):
__id__ = 50
def __init__(self, key, value):
@ -457,7 +457,7 @@ class StringDict(Message):
self.value = value
class SetNodeAttributeDict(Message):
class SetNodeAttributeDictDeprecated(Message):
__id__ = 51
def __init__(self, id, name_key, value_key):
@ -466,6 +466,23 @@ class SetNodeAttributeDict(Message):
self.value_key = value_key
class StringDict(Message):
__id__ = 43
def __init__(self, key, value):
self.key = key
self.value = value
class SetNodeAttributeDict(Message):
__id__ = 52
def __init__(self, id, name, value):
self.id = id
self.name = name
self.value = value
class ResourceTimingDeprecated(Message):
__id__ = 53

View file

@ -671,7 +671,7 @@ cdef class PerformanceTrack(PyMessage):
self.used_js_heap_size = used_js_heap_size
cdef class StringDict(PyMessage):
cdef class StringDictDeprecated(PyMessage):
cdef public int __id__
cdef public unsigned long key
cdef public str value
@ -682,7 +682,7 @@ cdef class StringDict(PyMessage):
self.value = value
cdef class SetNodeAttributeDict(PyMessage):
cdef class SetNodeAttributeDictDeprecated(PyMessage):
cdef public int __id__
cdef public unsigned long id
cdef public unsigned long name_key
@ -695,6 +695,30 @@ cdef class SetNodeAttributeDict(PyMessage):
self.value_key = value_key
cdef class StringDict(PyMessage):
cdef public int __id__
cdef public str key
cdef public str value
def __init__(self, str key, str value):
self.__id__ = 43
self.key = key
self.value = value
cdef class SetNodeAttributeDict(PyMessage):
cdef public int __id__
cdef public unsigned long id
cdef public str name
cdef public str value
def __init__(self, unsigned long id, str name, str value):
self.__id__ = 52
self.id = id
self.name = name
self.value = value
cdef class ResourceTimingDeprecated(PyMessage):
cdef public int __id__
cdef public unsigned long timestamp

View file

@ -447,18 +447,31 @@ class MessageCodec(Codec):
)
if message_id == 50:
return StringDict(
return StringDictDeprecated(
key=self.read_uint(reader),
value=self.read_string(reader)
)
if message_id == 51:
return SetNodeAttributeDict(
return SetNodeAttributeDictDeprecated(
id=self.read_uint(reader),
name_key=self.read_uint(reader),
value_key=self.read_uint(reader)
)
if message_id == 43:
return StringDict(
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 52:
return SetNodeAttributeDict(
id=self.read_uint(reader),
name=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 53:
return ResourceTimingDeprecated(
timestamp=self.read_uint(reader),

View file

@ -545,18 +545,31 @@ cdef class MessageCodec:
)
if message_id == 50:
return StringDict(
return StringDictDeprecated(
key=self.read_uint(reader),
value=self.read_string(reader)
)
if message_id == 51:
return SetNodeAttributeDict(
return SetNodeAttributeDictDeprecated(
id=self.read_uint(reader),
name_key=self.read_uint(reader),
value_key=self.read_uint(reader)
)
if message_id == 43:
return StringDict(
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 52:
return SetNodeAttributeDict(
id=self.read_uint(reader),
name=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 53:
return ResourceTimingDeprecated(
timestamp=self.read_uint(reader),

View file

@ -7,7 +7,7 @@ export default class ListWalker<T extends Timed> {
append(m: T): void {
if (this.length > 0 && this.last && m.time < this.last.time) {
console.error("Trying to append message with the less time then the list tail:", m.time, 'vs', this.last.time, m, this)
console.error("Trying to append message with the less time then the list tail:", m.time, 'vs', this.last.time, m, this.last, this)
return
}
this.list.push(m);

View file

@ -77,6 +77,7 @@ export default class MessageLoader {
let artificialStartTime = Infinity;
let startTimeSet = false;
msgs.forEach((msg) => {
if (msg.tp === MType.Redux || msg.tp === MType.ReduxDeprecated) {
if ('actionTime' in msg && msg.actionTime) {

View file

@ -19,9 +19,10 @@ import {
} from './VirtualDOM';
import { deleteRule, insertRule } from './safeCSSRules';
function isStyleVElement(vElem: VElement): vElem is VElement & { node: StyleElement } {
return vElem.tagName.toLowerCase() === "style"
function isStyleVElement(
vElem: VElement
): vElem is VElement & { node: StyleElement } {
return vElem.tagName.toLowerCase() === 'style';
}
function setupWindowLogging(vTexts: Map<number, VText>, vElements: Map<number, VElement>, olVRoots: Map<number, OnloadVRoot>) {
@ -33,38 +34,50 @@ function setupWindowLogging(vTexts: Map<number, VText>, vElements: Map<number, V
window.checkVRoots = () => olVRoots
}
const IGNORED_ATTRS = [ "autocomplete" ]
const ATTR_NAME_REGEXP = /([^\t\n\f \/>"'=]+)/
const IGNORED_ATTRS = ['autocomplete'];
const ATTR_NAME_REGEXP = /([^\t\n\f \/>"'=]+)/;
export default class DOMManager extends ListWalker<Message> {
private readonly vTexts: Map<number, VText> = new Map() // map vs object here?
private readonly vElements: Map<number, VElement> = new Map()
private readonly olVRoots: Map<number, OnloadVRoot> = new Map()
private readonly vTexts: Map<number, VText> = new Map(); // map vs object here?
private readonly vElements: Map<number, VElement> = new Map();
private readonly olVRoots: Map<number, OnloadVRoot> = new Map();
/** required to keep track of iframes, frameId : vnodeId */
private readonly iframeRoots: Record<number, number> = {}
private readonly iframeRoots: Record<number, number> = {};
/** Constructed StyleSheets https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets
* as well as <style> tag owned StyleSheets
*/
private olStyleSheets: Map<number, OnloadStyleSheet> = new Map()
private olStyleSheets: Map<number, OnloadStyleSheet> = new Map();
/** @depreacted since tracker 4.0.2 Mapping by nodeID */
private olStyleSheetsDeprecated: Map<number, OnloadStyleSheet> = new Map()
private olStyleSheetsDeprecated: Map<number, OnloadStyleSheet> = new Map();
private upperBodyId: number = -1;
private nodeScrollManagers: Map<number, ListWalker<SetNodeScroll>> = new Map()
private stylesManager: StylesManager
private focusManager: FocusManager = new FocusManager(this.vElements)
private selectionManager: SelectionManager
private nodeScrollManagers: Map<number, ListWalker<SetNodeScroll>> =
new Map();
private stylesManager: StylesManager;
private focusManager: FocusManager = new FocusManager(this.vElements);
private selectionManager: SelectionManager;
private readonly screen: Screen;
private readonly isMobile: boolean;
private readonly stringDict: Record<number, string>;
private readonly globalDict: { get: (key: string) => string | undefined, all: () => Record<string, string> };
public readonly time: number;
constructor(
private readonly screen: Screen,
private readonly isMobile: boolean,
private stringDict: Record<number,string>,
public readonly time: number,
setCssLoading: ConstructorParameters<typeof StylesManager>[1],
) {
super()
this.selectionManager = new SelectionManager(this.vElements, screen)
this.stylesManager = new StylesManager(screen, setCssLoading)
constructor(params: {
screen: Screen;
isMobile: boolean;
setCssLoading: ConstructorParameters<typeof StylesManager>[1];
time: number;
stringDict: Record<number, string>;
globalDict: { get: (key: string) => string | undefined, all: () => Record<string, string> };
}) {
super();
this.screen = params.screen;
this.isMobile = params.isMobile;
this.time = params.time;
this.stringDict = params.stringDict;
this.globalDict = params.globalDict;
this.selectionManager = new SelectionManager(this.vElements, params.screen);
this.stylesManager = new StylesManager(params.screen, params.setCssLoading);
setupWindowLogging(
this.vTexts,
this.vElements,
@ -72,127 +85,143 @@ export default class DOMManager extends ListWalker<Message> {
)
}
setStringDict(stringDict: Record<number,string>) {
this.stringDict = stringDict
}
public clearSelectionManager() {
this.selectionManager.clearSelection()
this.selectionManager.clearSelection();
}
append(m: Message): void {
if (m.tp === MType.SetNodeScroll) {
let scrollManager = this.nodeScrollManagers.get(m.id)
let scrollManager = this.nodeScrollManagers.get(m.id);
if (!scrollManager) {
scrollManager = new ListWalker()
this.nodeScrollManagers.set(m.id, scrollManager)
scrollManager = new ListWalker();
this.nodeScrollManagers.set(m.id, scrollManager);
}
scrollManager.append(m)
return
scrollManager.append(m);
return;
}
if (m.tp === MType.SetNodeFocus) {
this.focusManager.append(m)
return
this.focusManager.append(m);
return;
}
if (m.tp === MType.SelectionChange) {
this.selectionManager.append(m)
return
this.selectionManager.append(m);
return;
}
if (m.tp === MType.CreateElementNode) {
if(m.tag === "BODY" && this.upperBodyId === -1) {
this.upperBodyId = m.id
if (m.tag === 'BODY' && this.upperBodyId === -1) {
this.upperBodyId = m.id;
}
} else if (m.tp === MType.SetNodeAttribute &&
(IGNORED_ATTRS.includes(m.name) || !ATTR_NAME_REGEXP.test(m.name))) {
logger.log("Ignorring message: ", m)
} else if (
m.tp === MType.SetNodeAttribute &&
(IGNORED_ATTRS.includes(m.name) || !ATTR_NAME_REGEXP.test(m.name))
) {
logger.log('Ignorring message: ', m);
return; // Ignoring
}
super.append(m)
super.append(m);
}
private removeBodyScroll(id: number, vElem: VElement): void {
if (this.isMobile && this.upperBodyId === id) { // Need more type safety!
(vElem.node as HTMLBodyElement).style.overflow = "hidden"
if (this.isMobile && this.upperBodyId === id) {
// Need more type safety!
(vElem.node as HTMLBodyElement).style.overflow = 'hidden';
}
}
private removeAutocomplete(vElem: VElement): boolean {
const tag = vElem.tagName
if ([ "FORM", "TEXTAREA", "SELECT" ].includes(tag)) {
vElem.setAttribute("autocomplete", "off");
const tag = vElem.tagName;
if (['FORM', 'TEXTAREA', 'SELECT'].includes(tag)) {
vElem.setAttribute('autocomplete', 'off');
return true;
}
if (tag === "INPUT") {
vElem.setAttribute("autocomplete", "new-password");
if (tag === 'INPUT') {
vElem.setAttribute('autocomplete', 'new-password');
return true;
}
return false;
}
public getNode(id: number) {
return this.vElements.get(id) || this.vTexts.get(id)
return this.vElements.get(id) || this.vTexts.get(id);
}
private insertNode(msg: { parentID: number, id: number, index: number }): void {
const { parentID, id, index } = msg
const child = this.vElements.get(id) || this.vTexts.get(id)
private insertNode(msg: {
parentID: number;
id: number;
index: number;
}): void {
const { parentID, id, index } = msg;
const child = this.vElements.get(id) || this.vTexts.get(id);
if (!child) {
logger.error("Insert error. Node not found", id);
logger.error('Insert error. Node not found', id);
return;
}
const parent = this.vElements.get(parentID) || this.olVRoots.get(parentID)
const parent = this.vElements.get(parentID) || this.olVRoots.get(parentID);
if (!parent) {
logger.error(`${id} Insert error. Parent vNode ${parentID} not found`, msg, this.vElements, this.olVRoots);
logger.error(
`${id} Insert error. Parent vNode ${parentID} not found`,
msg,
this.vElements,
this.olVRoots
);
return;
}
if (parent instanceof VElement && isStyleVElement(parent)) {
// TODO: if this ever happens? ; Maybe do not send empty TextNodes in tracker
const styleNode = parent.node
if (styleNode.sheet &&
const styleNode = parent.node;
if (
styleNode.sheet &&
styleNode.sheet.cssRules &&
styleNode.sheet.cssRules.length > 0 &&
styleNode.textContent &&
styleNode.textContent.trim().length === 0
) {
logger.log("Trying to insert child to a style tag with virtual rules: ", parent, child);
logger.log(
'Trying to insert child to a style tag with virtual rules: ',
parent,
child
);
return;
}
}
parent.insertChildAt(child, index)
parent.insertChildAt(child, index);
}
private setNodeAttribute(msg: { id: number, name: string, value: string }) {
private setNodeAttribute(msg: { id: number; name: string; value: string }) {
let { name, value } = msg;
const vn = this.vElements.get(msg.id)
if (!vn) { logger.error("SetNodeAttribute: Node not found", msg); return }
if (vn.tagName === "INPUT" && name === "name") {
// Otherwise binds local autocomplete values (maybe should ignore on the tracker level?)
return
const vn = this.vElements.get(msg.id);
if (!vn) {
logger.error('SetNodeAttribute: Node not found', msg);
return;
}
if (name === "href" && vn.tagName === "LINK") {
if (vn.tagName === 'INPUT' && name === 'name') {
// Otherwise binds local autocomplete values (maybe should ignore on the tracker level?)
return;
}
if (name === 'href' && vn.tagName === 'LINK') {
// @ts-ignore ?global ENV type // It've been done on backend (remove after testing in saas)
// if (value.startsWith(window.env.ASSETS_HOST || window.location.origin + '/assets')) {
// value = value.replace("?", "%3F");
// }
if (!value.startsWith("http")) {
if (!value.startsWith('http')) {
/* blob:... value can happen here for some reason.
* which will result in that link being unable to load and having 4sec timeout in the below function.
*/
return
return;
}
// TODOTODO: check if node actually exists on the page, not just in memory
this.stylesManager.setStyleHandlers(vn.node as HTMLLinkElement, value);
}
if (vn.isSVG && value.startsWith("url(")) {
if (vn.isSVG && value.startsWith('url(')) {
/* SVG shape ID-s for masks etc. Sometimes referred with the full-page url, which we don't have in replay */
value = "url(#" + (value.split("#")[1] ||")")
value = 'url(#' + (value.split('#')[1] || ')');
}
vn.setAttribute(name, value)
this.removeBodyScroll(msg.id, vn)
vn.setAttribute(name, value);
this.removeBodyScroll(msg.id, vn);
}
private applyMessage = (msg: Message): Promise<any> | undefined => {
@ -200,240 +229,338 @@ export default class DOMManager extends ListWalker<Message> {
case MType.CreateDocument: {
const doc = this.screen.document;
if (!doc) {
logger.error("No root iframe document found", msg, this.screen)
logger.error('No root iframe document found', msg, this.screen);
return;
}
doc.open();
doc.write("<!DOCTYPE html><html></html>");
doc.write('<!DOCTYPE html><html></html>');
doc.close();
const fRoot = doc.documentElement;
fRoot.innerText = '';
const vHTMLElement = new VHTMLElement(fRoot)
this.vElements.clear()
this.vElements.set(0, vHTMLElement)
const vDoc = OnloadVRoot.fromDocumentNode(doc)
vDoc.insertChildAt(vHTMLElement, 0)
this.olVRoots.clear()
this.olVRoots.set(0, vDoc) // watchout: id==0 for both Document and documentElement
const vHTMLElement = new VHTMLElement(fRoot);
this.vElements.clear();
this.vElements.set(0, vHTMLElement);
const vDoc = OnloadVRoot.fromDocumentNode(doc);
vDoc.insertChildAt(vHTMLElement, 0);
this.olVRoots.clear();
this.olVRoots.set(0, vDoc); // watchout: id==0 for both Document and documentElement
// this is done for the AdoptedCSS logic
// Maybetodo: start Document as 0-node in tracker
this.vTexts.clear()
this.stylesManager.reset()
return
this.vTexts.clear();
this.stylesManager.reset();
return;
}
case MType.CreateTextNode: {
const vText = new VText()
this.vTexts.set(msg.id, vText)
this.insertNode(msg)
return
const vText = new VText();
this.vTexts.set(msg.id, vText);
this.insertNode(msg);
return;
}
case MType.CreateElementNode: {
// if (msg.tag.toLowerCase() === 'canvas') msg.tag = 'video'
const vElem = new VElement(msg.tag, msg.svg, msg.index, msg.id)
const vElem = new VElement(msg.tag, msg.svg, msg.index, msg.id);
if (['STYLE', 'style', 'LINK'].includes(msg.tag)) {
vElem.prioritized = true
vElem.prioritized = true;
}
if (this.vElements.has(msg.id)) {
logger.error("CreateElementNode: Node already exists", msg)
return
logger.error('CreateElementNode: Node already exists', msg);
return;
}
this.vElements.set(msg.id, vElem)
this.insertNode(msg)
this.removeBodyScroll(msg.id, vElem)
this.removeAutocomplete(vElem)
return
this.vElements.set(msg.id, vElem);
this.insertNode(msg);
this.removeBodyScroll(msg.id, vElem);
this.removeAutocomplete(vElem);
return;
}
case MType.MoveNode:
this.insertNode(msg)
return
this.insertNode(msg);
return;
case MType.RemoveNode: {
const vChild = this.vElements.get(msg.id) || this.vTexts.get(msg.id)
if (!vChild) { logger.error("RemoveNode: Node not found", msg); return }
if (!vChild.parentNode) { logger.error("RemoveNode: Parent node not found", msg); return }
vChild.parentNode.removeChild(vChild)
this.vElements.delete(msg.id)
this.vTexts.delete(msg.id)
return
const vChild = this.vElements.get(msg.id) || this.vTexts.get(msg.id);
if (!vChild) {
logger.error('RemoveNode: Node not found', msg);
return;
}
if (!vChild.parentNode) {
logger.error('RemoveNode: Parent node not found', msg);
return;
}
vChild.parentNode.removeChild(vChild);
this.vElements.delete(msg.id);
this.vTexts.delete(msg.id);
return;
}
case MType.SetNodeAttribute:
this.setNodeAttribute(msg)
return
this.setNodeAttribute(msg);
return;
case MType.SetNodeAttributeDict:
this.stringDict[msg.nameKey] === undefined && logger.error("No dictionary key for msg 'name': ", msg, this.stringDict)
this.stringDict[msg.valueKey] === undefined && logger.error("No dictionary key for msg 'value': ", msg, this.stringDict)
if (this.stringDict[msg.nameKey] === undefined || this.stringDict[msg.valueKey] === undefined ) { return }
const name = this.globalDict.get(msg.name);
const value = this.globalDict.get(msg.value);
if (name === undefined) {
logger.error(
"No dictionary key for msg 'name': ",
msg,
this.globalDict.all()
);
return;
}
if (value === undefined) {
logger.error(
"No dictionary key for msg 'value': ",
msg,
this.globalDict.all()
);
return;
}
this.setNodeAttribute({
id: msg.id,
name,
value,
});
return;
case MType.SetNodeAttributeDictDeprecated:
this.stringDict[msg.nameKey] === undefined &&
logger.error(
"No local dictionary key for msg 'name': ",
msg,
this.stringDict
);
this.stringDict[msg.valueKey] === undefined &&
logger.error(
"No local dictionary key for msg 'value': ",
msg,
this.stringDict
);
if (
this.stringDict[msg.nameKey] === undefined ||
this.stringDict[msg.valueKey] === undefined
) {
return;
}
this.setNodeAttribute({
id: msg.id,
name: this.stringDict[msg.nameKey],
value: this.stringDict[msg.valueKey],
})
return
});
return;
case MType.RemoveNodeAttribute: {
const vElem = this.vElements.get(msg.id)
if (!vElem) { logger.error("RemoveNodeAttribute: Node not found", msg); return }
vElem.removeAttribute(msg.name)
return
const vElem = this.vElements.get(msg.id);
if (!vElem) {
logger.error('RemoveNodeAttribute: Node not found', msg);
return;
}
vElem.removeAttribute(msg.name);
return;
}
case MType.SetInputValue: {
const vElem = this.vElements.get(msg.id)
if (!vElem) { logger.error("SetInoputValue: Node not found", msg); return }
const nodeWithValue = vElem.node
if (!(nodeWithValue instanceof HTMLInputElement
|| nodeWithValue instanceof HTMLTextAreaElement
|| nodeWithValue instanceof HTMLSelectElement)
) {
logger.error("Trying to set value of non-Input element", msg)
return
const vElem = this.vElements.get(msg.id);
if (!vElem) {
logger.error('SetInoputValue: Node not found', msg);
return;
}
const val = msg.mask > 0 ? '*'.repeat(msg.mask) : msg.value
const doc = this.screen.document
const nodeWithValue = vElem.node;
if (
!(
nodeWithValue instanceof HTMLInputElement ||
nodeWithValue instanceof HTMLTextAreaElement ||
nodeWithValue instanceof HTMLSelectElement
)
) {
logger.error('Trying to set value of non-Input element', msg);
return;
}
const val = msg.mask > 0 ? '*'.repeat(msg.mask) : msg.value;
const doc = this.screen.document;
if (doc && nodeWithValue === doc.activeElement) {
// For the case of Remote Control
nodeWithValue.onblur = () => { nodeWithValue.value = val }
return
nodeWithValue.onblur = () => {
nodeWithValue.value = val;
};
return;
}
nodeWithValue.value = val // Maybe make special VInputValueElement type for lazy value update
return
nodeWithValue.value = val; // Maybe make special VInputValueElement type for lazy value update
return;
}
case MType.SetInputChecked: {
const vElem = this.vElements.get(msg.id)
if (!vElem) { logger.error("SetInputChecked: Node not found", msg); return }
(vElem.node as HTMLInputElement).checked = msg.checked // Maybe make special VCheckableElement type for lazy checking
return
const vElem = this.vElements.get(msg.id);
if (!vElem) {
logger.error('SetInputChecked: Node not found', msg);
return;
}
(vElem.node as HTMLInputElement).checked = msg.checked; // Maybe make special VCheckableElement type for lazy checking
return;
}
case MType.SetNodeData:
case MType.SetCssData: {
const vText = this.vTexts.get(msg.id)
if (!vText) { logger.error("SetNodeData/SetCssData: Node not found", msg); return }
vText.setData(msg.data)
return
const vText = this.vTexts.get(msg.id);
if (!vText) {
logger.error('SetNodeData/SetCssData: Node not found', msg);
return;
}
vText.setData(msg.data);
return;
}
/** @deprecated
* since 4.0.2 in favor of AdoptedSsInsertRule/DeleteRule + AdoptedSsAddOwner as a common case for StyleSheets
*/
case MType.CssInsertRule: {
let styleSheet = this.olStyleSheetsDeprecated.get(msg.id)
let styleSheet = this.olStyleSheetsDeprecated.get(msg.id);
if (!styleSheet) {
const vElem = this.vElements.get(msg.id)
if (!vElem) { logger.error("CssInsertRule: Node not found", msg); return }
if (!isStyleVElement(vElem)) { logger.error("CssInsertRule: Non-style element", msg); return }
styleSheet = OnloadStyleSheet.fromStyleElement(vElem.node)
this.olStyleSheetsDeprecated.set(msg.id, styleSheet)
const vElem = this.vElements.get(msg.id);
if (!vElem) {
logger.error('CssInsertRule: Node not found', msg);
return;
}
if (!isStyleVElement(vElem)) {
logger.error('CssInsertRule: Non-style element', msg);
return;
}
styleSheet = OnloadStyleSheet.fromStyleElement(vElem.node);
this.olStyleSheetsDeprecated.set(msg.id, styleSheet);
}
styleSheet.insertRule(msg.rule, msg.index)
return
styleSheet.insertRule(msg.rule, msg.index);
return;
}
case MType.CssDeleteRule: {
const styleSheet = this.olStyleSheetsDeprecated.get(msg.id)
if (!styleSheet) { logger.error("CssDeleteRule: StyleSheet was not created", msg); return }
styleSheet.deleteRule(msg.index)
return
const styleSheet = this.olStyleSheetsDeprecated.get(msg.id);
if (!styleSheet) {
logger.error('CssDeleteRule: StyleSheet was not created', msg);
return;
}
styleSheet.deleteRule(msg.index);
return;
}
/* end @deprecated */
case MType.CreateIFrameDocument: {
const vElem = this.vElements.get(msg.frameID)
if (!vElem) { logger.error("CreateIFrameDocument: Node not found", msg); return }
if (this.iframeRoots[msg.frameID] && !this.olVRoots.has(msg.id)) {
this.olVRoots.delete(this.iframeRoots[msg.frameID])
const vElem = this.vElements.get(msg.frameID);
if (!vElem) {
logger.error('CreateIFrameDocument: Node not found', msg);
return;
}
this.iframeRoots[msg.frameID] = msg.id
const vRoot = OnloadVRoot.fromVElement(vElem)
vRoot.catch(e => logger.warn(e, msg))
this.olVRoots.set(msg.id, vRoot)
return
if (this.iframeRoots[msg.frameID] && !this.olVRoots.has(msg.id)) {
this.olVRoots.delete(this.iframeRoots[msg.frameID]);
}
this.iframeRoots[msg.frameID] = msg.id;
const vRoot = OnloadVRoot.fromVElement(vElem);
vRoot.catch((e) => logger.warn(e, msg));
this.olVRoots.set(msg.id, vRoot);
return;
}
case MType.AdoptedSsInsertRule: {
const styleSheet = this.olStyleSheets.get(msg.sheetID)
const styleSheet = this.olStyleSheets.get(msg.sheetID);
if (!styleSheet) {
logger.warn("No stylesheet was created for ", msg)
return
logger.warn('No stylesheet was created for ', msg);
return;
}
insertRule(styleSheet, msg)
return
insertRule(styleSheet, msg);
return;
}
case MType.AdoptedSsDeleteRule: {
const styleSheet = this.olStyleSheets.get(msg.sheetID)
const styleSheet = this.olStyleSheets.get(msg.sheetID);
if (!styleSheet) {
logger.warn("No stylesheet was created for ", msg)
return
logger.warn('No stylesheet was created for ', msg);
return;
}
deleteRule(styleSheet, msg)
return
deleteRule(styleSheet, msg);
return;
}
case MType.AdoptedSsReplace: {
const styleSheet = this.olStyleSheets.get(msg.sheetID)
const styleSheet = this.olStyleSheets.get(msg.sheetID);
if (!styleSheet) {
logger.warn("No stylesheet was created for ", msg)
return
logger.warn('No stylesheet was created for ', msg);
return;
}
// @ts-ignore (configure ts with recent WebaAPI)
styleSheet.replaceSync(msg.text)
return
styleSheet.replaceSync(msg.text);
return;
}
case MType.AdoptedSsAddOwner: {
const vRoot = this.olVRoots.get(msg.id)
const vRoot = this.olVRoots.get(msg.id);
if (!vRoot) {
/* <style> tag case */
const vElem = this.vElements.get(msg.id)
if (!vElem) { logger.error("AdoptedSsAddOwner: Node not found", msg); return }
if (!isStyleVElement(vElem)) { logger.error("Non-style owner", msg); return }
this.olStyleSheets.set(msg.sheetID, OnloadStyleSheet.fromStyleElement(vElem.node))
return
const vElem = this.vElements.get(msg.id);
if (!vElem) {
logger.error('AdoptedSsAddOwner: Node not found', msg);
return;
}
if (!isStyleVElement(vElem)) {
logger.error('Non-style owner', msg);
return;
}
this.olStyleSheets.set(
msg.sheetID,
OnloadStyleSheet.fromStyleElement(vElem.node)
);
return;
}
/* Constructed StyleSheet case */
let olStyleSheet = this.olStyleSheets.get(msg.sheetID)
let olStyleSheet = this.olStyleSheets.get(msg.sheetID);
if (!olStyleSheet) {
olStyleSheet = OnloadStyleSheet.fromVRootContext(vRoot)
this.olStyleSheets.set(msg.sheetID, olStyleSheet)
olStyleSheet = OnloadStyleSheet.fromVRootContext(vRoot);
this.olStyleSheets.set(msg.sheetID, olStyleSheet);
}
olStyleSheet.whenReady(styleSheet => {
vRoot.onNode(node => {
olStyleSheet.whenReady((styleSheet) => {
vRoot.onNode((node) => {
// @ts-ignore
node.adoptedStyleSheets = [...node.adoptedStyleSheets, styleSheet]
})
})
return
node.adoptedStyleSheets = [...node.adoptedStyleSheets, styleSheet];
});
});
return;
}
case MType.AdoptedSsRemoveOwner: {
const olStyleSheet = this.olStyleSheets.get(msg.sheetID)
const olStyleSheet = this.olStyleSheets.get(msg.sheetID);
if (!olStyleSheet) {
logger.warn("AdoptedSsRemoveOwner: No stylesheet was created for ", msg)
return
logger.warn(
'AdoptedSsRemoveOwner: No stylesheet was created for ',
msg
);
return;
}
const vRoot = this.olVRoots.get(msg.id)
if (!vRoot) { logger.error("AdoptedSsRemoveOwner: Owner node not found", msg); return }
olStyleSheet.whenReady(styleSheet => {
vRoot.onNode(node => {
const vRoot = this.olVRoots.get(msg.id);
if (!vRoot) {
logger.error('AdoptedSsRemoveOwner: Owner node not found', msg);
return;
}
olStyleSheet.whenReady((styleSheet) => {
vRoot.onNode((node) => {
// @ts-ignore
node.adoptedStyleSheets = [...vRoot.node.adoptedStyleSheets].filter(s => s !== styleSheet)
})
})
return
node.adoptedStyleSheets = [...vRoot.node.adoptedStyleSheets].filter(
(s) => s !== styleSheet
);
});
});
return;
}
case MType.LoadFontFace: {
const vRoot = this.olVRoots.get(msg.parentID)
if (!vRoot) { logger.error("LoadFontFace: Node not found", msg); return }
vRoot.whenReady(vNode => {
if (vNode instanceof VShadowRoot) { logger.error(`Node ${vNode} expected to be a Document`, msg); return }
let descr: Object | undefined
const vRoot = this.olVRoots.get(msg.parentID);
if (!vRoot) {
logger.error('LoadFontFace: Node not found', msg);
return;
}
vRoot.whenReady((vNode) => {
if (vNode instanceof VShadowRoot) {
logger.error(`Node ${vNode} expected to be a Document`, msg);
return;
}
let descr: Object | undefined;
if (msg.descriptors) {
try {
descr = JSON.parse(msg.descriptors)
descr = typeof descr === 'object' ? descr : undefined
descr = JSON.parse(msg.descriptors);
descr = typeof descr === 'object' ? descr : undefined;
} catch {
logger.warn("Can't parse font-face descriptors: ", msg)
logger.warn("Can't parse font-face descriptors: ", msg);
}
}
const ff = new FontFace(msg.family, msg.source, descr)
vNode.node.fonts.add(ff)
void ff.load()
})
return
const ff = new FontFace(msg.family, msg.source, descr);
vNode.node.fonts.add(ff);
void ff.load();
});
return;
}
}
}
};
/**
* Moves and applies all the messages from the current (or from the beginning, if t < current.time)
@ -445,33 +572,33 @@ export default class DOMManager extends ListWalker<Message> {
* (the async part exists mostly due to styles loading)
*/
async moveReady(t: number): Promise<void> {
this.moveApply(t, this.applyMessage)
this.olVRoots.forEach(rt => rt.applyChanges())
this.moveApply(t, this.applyMessage);
this.olVRoots.forEach((rt) => rt.applyChanges());
// Thinkabout (read): css preload
// What if we go back before it is ready? We'll have two handlres?
return this.stylesManager.moveReady().then(() => {
/* Waiting for styles to be applied first */
/* Applying focus */
this.focusManager.move(t)
this.focusManager.move(t);
/* Applying text selections */
this.selectionManager.move(t)
this.selectionManager.move(t);
/* Applying all scrolls */
this.nodeScrollManagers.forEach(manager => {
const msg = manager.moveGetLast(t)
this.nodeScrollManagers.forEach((manager) => {
const msg = manager.moveGetLast(t);
if (msg) {
let scrollVHost: VElement | OnloadVRoot | undefined
if (scrollVHost = this.vElements.get(msg.id)) {
scrollVHost.node.scrollLeft = msg.x
scrollVHost.node.scrollTop = msg.y
let scrollVHost: VElement | OnloadVRoot | undefined;
if ((scrollVHost = this.vElements.get(msg.id))) {
scrollVHost.node.scrollLeft = msg.x;
scrollVHost.node.scrollTop = msg.y;
} else if ((scrollVHost = this.olVRoots.get(msg.id))) {
scrollVHost.whenReady(vNode => {
scrollVHost.whenReady((vNode) => {
if (vNode instanceof VDocument) {
vNode.node.defaultView?.scrollTo(msg.x, msg.y)
vNode.node.defaultView?.scrollTo(msg.x, msg.y);
}
})
});
}
}
})
})
});
});
}
}

View file

@ -1,75 +1,94 @@
import logger from 'App/logger';
import ListWalker from '../../common/ListWalker';
import { Message, MType } from '../messages';
import type Screen from '../Screen/Screen';
import type { Message, StringDict } from '../messages';
import { MType} from '../messages';
import ListWalker from '../../common/ListWalker';
import DOMManager from './DOM/DOMManager';
import DOMManager from './DOM/DOMManager';
export default class PagesManager extends ListWalker<DOMManager> {
private currentPage: DOMManager | null = null
/**
* String Dictionary in tracker may be desync with CreateDocument (why???)
* e.g. some StringDictionary and other messages before any 'CreateDocument' one
* TODO: understand why and fix
*/
private stringDicts: Record<number, string>[] = [{}]
private currentPage: DOMManager | null = null;
/**
* String Dictionary in tracker may be desync with CreateDocument (why???)
* e.g. some StringDictionary and other messages before any 'CreateDocument' one
* TODO: understand why and fix
*/
private stringDicts: Record<number, string>[] = [{}];
private globalDictionary: Map<string, string> = new Map();
constructor(
private screen: Screen,
private isMobile: boolean,
private setCssLoading: ConstructorParameters<typeof DOMManager>[4],
) { super() }
constructor(
private screen: Screen,
private isMobile: boolean,
private setCssLoading: (flag: boolean) => void
) {
super();
}
/*
/*
Assumed that messages added in a correct time sequence.
*/
falseOrder = false
appendMessage(m: Message): void {
if (m.tp === MType.StringDict) {
let currentDict = this.stringDicts[0]
if (currentDict[m.key] !== undefined && currentDict[m.key] !== m.value) {
this.falseOrder = true
this.stringDicts.unshift({})
currentDict = this.stringDicts[0]
}
currentDict[m.key] = m.value
return
}
if (m.tp === MType.CreateDocument) {
if (!this.falseOrder) {
this.stringDicts.unshift({})
}
super.append(new DOMManager(this.screen, this.isMobile, this.stringDicts[0], m.time, this.setCssLoading))
this.falseOrder = false
}
if (this.last === null) {
logger.warn("DOMMessage before any document created, skipping:", m)
return;
}
this.last.append(m)
}
falseOrder = false;
appendMessage(m: Message): void {
if (m.tp === MType.StringDict) {
this.globalDictionary.set(m.key, m.value);
return;
}
if (m.tp === MType.StringDictDeprecated) {
let currentDict = this.stringDicts[0];
if (currentDict[m.key] !== undefined && currentDict[m.key] !== m.value) {
this.falseOrder = true;
this.stringDicts.unshift({});
currentDict = this.stringDicts[0];
}
currentDict[m.key] = m.value;
return;
}
if (m.tp === MType.CreateDocument) {
if (!this.falseOrder) {
this.stringDicts.unshift({});
}
super.append(
new DOMManager({
screen: this.screen,
isMobile: this.isMobile,
// TODO: this is a deprecated code on life support, remove it after 09.2025
stringDict: this.stringDicts[0],
time: m.time,
setCssLoading: this.setCssLoading,
globalDict: {
get: (key: string) => this.globalDictionary.get(key),
all: () => Object.fromEntries(this.globalDictionary),
},
})
);
this.falseOrder = false;
}
if (this.last === null) {
logger.warn('DOMMessage before any document created, skipping:', m);
return;
}
sortPages(comparator: (a: Message, b: Message) => number) {
this.forEach(page => page.sort(comparator))
}
this.last.append(m);
}
public getNode(id: number) {
return this.currentPage?.getNode(id)
}
sortPages(comparator: (a: Message, b: Message) => number) {
this.forEach((page) => page.sort(comparator));
}
moveReady(t: number): Promise<void> {
const requiredPage = this.moveGetLast(t)
if (requiredPage != null) {
this.currentPage?.clearSelectionManager()
this.currentPage = requiredPage
this.currentPage.reset() // Otherwise it won't apply create_document
}
if (this.currentPage != null) {
return this.currentPage.moveReady(t)
}
return Promise.resolve()
}
}
public getNode(id: number) {
return this.currentPage?.getNode(id);
}
moveReady(t: number): Promise<void> {
const requiredPage = this.moveGetLast(t);
if (requiredPage != null) {
this.currentPage?.clearSelectionManager();
this.currentPage = requiredPage;
this.currentPage.reset(); // Otherwise it won't apply create_document
}
if (this.currentPage != null) {
return this.currentPage.moveReady(t);
}
return Promise.resolve();
}
}

View file

@ -377,7 +377,7 @@ export default class RawMessageReader extends PrimitiveReader {
const key = this.readUint(); if (key === null) { return resetPointer() }
const value = this.readString(); if (value === null) { return resetPointer() }
return {
tp: MType.StringDict,
tp: MType.StringDictDeprecated,
key,
value,
};
@ -388,13 +388,35 @@ export default class RawMessageReader extends PrimitiveReader {
const nameKey = this.readUint(); if (nameKey === null) { return resetPointer() }
const valueKey = this.readUint(); if (valueKey === null) { return resetPointer() }
return {
tp: MType.SetNodeAttributeDict,
tp: MType.SetNodeAttributeDictDeprecated,
id,
nameKey,
valueKey,
};
}
case 43: {
const key = this.readString(); if (key === null) { return resetPointer() }
const value = this.readString(); if (value === null) { return resetPointer() }
return {
tp: MType.StringDict,
key,
value,
};
}
case 52: {
const id = this.readUint(); if (id === null) { return resetPointer() }
const name = this.readString(); if (name === null) { return resetPointer() }
const value = this.readString(); if (value === null) { return resetPointer() }
return {
tp: MType.SetNodeAttributeDict,
id,
name,
value,
};
}
case 53: {
const timestamp = this.readUint(); if (timestamp === null) { return resetPointer() }
const duration = this.readUint(); if (duration === null) { return resetPointer() }

View file

@ -4,7 +4,7 @@
import { MType } from './raw.gen'
const IOS_TYPES = [90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,110,111]
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,37,38,49,50,51,54,55,57,58,59,60,61,67,68,69,70,71,72,73,74,75,76,77,113,114,117,118,119,122]
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,37,38,49,50,51,43,52,54,55,57,58,59,60,61,67,68,69,70,71,72,73,74,75,76,77,113,114,117,118,119,122]
export function isDOMType(t: MType) {
return DOM_TYPES.includes(t)
}

View file

@ -34,6 +34,8 @@ import type {
RawNgRx,
RawGraphQlDeprecated,
RawPerformanceTrack,
RawStringDictDeprecated,
RawSetNodeAttributeDictDeprecated,
RawStringDict,
RawSetNodeAttributeDict,
RawResourceTimingDeprecated,
@ -143,6 +145,10 @@ export type GraphQlDeprecated = RawGraphQlDeprecated & Timed
export type PerformanceTrack = RawPerformanceTrack & Timed
export type StringDictDeprecated = RawStringDictDeprecated & Timed
export type SetNodeAttributeDictDeprecated = RawSetNodeAttributeDictDeprecated & Timed
export type StringDict = RawStringDict & Timed
export type SetNodeAttributeDict = RawSetNodeAttributeDict & Timed

View file

@ -32,8 +32,10 @@ export const enum MType {
NgRx = 47,
GraphQlDeprecated = 48,
PerformanceTrack = 49,
StringDict = 50,
SetNodeAttributeDict = 51,
StringDictDeprecated = 50,
SetNodeAttributeDictDeprecated = 51,
StringDict = 43,
SetNodeAttributeDict = 52,
ResourceTimingDeprecated = 53,
ConnectionInformation = 54,
SetPageVisibility = 55,
@ -286,17 +288,30 @@ export interface RawPerformanceTrack {
usedJSHeapSize: number,
}
export interface RawStringDictDeprecated {
tp: MType.StringDictDeprecated,
key: number,
value: string,
}
export interface RawSetNodeAttributeDictDeprecated {
tp: MType.SetNodeAttributeDictDeprecated,
id: number,
nameKey: number,
valueKey: number,
}
export interface RawStringDict {
tp: MType.StringDict,
key: number,
key: string,
value: string,
}
export interface RawSetNodeAttributeDict {
tp: MType.SetNodeAttributeDict,
id: number,
nameKey: number,
valueKey: number,
name: string,
value: string,
}
export interface RawResourceTimingDeprecated {
@ -632,4 +647,4 @@ export interface RawMobileIssueEvent {
}
export type RawMessage = RawTimestamp | RawSetPageLocationDeprecated | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequestDeprecated | RawConsoleLog | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawReduxDeprecated | RawVuex | RawMobX | RawNgRx | RawGraphQlDeprecated | RawPerformanceTrack | RawStringDict | RawSetNodeAttributeDict | RawResourceTimingDeprecated | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawCssInsertRuleURLBased | RawMouseClick | RawMouseClickDeprecated | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawNetworkRequest | RawWsChannel | RawSelectionChange | RawMouseThrashing | RawResourceTiming | RawTabChange | RawTabData | RawCanvasNode | RawTagTrigger | RawRedux | RawSetPageLocation | RawGraphQl | RawMobileEvent | RawMobileScreenChanges | RawMobileClickEvent | RawMobileInputEvent | RawMobilePerformanceEvent | RawMobileLog | RawMobileInternalError | RawMobileNetworkCall | RawMobileSwipeEvent | RawMobileIssueEvent;
export type RawMessage = RawTimestamp | RawSetPageLocationDeprecated | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequestDeprecated | RawConsoleLog | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawReduxDeprecated | RawVuex | RawMobX | RawNgRx | RawGraphQlDeprecated | RawPerformanceTrack | RawStringDictDeprecated | RawSetNodeAttributeDictDeprecated | RawStringDict | RawSetNodeAttributeDict | RawResourceTimingDeprecated | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawCssInsertRuleURLBased | RawMouseClick | RawMouseClickDeprecated | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawNetworkRequest | RawWsChannel | RawSelectionChange | RawMouseThrashing | RawResourceTiming | RawTabChange | RawTabData | RawCanvasNode | RawTagTrigger | RawRedux | RawSetPageLocation | RawGraphQl | RawMobileEvent | RawMobileScreenChanges | RawMobileClickEvent | RawMobileInputEvent | RawMobilePerformanceEvent | RawMobileLog | RawMobileInternalError | RawMobileNetworkCall | RawMobileSwipeEvent | RawMobileIssueEvent;

View file

@ -33,8 +33,10 @@ export const TP_MAP = {
47: MType.NgRx,
48: MType.GraphQlDeprecated,
49: MType.PerformanceTrack,
50: MType.StringDict,
51: MType.SetNodeAttributeDict,
50: MType.StringDictDeprecated,
51: MType.SetNodeAttributeDictDeprecated,
43: MType.StringDict,
52: MType.SetNodeAttributeDict,
53: MType.ResourceTimingDeprecated,
54: MType.ConnectionInformation,
55: MType.SetPageVisibility,

View file

@ -259,19 +259,32 @@ type TrPerformanceTrack = [
usedJSHeapSize: number,
]
type TrStringDict = [
type TrStringDictDeprecated = [
type: 50,
key: number,
value: string,
]
type TrSetNodeAttributeDict = [
type TrSetNodeAttributeDictDeprecated = [
type: 51,
id: number,
nameKey: number,
valueKey: number,
]
type TrStringDict = [
type: 43,
key: string,
value: string,
]
type TrSetNodeAttributeDict = [
type: 52,
id: number,
name: string,
value: string,
]
type TrResourceTimingDeprecated = [
type: 53,
timestamp: number,
@ -557,7 +570,7 @@ type TrWebVitals = [
]
export type TrackerMessage = TrTimestamp | TrSetPageLocationDeprecated | TrSetViewportSize | TrSetViewportScroll | TrCreateDocument | TrCreateElementNode | TrCreateTextNode | TrMoveNode | TrRemoveNode | TrSetNodeAttribute | TrRemoveNodeAttribute | TrSetNodeData | TrSetNodeScroll | TrSetInputTarget | TrSetInputValue | TrSetInputChecked | TrMouseMove | TrNetworkRequestDeprecated | TrConsoleLog | TrPageLoadTiming | TrPageRenderTiming | TrCustomEvent | TrUserID | TrUserAnonymousID | TrMetadata | TrCSSInsertRule | TrCSSDeleteRule | TrFetch | TrProfiler | TrOTable | TrStateAction | TrReduxDeprecated | TrVuex | TrMobX | TrNgRx | TrGraphQLDeprecated | TrPerformanceTrack | TrStringDict | TrSetNodeAttributeDict | TrResourceTimingDeprecated | TrConnectionInformation | TrSetPageVisibility | TrLoadFontFace | TrSetNodeFocus | TrLongTask | TrSetNodeAttributeURLBased | TrSetCSSDataURLBased | TrTechnicalInfo | TrCustomIssue | TrCSSInsertRuleURLBased | TrMouseClick | TrMouseClickDeprecated | TrCreateIFrameDocument | TrAdoptedSSReplaceURLBased | TrAdoptedSSInsertRuleURLBased | TrAdoptedSSDeleteRule | TrAdoptedSSAddOwner | TrAdoptedSSRemoveOwner | TrJSException | TrZustand | TrBatchMetadata | TrPartitionedMessage | TrNetworkRequest | TrWSChannel | TrInputChange | TrSelectionChange | TrMouseThrashing | TrUnbindNodes | TrResourceTiming | TrTabChange | TrTabData | TrCanvasNode | TrTagTrigger | TrRedux | TrSetPageLocation | TrGraphQL | TrWebVitals
export type TrackerMessage = TrTimestamp | TrSetPageLocationDeprecated | TrSetViewportSize | TrSetViewportScroll | TrCreateDocument | TrCreateElementNode | TrCreateTextNode | TrMoveNode | TrRemoveNode | TrSetNodeAttribute | TrRemoveNodeAttribute | TrSetNodeData | TrSetNodeScroll | TrSetInputTarget | TrSetInputValue | TrSetInputChecked | TrMouseMove | TrNetworkRequestDeprecated | TrConsoleLog | TrPageLoadTiming | TrPageRenderTiming | TrCustomEvent | TrUserID | TrUserAnonymousID | TrMetadata | TrCSSInsertRule | TrCSSDeleteRule | TrFetch | TrProfiler | TrOTable | TrStateAction | TrReduxDeprecated | TrVuex | TrMobX | TrNgRx | TrGraphQLDeprecated | TrPerformanceTrack | TrStringDictDeprecated | TrSetNodeAttributeDictDeprecated | TrStringDict | TrSetNodeAttributeDict | TrResourceTimingDeprecated | TrConnectionInformation | TrSetPageVisibility | TrLoadFontFace | TrSetNodeFocus | TrLongTask | TrSetNodeAttributeURLBased | TrSetCSSDataURLBased | TrTechnicalInfo | TrCustomIssue | TrCSSInsertRuleURLBased | TrMouseClick | TrMouseClickDeprecated | TrCreateIFrameDocument | TrAdoptedSSReplaceURLBased | TrAdoptedSSInsertRuleURLBased | TrAdoptedSSDeleteRule | TrAdoptedSSAddOwner | TrAdoptedSSRemoveOwner | TrJSException | TrZustand | TrBatchMetadata | TrPartitionedMessage | TrNetworkRequest | TrWSChannel | TrInputChange | TrSelectionChange | TrMouseThrashing | TrUnbindNodes | TrResourceTiming | TrTabChange | TrTabData | TrCanvasNode | TrTagTrigger | TrRedux | TrSetPageLocation | TrGraphQL | TrWebVitals
export default function translate(tMsg: TrackerMessage): RawMessage | null {
switch(tMsg[0]) {
@ -823,7 +836,7 @@ export default function translate(tMsg: TrackerMessage): RawMessage | null {
case 50: {
return {
tp: MType.StringDict,
tp: MType.StringDictDeprecated,
key: tMsg[1],
value: tMsg[2],
}
@ -831,13 +844,30 @@ export default function translate(tMsg: TrackerMessage): RawMessage | null {
case 51: {
return {
tp: MType.SetNodeAttributeDict,
tp: MType.SetNodeAttributeDictDeprecated,
id: tMsg[1],
nameKey: tMsg[2],
valueKey: tMsg[3],
}
}
case 43: {
return {
tp: MType.StringDict,
key: tMsg[1],
value: tMsg[2],
}
}
case 52: {
return {
tp: MType.SetNodeAttributeDict,
id: tMsg[1],
name: tMsg[2],
value: tMsg[3],
}
}
case 53: {
return {
tp: MType.ResourceTimingDeprecated,

View file

@ -21,8 +21,6 @@ message 1, 'SessionStart', :tracker => false, :replayer => false do
string 'UserCountry'
string 'UserID'
end
## message 2, 'CreateDocument', do
# end
# DEPRECATED; backend only (TODO: remove in the next release)
message 3, 'SessionEndDeprecated', :tracker => false, :replayer => false do
@ -43,8 +41,7 @@ message 6, 'SetViewportScroll' do
int 'X'
int 'Y'
end
# (should be) Deprecated sinse tracker ?.?.? in favor of CreateDocument(id=2)
# in order to use Document as a default root node instead of the documentElement
message 7, 'CreateDocument' do
end
message 8, 'CreateElementNode' do
@ -106,6 +103,7 @@ message 20, 'MouseMove' do
uint 'X'
uint 'Y'
end
# to remove in 2025
message 21, 'NetworkRequestDeprecated', :replayer => :devtools do
string 'Type' # fetch/xhr/anythingElse(axios,gql,fonts,image?)
string 'Method'
@ -247,7 +245,7 @@ end
message 42, 'StateAction', :replayer => false do
string 'Type'
end
## 43
message 44, 'ReduxDeprecated', :replayer => :devtools do
string 'Action'
string 'State'
@ -279,17 +277,28 @@ message 49, 'PerformanceTrack' do #, :replayer => :devtools --> requires player
uint 'TotalJSHeapSize'
uint 'UsedJSHeapSize'
end
# since 4.1.9
message 50, "StringDict" do
# deprecated @ 10.2024 (v1.21) -> removed @ 2025
message 50, "StringDictDeprecated" do
uint "Key"
string "Value"
end
# since 4.1.9
message 51, "SetNodeAttributeDict" do
# deprecated @ 10.2024 (v1.21) -> removed @ 2025
message 51, "SetNodeAttributeDictDeprecated" do
uint 'ID'
uint 'NameKey'
uint 'ValueKey'
end
message 43, "StringDict" do
string "Key"
string "Value"
end
message 52, 'SetNodeAttributeDict' do
uint 'ID'
string 'Name'
string 'Value'
end
message 53, 'ResourceTimingDeprecated', :replayer => :devtools do
uint 'Timestamp'
uint 'Duration'
@ -375,7 +384,7 @@ message 64, 'CustomIssue', :replayer => false do
string 'Name'
string 'Payload'
end
## 65
message 66, 'AssetCache', :replayer => false, :tracker => false do
string 'URL'
end
@ -601,3 +610,5 @@ message 127, 'SessionSearch', :tracker => false, :replayer => false do
uint 'Timestamp'
uint 'Partition'
end
# FREE 2, 34, 35, 36, 65, 85, 86, 87, 88, 89

View file

@ -56,5 +56,5 @@
"eslint --fix --quiet"
]
},
"packageManager": "yarn@4.5.0"
"packageManager": "yarn@4.5.1"
}

View file

@ -1,6 +1,7 @@
# 15.0.0
- new webvitals messages source
- new webvitals messages source (new msg type)
- new structure for string dictionary (new msg type)
## 14.0.11 & .12

View file

@ -1,7 +1,7 @@
{
"name": "@openreplay/tracker",
"description": "The OpenReplay tracker main package",
"version": "15.0.1-32",
"version": "15.0.0",
"keywords": [
"logging",
"replay"
@ -35,7 +35,7 @@
"lint": "eslint src --ext .ts,.js --fix --quiet",
"clean": "rm -Rf build && rm -Rf lib && rm -Rf cjs",
"build:common": "tsc -b src/common",
"build": "yarn run clean && yarn build:common && rollup --config rollup.config.js",
"build": "yarn run clean && rollup --config rollup.config.js",
"lint-front": "lint-staged",
"test": "jest --coverage=false",
"test:ci": "jest --coverage=true",

View file

@ -36,8 +36,10 @@ export declare const enum Type {
NgRx = 47,
GraphQLDeprecated = 48,
PerformanceTrack = 49,
StringDict = 50,
SetNodeAttributeDict = 51,
StringDictDeprecated = 50,
SetNodeAttributeDictDeprecated = 51,
StringDict = 43,
SetNodeAttributeDict = 52,
ResourceTimingDeprecated = 53,
ConnectionInformation = 54,
SetPageVisibility = 55,
@ -293,16 +295,27 @@ export type PerformanceTrack = [
number,
number
];
export type StringDictDeprecated = [
Type.StringDictDeprecated,
number,
string
];
export type SetNodeAttributeDictDeprecated = [
Type.SetNodeAttributeDictDeprecated,
number,
number,
number
];
export type StringDict = [
Type.StringDict,
number,
string,
string
];
export type SetNodeAttributeDict = [
Type.SetNodeAttributeDict,
number,
number,
number
string,
string
];
export type ResourceTimingDeprecated = [
Type.ResourceTimingDeprecated,
@ -550,5 +563,5 @@ export type WebVitals = [
string,
string
];
type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDict | SetNodeAttributeDict | ResourceTimingDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTiming | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals;
type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDictDeprecated | SetNodeAttributeDictDeprecated | StringDict | SetNodeAttributeDict | ResourceTimingDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTiming | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals;
export default Message;

View file

@ -39,8 +39,10 @@ export declare const enum Type {
NgRx = 47,
GraphQLDeprecated = 48,
PerformanceTrack = 49,
StringDict = 50,
SetNodeAttributeDict = 51,
StringDictDeprecated = 50,
SetNodeAttributeDictDeprecated = 51,
StringDict = 43,
SetNodeAttributeDict = 52,
ResourceTimingDeprecated = 53,
ConnectionInformation = 54,
SetPageVisibility = 55,
@ -336,17 +338,30 @@ export type PerformanceTrack = [
/*usedJSHeapSize:*/ number,
]
export type StringDictDeprecated = [
/*type:*/ Type.StringDictDeprecated,
/*key:*/ number,
/*value:*/ string,
]
export type SetNodeAttributeDictDeprecated = [
/*type:*/ Type.SetNodeAttributeDictDeprecated,
/*id:*/ number,
/*nameKey:*/ number,
/*valueKey:*/ number,
]
export type StringDict = [
/*type:*/ Type.StringDict,
/*key:*/ number,
/*key:*/ string,
/*value:*/ string,
]
export type SetNodeAttributeDict = [
/*type:*/ Type.SetNodeAttributeDict,
/*id:*/ number,
/*nameKey:*/ number,
/*valueKey:*/ number,
/*name:*/ string,
/*value:*/ string,
]
export type ResourceTimingDeprecated = [
@ -634,5 +649,5 @@ export type WebVitals = [
]
type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDict | SetNodeAttributeDict | ResourceTimingDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTiming | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals
type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDictDeprecated | SetNodeAttributeDictDeprecated | StringDict | SetNodeAttributeDict | ResourceTimingDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTiming | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals
export default Message

View file

@ -1,7 +0,0 @@
{
"extends": "../../tsconfig-base.json",
"compilerOptions": {
"composite": true,
"lib": ["es6"],
}
}

File diff suppressed because one or more lines are too long

View file

@ -476,9 +476,33 @@ export function PerformanceTrack(
]
}
export function StringDict(
export function StringDictDeprecated(
key: number,
value: string,
): Messages.StringDictDeprecated {
return [
Messages.Type.StringDictDeprecated,
key,
value,
]
}
export function SetNodeAttributeDictDeprecated(
id: number,
nameKey: number,
valueKey: number,
): Messages.SetNodeAttributeDictDeprecated {
return [
Messages.Type.SetNodeAttributeDictDeprecated,
id,
nameKey,
valueKey,
]
}
export function StringDict(
key: string,
value: string,
): Messages.StringDict {
return [
Messages.Type.StringDict,
@ -489,14 +513,14 @@ export function StringDict(
export function SetNodeAttributeDict(
id: number,
nameKey: number,
valueKey: number,
name: string,
value: string,
): Messages.SetNodeAttributeDict {
return [
Messages.Type.SetNodeAttributeDict,
id,
nameKey,
valueKey,
name,
value,
]
}

View file

@ -91,7 +91,7 @@ export default class Session {
this.userInfo = userInfo
}
private getPageNumber(): number | undefined {
public getPageNumber = (): number | undefined => {
const pageNoStr = this.app.sessionStorage.getItem(this.options.session_pageno_key)
if (pageNoStr == null) {
return undefined
@ -99,7 +99,7 @@ export default class Session {
return parseInt(pageNoStr)
}
incPageNo(): number {
incPageNo = (): number => {
let pageNo = this.getPageNumber()
if (pageNo === undefined) {
pageNo = 0

View file

@ -3,28 +3,35 @@ import App from '../app/index.js'
export class StringDictionary {
private idx = 1
private backDict: Record<string, number> = {}
/** backwards dictionary of
* [repeated str:key]
* */
private backDict: Record<string, string> = {}
getKey(str: string): [number, boolean] {
constructor(private readonly getPageNo: () => number | undefined) {}
getKey = (str: string): [string, boolean] => {
let isNew = false
if (!this.backDict[str]) {
isNew = true
this.backDict[str] = this.idx++
this.backDict[str] = `${this.getPageNo() ?? 0}_${this.idx}`
this.idx += 1
}
return [this.backDict[str], isNew]
}
}
export default class AttributeSender {
private dict = new StringDictionary()
private dict: StringDictionary
private readonly app: App
private readonly isDictDisabled: boolean
constructor(options: { app: App; isDictDisabled: boolean }) {
this.app = options.app
this.isDictDisabled = options.isDictDisabled
this.dict = new StringDictionary(this.app.session.getPageNumber)
}
public sendSetAttribute(id: number, name: string, value: string) {
public sendSetAttribute = (id: number, name: string, value: string) => {
if (this.isDictDisabled) {
const msg: SetNodeAttribute = [Type.SetNodeAttribute, id, name, value]
return this.app.send(msg)
@ -39,7 +46,7 @@ export default class AttributeSender {
}
}
private applyDict(str: string): number {
private applyDict(str: string): string {
const [key, isNew] = this.dict.getKey(str)
if (isNew) {
this.app.send([Type.StringDict, key, str])
@ -48,6 +55,6 @@ export default class AttributeSender {
}
clear() {
this.dict = new StringDictionary()
this.dict = new StringDictionary(this.app.session.getPageNumber)
}
}

View file

@ -5,5 +5,4 @@
"moduleResolution": "Node",
"declarationDir": "../../dist/cjs"
},
"references": [{ "path": "../common" }]
}

View file

@ -6,5 +6,4 @@
"declaration": true,
"declarationDir": "../../dist/lib",
},
"references": [{ "path": "../common" }]
}

View file

@ -158,14 +158,22 @@ export default class MessageEncoder extends PrimitiveEncoder {
return this.int(msg[1]) && this.int(msg[2]) && this.uint(msg[3]) && this.uint(msg[4])
break
case Messages.Type.StringDict:
case Messages.Type.StringDictDeprecated:
return this.uint(msg[1]) && this.string(msg[2])
break
case Messages.Type.SetNodeAttributeDict:
case Messages.Type.SetNodeAttributeDictDeprecated:
return this.uint(msg[1]) && this.uint(msg[2]) && this.uint(msg[3])
break
case Messages.Type.StringDict:
return this.string(msg[1]) && this.string(msg[2])
break
case Messages.Type.SetNodeAttributeDict:
return this.uint(msg[1]) && this.string(msg[2]) && this.string(msg[3])
break
case Messages.Type.ResourceTimingDeprecated:
return this.uint(msg[1]) && this.uint(msg[2]) && this.uint(msg[3]) && this.uint(msg[4]) && this.uint(msg[5]) && this.uint(msg[6]) && this.string(msg[7]) && this.string(msg[8])
break

View file

@ -8,5 +8,4 @@
"preserveConstEnums": false,
"declaration": false
},
"references": [{ "path": "../../common" }]
}