@cloudcare/browser-core 1.1.2 → 1.2.0

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.
Files changed (134) hide show
  1. package/cjs/{cookie.js → browser/cookie.js} +6 -37
  2. package/cjs/browser/fetchObservable.js +91 -0
  3. package/cjs/browser/xhrObservable.js +118 -0
  4. package/cjs/configuration/configuration.js +70 -0
  5. package/cjs/configuration/transportConfiguration.js +64 -0
  6. package/cjs/console/consoleObservable.js +84 -0
  7. package/cjs/dataMap.js +26 -21
  8. package/cjs/error/trackRuntimeError.js +27 -0
  9. package/cjs/helper/catchUserErrors.js +20 -0
  10. package/cjs/helper/contextHistory.js +134 -0
  11. package/cjs/helper/createEventRateLimiter.js +47 -0
  12. package/cjs/helper/deviceInfo.js +8 -25
  13. package/cjs/helper/display.js +31 -0
  14. package/cjs/helper/enums.js +28 -2
  15. package/cjs/helper/errorTools.js +63 -2
  16. package/cjs/helper/instrumentMethod.js +93 -0
  17. package/cjs/helper/lifeCycle.js +5 -3
  18. package/cjs/helper/observable.js +40 -2
  19. package/cjs/helper/tools.js +217 -11
  20. package/cjs/index.js +153 -23
  21. package/cjs/init.js +17 -27
  22. package/cjs/report/reportObservable.js +112 -0
  23. package/cjs/session/sessionConstants.js +13 -0
  24. package/cjs/session/sessionCookieStore.js +188 -0
  25. package/cjs/session/sessionManagement.js +96 -0
  26. package/cjs/session/sessionStore.js +150 -0
  27. package/cjs/synthetics/syntheticsWorkerValues.js +32 -0
  28. package/cjs/synthetics/usr.js +32 -0
  29. package/cjs/tracekit/computeStackTrace.js +73 -563
  30. package/cjs/tracekit/index.js +3 -15
  31. package/cjs/tracekit/tracekit.js +113 -0
  32. package/cjs/transport/batch.js +332 -0
  33. package/cjs/transport/httpRequest.js +112 -0
  34. package/cjs/transport/index.js +29 -0
  35. package/cjs/transport/sendWithRetryStrategy.js +177 -0
  36. package/cjs/transport/startBatchWithReplica.js +24 -0
  37. package/esm/{cookie.js → browser/cookie.js} +4 -35
  38. package/esm/browser/fetchObservable.js +77 -0
  39. package/esm/browser/xhrObservable.js +106 -0
  40. package/esm/configuration/configuration.js +55 -0
  41. package/esm/configuration/transportConfiguration.js +54 -0
  42. package/esm/console/consoleObservable.js +70 -0
  43. package/esm/dataMap.js +26 -21
  44. package/esm/error/trackRuntimeError.js +16 -0
  45. package/esm/helper/catchUserErrors.js +12 -0
  46. package/esm/helper/contextHistory.js +106 -0
  47. package/esm/helper/createEventRateLimiter.js +38 -0
  48. package/esm/helper/deviceInfo.js +6 -25
  49. package/esm/helper/display.js +21 -0
  50. package/esm/helper/enums.js +25 -1
  51. package/esm/helper/errorTools.js +58 -3
  52. package/esm/helper/instrumentMethod.js +81 -0
  53. package/esm/helper/lifeCycle.js +5 -3
  54. package/esm/helper/observable.js +39 -3
  55. package/esm/helper/tools.js +173 -3
  56. package/esm/index.js +17 -7
  57. package/esm/init.js +17 -22
  58. package/esm/report/reportObservable.js +98 -0
  59. package/esm/session/sessionConstants.js +3 -0
  60. package/esm/session/sessionCookieStore.js +168 -0
  61. package/esm/session/sessionManagement.js +78 -0
  62. package/esm/session/sessionStore.js +139 -0
  63. package/esm/synthetics/syntheticsWorkerValues.js +15 -0
  64. package/esm/synthetics/usr.js +18 -0
  65. package/esm/tracekit/computeStackTrace.js +73 -557
  66. package/esm/tracekit/index.js +1 -1
  67. package/esm/tracekit/tracekit.js +103 -0
  68. package/esm/transport/batch.js +316 -0
  69. package/esm/transport/httpRequest.js +104 -0
  70. package/esm/transport/index.js +3 -0
  71. package/esm/transport/sendWithRetryStrategy.js +165 -0
  72. package/esm/transport/startBatchWithReplica.js +15 -0
  73. package/package.json +2 -2
  74. package/src/.DS_Store +0 -0
  75. package/src/{cookie.js → browser/cookie.js} +6 -34
  76. package/src/browser/fetchObservable.js +86 -0
  77. package/src/browser/xhrObservable.js +102 -0
  78. package/src/configuration/configuration.js +61 -0
  79. package/src/configuration/transportConfiguration.js +42 -0
  80. package/src/console/consoleObservable.js +65 -0
  81. package/src/dataMap.js +26 -21
  82. package/src/error/trackRuntimeError.js +19 -0
  83. package/src/helper/catchUserErrors.js +12 -0
  84. package/src/helper/contextHistory.js +85 -0
  85. package/src/helper/createEventRateLimiter.js +37 -0
  86. package/src/helper/deviceInfo.js +5 -51
  87. package/src/helper/display.js +21 -0
  88. package/src/helper/enums.js +38 -14
  89. package/src/helper/errorTools.js +76 -12
  90. package/src/helper/instrumentMethod.js +97 -0
  91. package/src/helper/lifeCycle.js +5 -3
  92. package/src/helper/observable.js +33 -2
  93. package/src/helper/tools.js +159 -5
  94. package/src/index.js +18 -7
  95. package/src/init.js +17 -18
  96. package/src/report/reportObservable.js +113 -0
  97. package/src/session/sessionConstants.js +3 -0
  98. package/src/session/sessionCookieStore.js +159 -0
  99. package/src/session/sessionManagement.js +89 -0
  100. package/src/session/sessionStore.js +139 -0
  101. package/src/synthetics/syntheticsWorkerValues.js +22 -0
  102. package/src/synthetics/usr.js +18 -0
  103. package/src/tracekit/computeStackTrace.js +75 -551
  104. package/src/tracekit/index.js +1 -1
  105. package/src/tracekit/tracekit.js +100 -0
  106. package/src/transport/batch.js +289 -0
  107. package/src/transport/httpRequest.js +109 -0
  108. package/src/transport/index.js +3 -0
  109. package/src/transport/sendWithRetryStrategy.js +186 -0
  110. package/src/transport/startBatchWithReplica.js +26 -0
  111. package/cjs/configuration.js +0 -184
  112. package/cjs/errorCollection.js +0 -167
  113. package/cjs/fetchProxy.js +0 -162
  114. package/cjs/helper/errorFilter.js +0 -47
  115. package/cjs/sessionManagement.js +0 -221
  116. package/cjs/tracekit/report.js +0 -289
  117. package/cjs/transport.js +0 -373
  118. package/cjs/xhrProxy.js +0 -122
  119. package/esm/configuration.js +0 -167
  120. package/esm/errorCollection.js +0 -141
  121. package/esm/fetchProxy.js +0 -116
  122. package/esm/helper/errorFilter.js +0 -38
  123. package/esm/sessionManagement.js +0 -195
  124. package/esm/tracekit/report.js +0 -273
  125. package/esm/transport.js +0 -357
  126. package/esm/xhrProxy.js +0 -110
  127. package/src/configuration.js +0 -156
  128. package/src/errorCollection.js +0 -170
  129. package/src/fetchProxy.js +0 -109
  130. package/src/helper/errorFilter.js +0 -38
  131. package/src/sessionManagement.js +0 -224
  132. package/src/tracekit/report.js +0 -284
  133. package/src/transport.js +0 -380
  134. package/src/xhrProxy.js +0 -106
