@cloudcare/browser-core 3.2.28 → 3.2.30
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/dataMap.js +1 -0
- package/cjs/dataMap.js.map +1 -1
- package/cjs/helper/encoder.js +1 -1
- package/cjs/helper/encoder.js.map +1 -1
- package/cjs/index.js +7 -0
- package/cjs/index.js.map +1 -1
- package/cjs/session/sessionConstants.js +5 -1
- package/cjs/session/sessionConstants.js.map +1 -1
- package/cjs/session/sessionInCookie.js +1 -1
- package/cjs/session/sessionInCookie.js.map +1 -1
- package/cjs/session/sessionInLocalStorage.js +1 -1
- package/cjs/session/sessionInLocalStorage.js.map +1 -1
- package/cjs/session/sessionStore.js +18 -5
- package/cjs/session/sessionStore.js.map +1 -1
- package/cjs/session/sessionStoreOperations.js +34 -8
- package/cjs/session/sessionStoreOperations.js.map +1 -1
- package/cjs/transport/batch.js +7 -2
- package/cjs/transport/batch.js.map +1 -1
- package/cjs/transport/httpRequest.js +37 -6
- package/cjs/transport/httpRequest.js.map +1 -1
- package/esm/dataMap.js +1 -0
- package/esm/dataMap.js.map +1 -1
- package/esm/helper/encoder.js +1 -1
- package/esm/helper/encoder.js.map +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/session/sessionConstants.js +4 -0
- package/esm/session/sessionConstants.js.map +1 -1
- package/esm/session/sessionInCookie.js +2 -2
- package/esm/session/sessionInCookie.js.map +1 -1
- package/esm/session/sessionInLocalStorage.js +2 -2
- package/esm/session/sessionInLocalStorage.js.map +1 -1
- package/esm/session/sessionStore.js +18 -5
- package/esm/session/sessionStore.js.map +1 -1
- package/esm/session/sessionStoreOperations.js +34 -9
- package/esm/session/sessionStoreOperations.js.map +1 -1
- package/esm/transport/batch.js +7 -2
- package/esm/transport/batch.js.map +1 -1
- package/esm/transport/httpRequest.js +37 -6
- package/esm/transport/httpRequest.js.map +1 -1
- package/package.json +2 -2
- package/src/dataMap.js +1 -0
- package/src/helper/encoder.js +1 -1
- package/src/index.js +2 -1
- package/src/session/sessionConstants.js +4 -0
- package/src/session/sessionInCookie.js +3 -2
- package/src/session/sessionInLocalStorage.js +4 -2
- package/src/session/sessionStore.js +27 -8
- package/src/session/sessionStoreOperations.js +31 -13
- package/src/transport/batch.js +1 -2
- package/src/transport/httpRequest.js +52 -15
- package/types/index.d.ts +16 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { clearInterval, setInterval } from '../helper/timer'
|
|
2
2
|
import { Observable } from '../helper/observable'
|
|
3
|
+
import { display } from '../helper/display'
|
|
3
4
|
import { ONE_SECOND, dateNow, throttle, UUID, assign } from '../helper/tools'
|
|
4
5
|
import { selectCookieStrategy, initCookieStrategy } from './sessionInCookie'
|
|
5
6
|
import {
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
selectLocalStorageStrategy
|
|
14
15
|
} from './sessionInLocalStorage'
|
|
15
16
|
import { processSessionStoreOperations } from './sessionStoreOperations'
|
|
17
|
+
import { SessionPersistence } from './sessionConstants'
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Every second, the storage will be polled to check for any change that can occur
|
|
@@ -26,14 +28,31 @@ export const STORAGE_POLL_DELAY = ONE_SECOND
|
|
|
26
28
|
* Else, checks if LocalStorage is allowed and available
|
|
27
29
|
*/
|
|
28
30
|
export function selectSessionStoreStrategyType(initConfiguration) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
switch (initConfiguration.sessionPersistence) {
|
|
32
|
+
case SessionPersistence.COOKIE:
|
|
33
|
+
return selectCookieStrategy(initConfiguration)
|
|
34
|
+
|
|
35
|
+
case SessionPersistence.LOCAL_STORAGE:
|
|
36
|
+
return selectLocalStorageStrategy()
|
|
37
|
+
|
|
38
|
+
case undefined: {
|
|
39
|
+
let sessionStoreStrategyType = selectCookieStrategy(initConfiguration)
|
|
40
|
+
if (
|
|
41
|
+
!sessionStoreStrategyType &&
|
|
42
|
+
initConfiguration.allowFallbackToLocalStorage
|
|
43
|
+
) {
|
|
44
|
+
sessionStoreStrategyType = selectLocalStorageStrategy()
|
|
45
|
+
}
|
|
46
|
+
return sessionStoreStrategyType
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
default:
|
|
50
|
+
display.error(
|
|
51
|
+
`Invalid session persistence '${String(
|
|
52
|
+
initConfiguration.sessionPersistence
|
|
53
|
+
)}'`
|
|
54
|
+
)
|
|
35
55
|
}
|
|
36
|
-
return sessionStoreStrategyType
|
|
37
56
|
}
|
|
38
57
|
|
|
39
58
|
/**
|
|
@@ -51,7 +70,7 @@ export function startSessionStore(
|
|
|
51
70
|
const expireObservable = new Observable()
|
|
52
71
|
const sessionStateUpdateObservable = new Observable()
|
|
53
72
|
const sessionStoreStrategy =
|
|
54
|
-
sessionStoreStrategyType.type ===
|
|
73
|
+
sessionStoreStrategyType.type === SessionPersistence.COOKIE
|
|
55
74
|
? initCookieStrategy(sessionStoreStrategyType.cookieOptions)
|
|
56
75
|
: initLocalStorageStrategy()
|
|
57
76
|
const { expireSession } = sessionStoreStrategy
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { setTimeout } from '../helper/timer'
|
|
2
|
-
import { UUID, assign } from '../helper/tools'
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
UUID,
|
|
4
|
+
assign,
|
|
5
|
+
ONE_SECOND,
|
|
6
|
+
timeStampNow,
|
|
7
|
+
elapsed
|
|
8
|
+
} from '../helper/tools'
|
|
9
|
+
import { expandSessionState, isSessionInExpiredState } from './sessionState'
|
|
10
|
+
import { addTelemetryDebug } from '../telemetry/telemetry'
|
|
9
11
|
export const LOCK_RETRY_DELAY = 10
|
|
10
12
|
export const LOCK_MAX_TRIES = 100
|
|
13
|
+
|
|
14
|
+
// Locks should be hold for a few milliseconds top, just the time it takes to read and write a
|
|
15
|
+
// cookie. Using one second should be enough in most situations.
|
|
16
|
+
export const LOCK_EXPIRATION_DELAY = ONE_SECOND
|
|
17
|
+
const LOCK_SEPARATOR = '--'
|
|
11
18
|
const bufferedOperations = []
|
|
12
19
|
let ongoingOperations
|
|
13
20
|
|
|
@@ -21,15 +28,11 @@ export function processSessionStoreOperations(
|
|
|
21
28
|
return persistSession(assign({}, session, { lock: currentLock }))
|
|
22
29
|
}
|
|
23
30
|
const retrieveStore = function () {
|
|
24
|
-
const session = sessionStoreStrategy.retrieveSession()
|
|
25
|
-
const lock = session.lock
|
|
26
|
-
if (session.lock) {
|
|
27
|
-
delete session.lock
|
|
28
|
-
}
|
|
31
|
+
const { lock, ...session } = sessionStoreStrategy.retrieveSession()
|
|
29
32
|
|
|
30
33
|
return {
|
|
31
34
|
session,
|
|
32
|
-
lock
|
|
35
|
+
lock: lock && !isLockExpired(lock) ? lock : undefined
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
|
|
@@ -41,6 +44,9 @@ export function processSessionStoreOperations(
|
|
|
41
44
|
return
|
|
42
45
|
}
|
|
43
46
|
if (isLockEnabled && numberOfRetries >= LOCK_MAX_TRIES) {
|
|
47
|
+
addTelemetryDebug('Aborted session operation after max lock retries', {
|
|
48
|
+
currentStore: retrieveStore()
|
|
49
|
+
})
|
|
44
50
|
next(sessionStoreStrategy)
|
|
45
51
|
return
|
|
46
52
|
}
|
|
@@ -53,7 +59,7 @@ export function processSessionStoreOperations(
|
|
|
53
59
|
return
|
|
54
60
|
}
|
|
55
61
|
// acquire lock
|
|
56
|
-
currentLock =
|
|
62
|
+
currentLock = createLock()
|
|
57
63
|
persistWithLock(currentStore.session)
|
|
58
64
|
// if lock is not acquired, retry later
|
|
59
65
|
currentStore = retrieveStore()
|
|
@@ -120,3 +126,15 @@ function next(sessionStore) {
|
|
|
120
126
|
processSessionStoreOperations(nextOperations, sessionStore)
|
|
121
127
|
}
|
|
122
128
|
}
|
|
129
|
+
|
|
130
|
+
export function createLock() {
|
|
131
|
+
return UUID() + LOCK_SEPARATOR + timeStampNow()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isLockExpired(lock) {
|
|
135
|
+
const [, timeStamp] = lock.split(LOCK_SEPARATOR)
|
|
136
|
+
return (
|
|
137
|
+
!timeStamp ||
|
|
138
|
+
elapsed(Number(timeStamp), timeStampNow()) > LOCK_EXPIRATION_DELAY
|
|
139
|
+
)
|
|
140
|
+
}
|
package/src/transport/batch.js
CHANGED
|
@@ -234,9 +234,8 @@ export function createBatch(options) {
|
|
|
234
234
|
if (encoderResult.outputBytesCount) {
|
|
235
235
|
send(formatPayloadFromEncoder(encoderResult, sendContentTypeByJson))
|
|
236
236
|
}
|
|
237
|
-
|
|
238
237
|
// Send messages that are not yet encoded at this point
|
|
239
|
-
var pendingMessages = [encoderResult.pendingData, upsertMessages]
|
|
238
|
+
var pendingMessages = [...encoderResult.pendingData, upsertMessages]
|
|
240
239
|
.filter(Boolean)
|
|
241
240
|
.join('\n')
|
|
242
241
|
|
|
@@ -104,22 +104,28 @@ export function fetchKeepAliveStrategy(
|
|
|
104
104
|
keepalive: true,
|
|
105
105
|
mode: 'cors'
|
|
106
106
|
}
|
|
107
|
+
const headers = {
|
|
108
|
+
'x-client-timestamp': Date.now().toString()
|
|
109
|
+
}
|
|
110
|
+
|
|
107
111
|
if (payload.type) {
|
|
108
|
-
|
|
109
|
-
'Content-Type': payload.type
|
|
110
|
-
}
|
|
112
|
+
headers['Content-Type'] = payload.type
|
|
111
113
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
114
|
+
|
|
115
|
+
fetchOption.headers = headers
|
|
116
|
+
fetch(url, fetchOption)
|
|
117
|
+
.then(
|
|
118
|
+
monitor(function (response) {
|
|
119
|
+
if (typeof onResponse === 'function') {
|
|
120
|
+
onResponse({ status: response.status, type: response.type })
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
)
|
|
124
|
+
.catch(
|
|
125
|
+
monitor(function () {
|
|
126
|
+
fetchStrategy(url, payload, onResponse)
|
|
127
|
+
})
|
|
128
|
+
)
|
|
123
129
|
} else {
|
|
124
130
|
sendXHR(url, payload, onResponse)
|
|
125
131
|
}
|
|
@@ -143,7 +149,7 @@ function sendXHR(url, payload, onResponse) {
|
|
|
143
149
|
} else if (payload.type) {
|
|
144
150
|
request.setRequestHeader('Content-Type', payload.type)
|
|
145
151
|
}
|
|
146
|
-
|
|
152
|
+
request.setRequestHeader('x-client-timestamp', Date.now().toString())
|
|
147
153
|
addEventListener(
|
|
148
154
|
request,
|
|
149
155
|
'loadend',
|
|
@@ -158,3 +164,34 @@ function sendXHR(url, payload, onResponse) {
|
|
|
158
164
|
)
|
|
159
165
|
request.send(data)
|
|
160
166
|
}
|
|
167
|
+
function fetchStrategy(url, payload, onResponse) {
|
|
168
|
+
const fetchOption = {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
body: payload.data,
|
|
171
|
+
keepalive: true,
|
|
172
|
+
mode: 'cors'
|
|
173
|
+
}
|
|
174
|
+
const headers = {
|
|
175
|
+
'x-client-timestamp': Date.now().toString()
|
|
176
|
+
}
|
|
177
|
+
if (payload.type) {
|
|
178
|
+
headers['Content-Type'] = payload.type
|
|
179
|
+
}
|
|
180
|
+
fetchOption.headers = headers
|
|
181
|
+
|
|
182
|
+
fetch(url, fetchOption)
|
|
183
|
+
.then(
|
|
184
|
+
monitor(function (response) {
|
|
185
|
+
if (typeof onResponse === 'function') {
|
|
186
|
+
onResponse({ status: response.status, type: response.type })
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
)
|
|
190
|
+
.catch(
|
|
191
|
+
monitor(function () {
|
|
192
|
+
if (typeof onResponse === 'function') {
|
|
193
|
+
onResponse({ status: 0 })
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
)
|
|
197
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface User {
|
|
|
7
7
|
name?: string | undefined
|
|
8
8
|
[key: string]: unknown
|
|
9
9
|
}
|
|
10
|
+
export type SessionPersistence = 'cookie' | 'local-storage'
|
|
11
|
+
|
|
10
12
|
export declare const ConsoleApiName: {
|
|
11
13
|
readonly log: 'log'
|
|
12
14
|
readonly debug: 'debug'
|
|
@@ -91,6 +93,13 @@ export interface InitConfiguration {
|
|
|
91
93
|
* When cookies are not available, you can enable this option to store data in localStorage
|
|
92
94
|
*/
|
|
93
95
|
allowFallbackToLocalStorage?: boolean | undefined
|
|
96
|
+
/**
|
|
97
|
+
* Which storage strategy to use for persisting sessions. Can be either 'cookie' or 'local-storage'.
|
|
98
|
+
*
|
|
99
|
+
* Important: If you are using the RUM and Logs Browser SDKs, this option must be configured with identical values
|
|
100
|
+
* @default "cookie"
|
|
101
|
+
*/
|
|
102
|
+
sessionPersistence?: SessionPersistence | undefined
|
|
94
103
|
}
|
|
95
104
|
export enum TraceType {
|
|
96
105
|
DDTRACE = 'ddtrace',
|
|
@@ -118,7 +127,7 @@ export const NodePrivacyLevel = {
|
|
|
118
127
|
} as const
|
|
119
128
|
export type NodePrivacyLevel =
|
|
120
129
|
(typeof NodePrivacyLevel)[keyof typeof NodePrivacyLevel]
|
|
121
|
-
|
|
130
|
+
export type OriginMatchOption = string | RegExp
|
|
122
131
|
export type MatchOption = string | RegExp | ((value: string) => boolean)
|
|
123
132
|
export type TracingOption = {
|
|
124
133
|
match: MatchOption
|
|
@@ -145,11 +154,16 @@ export interface RumBaseInitConfiguration extends InitConfiguration {
|
|
|
145
154
|
* https://docs.truewatch.com/security/page-performance/#_3
|
|
146
155
|
*/
|
|
147
156
|
excludedActivityUrls?: MatchOption[] | undefined
|
|
157
|
+
/**
|
|
158
|
+
* List of all requests allowed to inject trace collector required headers. For example:
|
|
159
|
+
["https://api.example.com/test", /https:\\/\\/.*\\.my-api-domain\\.com/, (url) => { return true }].
|
|
160
|
+
*/
|
|
161
|
+
allowedTracingUrls?: Array<MatchOption | TracingOption> | undefined
|
|
148
162
|
/**
|
|
149
163
|
* List of all requests allowed to inject trace collector required headers. Can be the request origin or a regex. Origin: protocol (including ://), domain name (or IP address) [and port number]. For example:
|
|
150
164
|
["https://api.example.com", /https:\\/\\/.*\\.my-api-domain\\.com/].
|
|
151
165
|
*/
|
|
152
|
-
|
|
166
|
+
allowedTracingOrigins?: Array<OriginMatchOption> | undefined
|
|
153
167
|
defaultPrivacyLevel?: DefaultPrivacyLevel | undefined
|
|
154
168
|
/**
|
|
155
169
|
* Error session compensation sample rate:
|