@cloudcare/browser-core 3.2.4 → 3.2.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/cookie.js +14 -9
- package/cjs/browser/cookie.js.map +1 -1
- package/cjs/configuration/configuration.js +2 -23
- package/cjs/configuration/configuration.js.map +1 -1
- package/cjs/index.js +90 -41
- package/cjs/index.js.map +1 -1
- package/cjs/init.js +0 -19
- package/cjs/init.js.map +1 -1
- package/cjs/session/sessionConstants.js +3 -1
- package/cjs/session/sessionConstants.js.map +1 -1
- package/cjs/session/sessionInCookie.js +59 -0
- package/cjs/session/sessionInCookie.js.map +1 -0
- package/cjs/session/sessionInLocalStorage.js +44 -0
- package/cjs/session/sessionInLocalStorage.js.map +1 -0
- package/cjs/session/sessionManagement.js +38 -31
- package/cjs/session/sessionManagement.js.map +1 -1
- package/cjs/session/sessionState.js +73 -0
- package/cjs/session/sessionState.js.map +1 -0
- package/cjs/session/sessionStore.js +113 -90
- package/cjs/session/sessionStore.js.map +1 -1
- package/cjs/session/sessionStoreOperations.js +117 -0
- package/cjs/session/sessionStoreOperations.js.map +1 -0
- package/esm/browser/cookie.js +15 -8
- package/esm/browser/cookie.js.map +1 -1
- package/esm/configuration/configuration.js +2 -22
- package/esm/configuration/configuration.js.map +1 -1
- package/esm/index.js +3 -4
- package/esm/index.js.map +1 -1
- package/esm/init.js +0 -19
- package/esm/init.js.map +1 -1
- package/esm/session/sessionConstants.js +1 -0
- package/esm/session/sessionConstants.js.map +1 -1
- package/esm/session/sessionInCookie.js +51 -0
- package/esm/session/sessionInCookie.js.map +1 -0
- package/esm/session/sessionInLocalStorage.js +37 -0
- package/esm/session/sessionInLocalStorage.js.map +1 -0
- package/esm/session/sessionManagement.js +35 -28
- package/esm/session/sessionManagement.js.map +1 -1
- package/esm/session/sessionState.js +59 -0
- package/esm/session/sessionState.js.map +1 -0
- package/esm/session/sessionStore.js +113 -90
- package/esm/session/sessionStore.js.map +1 -1
- package/esm/session/sessionStoreOperations.js +108 -0
- package/esm/session/sessionStoreOperations.js.map +1 -0
- package/package.json +2 -2
- package/src/browser/cookie.js +23 -11
- package/src/configuration/configuration.js +3 -30
- package/src/index.js +9 -4
- package/src/init.js +0 -19
- package/src/session/sessionConstants.js +1 -0
- package/src/session/sessionInCookie.js +87 -0
- package/src/session/sessionInLocalStorage.js +45 -0
- package/src/session/sessionManagement.js +48 -36
- package/src/session/sessionState.js +72 -0
- package/src/session/sessionStore.js +163 -108
- package/src/session/sessionStoreOperations.js +134 -0
- package/types/index.d.ts +4 -0
- package/cjs/session/sessionCookieStore.js +0 -156
- package/cjs/session/sessionCookieStore.js.map +0 -1
- package/cjs/synthetics/usr.js +0 -26
- package/cjs/synthetics/usr.js.map +0 -1
- package/esm/session/sessionCookieStore.js +0 -142
- package/esm/session/sessionCookieStore.js.map +0 -1
- package/esm/synthetics/usr.js +0 -17
- package/esm/synthetics/usr.js.map +0 -1
- package/src/session/sessionCookieStore.js +0 -169
- package/src/synthetics/usr.js +0 -18
|
@@ -1,170 +1,225 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { clearInterval, setInterval } from '../helper/timer'
|
|
2
2
|
import { Observable } from '../helper/observable'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { ONE_SECOND, dateNow, throttle, UUID, assign } from '../helper/tools'
|
|
4
|
+
import { selectCookieStrategy, initCookieStrategy } from './sessionInCookie'
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
getExpiredSessionState,
|
|
7
|
+
isSessionInExpiredState,
|
|
8
|
+
isSessionInNotStartedState,
|
|
9
|
+
isSessionStarted
|
|
10
|
+
} from './sessionState'
|
|
11
|
+
import {
|
|
12
|
+
initLocalStorageStrategy,
|
|
13
|
+
selectLocalStorageStrategy
|
|
14
|
+
} from './sessionInLocalStorage'
|
|
15
|
+
import { processSessionStoreOperations } from './sessionStoreOperations'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Every second, the storage will be polled to check for any change that can occur
|
|
19
|
+
* to the session state in another browser tab, or another window.
|
|
20
|
+
* This value has been determined from our previous cookie-only implementation.
|
|
21
|
+
*/
|
|
22
|
+
export const STORAGE_POLL_DELAY = ONE_SECOND
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Checks if cookies are available as the preferred storage
|
|
26
|
+
* Else, checks if LocalStorage is allowed and available
|
|
27
|
+
*/
|
|
28
|
+
export function selectSessionStoreStrategyType(initConfiguration) {
|
|
29
|
+
let sessionStoreStrategyType = selectCookieStrategy(initConfiguration)
|
|
30
|
+
if (
|
|
31
|
+
!sessionStoreStrategyType &&
|
|
32
|
+
initConfiguration.allowFallbackToLocalStorage
|
|
33
|
+
) {
|
|
34
|
+
sessionStoreStrategyType = selectLocalStorageStrategy()
|
|
35
|
+
}
|
|
36
|
+
return sessionStoreStrategyType
|
|
37
|
+
}
|
|
11
38
|
|
|
12
|
-
export var STORAGE_POLL_DELAY = ONE_SECOND
|
|
13
39
|
/**
|
|
14
40
|
* Different session concepts:
|
|
15
41
|
* - tracked, the session has an id and is updated along the user navigation
|
|
16
42
|
* - not tracked, the session does not have an id but it is updated along the user navigation
|
|
17
43
|
* - inactive, no session in store or session expired, waiting for a renew session
|
|
18
44
|
*/
|
|
19
|
-
export function startSessionStore(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
export function startSessionStore(
|
|
46
|
+
sessionStoreStrategyType,
|
|
47
|
+
productKey,
|
|
48
|
+
computeSessionState
|
|
49
|
+
) {
|
|
50
|
+
const renewObservable = new Observable()
|
|
51
|
+
const expireObservable = new Observable()
|
|
52
|
+
const sessionStateUpdateObservable = new Observable()
|
|
53
|
+
const sessionStoreStrategy =
|
|
54
|
+
sessionStoreStrategyType.type === 'Cookie'
|
|
55
|
+
? initCookieStrategy(sessionStoreStrategyType.cookieOptions)
|
|
56
|
+
: initLocalStorageStrategy()
|
|
57
|
+
const { expireSession } = sessionStoreStrategy
|
|
58
|
+
|
|
59
|
+
const watchSessionTimeoutId = setInterval(watchSession, STORAGE_POLL_DELAY)
|
|
60
|
+
let sessionCache
|
|
61
|
+
|
|
62
|
+
startSession()
|
|
63
|
+
|
|
64
|
+
const {
|
|
65
|
+
throttled: throttledExpandOrRenewSession,
|
|
66
|
+
cancel: cancelExpandOrRenewSession
|
|
67
|
+
} = throttle(function () {
|
|
68
|
+
processSessionStoreOperations(
|
|
69
|
+
{
|
|
70
|
+
process: function (sessionState) {
|
|
71
|
+
if (isSessionInNotStartedState(sessionState)) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const synchronizedSession = synchronizeSession(sessionState)
|
|
76
|
+
expandOrRenewSessionState(synchronizedSession)
|
|
77
|
+
return synchronizedSession
|
|
78
|
+
},
|
|
79
|
+
after: function (sessionState) {
|
|
80
|
+
if (isSessionStarted(sessionState) && !hasSessionInCache()) {
|
|
81
|
+
renewSessionInCache(sessionState)
|
|
82
|
+
}
|
|
83
|
+
sessionCache = sessionState
|
|
37
84
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
85
|
+
},
|
|
86
|
+
sessionStoreStrategy
|
|
87
|
+
)
|
|
41
88
|
}, STORAGE_POLL_DELAY)
|
|
42
|
-
var throttledExpandOrRenewSession = _throttleExpandOrRenewSession.throttled
|
|
43
|
-
var cancelExpandOrRenewSession = _throttleExpandOrRenewSession.cancel
|
|
44
|
-
// function expandOrRenewSession() {
|
|
45
|
-
// var isTracked
|
|
46
|
-
// withCookieLockAccess({
|
|
47
|
-
// options: options,
|
|
48
|
-
// process: function (cookieSession) {
|
|
49
|
-
// var synchronizedSession = synchronizeSession(cookieSession)
|
|
50
|
-
// isTracked = expandOrRenewCookie(synchronizedSession)
|
|
51
|
-
// return synchronizedSession
|
|
52
|
-
// },
|
|
53
|
-
// after: function (cookieSession) {
|
|
54
|
-
// if (isTracked && !hasSessionInCache()) {
|
|
55
|
-
// renewSession(cookieSession)
|
|
56
|
-
// }
|
|
57
|
-
// sessionCache = cookieSession
|
|
58
|
-
// }
|
|
59
|
-
// })
|
|
60
|
-
// }
|
|
61
89
|
|
|
62
90
|
function expandSession() {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
91
|
+
processSessionStoreOperations(
|
|
92
|
+
{
|
|
93
|
+
process: function (sessionState) {
|
|
94
|
+
return hasSessionInCache()
|
|
95
|
+
? synchronizeSession(sessionState)
|
|
96
|
+
: undefined
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
sessionStoreStrategy
|
|
100
|
+
)
|
|
71
101
|
}
|
|
72
102
|
|
|
73
103
|
/**
|
|
74
104
|
* allows two behaviors:
|
|
75
|
-
* - if the session is active, synchronize the session cache without updating the session
|
|
76
|
-
* - if the session is not active, clear the session
|
|
105
|
+
* - if the session is active, synchronize the session cache without updating the session store
|
|
106
|
+
* - if the session is not active, clear the session store and expire the session cache
|
|
77
107
|
*/
|
|
78
108
|
function watchSession() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
processSessionStoreOperations(
|
|
110
|
+
{
|
|
111
|
+
process: function (sessionState) {
|
|
112
|
+
return isSessionInExpiredState(sessionState)
|
|
113
|
+
? getExpiredSessionState()
|
|
114
|
+
: undefined
|
|
115
|
+
},
|
|
116
|
+
after: synchronizeSession
|
|
83
117
|
},
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
sessionStoreStrategy
|
|
119
|
+
)
|
|
86
120
|
}
|
|
87
121
|
|
|
88
|
-
function synchronizeSession(
|
|
89
|
-
if (
|
|
90
|
-
|
|
122
|
+
function synchronizeSession(sessionState) {
|
|
123
|
+
if (isSessionInExpiredState(sessionState)) {
|
|
124
|
+
sessionState = getExpiredSessionState()
|
|
91
125
|
}
|
|
92
126
|
if (hasSessionInCache()) {
|
|
93
|
-
if (isSessionInCacheOutdated(
|
|
127
|
+
if (isSessionInCacheOutdated(sessionState)) {
|
|
94
128
|
expireSessionInCache()
|
|
95
129
|
} else {
|
|
96
|
-
|
|
130
|
+
sessionStateUpdateObservable.notify({
|
|
131
|
+
previousState: sessionCache,
|
|
132
|
+
newState: sessionState
|
|
133
|
+
})
|
|
134
|
+
sessionCache = sessionState
|
|
97
135
|
}
|
|
98
136
|
}
|
|
99
|
-
return
|
|
137
|
+
return sessionState
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function startSession() {
|
|
141
|
+
processSessionStoreOperations(
|
|
142
|
+
{
|
|
143
|
+
process: function (sessionState) {
|
|
144
|
+
if (isSessionInNotStartedState(sessionState)) {
|
|
145
|
+
return getExpiredSessionState()
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
after: function (sessionState) {
|
|
149
|
+
sessionCache = sessionState
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
sessionStoreStrategy
|
|
153
|
+
)
|
|
100
154
|
}
|
|
101
155
|
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
156
|
+
function expandOrRenewSessionState(sessionState) {
|
|
157
|
+
if (isSessionInNotStartedState(sessionState)) {
|
|
158
|
+
return false
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { trackingType, isTracked } = computeSessionState(
|
|
162
|
+
sessionState[productKey]
|
|
163
|
+
)
|
|
164
|
+
sessionState[productKey] = trackingType
|
|
165
|
+
delete sessionState.isExpired
|
|
166
|
+
if (isTracked && !sessionState.id) {
|
|
167
|
+
sessionState.id = UUID()
|
|
168
|
+
sessionState.created = String(dateNow())
|
|
110
169
|
}
|
|
111
|
-
return isTracked
|
|
112
170
|
}
|
|
113
171
|
|
|
114
172
|
function hasSessionInCache() {
|
|
115
173
|
return sessionCache[productKey] !== undefined
|
|
116
174
|
}
|
|
117
175
|
|
|
118
|
-
function isSessionInCacheOutdated(
|
|
176
|
+
function isSessionInCacheOutdated(sessionState) {
|
|
119
177
|
return (
|
|
120
|
-
sessionCache.id !==
|
|
121
|
-
sessionCache[productKey] !==
|
|
178
|
+
sessionCache.id !== sessionState.id ||
|
|
179
|
+
sessionCache[productKey] !== sessionState[productKey]
|
|
122
180
|
)
|
|
123
181
|
}
|
|
124
182
|
|
|
125
183
|
function expireSessionInCache() {
|
|
126
|
-
sessionCache =
|
|
184
|
+
sessionCache = getExpiredSessionState()
|
|
127
185
|
expireObservable.notify()
|
|
128
186
|
}
|
|
129
187
|
|
|
130
|
-
function
|
|
131
|
-
sessionCache =
|
|
188
|
+
function renewSessionInCache(sessionState) {
|
|
189
|
+
sessionCache = sessionState
|
|
132
190
|
renewObservable.notify()
|
|
133
191
|
}
|
|
134
192
|
|
|
135
|
-
function
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// created and expire can be undefined for versions which was not storing them
|
|
145
|
-
// these checks could be removed when older versions will not be available/live anymore
|
|
146
|
-
return (
|
|
147
|
-
(session.created === undefined ||
|
|
148
|
-
dateNow() - Number(session.created) < SESSION_TIME_OUT_DELAY) &&
|
|
149
|
-
(session.expire === undefined || dateNow() < Number(session.expire))
|
|
193
|
+
function updateSessionState(partialSessionState) {
|
|
194
|
+
processSessionStoreOperations(
|
|
195
|
+
{
|
|
196
|
+
process: function (sessionState) {
|
|
197
|
+
return assign({}, sessionState, partialSessionState)
|
|
198
|
+
},
|
|
199
|
+
after: synchronizeSession
|
|
200
|
+
},
|
|
201
|
+
sessionStoreStrategy
|
|
150
202
|
)
|
|
151
203
|
}
|
|
152
204
|
|
|
153
205
|
return {
|
|
154
206
|
expandOrRenewSession: throttledExpandOrRenewSession,
|
|
155
|
-
expandSession
|
|
207
|
+
expandSession,
|
|
156
208
|
getSession: function () {
|
|
157
|
-
return sessionCache
|
|
209
|
+
return sessionCache || {}
|
|
158
210
|
},
|
|
159
|
-
renewObservable
|
|
160
|
-
expireObservable
|
|
211
|
+
renewObservable,
|
|
212
|
+
expireObservable,
|
|
213
|
+
sessionStateUpdateObservable,
|
|
214
|
+
restartSession: startSession,
|
|
161
215
|
expire: function () {
|
|
162
216
|
cancelExpandOrRenewSession()
|
|
163
|
-
|
|
164
|
-
synchronizeSession(
|
|
217
|
+
expireSession()
|
|
218
|
+
synchronizeSession(getExpiredSessionState())
|
|
165
219
|
},
|
|
166
220
|
stop: function () {
|
|
167
221
|
clearInterval(watchSessionTimeoutId)
|
|
168
|
-
}
|
|
222
|
+
},
|
|
223
|
+
updateSessionState
|
|
169
224
|
}
|
|
170
225
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { setTimeout } from '../helper/timer'
|
|
2
|
+
import { UUID, assign } from '../helper/tools'
|
|
3
|
+
import {
|
|
4
|
+
expandSessionState,
|
|
5
|
+
isSessionInExpiredState,
|
|
6
|
+
isSessionInNotStartedState
|
|
7
|
+
} from './sessionState'
|
|
8
|
+
|
|
9
|
+
export const LOCK_RETRY_DELAY = 10
|
|
10
|
+
export const LOCK_MAX_TRIES = 100
|
|
11
|
+
const bufferedOperations = []
|
|
12
|
+
let ongoingOperations
|
|
13
|
+
|
|
14
|
+
export function processSessionStoreOperations(
|
|
15
|
+
operations,
|
|
16
|
+
sessionStoreStrategy,
|
|
17
|
+
numberOfRetries = 0
|
|
18
|
+
) {
|
|
19
|
+
const { isLockEnabled, persistSession, expireSession } = sessionStoreStrategy
|
|
20
|
+
const persistWithLock = function (session) {
|
|
21
|
+
return persistSession(assign({}, session, { lock: currentLock }))
|
|
22
|
+
}
|
|
23
|
+
const retrieveStore = function () {
|
|
24
|
+
const session = sessionStoreStrategy.retrieveSession()
|
|
25
|
+
const lock = session.lock
|
|
26
|
+
if (session.lock) {
|
|
27
|
+
delete session.lock
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
session,
|
|
32
|
+
lock
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!ongoingOperations) {
|
|
37
|
+
ongoingOperations = operations
|
|
38
|
+
}
|
|
39
|
+
if (operations !== ongoingOperations) {
|
|
40
|
+
bufferedOperations.push(operations)
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
if (isLockEnabled && numberOfRetries >= LOCK_MAX_TRIES) {
|
|
44
|
+
next(sessionStoreStrategy)
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
let currentLock
|
|
48
|
+
let currentStore = retrieveStore()
|
|
49
|
+
if (isLockEnabled) {
|
|
50
|
+
// if someone has lock, retry later
|
|
51
|
+
if (
|
|
52
|
+
currentStore.lock &&
|
|
53
|
+
!isSessionInNotStartedState(currentStore.session)
|
|
54
|
+
) {
|
|
55
|
+
retryLater(operations, sessionStoreStrategy, numberOfRetries)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
// acquire lock
|
|
59
|
+
currentLock = UUID()
|
|
60
|
+
persistWithLock(currentStore.session)
|
|
61
|
+
// if lock is not acquired, retry later
|
|
62
|
+
currentStore = retrieveStore()
|
|
63
|
+
if (
|
|
64
|
+
currentStore.lock !== currentLock &&
|
|
65
|
+
!isSessionInNotStartedState(currentStore.session)
|
|
66
|
+
) {
|
|
67
|
+
retryLater(operations, sessionStoreStrategy, numberOfRetries)
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
let processedSession = operations.process(currentStore.session)
|
|
72
|
+
if (isLockEnabled) {
|
|
73
|
+
// if lock corrupted after process, retry later
|
|
74
|
+
currentStore = retrieveStore()
|
|
75
|
+
if (
|
|
76
|
+
currentStore.lock !== currentLock &&
|
|
77
|
+
!isSessionInNotStartedState(currentStore.session)
|
|
78
|
+
) {
|
|
79
|
+
retryLater(operations, sessionStoreStrategy, numberOfRetries)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (processedSession) {
|
|
84
|
+
if (isSessionInExpiredState(processedSession)) {
|
|
85
|
+
expireSession()
|
|
86
|
+
} else {
|
|
87
|
+
expandSessionState(processedSession)
|
|
88
|
+
isLockEnabled
|
|
89
|
+
? persistWithLock(processedSession)
|
|
90
|
+
: persistSession(processedSession)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (isLockEnabled) {
|
|
94
|
+
// correctly handle lock around expiration would require to handle this case properly at several levels
|
|
95
|
+
// since we don't have evidence of lock issues around expiration, let's just not do the corruption check for it
|
|
96
|
+
if (!(processedSession && isSessionInExpiredState(processedSession))) {
|
|
97
|
+
// if lock corrupted after persist, retry later
|
|
98
|
+
currentStore = retrieveStore()
|
|
99
|
+
if (
|
|
100
|
+
currentStore.lock !== currentLock &&
|
|
101
|
+
!isSessionInNotStartedState(currentStore.session)
|
|
102
|
+
) {
|
|
103
|
+
retryLater(operations, sessionStoreStrategy, numberOfRetries)
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
persistSession(currentStore.session)
|
|
107
|
+
processedSession = currentStore.session
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// call after even if session is not persisted in order to perform operations on
|
|
111
|
+
// up-to-date session state value => the value could have been modified by another tab
|
|
112
|
+
if (operations.after) {
|
|
113
|
+
operations.after(processedSession || currentStore.session)
|
|
114
|
+
}
|
|
115
|
+
next(sessionStoreStrategy)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function retryLater(operations, sessionStore, currentNumberOfRetries) {
|
|
119
|
+
setTimeout(function () {
|
|
120
|
+
processSessionStoreOperations(
|
|
121
|
+
operations,
|
|
122
|
+
sessionStore,
|
|
123
|
+
currentNumberOfRetries + 1
|
|
124
|
+
)
|
|
125
|
+
}, LOCK_RETRY_DELAY)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function next(sessionStore) {
|
|
129
|
+
ongoingOperations = undefined
|
|
130
|
+
const nextOperations = bufferedOperations.shift()
|
|
131
|
+
if (nextOperations) {
|
|
132
|
+
processSessionStoreOperations(nextOperations, sessionStore)
|
|
133
|
+
}
|
|
134
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -87,6 +87,10 @@ export interface InitConfiguration {
|
|
|
87
87
|
* 数据以 application/json 的发送方式,默认text
|
|
88
88
|
*/
|
|
89
89
|
sendContentTypeByJson?: boolean | undefined
|
|
90
|
+
/**
|
|
91
|
+
* 在 cookie 不可用的情况下,可以开启该选项,把数据储存到 localstorage
|
|
92
|
+
*/
|
|
93
|
+
allowFallbackToLocalStorage?: boolean | undefined
|
|
90
94
|
}
|
|
91
95
|
export enum TraceType {
|
|
92
96
|
DDTRACE = 'ddtrace',
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.SESSION_COOKIE_NAME = exports.MAX_NUMBER_OF_LOCK_RETRIES = exports.LOCK_RETRY_DELAY = void 0;
|
|
7
|
-
exports.clearSession = clearSession;
|
|
8
|
-
exports.persistSession = persistSession;
|
|
9
|
-
exports.retrieveSession = retrieveSession;
|
|
10
|
-
exports.toSessionString = toSessionString;
|
|
11
|
-
exports.withCookieLockAccess = withCookieLockAccess;
|
|
12
|
-
var _cookie = require("../browser/cookie");
|
|
13
|
-
var _tools = require("../helper/tools");
|
|
14
|
-
var _sessionConstants = require("./sessionConstants");
|
|
15
|
-
var _timer = require("../helper/timer");
|
|
16
|
-
var SESSION_ENTRY_REGEXP = /^([a-z]+)=([a-z0-9-]+)$/;
|
|
17
|
-
var SESSION_ENTRY_SEPARATOR = '&';
|
|
18
|
-
var SESSION_COOKIE_NAME = '_dataflux_s';
|
|
19
|
-
|
|
20
|
-
// arbitrary values
|
|
21
|
-
exports.SESSION_COOKIE_NAME = SESSION_COOKIE_NAME;
|
|
22
|
-
var LOCK_RETRY_DELAY = 10;
|
|
23
|
-
exports.LOCK_RETRY_DELAY = LOCK_RETRY_DELAY;
|
|
24
|
-
var MAX_NUMBER_OF_LOCK_RETRIES = 100;
|
|
25
|
-
exports.MAX_NUMBER_OF_LOCK_RETRIES = MAX_NUMBER_OF_LOCK_RETRIES;
|
|
26
|
-
var bufferedOperations = [];
|
|
27
|
-
var ongoingOperations;
|
|
28
|
-
function withCookieLockAccess(operations, numberOfRetries) {
|
|
29
|
-
if (typeof numberOfRetries === 'undefined') {
|
|
30
|
-
numberOfRetries = 0;
|
|
31
|
-
}
|
|
32
|
-
if (!ongoingOperations) {
|
|
33
|
-
ongoingOperations = operations;
|
|
34
|
-
}
|
|
35
|
-
if (operations !== ongoingOperations) {
|
|
36
|
-
bufferedOperations.push(operations);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (numberOfRetries >= MAX_NUMBER_OF_LOCK_RETRIES) {
|
|
40
|
-
next();
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
var currentLock;
|
|
44
|
-
var currentSession = retrieveSession();
|
|
45
|
-
if (isCookieLockEnabled()) {
|
|
46
|
-
// if someone has lock, retry later
|
|
47
|
-
if (currentSession.lock) {
|
|
48
|
-
retryLater(operations, numberOfRetries);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
// acquire lock
|
|
52
|
-
currentLock = (0, _tools.UUID)();
|
|
53
|
-
currentSession.lock = currentLock;
|
|
54
|
-
setSession(currentSession, operations.options);
|
|
55
|
-
// if lock is not acquired, retry later
|
|
56
|
-
currentSession = retrieveSession();
|
|
57
|
-
if (currentSession.lock !== currentLock) {
|
|
58
|
-
retryLater(operations, numberOfRetries);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
var processedSession = operations.process(currentSession);
|
|
63
|
-
if (isCookieLockEnabled()) {
|
|
64
|
-
// if lock corrupted after process, retry later
|
|
65
|
-
currentSession = retrieveSession();
|
|
66
|
-
if (currentSession.lock !== currentLock) {
|
|
67
|
-
retryLater(operations, numberOfRetries);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (processedSession) {
|
|
72
|
-
persistSession(processedSession, operations.options);
|
|
73
|
-
}
|
|
74
|
-
if (isCookieLockEnabled()) {
|
|
75
|
-
// correctly handle lock around expiration would require to handle this case properly at several levels
|
|
76
|
-
// since we don't have evidence of lock issues around expiration, let's just not do the corruption check for it
|
|
77
|
-
if (!(processedSession && isExpiredState(processedSession))) {
|
|
78
|
-
// if lock corrupted after persist, retry later
|
|
79
|
-
currentSession = retrieveSession();
|
|
80
|
-
if (currentSession.lock !== currentLock) {
|
|
81
|
-
retryLater(operations, numberOfRetries);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
delete currentSession.lock;
|
|
85
|
-
setSession(currentSession, operations.options);
|
|
86
|
-
processedSession = currentSession;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// call after even if session is not persisted in order to perform operations on
|
|
90
|
-
// up-to-date cookie value, the value could have been modified by another tab
|
|
91
|
-
if (operations.after) {
|
|
92
|
-
operations.after(processedSession || currentSession);
|
|
93
|
-
}
|
|
94
|
-
next();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Cookie lock strategy allows mitigating issues due to concurrent access to cookie.
|
|
99
|
-
* This issue concerns only chromium browsers and enabling this on firefox increase cookie write failures.
|
|
100
|
-
*/
|
|
101
|
-
function isCookieLockEnabled() {
|
|
102
|
-
return (0, _tools.isChromium)();
|
|
103
|
-
}
|
|
104
|
-
function retryLater(operations, currentNumberOfRetries) {
|
|
105
|
-
(0, _timer.setTimeout)(function () {
|
|
106
|
-
withCookieLockAccess(operations, currentNumberOfRetries + 1);
|
|
107
|
-
}, LOCK_RETRY_DELAY);
|
|
108
|
-
}
|
|
109
|
-
function next() {
|
|
110
|
-
ongoingOperations = undefined;
|
|
111
|
-
var nextOperations = bufferedOperations.shift();
|
|
112
|
-
if (nextOperations) {
|
|
113
|
-
withCookieLockAccess(nextOperations);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function persistSession(session, options) {
|
|
117
|
-
if (isExpiredState(session)) {
|
|
118
|
-
clearSession(options);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
session.expire = String((0, _tools.dateNow)() + _sessionConstants.SESSION_EXPIRATION_DELAY);
|
|
122
|
-
setSession(session, options);
|
|
123
|
-
}
|
|
124
|
-
function setSession(session, options) {
|
|
125
|
-
(0, _cookie.setCookie)(SESSION_COOKIE_NAME, toSessionString(session), _sessionConstants.SESSION_EXPIRATION_DELAY, options);
|
|
126
|
-
}
|
|
127
|
-
function toSessionString(session) {
|
|
128
|
-
return (0, _tools.map)((0, _tools.objectEntries)(session), function (item) {
|
|
129
|
-
return item[0] + '=' + item[1];
|
|
130
|
-
}).join(SESSION_ENTRY_SEPARATOR);
|
|
131
|
-
}
|
|
132
|
-
function retrieveSession() {
|
|
133
|
-
var sessionString = (0, _cookie.getCookie)(SESSION_COOKIE_NAME);
|
|
134
|
-
var session = {};
|
|
135
|
-
if (isValidSessionString(sessionString)) {
|
|
136
|
-
(0, _tools.each)(sessionString.split(SESSION_ENTRY_SEPARATOR), function (entry) {
|
|
137
|
-
var matches = SESSION_ENTRY_REGEXP.exec(entry);
|
|
138
|
-
if (matches !== null) {
|
|
139
|
-
var key = matches[1];
|
|
140
|
-
var value = matches[2];
|
|
141
|
-
session[key] = value;
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
return session;
|
|
146
|
-
}
|
|
147
|
-
function isValidSessionString(sessionString) {
|
|
148
|
-
return sessionString !== undefined && (sessionString.indexOf(SESSION_ENTRY_SEPARATOR) !== -1 || SESSION_ENTRY_REGEXP.test(sessionString));
|
|
149
|
-
}
|
|
150
|
-
function isExpiredState(session) {
|
|
151
|
-
return (0, _tools.isEmptyObject)(session);
|
|
152
|
-
}
|
|
153
|
-
function clearSession(options) {
|
|
154
|
-
(0, _cookie.setCookie)(SESSION_COOKIE_NAME, '', 0, options);
|
|
155
|
-
}
|
|
156
|
-
//# sourceMappingURL=sessionCookieStore.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessionCookieStore.js","names":["_cookie","require","_tools","_sessionConstants","_timer","SESSION_ENTRY_REGEXP","SESSION_ENTRY_SEPARATOR","SESSION_COOKIE_NAME","exports","LOCK_RETRY_DELAY","MAX_NUMBER_OF_LOCK_RETRIES","bufferedOperations","ongoingOperations","withCookieLockAccess","operations","numberOfRetries","push","next","currentLock","currentSession","retrieveSession","isCookieLockEnabled","lock","retryLater","UUID","setSession","options","processedSession","process","persistSession","isExpiredState","after","isChromium","currentNumberOfRetries","setTimeout","undefined","nextOperations","shift","session","clearSession","expire","String","dateNow","SESSION_EXPIRATION_DELAY","setCookie","toSessionString","map","objectEntries","item","join","sessionString","getCookie","isValidSessionString","each","split","entry","matches","exec","key","value","indexOf","test","isEmptyObject"],"sources":["../../src/session/sessionCookieStore.js"],"sourcesContent":["import { getCookie, setCookie } from '../browser/cookie'\nimport {\n isChromium,\n dateNow,\n isEmptyObject,\n UUID,\n objectEntries,\n map,\n each\n} from '../helper/tools'\nimport { SESSION_EXPIRATION_DELAY } from './sessionConstants'\nimport { setTimeout } from '../helper/timer'\nvar SESSION_ENTRY_REGEXP = /^([a-z]+)=([a-z0-9-]+)$/\nvar SESSION_ENTRY_SEPARATOR = '&'\n\nexport var SESSION_COOKIE_NAME = '_dataflux_s'\n\n// arbitrary values\nexport var LOCK_RETRY_DELAY = 10\nexport var MAX_NUMBER_OF_LOCK_RETRIES = 100\n\nvar bufferedOperations = []\nvar ongoingOperations\n\nexport function withCookieLockAccess(operations, numberOfRetries) {\n if (typeof numberOfRetries === 'undefined') {\n numberOfRetries = 0\n }\n if (!ongoingOperations) {\n ongoingOperations = operations\n }\n if (operations !== ongoingOperations) {\n bufferedOperations.push(operations)\n return\n }\n if (numberOfRetries >= MAX_NUMBER_OF_LOCK_RETRIES) {\n next()\n return\n }\n var currentLock\n var currentSession = retrieveSession()\n if (isCookieLockEnabled()) {\n // if someone has lock, retry later\n if (currentSession.lock) {\n retryLater(operations, numberOfRetries)\n return\n }\n // acquire lock\n currentLock = UUID()\n currentSession.lock = currentLock\n setSession(currentSession, operations.options)\n // if lock is not acquired, retry later\n currentSession = retrieveSession()\n if (currentSession.lock !== currentLock) {\n retryLater(operations, numberOfRetries)\n return\n }\n }\n var processedSession = operations.process(currentSession)\n if (isCookieLockEnabled()) {\n // if lock corrupted after process, retry later\n currentSession = retrieveSession()\n if (currentSession.lock !== currentLock) {\n retryLater(operations, numberOfRetries)\n return\n }\n }\n if (processedSession) {\n persistSession(processedSession, operations.options)\n }\n if (isCookieLockEnabled()) {\n // correctly handle lock around expiration would require to handle this case properly at several levels\n // since we don't have evidence of lock issues around expiration, let's just not do the corruption check for it\n if (!(processedSession && isExpiredState(processedSession))) {\n // if lock corrupted after persist, retry later\n currentSession = retrieveSession()\n if (currentSession.lock !== currentLock) {\n retryLater(operations, numberOfRetries)\n return\n }\n delete currentSession.lock\n setSession(currentSession, operations.options)\n processedSession = currentSession\n }\n }\n // call after even if session is not persisted in order to perform operations on\n // up-to-date cookie value, the value could have been modified by another tab\n if (operations.after) {\n operations.after(processedSession || currentSession)\n }\n next()\n}\n\n/**\n * Cookie lock strategy allows mitigating issues due to concurrent access to cookie.\n * This issue concerns only chromium browsers and enabling this on firefox increase cookie write failures.\n */\nfunction isCookieLockEnabled() {\n return isChromium()\n}\n\nfunction retryLater(operations, currentNumberOfRetries) {\n setTimeout(function () {\n withCookieLockAccess(operations, currentNumberOfRetries + 1)\n }, LOCK_RETRY_DELAY)\n}\n\nfunction next() {\n ongoingOperations = undefined\n var nextOperations = bufferedOperations.shift()\n if (nextOperations) {\n withCookieLockAccess(nextOperations)\n }\n}\n\nexport function persistSession(session, options) {\n if (isExpiredState(session)) {\n clearSession(options)\n return\n }\n session.expire = String(dateNow() + SESSION_EXPIRATION_DELAY)\n setSession(session, options)\n}\n\nfunction setSession(session, options) {\n setCookie(\n SESSION_COOKIE_NAME,\n toSessionString(session),\n SESSION_EXPIRATION_DELAY,\n options\n )\n}\n\nexport function toSessionString(session) {\n return map(objectEntries(session), function (item) {\n return item[0] + '=' + item[1]\n }).join(SESSION_ENTRY_SEPARATOR)\n}\n\nexport function retrieveSession() {\n var sessionString = getCookie(SESSION_COOKIE_NAME)\n var session = {}\n if (isValidSessionString(sessionString)) {\n each(sessionString.split(SESSION_ENTRY_SEPARATOR), function (entry) {\n var matches = SESSION_ENTRY_REGEXP.exec(entry)\n if (matches !== null) {\n var key = matches[1]\n var value = matches[2]\n session[key] = value\n }\n })\n }\n return session\n}\n\nfunction isValidSessionString(sessionString) {\n return (\n sessionString !== undefined &&\n (sessionString.indexOf(SESSION_ENTRY_SEPARATOR) !== -1 ||\n SESSION_ENTRY_REGEXP.test(sessionString))\n )\n}\n\nfunction isExpiredState(session) {\n return isEmptyObject(session)\n}\nexport function clearSession(options) {\n setCookie(SESSION_COOKIE_NAME, '', 0, options)\n}\n"],"mappings":"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","ignoreList":[]}
|