@@ -178,6 +178,63 @@ export var map = function (arr, fn, self) {
178
178
  }
179
179
  return ret
180
180
  }
181
+ export var some = function(arr, fn, self) {
182
+ if (arr.some) {
183
+ return arr.some(fn)
184
+ }
185
+ var flag = false
186
+ for(var i = 0; i < arr.length; i++) {
187
+ if (!hasOwnProperty.call(arr, i)) {
188
+ continue
189
+ }
190
+ var val = arr[i]
191
+ if (fn.call(self, val, i, arr)) {
192
+ flag = true
193
+ break;
194
+ }
195
+ }
196
+ return flag
197
+ }
198
+ export var every = function(arr, fn, self) {
199
+ if (arr.every) {
200
+ return arr.every(fn)
201
+ }
202
+ var flag = true
203
+ for(var i = 0; i < arr.length; i++) {
204
+ if (!hasOwnProperty.call(arr, i)) {
205
+ continue
206
+ }
207
+ var val = arr[i]
208
+ if (!fn.call(self, val, i, arr)) {
209
+ flag = false
210
+ break;
211
+ }
212
+ }
213
+ return flag
214
+ }
215
+ export var matchList = function(list, value) {
216
+ return some(list, function(item) {return item === value || (item instanceof RegExp && item.test(value))})
217
+ }
218
+ // https://github.com/jquery/jquery/blob/a684e6ba836f7c553968d7d026ed7941e1a612d8/src/selector/escapeSelector.js
219
+ export var cssEscape = function(str) {
220
+ if (window.CSS && window.CSS.escape) {
221
+ return window.CSS.escape(str)
222
+ }
223
+
224
+ // eslint-disable-next-line no-control-regex
225
+ return str.replace(/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g, function (ch, asCodePoint) {
226
+ if (asCodePoint) {
227
+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
228
+ if (ch === '\0') {
229
+ return '\uFFFD'
230
+ }
231
+ // Control characters and (dependent upon position) numbers get escaped as code points
232
+ return ch.slice(0, -1) + '\\' + ch.charCodeAt(ch.length - 1).toString(16) + ' '
233
+ }
234
+ // Other potentially-special ASCII characters get backslash-escaped
235
+ return '\\' + ch
236
+ })
237
+ }
181
238
  export var inherit = function (subclass, superclass) {
182
239
  var F = function () {}
183
240
  F.prototype = superclass.prototype
@@ -654,6 +711,16 @@ export var urlParse = function (para) {
654
711
  }
655
712
  return new URLParser(para)
656
713
  }
