@cloudcare/browser-core 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/browser/addEventListener.js +57 -0
- package/cjs/browser/fetchObservable.js +4 -5
- package/cjs/browser/pageExitObservable.js +4 -2
- package/cjs/browser/runOnReadyState.js +21 -0
- package/cjs/browser/xhrObservable.js +7 -5
- package/cjs/configuration/configuration.js +5 -3
- package/cjs/console/consoleObservable.js +3 -1
- package/cjs/dataMap.js +1 -0
- package/cjs/helper/byteUtils.js +26 -0
- package/cjs/helper/contextHistory.js +4 -2
- package/cjs/helper/createEventRateLimiter.js +3 -1
- package/cjs/helper/errorTools.js +4 -2
- package/cjs/helper/instrumentMethod.js +2 -4
- package/cjs/helper/serialisation/contextManager.js +84 -0
- package/cjs/helper/serialisation/heavyCustomerDataWarning.js +34 -0
- package/cjs/helper/serialisation/jsonStringify.js +57 -0
- package/cjs/helper/serialisation/rowData.js +50 -0
- package/cjs/helper/timer.js +29 -0
- package/cjs/helper/tools.js +10 -331
- package/cjs/index.js +117 -0
- package/cjs/init.js +6 -6
- package/cjs/report/reportObservable.js +4 -2
- package/cjs/session/sessionCookieStore.js +3 -1
- package/cjs/session/sessionManagement.js +10 -5
- package/cjs/session/sessionStore.js +10 -4
- package/cjs/transport/batch.js +40 -91
- package/cjs/transport/flushController.js +121 -0
- package/cjs/transport/httpRequest.js +6 -2
- package/cjs/transport/index.js +9 -1
- package/cjs/transport/sendWithRetryStrategy.js +8 -4
- package/cjs/transport/startBatchWithReplica.js +10 -2
- package/cjs/user/index.js +18 -0
- package/cjs/user/user.js +42 -0
- package/esm/browser/addEventListener.js +46 -0
- package/esm/browser/fetchObservable.js +4 -3
- package/esm/browser/pageExitObservable.js +2 -1
- package/esm/browser/runOnReadyState.js +12 -0
- package/esm/browser/xhrObservable.js +6 -5
- package/esm/configuration/configuration.js +2 -1
- package/esm/console/consoleObservable.js +2 -1
- package/esm/dataMap.js +1 -0
- package/esm/helper/byteUtils.js +16 -0
- package/esm/helper/contextHistory.js +1 -0
- package/esm/helper/createEventRateLimiter.js +1 -0
- package/esm/helper/errorTools.js +2 -1
- package/esm/helper/instrumentMethod.js +1 -3
- package/esm/helper/serialisation/contextManager.js +70 -0
- package/esm/helper/serialisation/heavyCustomerDataWarning.js +20 -0
- package/esm/helper/serialisation/jsonStringify.js +46 -0
- package/esm/helper/serialisation/rowData.js +33 -0
- package/esm/helper/timer.js +14 -0
- package/esm/helper/tools.js +1 -292
- package/esm/index.js +10 -1
- package/esm/init.js +6 -6
- package/esm/report/reportObservable.js +3 -2
- package/esm/session/sessionCookieStore.js +1 -0
- package/esm/session/sessionManagement.js +5 -2
- package/esm/session/sessionStore.js +7 -2
- package/esm/transport/batch.js +31 -85
- package/esm/transport/flushController.js +114 -0
- package/esm/transport/httpRequest.js +5 -2
- package/esm/transport/index.js +2 -1
- package/esm/transport/sendWithRetryStrategy.js +3 -1
- package/esm/transport/startBatchWithReplica.js +9 -2
- package/esm/user/index.js +1 -0
- package/esm/user/user.js +32 -0
- package/package.json +22 -22
- package/src/browser/addEventListener.js +50 -0
- package/src/browser/fetchObservable.js +5 -5
- package/src/browser/pageExitObservable.js +4 -5
- package/src/browser/runOnReadyState.js +16 -0
- package/src/browser/xhrObservable.js +57 -32
- package/src/configuration/configuration.js +1 -1
- package/src/console/consoleObservable.js +22 -12
- package/src/dataMap.js +1 -0
- package/src/helper/byteUtils.js +17 -0
- package/src/helper/contextHistory.js +1 -1
- package/src/helper/createEventRateLimiter.js +7 -9
- package/src/helper/errorTools.js +2 -1
- package/src/helper/instrumentMethod.js +1 -2
- package/src/helper/serialisation/contextManager.js +79 -0
- package/src/helper/serialisation/heavyCustomerDataWarning.js +28 -0
- package/src/helper/serialisation/jsonStringify.js +47 -0
- package/src/helper/serialisation/rowData.js +41 -0
- package/src/helper/timer.js +21 -0
- package/src/helper/tools.js +2 -301
- package/src/index.js +11 -0
- package/src/init.js +6 -6
- package/src/report/reportObservable.js +40 -25
- package/src/session/sessionCookieStore.js +24 -14
- package/src/session/sessionManagement.js +34 -17
- package/src/session/sessionStore.js +7 -2
- package/src/transport/batch.js +39 -91
- package/src/transport/flushController.js +115 -0
- package/src/transport/httpRequest.js +13 -6
- package/src/transport/index.js +1 -0
- package/src/transport/sendWithRetryStrategy.js +3 -7
- package/src/transport/startBatchWithReplica.js +11 -7
- package/src/user/index.js +1 -0
- package/src/user/user.js +31 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { toStackTraceString } from '../helper/errorTools'
|
|
2
2
|
import { mergeObservables, Observable } from '../helper/observable'
|
|
3
|
-
import { includes,
|
|
3
|
+
import { includes, safeTruncate, filter, each } from '../helper/tools'
|
|
4
|
+
import { addEventListener } from '../browser/addEventListener'
|
|
4
5
|
import { DOM_EVENT } from '../helper/enums'
|
|
5
6
|
export var RawReportType = {
|
|
6
7
|
intervention: 'intervention',
|
|
7
8
|
deprecation: 'deprecation',
|
|
8
|
-
cspViolation: 'csp_violation'
|
|
9
|
+
cspViolation: 'csp_violation'
|
|
9
10
|
}
|
|
10
11
|
export function initReportObservable(apis) {
|
|
11
12
|
var observables = []
|
|
@@ -14,7 +15,9 @@ export function initReportObservable(apis) {
|
|
|
14
15
|
observables.push(createCspViolationReportObservable())
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
var reportTypes = filter(apis, function(api) {
|
|
18
|
+
var reportTypes = filter(apis, function (api) {
|
|
19
|
+
return api !== RawReportType.cspViolation
|
|
20
|
+
})
|
|
18
21
|
if (reportTypes.length) {
|
|
19
22
|
observables.push(createReportObservable(reportTypes))
|
|
20
23
|
}
|
|
@@ -22,24 +25,24 @@ export function initReportObservable(apis) {
|
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
function createReportObservable(reportTypes) {
|
|
25
|
-
var observable = new Observable(function() {
|
|
28
|
+
var observable = new Observable(function () {
|
|
26
29
|
if (!window.ReportingObserver) {
|
|
27
30
|
return
|
|
28
31
|
}
|
|
29
32
|
|
|
30
|
-
var handleReports = function(reports) {
|
|
31
|
-
each(reports, function(report) {
|
|
33
|
+
var handleReports = function (reports) {
|
|
34
|
+
each(reports, function (report) {
|
|
32
35
|
observable.notify(buildRawReportFromReport(report))
|
|
33
36
|
})
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
var observer = new window.ReportingObserver(handleReports, {
|
|
37
40
|
types: reportTypes,
|
|
38
|
-
buffered: true
|
|
41
|
+
buffered: true
|
|
39
42
|
})
|
|
40
43
|
|
|
41
44
|
observer.observe()
|
|
42
|
-
return function() {
|
|
45
|
+
return function () {
|
|
43
46
|
observer.disconnect()
|
|
44
47
|
}
|
|
45
48
|
})
|
|
@@ -48,12 +51,16 @@ function createReportObservable(reportTypes) {
|
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
function createCspViolationReportObservable() {
|
|
51
|
-
var observable = new Observable(function() {
|
|
52
|
-
var handleCspViolation = function(event) {
|
|
54
|
+
var observable = new Observable(function () {
|
|
55
|
+
var handleCspViolation = function (event) {
|
|
53
56
|
observable.notify(buildRawReportFromCspViolation(event))
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
var _addEventListener = addEventListener(
|
|
59
|
+
var _addEventListener = addEventListener(
|
|
60
|
+
document,
|
|
61
|
+
DOM_EVENT.SECURITY_POLICY_VIOLATION,
|
|
62
|
+
handleCspViolation
|
|
63
|
+
)
|
|
57
64
|
|
|
58
65
|
return _addEventListener.stop
|
|
59
66
|
})
|
|
@@ -67,34 +74,42 @@ function buildRawReportFromReport(report) {
|
|
|
67
74
|
type: type,
|
|
68
75
|
subtype: body.id,
|
|
69
76
|
message: type + ': ' + body.message,
|
|
70
|
-
stack: buildStack(
|
|
77
|
+
stack: buildStack(
|
|
78
|
+
body.id,
|
|
79
|
+
body.message,
|
|
80
|
+
body.sourceFile,
|
|
81
|
+
body.lineNumber,
|
|
82
|
+
body.columnNumber
|
|
83
|
+
)
|
|
71
84
|
}
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
function buildRawReportFromCspViolation(event) {
|
|
75
88
|
var type = RawReportType.cspViolation
|
|
76
|
-
var message =
|
|
89
|
+
var message =
|
|
90
|
+
"'" +
|
|
91
|
+
event.blockedURI +
|
|
92
|
+
"' blocked by '" +
|
|
93
|
+
event.effectiveDirective +
|
|
94
|
+
"' directive"
|
|
77
95
|
return {
|
|
78
96
|
type: RawReportType.cspViolation,
|
|
79
97
|
subtype: event.effectiveDirective,
|
|
80
98
|
message: type + ': ' + message,
|
|
81
99
|
stack: buildStack(
|
|
82
100
|
event.effectiveDirective,
|
|
83
|
-
message +
|
|
101
|
+
message +
|
|
102
|
+
' of the policy "' +
|
|
103
|
+
safeTruncate(event.originalPolicy, 100, '...') +
|
|
104
|
+
'"',
|
|
84
105
|
event.sourceFile,
|
|
85
106
|
event.lineNumber,
|
|
86
107
|
event.columnNumber
|
|
87
|
-
)
|
|
108
|
+
)
|
|
88
109
|
}
|
|
89
110
|
}
|
|
90
111
|
|
|
91
|
-
function buildStack(
|
|
92
|
-
name,
|
|
93
|
-
message,
|
|
94
|
-
sourceFile,
|
|
95
|
-
lineNumber,
|
|
96
|
-
columnNumber
|
|
97
|
-
){
|
|
112
|
+
function buildStack(name, message, sourceFile, lineNumber, columnNumber) {
|
|
98
113
|
return (
|
|
99
114
|
sourceFile &&
|
|
100
115
|
toStackTraceString({
|
|
@@ -105,9 +120,9 @@ function buildStack(
|
|
|
105
120
|
func: '?',
|
|
106
121
|
url: sourceFile,
|
|
107
122
|
line: lineNumber,
|
|
108
|
-
column: columnNumber
|
|
109
|
-
}
|
|
110
|
-
]
|
|
123
|
+
column: columnNumber
|
|
124
|
+
}
|
|
125
|
+
]
|
|
111
126
|
})
|
|
112
127
|
)
|
|
113
128
|
}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { getCookie, setCookie } from '../browser/cookie'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
isChromium,
|
|
4
|
+
dateNow,
|
|
5
|
+
isEmptyObject,
|
|
6
|
+
UUID,
|
|
7
|
+
objectEntries,
|
|
8
|
+
map,
|
|
9
|
+
each
|
|
10
|
+
} from '../helper/tools'
|
|
3
11
|
import { SESSION_EXPIRATION_DELAY } from './sessionConstants'
|
|
4
|
-
|
|
12
|
+
import { setTimeout } from '../helper/timer'
|
|
5
13
|
var SESSION_ENTRY_REGEXP = /^([a-z]+)=([a-z0-9-]+)$/
|
|
6
14
|
var SESSION_ENTRY_SEPARATOR = '&'
|
|
7
15
|
|
|
@@ -11,8 +19,7 @@ export var SESSION_COOKIE_NAME = '_dataflux_s'
|
|
|
11
19
|
export var LOCK_RETRY_DELAY = 10
|
|
12
20
|
export var MAX_NUMBER_OF_LOCK_RETRIES = 100
|
|
13
21
|
|
|
14
|
-
|
|
15
|
-
var bufferedOperations= []
|
|
22
|
+
var bufferedOperations = []
|
|
16
23
|
var ongoingOperations
|
|
17
24
|
|
|
18
25
|
export function withCookieLockAccess(operations, numberOfRetries) {
|
|
@@ -93,12 +100,9 @@ function isCookieLockEnabled() {
|
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
function retryLater(operations, currentNumberOfRetries) {
|
|
96
|
-
setTimeout(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
},
|
|
100
|
-
LOCK_RETRY_DELAY
|
|
101
|
-
)
|
|
103
|
+
setTimeout(function () {
|
|
104
|
+
withCookieLockAccess(operations, currentNumberOfRetries + 1)
|
|
105
|
+
}, LOCK_RETRY_DELAY)
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
function next() {
|
|
@@ -119,11 +123,16 @@ export function persistSession(session, options) {
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
function setSession(session, options) {
|
|
122
|
-
setCookie(
|
|
126
|
+
setCookie(
|
|
127
|
+
SESSION_COOKIE_NAME,
|
|
128
|
+
toSessionString(session),
|
|
129
|
+
SESSION_EXPIRATION_DELAY,
|
|
130
|
+
options
|
|
131
|
+
)
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
export function toSessionString(session) {
|
|
126
|
-
return map(objectEntries(session), function(item) {
|
|
135
|
+
return map(objectEntries(session), function (item) {
|
|
127
136
|
return item[0] + '=' + item[1]
|
|
128
137
|
}).join(SESSION_ENTRY_SEPARATOR)
|
|
129
138
|
}
|
|
@@ -132,7 +141,7 @@ export function retrieveSession() {
|
|
|
132
141
|
var sessionString = getCookie(SESSION_COOKIE_NAME)
|
|
133
142
|
var session = {}
|
|
134
143
|
if (isValidSessionString(sessionString)) {
|
|
135
|
-
each(sessionString.split(SESSION_ENTRY_SEPARATOR), function(entry) {
|
|
144
|
+
each(sessionString.split(SESSION_ENTRY_SEPARATOR), function (entry) {
|
|
136
145
|
var matches = SESSION_ENTRY_REGEXP.exec(entry)
|
|
137
146
|
if (matches !== null) {
|
|
138
147
|
var key = matches[1]
|
|
@@ -147,7 +156,8 @@ export function retrieveSession() {
|
|
|
147
156
|
function isValidSessionString(sessionString) {
|
|
148
157
|
return (
|
|
149
158
|
sessionString !== undefined &&
|
|
150
|
-
(sessionString.indexOf(SESSION_ENTRY_SEPARATOR) !== -1 ||
|
|
159
|
+
(sessionString.indexOf(SESSION_ENTRY_SEPARATOR) !== -1 ||
|
|
160
|
+
SESSION_ENTRY_REGEXP.test(sessionString))
|
|
151
161
|
)
|
|
152
162
|
}
|
|
153
163
|
|
|
@@ -1,63 +1,68 @@
|
|
|
1
|
-
import { relativeNow, clocksOrigin, ONE_MINUTE, each
|
|
1
|
+
import { relativeNow, clocksOrigin, ONE_MINUTE, each } from '../helper/tools'
|
|
2
|
+
import {
|
|
3
|
+
addEventListeners,
|
|
4
|
+
addEventListener
|
|
5
|
+
} from '../browser/addEventListener'
|
|
2
6
|
import { ContextHistory } from '../helper/contextHistory'
|
|
3
7
|
import { startSessionStore } from './sessionStore'
|
|
4
8
|
import { SESSION_TIME_OUT_DELAY } from './sessionConstants'
|
|
5
9
|
import { DOM_EVENT } from '../helper/enums'
|
|
6
|
-
|
|
10
|
+
import { clearInterval, setInterval } from '../helper/timer'
|
|
7
11
|
export var VISIBILITY_CHECK_DELAY = ONE_MINUTE
|
|
8
12
|
var SESSION_CONTEXT_TIMEOUT_DELAY = SESSION_TIME_OUT_DELAY
|
|
9
13
|
var stopCallbacks = []
|
|
10
14
|
|
|
11
|
-
export var startSessionManager = function(
|
|
15
|
+
export var startSessionManager = function (
|
|
12
16
|
options,
|
|
13
17
|
productKey,
|
|
14
18
|
computeSessionState
|
|
15
19
|
) {
|
|
16
20
|
var sessionStore = startSessionStore(options, productKey, computeSessionState)
|
|
17
|
-
stopCallbacks.push(function() {
|
|
21
|
+
stopCallbacks.push(function () {
|
|
18
22
|
return sessionStore.stop()
|
|
19
23
|
})
|
|
20
24
|
|
|
21
25
|
var sessionContextHistory = new ContextHistory(SESSION_CONTEXT_TIMEOUT_DELAY)
|
|
22
|
-
stopCallbacks.push(function() {
|
|
26
|
+
stopCallbacks.push(function () {
|
|
23
27
|
return sessionContextHistory.stop()
|
|
24
28
|
})
|
|
25
29
|
|
|
26
|
-
sessionStore.renewObservable.subscribe(function(){
|
|
30
|
+
sessionStore.renewObservable.subscribe(function () {
|
|
27
31
|
sessionContextHistory.add(buildSessionContext(), relativeNow())
|
|
28
32
|
})
|
|
29
|
-
sessionStore.expireObservable.subscribe(function() {
|
|
33
|
+
sessionStore.expireObservable.subscribe(function () {
|
|
30
34
|
sessionContextHistory.closeActive(relativeNow())
|
|
31
35
|
})
|
|
32
36
|
|
|
33
37
|
sessionStore.expandOrRenewSession()
|
|
34
38
|
sessionContextHistory.add(buildSessionContext(), clocksOrigin().relative)
|
|
35
39
|
|
|
36
|
-
trackActivity(function() {
|
|
40
|
+
trackActivity(function () {
|
|
37
41
|
return sessionStore.expandOrRenewSession()
|
|
38
42
|
})
|
|
39
|
-
trackVisibility(function() {
|
|
43
|
+
trackVisibility(function () {
|
|
40
44
|
return sessionStore.expandSession()
|
|
41
45
|
})
|
|
42
46
|
|
|
43
47
|
function buildSessionContext() {
|
|
44
48
|
return {
|
|
45
49
|
id: sessionStore.getSession().id,
|
|
46
|
-
trackingType: sessionStore.getSession()[productKey]
|
|
50
|
+
trackingType: sessionStore.getSession()[productKey]
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
return {
|
|
51
|
-
findActiveSession: function(startTime) {
|
|
55
|
+
findActiveSession: function (startTime) {
|
|
52
56
|
return sessionContextHistory.find(startTime)
|
|
53
57
|
},
|
|
54
58
|
renewObservable: sessionStore.renewObservable,
|
|
55
59
|
expireObservable: sessionStore.expireObservable,
|
|
60
|
+
expire: sessionStore.expire
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
export function stopSessionManager() {
|
|
60
|
-
each(stopCallbacks, function(e) {
|
|
65
|
+
each(stopCallbacks, function (e) {
|
|
61
66
|
return e()
|
|
62
67
|
})
|
|
63
68
|
stopCallbacks = []
|
|
@@ -66,7 +71,12 @@ export function stopSessionManager() {
|
|
|
66
71
|
function trackActivity(expandOrRenewSession) {
|
|
67
72
|
var _addEventListeners = addEventListeners(
|
|
68
73
|
window,
|
|
69
|
-
[
|
|
74
|
+
[
|
|
75
|
+
DOM_EVENT.CLICK,
|
|
76
|
+
DOM_EVENT.TOUCH_START,
|
|
77
|
+
DOM_EVENT.KEY_DOWN,
|
|
78
|
+
DOM_EVENT.SCROLL
|
|
79
|
+
],
|
|
70
80
|
expandOrRenewSession,
|
|
71
81
|
{ capture: true, passive: true }
|
|
72
82
|
)
|
|
@@ -74,16 +84,23 @@ function trackActivity(expandOrRenewSession) {
|
|
|
74
84
|
}
|
|
75
85
|
|
|
76
86
|
function trackVisibility(expandSession) {
|
|
77
|
-
var expandSessionWhenVisible = function() {
|
|
87
|
+
var expandSessionWhenVisible = function () {
|
|
78
88
|
if (document.visibilityState === 'visible') {
|
|
79
89
|
expandSession()
|
|
80
90
|
}
|
|
81
91
|
}
|
|
82
|
-
var _addEventListener= addEventListener(
|
|
92
|
+
var _addEventListener = addEventListener(
|
|
93
|
+
document,
|
|
94
|
+
DOM_EVENT.VISIBILITY_CHANGE,
|
|
95
|
+
expandSessionWhenVisible
|
|
96
|
+
)
|
|
83
97
|
stopCallbacks.push(_addEventListener.stop)
|
|
84
98
|
|
|
85
|
-
var visibilityCheckInterval = setInterval(
|
|
86
|
-
|
|
99
|
+
var visibilityCheckInterval = setInterval(
|
|
100
|
+
expandSessionWhenVisible,
|
|
101
|
+
VISIBILITY_CHECK_DELAY
|
|
102
|
+
)
|
|
103
|
+
stopCallbacks.push(function () {
|
|
87
104
|
clearInterval(visibilityCheckInterval)
|
|
88
105
|
})
|
|
89
106
|
}
|
|
@@ -3,6 +3,7 @@ import { Observable } from '../helper/observable'
|
|
|
3
3
|
import { dateNow, UUID, throttle } from '../helper/tools'
|
|
4
4
|
import { SESSION_TIME_OUT_DELAY } from './sessionConstants'
|
|
5
5
|
import { retrieveSession, withCookieLockAccess } from './sessionCookieStore'
|
|
6
|
+
import { clearInterval, setInterval } from '../helper/timer'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Different session concepts:
|
|
@@ -67,7 +68,7 @@ export function startSessionStore(options, productKey, computeSessionState) {
|
|
|
67
68
|
}
|
|
68
69
|
if (hasSessionInCache()) {
|
|
69
70
|
if (isSessionInCacheOutdated(cookieSession)) {
|
|
70
|
-
|
|
71
|
+
expireSessionInCache()
|
|
71
72
|
} else {
|
|
72
73
|
sessionCache = cookieSession
|
|
73
74
|
}
|
|
@@ -98,7 +99,7 @@ export function startSessionStore(options, productKey, computeSessionState) {
|
|
|
98
99
|
)
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
function
|
|
102
|
+
function expireSessionInCache() {
|
|
102
103
|
sessionCache = {}
|
|
103
104
|
expireObservable.notify()
|
|
104
105
|
}
|
|
@@ -135,6 +136,10 @@ export function startSessionStore(options, productKey, computeSessionState) {
|
|
|
135
136
|
},
|
|
136
137
|
renewObservable: renewObservable,
|
|
137
138
|
expireObservable: expireObservable,
|
|
139
|
+
expire: function () {
|
|
140
|
+
deleteSessionCookie(options)
|
|
141
|
+
synchronizeSession({})
|
|
142
|
+
},
|
|
138
143
|
stop: function () {
|
|
139
144
|
clearInterval(watchSessionTimeoutId)
|
|
140
145
|
}
|
package/src/transport/batch.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { display } from '../helper/display'
|
|
2
2
|
import {
|
|
3
|
-
addEventListener,
|
|
4
|
-
noop,
|
|
5
3
|
values,
|
|
6
4
|
findByPath,
|
|
7
|
-
escapeRowData,
|
|
8
5
|
each,
|
|
9
6
|
isNumber,
|
|
10
7
|
isArray,
|
|
@@ -13,12 +10,17 @@ import {
|
|
|
13
10
|
toServerDuration,
|
|
14
11
|
isBoolean,
|
|
15
12
|
isEmptyObject,
|
|
16
|
-
isObject
|
|
17
|
-
escapeJsonValue,
|
|
18
|
-
escapeRowField
|
|
13
|
+
isObject
|
|
19
14
|
} from '../helper/tools'
|
|
15
|
+
import {
|
|
16
|
+
escapeJsonValue,
|
|
17
|
+
escapeRowField,
|
|
18
|
+
escapeRowData
|
|
19
|
+
} from '../helper/serialisation/rowData'
|
|
20
20
|
import { commonTags, dataMap, commonFields } from '../dataMap'
|
|
21
|
-
import {
|
|
21
|
+
import { RumEventType } from '../helper/enums'
|
|
22
|
+
import { computeBytesCount } from '../helper/byteUtils'
|
|
23
|
+
import { isPageExitReason } from '../browser/pageExitObservable'
|
|
22
24
|
// https://en.wikipedia.org/wiki/UTF-8
|
|
23
25
|
// eslint-disable-next-line no-control-regex
|
|
24
26
|
var HAS_MULTI_BYTES_CHARACTERS = /[^\u0000-\u007F]/
|
|
@@ -133,28 +135,16 @@ export var processedMessageByDataMap = function (message) {
|
|
|
133
135
|
rowData: hasFileds ? rowData : undefined
|
|
134
136
|
}
|
|
135
137
|
}
|
|
136
|
-
var batch = function (
|
|
137
|
-
request,
|
|
138
|
-
batchMessagesLimit,
|
|
139
|
-
batchBytesLimit,
|
|
140
|
-
messageBytesLimit,
|
|
141
|
-
flushTimeout,
|
|
142
|
-
pageExitObservable
|
|
143
|
-
) {
|
|
138
|
+
var batch = function (request, flushController, messageBytesLimit) {
|
|
144
139
|
this.pushOnlyBuffer = []
|
|
145
140
|
this.upsertBuffer = {}
|
|
146
|
-
this.bufferBytesCount = 0
|
|
147
|
-
this.bufferMessagesCount = 0
|
|
148
141
|
this.request = request
|
|
149
|
-
this.
|
|
150
|
-
this.batchBytesLimit = batchBytesLimit
|
|
142
|
+
this.flushController = flushController
|
|
151
143
|
this.messageBytesLimit = messageBytesLimit
|
|
152
|
-
this.flushTimeout = flushTimeout
|
|
153
144
|
var _this = this
|
|
154
|
-
|
|
155
|
-
_this.flush(
|
|
145
|
+
this.flushController.flushObservable.subscribe(function (event) {
|
|
146
|
+
_this.flush(event)
|
|
156
147
|
})
|
|
157
|
-
this.flushPeriodically()
|
|
158
148
|
}
|
|
159
149
|
batch.prototype.add = function (message) {
|
|
160
150
|
this.addOrUpdate(message)
|
|
@@ -162,37 +152,24 @@ batch.prototype.add = function (message) {
|
|
|
162
152
|
batch.prototype.upsert = function (message, key) {
|
|
163
153
|
this.addOrUpdate(message, key)
|
|
164
154
|
}
|
|
165
|
-
batch.prototype.flush = function (
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
if (
|
|
170
|
-
var
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
155
|
+
batch.prototype.flush = function (event) {
|
|
156
|
+
var messages = this.pushOnlyBuffer.concat(values(this.upsertBuffer))
|
|
157
|
+
this.pushOnlyBuffer = []
|
|
158
|
+
this.upsertBuffer = {}
|
|
159
|
+
if (messages.length > 0) {
|
|
160
|
+
var payload = {
|
|
161
|
+
data: messages.join('\n'),
|
|
162
|
+
bytesCount: event.bytesCount,
|
|
163
|
+
flushReason: event.reason
|
|
164
|
+
}
|
|
165
|
+
if (isPageExitReason(event.reason)) {
|
|
166
|
+
this.request.sendOnExit(payload)
|
|
167
|
+
} else {
|
|
168
|
+
this.request.send(payload)
|
|
178
169
|
}
|
|
179
170
|
}
|
|
180
171
|
}
|
|
181
|
-
batch.prototype.flushOnExit = function () {
|
|
182
|
-
this.flush(this.request.sendOnExit)
|
|
183
|
-
}
|
|
184
|
-
batch.prototype.computeBytesCount = function (candidate) {
|
|
185
|
-
// Accurate bytes count computations can degrade performances when there is a lot of events to process
|
|
186
|
-
if (!HAS_MULTI_BYTES_CHARACTERS.test(candidate)) {
|
|
187
|
-
return candidate.length
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (window.TextEncoder !== undefined) {
|
|
191
|
-
return new TextEncoder().encode(candidate).length
|
|
192
|
-
}
|
|
193
172
|
|
|
194
|
-
return new Blob([candidate]).size
|
|
195
|
-
}
|
|
196
173
|
batch.prototype.addOrUpdate = function (message, key) {
|
|
197
174
|
var _process = this.process(message)
|
|
198
175
|
var processedMessage = _process.processedMessage
|
|
@@ -208,18 +185,11 @@ batch.prototype.addOrUpdate = function (message, key) {
|
|
|
208
185
|
if (this.hasMessageFor(key)) {
|
|
209
186
|
this.remove(key)
|
|
210
187
|
}
|
|
211
|
-
if (this.willReachedBytesLimitWith(messageBytesCount)) {
|
|
212
|
-
this.flush()
|
|
213
|
-
}
|
|
214
|
-
|
|
215
188
|
this.push(processedMessage, messageBytesCount, key)
|
|
216
|
-
if (this.isFull()) {
|
|
217
|
-
this.flush()
|
|
218
|
-
}
|
|
219
189
|
}
|
|
220
190
|
batch.prototype.process = function (message) {
|
|
221
191
|
var processedMessage = processedMessageByDataMap(message).rowStr
|
|
222
|
-
var messageBytesCount =
|
|
192
|
+
var messageBytesCount = computeBytesCount(processedMessage)
|
|
223
193
|
return {
|
|
224
194
|
processedMessage: processedMessage,
|
|
225
195
|
messageBytesCount: messageBytesCount
|
|
@@ -227,52 +197,30 @@ batch.prototype.process = function (message) {
|
|
|
227
197
|
}
|
|
228
198
|
|
|
229
199
|
batch.prototype.push = function (processedMessage, messageBytesCount, key) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
200
|
+
var separatorBytesCount = this.flushController.getMessagesCount() > 0 ? 1 : 0
|
|
201
|
+
this.flushController.notifyBeforeAddMessage(
|
|
202
|
+
messageBytesCount + separatorBytesCount
|
|
203
|
+
)
|
|
234
204
|
if (key !== undefined) {
|
|
235
205
|
this.upsertBuffer[key] = processedMessage
|
|
236
206
|
} else {
|
|
237
207
|
this.pushOnlyBuffer.push(processedMessage)
|
|
238
208
|
}
|
|
239
|
-
this.
|
|
240
|
-
this.bufferMessagesCount += 1
|
|
209
|
+
this.flushController.notifyAfterAddMessage()
|
|
241
210
|
}
|
|
242
211
|
|
|
243
212
|
batch.prototype.remove = function (key) {
|
|
244
213
|
var removedMessage = this.upsertBuffer[key]
|
|
245
214
|
delete this.upsertBuffer[key]
|
|
246
|
-
var messageBytesCount =
|
|
247
|
-
|
|
248
|
-
this.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
215
|
+
var messageBytesCount = computeBytesCount(removedMessage)
|
|
216
|
+
// If there are other messages, a '\n' will be added at serialization
|
|
217
|
+
var separatorBytesCount = this.flushController.getMessagesCount() > 1 ? 1 : 0
|
|
218
|
+
this.flushController.notifyAfterRemoveMessage(
|
|
219
|
+
messageBytesCount + separatorBytesCount
|
|
220
|
+
)
|
|
252
221
|
}
|
|
253
222
|
|
|
254
223
|
batch.prototype.hasMessageFor = function (key) {
|
|
255
224
|
return key !== undefined && this.upsertBuffer[key] !== undefined
|
|
256
225
|
}
|
|
257
|
-
|
|
258
|
-
batch.prototype.willReachedBytesLimitWith = function (messageBytesCount) {
|
|
259
|
-
// byte of the separator at the end of the message
|
|
260
|
-
return this.bufferBytesCount + messageBytesCount + 1 >= this.batchBytesLimit
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
batch.prototype.isFull = function () {
|
|
264
|
-
return (
|
|
265
|
-
this.bufferMessagesCount === this.batchMessagesLimit ||
|
|
266
|
-
this.bufferBytesCount >= this.batchBytesLimit
|
|
267
|
-
)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
batch.prototype.flushPeriodically = function () {
|
|
271
|
-
var _this = this
|
|
272
|
-
setTimeout(function () {
|
|
273
|
-
_this.flush()
|
|
274
|
-
_this.flushPeriodically()
|
|
275
|
-
}, this.flushTimeout)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
226
|
export var Batch = batch
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Observable } from '../helper/observable'
|
|
2
|
+
import { clearTimeout, setTimeout } from '../helper/timer'
|
|
3
|
+
|
|
4
|
+
// type FlushReason = PageExitReason | 'duration_limit' | 'bytes_limit' | 'messages_limit' | 'session_expire'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns a "flush controller", responsible of notifying when flushing a pool of pending data needs
|
|
8
|
+
* to happen. The implementation is designed to support both synchronous and asynchronous usages,
|
|
9
|
+
* but relies on invariants described in each method documentation to keep a coherent state.
|
|
10
|
+
*/
|
|
11
|
+
export function createFlushController({
|
|
12
|
+
messagesLimit,
|
|
13
|
+
bytesLimit,
|
|
14
|
+
durationLimit,
|
|
15
|
+
pageExitObservable,
|
|
16
|
+
sessionExpireObservable
|
|
17
|
+
}) {
|
|
18
|
+
var flushObservable = new Observable()
|
|
19
|
+
|
|
20
|
+
pageExitObservable.subscribe(function (event) {
|
|
21
|
+
return flush(event.reason)
|
|
22
|
+
})
|
|
23
|
+
sessionExpireObservable.subscribe(function () {
|
|
24
|
+
return flush('session_expire')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
var currentBytesCount = 0
|
|
28
|
+
var currentMessagesCount = 0
|
|
29
|
+
|
|
30
|
+
function flush(flushReason) {
|
|
31
|
+
if (currentMessagesCount === 0) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var messagesCount = currentMessagesCount
|
|
36
|
+
var bytesCount = currentBytesCount
|
|
37
|
+
|
|
38
|
+
currentMessagesCount = 0
|
|
39
|
+
currentBytesCount = 0
|
|
40
|
+
cancelDurationLimitTimeout()
|
|
41
|
+
|
|
42
|
+
flushObservable.notify({
|
|
43
|
+
reason: flushReason,
|
|
44
|
+
messagesCount: messagesCount,
|
|
45
|
+
bytesCount: bytesCount
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
var durationLimitTimeoutId
|
|
50
|
+
function scheduleDurationLimitTimeout() {
|
|
51
|
+
if (durationLimitTimeoutId === undefined) {
|
|
52
|
+
durationLimitTimeoutId = setTimeout(function () {
|
|
53
|
+
flush('duration_limit')
|
|
54
|
+
}, durationLimit)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function cancelDurationLimitTimeout() {
|
|
59
|
+
clearTimeout(durationLimitTimeoutId)
|
|
60
|
+
durationLimitTimeoutId = undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
flushObservable: flushObservable,
|
|
65
|
+
getMessagesCount: function () {
|
|
66
|
+
return currentMessagesCount
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Notifies that a message will be added to a pool of pending messages waiting to be flushed.
|
|
71
|
+
*
|
|
72
|
+
* This function needs to be called synchronously, right before adding the message, so no flush
|
|
73
|
+
* event can happen after `notifyBeforeAddMessage` and before adding the message.
|
|
74
|
+
*/
|
|
75
|
+
notifyBeforeAddMessage: function (messageBytesCount) {
|
|
76
|
+
if (currentBytesCount + messageBytesCount >= bytesLimit) {
|
|
77
|
+
flush('bytes_limit')
|
|
78
|
+
}
|
|
79
|
+
// Consider the message to be added now rather than in `notifyAfterAddMessage`, because if no
|
|
80
|
+
// message was added yet and `notifyAfterAddMessage` is called asynchronously, we still want
|
|
81
|
+
// to notify when a flush is needed (for example on page exit).
|
|
82
|
+
currentMessagesCount += 1
|
|
83
|
+
currentBytesCount += messageBytesCount
|
|
84
|
+
scheduleDurationLimitTimeout()
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Notifies that a message *was* added to a pool of pending messages waiting to be flushed.
|
|
89
|
+
*
|
|
90
|
+
* This function can be called asynchronously after the message was added, but in this case it
|
|
91
|
+
* should not be called if a flush event occurred in between.
|
|
92
|
+
*/
|
|
93
|
+
notifyAfterAddMessage: function () {
|
|
94
|
+
if (currentMessagesCount >= messagesLimit) {
|
|
95
|
+
flush('messages_limit')
|
|
96
|
+
} else if (currentBytesCount >= bytesLimit) {
|
|
97
|
+
flush('bytes_limit')
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Notifies that a message was removed from a pool of pending messages waiting to be flushed.
|
|
103
|
+
*
|
|
104
|
+
* This function needs to be called synchronously, right after removing the message, so no flush
|
|
105
|
+
* event can happen after removing the message and before `notifyAfterRemoveMessage`.
|
|
106
|
+
*/
|
|
107
|
+
notifyAfterRemoveMessage: function (messageBytesCount) {
|
|
108
|
+
currentBytesCount -= messageBytesCount
|
|
109
|
+
currentMessagesCount -= 1
|
|
110
|
+
if (currentMessagesCount === 0) {
|
|
111
|
+
cancelDurationLimitTimeout()
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|