714
+ export function elementMatches(element, selector) {
715
+ if (element.matches) {
716
+ return element.matches(selector)
717
+ }
718
+ // IE11 support
719
+ if (element.msMatchesSelector) {
720
+ return element.msMatchesSelector(selector)
721
+ }
722
+ return false
723
+ }
657
724
  export var addEvent = function () {
658
725
  function fixEvent(event) {
659
726
  if (event) {
@@ -1463,7 +1530,10 @@ export function noop() {}
1463
1530
  export var ONE_SECOND = 1000
1464
1531
  export var ONE_MINUTE = 60 * ONE_SECOND
1465
1532
  export var ONE_HOUR = 60 * ONE_MINUTE
1466
- export var ONE_KILO_BYTE = 1024
1533
+ export var ONE_DAY = 24 * ONE_HOUR
1534
+ export var ONE_YEAR = 365 * ONE_DAY
1535
+ export var ONE_KIBI_BYTE = 1024
1536
+ export var ONE_MEBI_BYTE = 1024 * ONE_KIBI_BYTE
1467
1537
  /**
1468
1538
  * Return true if the draw is successful
1469
1539
  * @param threshold between 0 and 100
@@ -1504,7 +1574,7 @@ export function preferredNow() {
1504
1574
  return relativeNow()
1505
1575
  }
1506
1576
  export function getTimestamp(relativeTime) {
1507
- return Math.floor(getNavigationStart() + relativeTime)
1577
+ return Math.round(getNavigationStart() + relativeTime)
1508
1578
  }
1509
1579
  export function relativeNow() {
1510
1580
  return performance.now()
@@ -1514,8 +1584,21 @@ export function clocksNow() {
1514
1584
  return { relative: relativeNow(), timeStamp: timeStampNow() }
1515
1585
  }
1516
1586
  export function timeStampNow() {
1587
+ return dateNow()
1588
+ }
1589
+
1590
+ export function looksLikeRelativeTime(time) {
1591
+ return time < ONE_YEAR
1592
+ }
1593
+ export function dateNow() {
1594
+ // Do not use `Date.now` because sometimes websites are wrongly "polyfilling" it. For example, we
1595
+ // had some users using a very old version of `datejs`, which patched `Date.now` to return a Date
1596
+ // instance instead of a timestamp[1]. Those users are unlikely to fix this, so let's handle this
1597
+ // case ourselves.
1598
+ // [1]: https://github.com/datejs/Datejs/blob/97f5c7c58c5bc5accdab8aa7602b6ac56462d778/src/core-debug.js#L14-L16
1517
1599
  return new Date().getTime()
1518
1600
  }
1601
+
1519
1602
  export function elapsed(start, end) {
1520
1603
  return end - start
1521
1604
  }
@@ -1530,7 +1613,20 @@ export function preferredTimeStamp(clocks) {
1530
1613
  return getTimestamp(clocks.relative)
1531
1614
  }
1532
1615
  export function relativeToClocks(relative) {
1533
- return { relative: relative, timeStamp: getTimestamp(relative) }
1616
+ return { relative: relative, timeStamp: getCorrectedTimeStamp(relative) }
1617
+ }
1618
+ export function currentDrift() {
1619
+ // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
1620
+ return Math.round(dateNow() - (getNavigationStart() + performance.now()))
1621
+ }
1622
+
1623
+ function getCorrectedTimeStamp(relativeTime) {
1624
+ var correctedOrigin = dateNow() - performance.now()
1625
+ // apply correction only for positive drift
1626
+ if (correctedOrigin > getNavigationStart()) {
1627
+ return Math.round(correctedOrigin + relativeTime)
1628
+ }
1629
+ return getTimestamp(relativeTime)
1534
1630
  }
1535
1631
  /**
1536
1632
  * Navigation start slightly change on some rare cases
@@ -1643,7 +1739,25 @@ export function createContextManager() {
1643
1739
  } else {
1644
1740
  console.error('content 需要传递对象类型数据')
1645
1741
  }
1646
-
1742
+ },
1743
+ getContext: function() {
1744
+ return deepClone(context)
1745
+ },
1746
+
1747
+ setContext: function(newContext) {
1748
+ context = deepClone(newContext)
1749
+ },
1750
+
1751
+ setContextProperty: function(key, property){
1752
+ context[key] = deepClone(property)
1753
+ },
1754
+
1755
+ removeContextProperty: function(key){
1756
+ delete context[key]
1757
+ },
1758
+
1759
+ clearContext: function(){
1760
+ context = {}
1647
1761
  }
1648
1762
  }
1649
1763
  }
@@ -1656,7 +1770,32 @@ export function find(array, predicate) {
1656
1770
  }
1657
1771
  return undefined
1658
1772
  }
1659
-
1773
+ export function arrayFrom(arrayLike) {
1774
+ if (Array.from) {
1775
+ return Array.from(arrayLike)
1776
+ }
1777
+ var array = []
1778
+ if (arrayLike instanceof Set) {
1779
+ arrayLike.forEach(function(item) { array.push(item) })
1780
+ } else {
1781
+ for (var i = 0; i < arrayLike.length; i++) {
1782
+ array.push(arrayLike[i])
1783
+ }
1784
+ }
1785
+ return array
1786
+ }
1787
+ export function findLast(
1788
+ array,
1789
+ predicate
1790
+ ) {
1791
+ for (var i = array.length - 1; i >= 0; i -= 1) {
1792
+ var item = array[i]
1793
+ if (predicate(item, i, array)) {
1794
+ return item
1795
+ }
1796
+ }
1797
+ return undefined
1798
+ }
1660
1799
  export function isPercentage(value) {
1661
1800
  return isNumber(value) && value >= 0 && value <= 100
1662
1801
  }
@@ -1665,6 +1804,14 @@ export function getLocationOrigin() {
1665
1804
  return getLinkElementOrigin(window.location)
1666
1805
  }
1667
1806
 
1807
+ export function isIE() {
1808
+ return Boolean(document.documentMode)
1809
+ }
1810
+
1811
+ export function isChromium() {
1812
+ return !!window.chrome || /HeadlessChrome/.test(window.navigator.userAgent)
1813
+ }
1814
+
1668
1815
  /**
1669
1816
  * IE fallback
1670
1817
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/origin
@@ -1738,3 +1885,10 @@ export function escapeRowField(value) {
1738
1885
  return value
1739
1886
  }
1740
1887
  }
1888
+ export function isNullUndefinedDefaultValue(data,defaultValue) {
1889
+ if (data !== null && data !== void 0) {
1890
+ return data
1891
+ } else {
1892
+ return defaultValue
1893
+ }
1894
+ }
package/src/index.js CHANGED
@@ -1,22 +1,33 @@
1
1
  export * from './helper/boundedBuffer'
2
+ export * from './helper/contextHistory'
2
3
  export * from './helper/deviceInfo'
3
4
  export * from './helper/enums'
4
- export * from './helper/errorFilter'
5
+ export * from './helper/instrumentMethod'
5
6
  export * from './helper/errorTools'
7
+ export * from './error/trackRuntimeError'
8
+ export * from './console/consoleObservable'
9
+ export * from './report/reportObservable'
10
+ export * from './helper/display'
6
11
  export * from './helper/eventEmitter'
7
12
  export * from './helper/lifeCycle'
8
13
  export * from './helper/limitModification'
14
+ export * from './helper/createEventRateLimiter'
9
15
  export * from './helper/observable'
10
16
  export * from './helper/tools'
11
17
  export * from './helper/urlPolyfill'
12
18
  export * from './helper/mobileUtil'
13
19
  export * from './tracekit'
14
- export * from './configuration'
15
- export * from './cookie'
20
+ export * from './configuration/configuration'
21
+ export * from './configuration/transportConfiguration'
22
+ export * from './browser/cookie'
23
+ export * from './browser/fetchObservable'
24
+ export * from './browser/xhrObservable'
16
25
  export * from './dataMap'
17
- export * from './errorCollection'
18
- export * from './fetchProxy'
19
26
  export * from './init'
20
- export * from './sessionManagement'
27
+ export * from './session/sessionManagement'
28
+ export * from './session/sessionConstants'
29
+ export * from './session/sessionCookieStore'
30
+ export * from './session/sessionStore'
21
31
  export * from './transport'
22
- export * from './xhrProxy'
32
+ export * from './synthetics/syntheticsWorkerValues'
33
+
package/src/init.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { extend, each } from './helper/tools'
2
- import { areCookiesAuthorized } from './cookie'
3
2
  export function makeGlobal(stub) {
4
3
  var global = extend({}, stub, {
5
4
  onReady: function (callback) {
@@ -63,22 +62,22 @@ export function getGlobalObject() {
63
62
  }
64
63
  return globalObject
65
64
  }
66
- export function checkCookiesAuthorized(options) {
67
- if (!areCookiesAuthorized(options)) {
68
- console.warn('Cookies are not authorized, we will not send any data.')
69
- return false
70
- }
71
- return true
72
- }
65
+ // export function checkCookiesAuthorized(options) {
66
+ // if (!areCookiesAuthorized(options)) {
67
+ // console.warn('Cookies are not authorized, we will not send any data.')
68
+ // return false
69
+ // }
70
+ // return true
71
+ // }
73
72
 
74
- export function checkIsNotLocalFile() {
75
- if (isLocalFile()) {
76
- console.error('Execution is not allowed in the current context.')
77
- return false
78
- }
79
- return true
80
- }
73
+ // export function checkIsNotLocalFile() {
74
+ // if (isLocalFile()) {
75
+ // console.error('Execution is not allowed in the current context.')
76
+ // return false
77
+ // }
78
+ // return true
79
+ // }
81
80
 
82
- function isLocalFile() {
83
- return window.location.protocol === 'file:'
84
- }
81
+ // function isLocalFile() {
82
+ // return window.location.protocol === 'file:'
83
+ // }
@@ -0,0 +1,113 @@
1
+ import { toStackTraceString } from '../helper/errorTools'
2
+ import { mergeObservables, Observable } from '../helper/observable'
3
+ import { includes, addEventListener, safeTruncate, filter, each } from '../helper/tools'
4
+ import { DOM_EVENT } from '../helper/enums'
5
+ export var RawReportType = {
6
+ intervention: 'intervention',
7
+ deprecation: 'deprecation',
8
+ cspViolation: 'csp_violation',
9
+ }
10
+ export function initReportObservable(apis) {
11
+ var observables = []
12
+
13
+ if (includes(apis, RawReportType.cspViolation)) {
14
+ observables.push(createCspViolationReportObservable())
15
+ }
16
+
17
+ var reportTypes = filter(apis, function(api) { return api !== RawReportType.cspViolation })
18
+ if (reportTypes.length) {
19
+ observables.push(createReportObservable(reportTypes))
20
+ }
21
+ return mergeObservables.apply(this, observables)
22
+ }
23
+
24
+ function createReportObservable(reportTypes) {
25
+ var observable = new Observable(function() {
26
+ if (!window.ReportingObserver) {
27
+ return
28
+ }
29
+
30
+ var handleReports = function(reports) {
31
+ each(reports, function(report) {
32
+ observable.notify(buildRawReportFromReport(report))
33
+ })
34
+ }
35
+
36
+ var observer = new window.ReportingObserver(handleReports, {
37
+ types: reportTypes,
38
+ buffered: true,
39
+ })
40
+
41
+ observer.observe()
42
+ return function() {
43
+ observer.disconnect()
44
+ }
45
+ })
46
+
47
+ return observable
48
+ }
49
+
50
+ function createCspViolationReportObservable() {
51
+ var observable = new Observable(function() {
52
+ var handleCspViolation = function(event) {
53
+ observable.notify(buildRawReportFromCspViolation(event))
54
+ }
55
+
56
+ var _addEventListener = addEventListener(document, DOM_EVENT.SECURITY_POLICY_VIOLATION, handleCspViolation)
57
+
58
+ return _addEventListener.stop
59
+ })
60
+ return observable
61
+ }
62
+
63
+ function buildRawReportFromReport(report) {
64
+ var body = report.body
65
+ var type = report.type
66
+ return {
67
+ type: type,
68
+ subtype: body.id,
69
+ message: type + ': ' + body.message,
70
+ stack: buildStack(body.id, body.message, body.sourceFile, body.lineNumber, body.columnNumber),
71
+ }
72
+ }
73
+
74
+ function buildRawReportFromCspViolation(event) {
75
+ var type = RawReportType.cspViolation
76
+ var message = '\''+ event.blockedURI + '\' blocked by \'' + event.effectiveDirective + '\' directive'
77
+ return {
78
+ type: RawReportType.cspViolation,
79
+ subtype: event.effectiveDirective,
80
+ message: type + ': ' + message,
81
+ stack: buildStack(
82
+ event.effectiveDirective,
83
+ message + ' of the policy "'+ safeTruncate(event.originalPolicy, 100, '...') + '"',
84
+ event.sourceFile,
85
+ event.lineNumber,
86
+ event.columnNumber
87
+ ),
88
+ }
89
+ }
90
+
91
+ function buildStack(
92
+ name,
93
+ message,
94
+ sourceFile,
95
+ lineNumber,
96
+ columnNumber
97
+ ){
98
+ return (
99
+ sourceFile &&
100
+ toStackTraceString({
101
+ name: name,
102
+ message: message,
103
+ stack: [
104
+ {
105
+ func: '?',
106
+ url: sourceFile,
107
+ line: lineNumber,
108
+ column: columnNumber,
109
+ },
110
+ ],
111
+ })
112
+ )
113
+ }
@@ -0,0 +1,3 @@
1
+ import { ONE_HOUR, ONE_MINUTE } from '../helper/tools'
2
+ export var SESSION_TIME_OUT_DELAY = 4 * ONE_HOUR
3
+ export var SESSION_EXPIRATION_DELAY = 15 * ONE_MINUTE
@@ -0,0 +1,159 @@
1
+ import { getCookie, setCookie } from '../browser/cookie'
2
+ import { isChromium, dateNow, isEmptyObject, UUID, objectEntries,map, each, } from '../helper/tools'
3
+ import { SESSION_EXPIRATION_DELAY } from './sessionConstants'
4
+
5
+ var SESSION_ENTRY_REGEXP = /^([a-z]+)=([a-z0-9-]+)$/
6
+ var SESSION_ENTRY_SEPARATOR = '&'
7
+
8
+ export var SESSION_COOKIE_NAME = '_dataflux_s'
9
+
10
+ // arbitrary values
11
+ export var LOCK_RETRY_DELAY = 10
12
+ export var MAX_NUMBER_OF_LOCK_RETRIES = 100
13
+
14
+
15
+ var bufferedOperations= []
16
+ var ongoingOperations
17
+
18
+ export function withCookieLockAccess(operations, numberOfRetries) {
19
+ if (typeof numberOfRetries === 'undefined') {
20
+ numberOfRetries = 0
21
+ }
22
+ if (!ongoingOperations) {
23
+ ongoingOperations = operations
24
+ }
25
+ if (operations !== ongoingOperations) {
26
+ bufferedOperations.push(operations)
27
+ return
28
+ }
29
+ if (numberOfRetries >= MAX_NUMBER_OF_LOCK_RETRIES) {
30
+ next()
31
+ return
32
+ }
33
+ var currentLock
34
+ var currentSession = retrieveSession()
35
+ if (isCookieLockEnabled()) {
36
+ // if someone has lock, retry later
37
+ if (currentSession.lock) {
38
+ retryLater(operations, numberOfRetries)
39
+ return
40
+ }
41
+ // acquire lock
42
+ currentLock = UUID()
43
+ currentSession.lock = currentLock
44
+ setSession(currentSession, operations.options)
45
+ // if lock is not acquired, retry later
46
+ currentSession = retrieveSession()
47
+ if (currentSession.lock !== currentLock) {
48
+ retryLater(operations, numberOfRetries)
49
+ return
50
+ }
51
+ }
52
+ var processedSession = operations.process(currentSession)
53
+ if (isCookieLockEnabled()) {
54
+ // if lock corrupted after process, retry later
55
+ currentSession = retrieveSession()
56
+ if (currentSession.lock !== currentLock) {
57
+ retryLater(operations, numberOfRetries)
58
+ return
59
+ }
60
+ }
61
+ if (processedSession) {
62
+ persistSession(processedSession, operations.options)
63
+ }
64
+ if (isCookieLockEnabled()) {
65
+ // correctly handle lock around expiration would require to handle this case properly at several levels
66
+ // since we don't have evidence of lock issues around expiration, let's just not do the corruption check for it
67
+ if (!(processedSession && isExpiredState(processedSession))) {
68
+ // if lock corrupted after persist, retry later
69
+ currentSession = retrieveSession()
70
+ if (currentSession.lock !== currentLock) {
71
+ retryLater(operations, numberOfRetries)
72
+ return
73
+ }
74
+ delete currentSession.lock
75
+ setSession(currentSession, operations.options)
76
+ processedSession = currentSession
77
+ }
78
+ }
79
+ // call after even if session is not persisted in order to perform operations on
80
+ // up-to-date cookie value, the value could have been modified by another tab
81
+ if (operations.after) {
82
+ operations.after(processedSession || currentSession)
83
+ }
84
+ next()
85
+ }
86
+
87
+ /**
88
+ * Cookie lock strategy allows mitigating issues due to concurrent access to cookie.
89
+ * This issue concerns only chromium browsers and enabling this on firefox increase cookie write failures.
90
+ */
91
+ function isCookieLockEnabled() {
92
+ return isChromium()
93
+ }
94
+
95
+ function retryLater(operations, currentNumberOfRetries) {
96
+ setTimeout(
97
+ function() {
98
+ withCookieLockAccess(operations, currentNumberOfRetries + 1)
99
+ },
100
+ LOCK_RETRY_DELAY
101
+ )
102
+ }
103
+
104
+ function next() {
105
+ ongoingOperations = undefined
106
+ var nextOperations = bufferedOperations.shift()
107
+ if (nextOperations) {
108
+ withCookieLockAccess(nextOperations)
109
+ }
110
+ }
111
+
112
+ export function persistSession(session, options) {
113
+ if (isExpiredState(session)) {
114
+ clearSession(options)
115
+ return
116
+ }
117
+ session.expire = String(dateNow() + SESSION_EXPIRATION_DELAY)
118
+ setSession(session, options)
119
+ }
120
+
121
+ function setSession(session, options) {
122
+ setCookie(SESSION_COOKIE_NAME, toSessionString(session), SESSION_EXPIRATION_DELAY, options)
123
+ }
124
+
125
+ export function toSessionString(session) {
126
+ return map(objectEntries(session), function(item) {
127
+ return item[0] + '=' + item[1]
128
+ }).join(SESSION_ENTRY_SEPARATOR)
129
+ }
130
+
131
+ export function retrieveSession() {
132
+ var sessionString = getCookie(SESSION_COOKIE_NAME)
133
+ var session = {}
134
+ if (isValidSessionString(sessionString)) {
135
+ each(sessionString.split(SESSION_ENTRY_SEPARATOR), function(entry) {
136
+ var matches = SESSION_ENTRY_REGEXP.exec(entry)
137
+ if (matches !== null) {
138
+ var key = matches[1]
139
+ var value = matches[2]
140
+ session[key] = value
141
+ }
142
+ })
143
+ }
144
+ return session
145
+ }
146
+
147
+ function isValidSessionString(sessionString) {
148
+ return (
149
+ sessionString !== undefined &&
150
+ (sessionString.indexOf(SESSION_ENTRY_SEPARATOR) !== -1 || SESSION_ENTRY_REGEXP.test(sessionString))
151
+ )
152
+ }
153
+
154
+ function isExpiredState(session) {
155
+ return isEmptyObject(session)
156
+ }
157
+ function clearSession(options) {
158
+ setCookie(SESSION_COOKIE_NAME, '', 0, options)
159
+ }
@@ -0,0 +1,89 @@
1
+ import { relativeNow, clocksOrigin, ONE_MINUTE, each, addEventListeners, addEventListener } from '../helper/tools'
2
+ import { ContextHistory } from '../helper/contextHistory'
3
+ import { startSessionStore } from './sessionStore'
4
+ import { SESSION_TIME_OUT_DELAY } from './sessionConstants'
5
+ import { DOM_EVENT } from '../helper/enums'
6
+
7
+ export var VISIBILITY_CHECK_DELAY = ONE_MINUTE
8
+ var SESSION_CONTEXT_TIMEOUT_DELAY = SESSION_TIME_OUT_DELAY
9
+ var stopCallbacks = []
10
+
11
+ export var startSessionManager = function(
12
+ options,
13
+ productKey,
14
+ computeSessionState
15
+ ) {
16
+ var sessionStore = startSessionStore(options, productKey, computeSessionState)
17
+ stopCallbacks.push(function() {
18
+ return sessionStore.stop()
19
+ })
20
+
21
+ var sessionContextHistory = new ContextHistory(SESSION_CONTEXT_TIMEOUT_DELAY)
22
+ stopCallbacks.push(function() {
23
+ return sessionContextHistory.stop()
24
+ })
25
+
26
+ sessionStore.renewObservable.subscribe(function(){
27
+ sessionContextHistory.add(buildSessionContext(), relativeNow())
28
+ })
29
+ sessionStore.expireObservable.subscribe(function() {
30
+ sessionContextHistory.closeActive(relativeNow())
31
+ })
32
+
33
+ sessionStore.expandOrRenewSession()
34
+ sessionContextHistory.add(buildSessionContext(), clocksOrigin().relative)
35
+
36
+ trackActivity(function() {
37
+ return sessionStore.expandOrRenewSession()
38
+ })
39
+ trackVisibility(function() {
40
+ return sessionStore.expandSession()
41
+ })
42
+
43
+ function buildSessionContext() {
44
+ return {
45
+ id: sessionStore.getSession().id,
46
+ trackingType: sessionStore.getSession()[productKey],
47
+ }
48
+ }
49
+
50
+ return {
51
+ findActiveSession: function(startTime) {
52
+ return sessionContextHistory.find(startTime)
53
+ },
54
+ renewObservable: sessionStore.renewObservable,
55
+ expireObservable: sessionStore.expireObservable,
56
+ }
57
+ }
58
+
59
+ export function stopSessionManager() {
60
+ each(stopCallbacks, function(e) {
61
+ return e()
62
+ })
63
+ stopCallbacks = []
64
+ }
65
+
66
+ function trackActivity(expandOrRenewSession) {
67
+ var _addEventListeners = addEventListeners(
68
+ window,
69
+ [DOM_EVENT.CLICK,DOM_EVENT.TOUCH_START, DOM_EVENT.KEY_DOWN, DOM_EVENT.SCROLL],
70
+ expandOrRenewSession,
71
+ { capture: true, passive: true }
72
+ )
73
+ stopCallbacks.push(_addEventListeners.stop)
74
+ }
75
+
76
+ function trackVisibility(expandSession) {
77
+ var expandSessionWhenVisible = function() {
78
+ if (document.visibilityState === 'visible') {
79
+ expandSession()
80
+ }
81
+ }
82
+ var _addEventListener= addEventListener(document, DOM_EVENT.VISIBILITY_CHANGE, expandSessionWhenVisible)
83
+ stopCallbacks.push(_addEventListener.stop)
84
+
85
+ var visibilityCheckInterval = setInterval(expandSessionWhenVisible, VISIBILITY_CHECK_DELAY)
86
+ stopCallbacks.push(function() {
87
+ clearInterval(visibilityCheckInterval)
88
+ })
89
+ }