@aicore/core-analytics-client-lib 1.0.4 → 1.0.7

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/README.md CHANGED
@@ -19,71 +19,127 @@ events for [Core-Analytics-Server](https://github.com/aicore/Core-Analytics-Serv
19
19
 
20
20
  # Usage
21
21
 
22
- ## Initialize the session
23
- Embed the script in your HTML file :
22
+ ## Load the Library
23
+ Embed the script in your HTML file and replace `your_analytics_account_ID` and `appName`
24
+ in the `initAnalyticsSession` call below:
24
25
  ```html
25
- <html lang="en">
26
- <script type="module">
27
- // For production use cases, use url: https://unpkg.com/@aicore/core-analytics-client-lib/dist/analytics.min.js
28
- // The below url is for development purposes only.
29
- import {initSession} from "https://unpkg.com/@aicore/core-analytics-client-lib/src/analytics.js";
30
- initSession("accountID", "appName");
26
+ <!-- Global window.analytics object - core.ai analytics services -->
27
+ <script async src="https://unpkg.com/@aicore/core-analytics-client-lib/src/analytics.js"
28
+ onload="analyticsLibLoaded()"></script>
29
+ <script>
30
+ if(!window.analytics){ window.analytics = {
31
+ _initData : [], loadStartTime: new Date().getTime(),
32
+ event: function (){window.analytics._initData.push(arguments);}
33
+ };}
34
+ function analyticsLibLoaded() {
35
+ initAnalyticsSession('your_analytics_account_ID', 'appName');
36
+ analytics.event("core-analytics", "client-lib", "loadTime", 1, (new Date().getTime())-analytics.loadStartTime);
37
+ }
31
38
  </script>
32
- </html>
33
39
  ```
40
+ This will create a global `analytics` variable which can be used to access the analytics APIs.
34
41
 
35
- initSession(): Initialize the analytics session. It takes the following parameters:
36
-
37
- * `accountID`: Your analytics account id as configured in the server or core.ai analytics
38
- * `appName`: The app name to log the events against. Eg: "phoenixCode"
39
- * `postIntervalSeconds` (_Optional_): This defines the interval between sending analytics events to the server. Default is 10 minutes
40
- * `granularitySec` (_Optional_): The smallest time period under which the events can be distinguished. Multiple
41
- events happening during this time period is aggregated to a count. The default granularity is 3 Seconds, which means
42
- that any events that happen within 3 seconds cannot be distinguished in ordering.
43
- * `analyticsURL` (_Optional_): Provide your own analytics server address if you self-hosted the server
44
- * `debug` (_Optional_): set to true if you want to see detailed debug logs.
45
-
46
- ```javascript
47
- // Example for custom initSession where the analytics aggregated data
48
- // is posted to custom server https://localhost:3000 every 600 secs
49
- // with a granularity(resolution) of 5 seconds.
50
-
51
- initSession("accountID", "appName", "https://localhost:3000", 600, 5);
52
-
53
- // To initSession in debug mode set debug arg in init to true:
54
- initSession("accountID", "appName", "https://localhost:3000", 600, 5, true);
55
- ```
42
+ NB: The script is loaded async, so it will not block other js scripts. `analytics.event` api can be called anytime
43
+ after the above code and need not wait for the script load to complete.
56
44
 
57
45
  ## Raising analytics events
58
- Once `initSession` is called, we can now start logging analytics events by calling `analyticsEvent` API.
59
- The API registers an analytics event. The events will be aggregated and send to the analytics server periodically.
46
+ We can now start logging analytics events by calling `analytics.event` API.
47
+ The events will be aggregated and send to the analytics server periodically.
60
48
 
61
49
  ```javascript
62
50
  // analyticsEvent(eventType, eventCategory, subCategory, eventCount, eventValue);
63
51
 
64
52
  // Eg: event without counts and values
65
- analyticsEvent("platform", "os", "linux");
53
+ analytics.event("platform", "os", "linux");
66
54
 
67
55
  // Eg: event with count, here it logs that html file is opened 100 times
68
- analyticsEvent("file", "opened", "html", 100);
56
+ analytics.event("file", "opened", "html", 100);
69
57
 
70
58
  // Eg: event with count and value, here it logs that the startup time is 250 milliseconds.
71
59
  // Note that the value is unitless from analytics perspective. unit is deduced from subCategory name
72
- analyticsEvent("platform", "performance", "startupTimeMs", 1, 250);
60
+ analytics.event("platform", "performance", "startupTimeMs", 1, 250);
73
61
 
74
62
  // Eg: event with fractional value.
75
- analyticsEvent("platform", "CPU", "utilization", 1, .45);
63
+ analytics.event("platform", "CPU", "utilization", 1, .45);
76
64
  // Eg. Here we register that the system has 8 cores with each core having 2300MHz frequency.
77
- analyticsEvent("platform", "CPU", "coreCountsAndFrequencyMhz", 8, 2300);
65
+ analytics.event("platform", "CPU", "coreCountsAndFrequencyMhz", 8, 2300);
78
66
  ```
79
67
  ### API parameters
80
68
  * `eventType` - A string, required
81
69
  * `eventCategory` - A string, required
82
70
  * `subCategory` - A string, required
83
71
  * `eventCount` (_Optional_) : A non-negative number indicating the number of times the event (or an event with a
84
- particular value if a value is specified) happened. defaults to 1.
72
+ particular value if a value is specified) happened. defaults to 1.
85
73
  * `eventValue` (_Optional_) : A number value associated with the event. defaults to 0
86
74
 
75
+
76
+ ## Advanced Usages
77
+
78
+ ### Pure JS loading instead of HTML scripts
79
+
80
+ There may be cases where you would want to load the script from JS alone. For Eg. you
81
+ may want to delay library loading till user consents GDPR. For such use cases, use the below code.
82
+
83
+ ```js
84
+ function _initCoreAnalytics() {
85
+ // Load core analytics scripts
86
+ if(!window.analytics){ window.analytics = {
87
+ _initData: [], loadStartTime: new Date().getTime(),
88
+ event: function (){window.analytics._initData.push(arguments);}
89
+ };}
90
+ let script = document.createElement('script');
91
+ script.type = 'text/javascript';
92
+ script.async = true;
93
+ script.onload = function(){
94
+ // replace `your_analytics_account_ID` and `appName` below with your values
95
+ window.initAnalyticsSession('your_analytics_account_ID', 'appName'); // if you have a custom analytics server
96
+ window.analytics.event("core-analytics", "client-lib", "loadTime", 1,
97
+ (new Date().getTime())- window.analytics.loadStartTime);
98
+ };
99
+ script.src = 'https://unpkg.com/@aicore/core-analytics-client-lib/dist/analytics.min.js';
100
+ document.getElementsByTagName('head')[0].appendChild(script);
101
+ }
102
+ _initCoreAnalytics();
103
+ ```
104
+ To load the library, just call `_initCoreAnalytics()` from JS. Note that you may not be able
105
+ to use `analytics.event()` APIs before `_initCoreAnalytics()` call is made.
106
+
107
+ ### initAnalyticsSession: modify when, where and how analytics lib sends events
108
+ If you want to modify how analytics library collects and sends information, it is recommended to do so
109
+ with analytics server [accountConfig](https://github.com/aicore/Core-Analytics-Server#accountconfig-configuration).
110
+
111
+ Alternatively for one off development time uses, the behavior of the library can be configured
112
+ during the `initAnalyticsSession` call. `initAnalyticsSession()` takes the following parameters:
113
+
114
+ * `accountID`: Your analytics account id as configured in the server or core.ai analytics
115
+ * `appName`: The app name to log the events against. Eg: "phoenixCode"
116
+ * `postIntervalSeconds` (_Optional_): This defines the interval between sending analytics events to the server. Default is 10 minutes
117
+ * `granularitySec` (_Optional_): The smallest time period under which the events can be distinguished. Multiple
118
+ events happening during this time period is aggregated to a count. The default granularity is 3 Seconds, which means
119
+ that any events that happen within 3 seconds cannot be distinguished in ordering.
120
+ * `analyticsURL` (_Optional_): Provide your own analytics server address if you self-hosted the server
121
+ * `debug` (_Optional_): set to true if you want to see detailed debug logs.
122
+
123
+ ### usageExample
124
+ ```javascript
125
+ // Init with default values and server controlled config. use the following `analyticsLibLoaded` function
126
+ function analyticsLibLoaded() {
127
+ initAnalyticsSession('your_analytics_account_ID', 'appName');
128
+ analytics.event("core-analytics", "client-lib", "loadTime", 1, (new Date().getTime())-analytics.loadStartTime);
129
+ }
130
+
131
+ //Replace initAnalyticsSession in analyticsLibLoaded function for the below use cases.
132
+
133
+ // Example for custom initSession where the analytics aggregated data
134
+ // is posted to custom server https://localhost:3000 every 600 secs
135
+ // with a granularity(resolution) of 5 seconds.
136
+ initAnalyticsSession("accountID", "appName", "https://localhost:3000", 600, 5);
137
+
138
+ // To initSession in debug mode set debug arg in init to true. In debug mode, details logs
139
+ // about analytics library events will be emitted.
140
+ initAnalyticsSession("accountID", "appName", "https://localhost:3000", 600, 5, true);
141
+ ```
142
+
87
143
  # Contribute to core-analytics-client-lib
88
144
 
89
145
  ## Building
@@ -1,4 +1,4 @@
1
- let accountID,appName,userID,sessionID,postIntervalSeconds,granularitySec,analyticsURL,postURL,serverConfig;const DEFAULT_GRANULARITY_IN_SECONDS=3,DEFAULT_RETRY_TIME_IN_SECONDS=30,DEFAULT_POST_INTERVAL_SECONDS=600,USERID_LOCAL_STORAGE_KEY="aicore.analytics.userID",POST_LARGE_DATA_THRESHOLD_BYTES=1e4;let currentAnalyticsEvent=null;const IS_NODE_ENV="undefined"==typeof window;let DEFAULT_BASE_URL="https://analytics.core.ai",granularityTimer,postTimer,currentQuantisedTime=0,disabled=!1,debugMode=!1;function debugLog(...e){debugMode&&console.log(...e)}function debugError(...e){debugMode&&console.error(...e)}if(IS_NODE_ENV)throw new Error("Node environment is not currently supported");function _createAnalyticsEvent(){return{schemaVersion:1,accountID:accountID,appName:appName,uuid:userID,sessionID:sessionID,unixTimestampUTC:+new Date,numEventsTotal:0,events:{}}}function _validateCurrentState(){if(!currentAnalyticsEvent)throw new Error("Please call initSession before using any analytics event")}function getCurrentAnalyticsEvent(){return _validateCurrentState(),JSON.parse(JSON.stringify(currentAnalyticsEvent))}function _getOrCreateUserID(){let e=localStorage.getItem(USERID_LOCAL_STORAGE_KEY);return e||(e=crypto.randomUUID(),localStorage.setItem(USERID_LOCAL_STORAGE_KEY,e)),e}function _getOrCreateSessionID(){let e=sessionStorage.getItem(USERID_LOCAL_STORAGE_KEY);return e||(e=Math.random().toString(36).substr(2,10),sessionStorage.setItem(USERID_LOCAL_STORAGE_KEY,e)),e}function _setupIDs(){userID=_getOrCreateUserID(),sessionID=_getOrCreateSessionID()}function _retryPost(e){e.backoffCount=(e.backoffCount||0)+1,debugLog(`Failed to call core analytics server. Will retry in ${DEFAULT_RETRY_TIME_IN_SECONDS*e.backoffCount}s: `),setTimeout(()=>{_postCurrentAnalyticsEvent(e)},1e3*DEFAULT_RETRY_TIME_IN_SECONDS*e.backoffCount)}function _postCurrentAnalyticsEvent(t){var e;disabled||(t||(t=currentAnalyticsEvent,currentQuantisedTime=0,_resetGranularityTimer(),currentAnalyticsEvent=_createAnalyticsEvent()),0!==t.numEventsTotal&&((e=JSON.stringify(t)).length>POST_LARGE_DATA_THRESHOLD_BYTES&&console.warn(`Analytics event generated is very large at greater than ${e.length}B. This
2
- typically means that you may be sending too many value events? .`),debugLog("Sending Analytics data of length: ",e.length,"B"),window.fetch(postURL,{method:"POST",headers:{"Content-Type":"application/json"},body:e}).then(e=>{200!==e.status&&(400!==e.status?_retryPost(t):console.error("Analytics client: Bad Request, this is most likely a problem with the library, update to latest version."))}).catch(e=>{debugError(e),_retryPost(t)})))}function _resetGranularityTimer(e){granularityTimer&&(clearInterval(granularityTimer),granularityTimer=null),e||(granularityTimer=setInterval(()=>{currentQuantisedTime+=granularitySec},1e3*granularitySec))}function _setupTimers(e){_resetGranularityTimer(e),postTimer&&(clearInterval(postTimer),postTimer=null),e||(postTimer=setInterval(_postCurrentAnalyticsEvent,1e3*postIntervalSeconds))}async function _getServerConfig(){return new Promise((n,r)=>{var e=analyticsURL+(`/getAppConfig?accountID=${accountID}&appName=`+appName);window.fetch(e).then(async e=>{switch(e.status){case 200:var t=await e.json();return void n(t);case 400:r("Bad Request, check library version compatible?",e);break;default:r("analytics client: Could not update from remote config. Continuing with defaults.",e)}}).catch(e=>{r("analytics client: Could not update from remote config. Continuing with defaults.",e)})})}function getAppConfig(){return{accountID:accountID,appName:appName,disabled:disabled,uuid:userID,sessionID:sessionID,postIntervalSeconds:postIntervalSeconds,granularitySec:granularitySec,analyticsURL:analyticsURL,serverConfig:serverConfig}}async function _initFromRemoteConfig(e,t){(serverConfig=await _getServerConfig())!=={}&&(postIntervalSeconds=e||serverConfig.postIntervalSecondsInit||DEFAULT_POST_INTERVAL_SECONDS,granularitySec=t||serverConfig.granularitySecInit||DEFAULT_GRANULARITY_IN_SECONDS,analyticsURL=serverConfig.analyticsURLInit||analyticsURL||DEFAULT_BASE_URL,_setupTimers(disabled=!0===serverConfig.disabled),debugLog(`Init analytics Config from remote. disabled: ${disabled}
3
- postIntervalSeconds:${postIntervalSeconds}, granularitySec: ${granularitySec} ,URL: `+analyticsURL),disabled&&console.warn(`Core Analytics is disabled from the server for app: ${accountID}:`+appName))}function _stripTrailingSlash(e){return e.replace(/\/$/,"")}function initSession(e,t,n,r,a,i){if(!e||!t)throw new Error("accountID and appName must exist for init");analyticsURL=n?_stripTrailingSlash(n):DEFAULT_BASE_URL,accountID=e,appName=t,debugMode=i||!1,postIntervalSeconds=r||DEFAULT_POST_INTERVAL_SECONDS,granularitySec=a||DEFAULT_GRANULARITY_IN_SECONDS,postURL=analyticsURL+"/ingest",_setupIDs(),currentAnalyticsEvent=_createAnalyticsEvent(),_setupTimers(),_initFromRemoteConfig(r,a)}function _ensureAnalyticsEventExists(e,t,n){let r=currentAnalyticsEvent.events;r[e]=r[e]||{},r[e][t]=r[e][t]||{},r[e][t][n]=r[e][t][n]||{time:[],valueCount:[]}}function _validateEvent(e,t,n,r,a){if(_validateCurrentState(),!e||!t||!n)throw new Error("missing eventType or category or subCategory");if("number"!=typeof r||r<0)throw new Error("invalid count");if("number"!=typeof a)throw new Error("invalid value")}function _updateExistingAnalyticsEvent(t,n,r,a,i,s){let o=currentAnalyticsEvent.events;var e="number"==typeof o[n][r][a].valueCount[t];if(e&&0===s)o[n][r][a].valueCount[t]+=i;else if(e&&0!==s){let e={};e[s]=i,e[0]=o[n][r][a].valueCount[t],o[n][r][a].valueCount[t]=e}else if(!e){let e=o[n][r][a].valueCount[t];e[s]=(e[s]||0)+i}currentAnalyticsEvent.numEventsTotal+=1}function analyticsEvent(n,r,a,i=1,s=0){if(!disabled){_validateEvent(n,r,a,i,s),_ensureAnalyticsEventExists(n,r,a);let t=currentAnalyticsEvent.events;var e=t[n][r][a].time;if((0<e.length?e[e.length-1]:null)!==currentQuantisedTime){if(t[n][r][a].time.push(currentQuantisedTime),0===s)t[n][r][a].valueCount.push(i);else{let e={};e[s]=i,t[n][r][a].valueCount.push(e)}currentAnalyticsEvent.numEventsTotal+=1}else _updateExistingAnalyticsEvent(t[n][r][a].valueCount.length-1,n,r,a,i,s)}}export{initSession,getCurrentAnalyticsEvent,analyticsEvent,getAppConfig};
1
+ function initAnalyticsSession(e,t,n,a,o,i){let s,r,l,u,c,f,y,v,d={};const m=30,p="aicore.analytics.userID",g="aicore.analytics.sessionID",h=1e4;let w=null;var C,b="undefined"==typeof window;let I="https://analytics.core.ai",S,D,E=0,T=!1,A=!1;function N(...e){A&&console.log(...e)}if(b)throw new Error("Node environment is not currently supported");function $(){return{schemaVersion:1,accountID:s,appName:r,uuid:l,sessionID:u,unixTimestampUTC:+new Date,numEventsTotal:0,events:{}}}function k(){if(!w)throw new Error("Please call initSession before using any analytics event")}function U(e){e.backoffCount=(e.backoffCount||0)+1,N(`Failed to call core analytics server. Will retry in ${m*e.backoffCount}s: `),setTimeout(()=>{R(e)},1e3*m*e.backoffCount)}function R(t){var e;T||(t||(t=w,E=0,_(),w=$()),0!==t.numEventsTotal&&((e=JSON.stringify(t)).length>h&&console.warn(`Analytics event generated is very large at greater than ${e.length}B. This
2
+ typically means that you may be sending too many value events? .`),N("Sending Analytics data of length: ",e.length,"B"),window.fetch(v,{method:"POST",headers:{"Content-Type":"application/json"},body:e}).then(e=>{200!==e.status&&(400!==e.status?U(t):console.error("Analytics client: Bad Request, this is most likely a problem with the library, update to latest version."))}).catch(e=>{e=[e],A&&console.error(...e),U(t)})))}function _(e){S&&(clearInterval(S),S=null),e||(S=setInterval(()=>{E+=f},1e3*f))}function B(e){_(e),D&&(clearInterval(D),D=null),e||(D=setInterval(R,1e3*c))}function O(n,a,o,i=1,s=0){if(!T){var r=n,l=a,u=o,c=i,f=s;if(k(),!r||!l||!u)throw new Error("missing eventType or category or subCategory");if("number"!=typeof c||c<0)throw new Error("invalid count, count should be a positive number");if("number"!=typeof f)throw new Error("invalid value, value should be a number");{r=n;l=a;u=o;let e=w.events;e[r]=e[r]||{},e[r][l]=e[r][l]||{},e[r][l][u]=e[r][l][u]||{time:[],valueCount:[]}}let t=w.events;c=t[n][a][o].time;if((0<c.length?c[c.length-1]:null)===E){f=t[n][a][o].valueCount.length-1;{var r=f,l=n,u=a,c=o,f=i,y=s;let t=w.events;var e="number"==typeof t[l][u][c].valueCount[r];if(e&&0===y)t[l][u][c].valueCount[r]+=f;else if(e&&0!==y){let e={};e[y]=f,e[0]=t[l][u][c].valueCount[r],t[l][u][c].valueCount[r]=e}else if(!e){let e=t[l][u][c].valueCount[r];e[y]=(e[y]||0)+f}w.numEventsTotal+=1}}else{if(t[n][a][o].time.push(E),0===s)t[n][a][o].valueCount.push(i);else{let e={};e[s]=i,t[n][a][o].valueCount.push(e)}w.numEventsTotal+=1}}}if(!e||!t)throw new Error("accountID and appName must exist for init");y=n?n.replace(/\/$/,""):I,s=e,r=t,A=i||!1,c=a||600,f=o||3,v=y+"/ingest",l=function(){let e=localStorage.getItem(p);return e||(e=crypto.randomUUID(),localStorage.setItem(p,e)),e}(),u=function(){let e=sessionStorage.getItem(g);return e||(e=Math.random().toString(36).substr(2,10),sessionStorage.setItem(g,e)),e}(),w=$(),B(),async function(e,t){(d=await new Promise((n,a)=>{var e=y+(`/getAppConfig?accountID=${s}&appName=`+r);window.fetch(e).then(async e=>{switch(e.status){case 200:var t=await e.json();return void n(t);case 400:a("Bad Request, check library version compatible?",e);break;default:a("analytics client: Could not update from remote config. Continuing with defaults.",e)}}).catch(e=>{a("analytics client: Could not update from remote config. Continuing with defaults.",e)})}))!=={}&&(c=e||d.postIntervalSecondsInit||600,f=t||d.granularitySecInit||3,y=d.analyticsURLInit||y||I,B(T=!0===d.disabled),N(`Init analytics Config from remote. disabled: ${T}
3
+ postIntervalSeconds:${c}, granularitySec: ${f} ,URL: `+y),T&&console.warn(`Core Analytics is disabled from the server for app: ${s}:`+r))}(a,o);for(C of analytics._initData)O(...C);analytics._initData=[],analytics._getCurrentAnalyticsEvent=function(){return k(),JSON.parse(JSON.stringify(w))},analytics._getAppConfig=function(){return{accountID:s,appName:r,disabled:T,uuid:l,sessionID:u,postIntervalSeconds:c,granularitySec:f,analyticsURL:y,serverConfig:d}},analytics.event=O}window.analytics||(window.analytics={_initData:[]});
4
4
  //# sourceMappingURL=analytics.min.js.map
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"src/analytics.js","sources":["src/analytics.js"],"names":["let","accountID","appName","userID","sessionID","postIntervalSeconds","granularitySec","analyticsURL","postURL","serverConfig","DEFAULT_GRANULARITY_IN_SECONDS","DEFAULT_RETRY_TIME_IN_SECONDS","DEFAULT_POST_INTERVAL_SECONDS","USERID_LOCAL_STORAGE_KEY","POST_LARGE_DATA_THRESHOLD_BYTES","currentAnalyticsEvent","IS_NODE_ENV","window","DEFAULT_BASE_URL","granularityTimer","postTimer","currentQuantisedTime","disabled","debugMode","debugLog","args","console","log","debugError","error","Error","_createAnalyticsEvent","schemaVersion","uuid","unixTimestampUTC","Date","numEventsTotal","events","_validateCurrentState","getCurrentAnalyticsEvent","JSON","parse","stringify","_getOrCreateUserID","localUserID","localStorage","getItem","crypto","randomUUID","setItem","_getOrCreateSessionID","localSessionID","sessionStorage","Math","random","toString","substr","_setupIDs","_retryPost","eventToSend","backoffCount","setTimeout","_postCurrentAnalyticsEvent","textToSend","_resetGranularityTimer","length","warn","fetch","method","headers","Content-Type","body","then","res","status","catch","disable","clearInterval","setInterval","_setupTimers","async","_getServerConfig","Promise","resolve","reject","configURL","serverResponse","json","err","getAppConfig","_initFromRemoteConfig","postIntervalSecondsInit","granularitySecInit","_stripTrailingSlash","url","replace","initSession","accountIDInit","appNameInit","analyticsURLInit","debug","_ensureAnalyticsEventExists","eventType","category","subCategory","time","valueCount","_validateEvent","count","value","_updateExistingAnalyticsEvent","index","newValue","storedValueIsCount","newValueCount","storedValueObject","analyticsEvent","eventCategory","eventCount","eventValue","timeArray","push"],"mappings":"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"}
1
+ {"version":3,"sourceRoot":"src/analytics.js","sources":["src/analytics.js"],"names":["initAnalyticsSession","accountIDInit","appNameInit","analyticsURLInit","postIntervalSecondsInit","granularitySecInit","debug","let","accountID","appName","userID","sessionID","postIntervalSeconds","granularitySec","analyticsURL","postURL","serverConfig","DEFAULT_RETRY_TIME_IN_SECONDS","USERID_LOCAL_STORAGE_KEY","SESSION_ID_LOCAL_STORAGE_KEY","POST_LARGE_DATA_THRESHOLD_BYTES","currentAnalyticsEvent","eventData","IS_NODE_ENV","window","DEFAULT_BASE_URL","granularityTimer","postTimer","currentQuantisedTime","disabled","debugMode","debugLog","args","console","log","Error","_createAnalyticsEvent","schemaVersion","uuid","unixTimestampUTC","Date","numEventsTotal","events","_validateCurrentState","_retryPost","eventToSend","backoffCount","setTimeout","_postCurrentAnalyticsEvent","textToSend","_resetGranularityTimer","JSON","stringify","length","warn","fetch","method","headers","Content-Type","body","then","res","status","error","catch","debugError","disable","clearInterval","setInterval","_setupTimers","event","eventType","eventCategory","subCategory","eventCount","eventValue","_validateEvent","category","count","value","_ensureAnalyticsEventExists","time","valueCount","timeArray","modificationIndex","_updateExistingAnalyticsEvent","index","newValue","storedValueIsCount","newValueCount","storedValueObject","push","replace","localUserID","localStorage","getItem","crypto","randomUUID","setItem","_getOrCreateUserID","localSessionID","sessionStorage","Math","random","toString","substr","_getOrCreateSessionID","async","postIntervalSecondsInitial","granularitySecInitial","Promise","resolve","reject","configURL","serverResponse","json","err","_initFromRemoteConfig","analytics","_initData","_getCurrentAnalyticsEvent","parse","_getAppConfig"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicore/core-analytics-client-lib",
3
- "version": "1.0.4",
3
+ "version": "1.0.7",
4
4
  "description": "Analytics client library for https://github.com/aicore/Core-Analytics-Server",
5
5
  "main": "dist/analytics.min.js",
6
6
  "type": "module",
@@ -19,17 +19,18 @@
19
19
  "lint": "eslint --quiet src test",
20
20
  "lint:fix": "eslint --quiet --fix src test",
21
21
  "prepare": "husky install",
22
- "test": "echo please open test/index.html in browser to run tests",
23
- "test:unit": "echo please open test/index.html in browser to run tests",
22
+ "test": "echo please run - npm run serve - and then open test/unit-test.html in browser to run tests",
23
+ "test:unit": "npm run test",
24
24
  "test:integ": "echo integration tests are disabled in this repo",
25
- "cover": "echo please open test/index.html in browser to run tests",
26
- "cover:unit": "echo please open test/index.html in browser to run tests",
27
- "cover:integ": "echo please open test/index.html in browser to run tests",
28
- "build": "",
25
+ "cover": "echo no coverage for now",
26
+ "cover:unit": "echo no coverage for now",
27
+ "cover:integ": "echo no coverage for now",
28
+ "build": "npm run minify",
29
29
  "minify": "echo creating minified package dist/analytics.min.js && mkdir -p dist && uglifyjs src/analytics.js --compress --mangle -o dist/analytics.min.js -c -m --source-map \"root='src/analytics.js',url='analytics.min.js.map'\"",
30
30
  "bumpPatchVersion": "npm --no-git-tag-version version patch",
31
31
  "bumpPatchVersionWithGitTag": "npm version patch",
32
- "release": "npm run minify && npm run bumpPatchVersionWithGitTag"
32
+ "release": "npm run minify && npm run bumpPatchVersionWithGitTag",
33
+ "serve": "http-server . -p 8000 -c-1"
33
34
  },
34
35
  "files": [
35
36
  "src",
@@ -53,6 +54,7 @@
53
54
  "eslint": "8.15.0",
54
55
  "husky": "7.0.4",
55
56
  "mocha": "9.2.2",
56
- "uglify-js": "3.15.5"
57
+ "uglify-js": "3.15.5",
58
+ "http-server": "14.1.0"
57
59
  }
58
60
  }
package/src/analytics.js CHANGED
@@ -1,233 +1,318 @@
1
1
  // GNU AGPL-3.0 License Copyright (c) 2021 - present core.ai . All rights reserved.
2
2
 
3
3
  // jshint ignore: start
4
- /*global localStorage, sessionStorage, crypto*/
4
+ /*global localStorage, sessionStorage, crypto, analytics*/
5
5
 
6
- let accountID, appName, userID, sessionID, postIntervalSeconds, granularitySec, analyticsURL, postURL, serverConfig;
7
- const DEFAULT_GRANULARITY_IN_SECONDS = 3;
8
- const DEFAULT_RETRY_TIME_IN_SECONDS = 30;
9
- const DEFAULT_POST_INTERVAL_SECONDS = 600; // 10 minutes
10
- const USERID_LOCAL_STORAGE_KEY = 'aicore.analytics.userID';
11
- const POST_LARGE_DATA_THRESHOLD_BYTES = 10000;
12
- let currentAnalyticsEvent = null;
13
- const IS_NODE_ENV = (typeof window === 'undefined');
14
- let DEFAULT_BASE_URL = "https://analytics.core.ai";
15
6
 
16
- let granularityTimer;
17
- let postTimer;
18
- let currentQuantisedTime = 0;
19
- let disabled = false;
20
- let debugMode = false;
21
-
22
- function debugLog(...args) {
23
- if(!debugMode){
24
- return;
25
- }
26
- console.log(...args);
27
- }
28
-
29
- function debugError(...args) {
30
- if(!debugMode){
31
- return;
32
- }
33
- console.error(...args);
7
+ if(!window.analytics){
8
+ window.analytics = {
9
+ _initData: []
10
+ };
34
11
  }
35
12
 
13
+ /**
14
+ * Initialize the analytics session
15
+ * @param accountIDInit Your analytics account id as configured in the server or core.ai analytics
16
+ * @param appNameInit The app name to log the events against.
17
+ * @param analyticsURLInit Optional: Provide your own analytics server address if you self-hosted the server
18
+ * @param postIntervalSecondsInit Optional: This defines the interval between sending analytics events to the server.
19
+ * Default is 10 minutes
20
+ * @param granularitySecInit Optional: The smallest time period under which the events can be distinguished. Multiple
21
+ * events happening during this time period is aggregated to a count. The default granularity is 3 Seconds, which means
22
+ * that any events that happen within 3 seconds cannot be distinguished in ordering.
23
+ * @param debug set to true if you want to see detailed debug logs.
24
+ */
25
+ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
26
+ postIntervalSecondsInit, granularitySecInit, debug) {
27
+ let accountID, appName, userID, sessionID, postIntervalSeconds,
28
+ granularitySec, analyticsURL, postURL, serverConfig={};
29
+ const DEFAULT_GRANULARITY_IN_SECONDS = 3;
30
+ const DEFAULT_RETRY_TIME_IN_SECONDS = 30;
31
+ const DEFAULT_POST_INTERVAL_SECONDS = 600; // 10 minutes
32
+ const USERID_LOCAL_STORAGE_KEY = 'aicore.analytics.userID';
33
+ const SESSION_ID_LOCAL_STORAGE_KEY = 'aicore.analytics.sessionID';
34
+ const POST_LARGE_DATA_THRESHOLD_BYTES = 10000;
35
+ let currentAnalyticsEvent = null;
36
+ const IS_NODE_ENV = (typeof window === 'undefined');
37
+ let DEFAULT_BASE_URL = "https://analytics.core.ai";
36
38
 
37
- if(IS_NODE_ENV){
38
- throw new Error("Node environment is not currently supported");
39
- }
39
+ let granularityTimer;
40
+ let postTimer;
41
+ let currentQuantisedTime = 0;
42
+ let disabled = false;
43
+ let debugMode = false;
40
44
 
41
- function _createAnalyticsEvent() {
42
- return {
43
- schemaVersion: 1,
44
- accountID: accountID,
45
- appName: appName,
46
- uuid: userID,
47
- sessionID: sessionID,
48
- unixTimestampUTC: +new Date(),
49
- numEventsTotal: 0,
50
- events: {}
51
- };
52
- }
45
+ function debugLog(...args) {
46
+ if(!debugMode){
47
+ return;
48
+ }
49
+ console.log(...args);
50
+ }
53
51
 
54
- function _validateCurrentState() {
55
- if(!currentAnalyticsEvent){
56
- throw new Error("Please call initSession before using any analytics event");
52
+ function debugError(...args) {
53
+ if(!debugMode){
54
+ return;
55
+ }
56
+ console.error(...args);
57
57
  }
58
- }
59
58
 
60
- function getCurrentAnalyticsEvent() {
61
- _validateCurrentState();
62
- // return a clone
63
- return JSON.parse(JSON.stringify(currentAnalyticsEvent));
64
- }
65
59
 
66
- function _getOrCreateUserID() {
67
- let localUserID = localStorage.getItem(USERID_LOCAL_STORAGE_KEY);
68
- if(!localUserID){
69
- localUserID = crypto.randomUUID();
70
- localStorage.setItem(USERID_LOCAL_STORAGE_KEY, localUserID);
60
+ if(IS_NODE_ENV){
61
+ throw new Error("Node environment is not currently supported");
71
62
  }
72
- return localUserID;
73
- }
74
63
 
75
- function _getOrCreateSessionID() {
76
- let localSessionID = sessionStorage.getItem(USERID_LOCAL_STORAGE_KEY);
77
- if(!localSessionID){
78
- localSessionID = Math.random().toString(36).substr(2, 10);
79
- sessionStorage.setItem(USERID_LOCAL_STORAGE_KEY, localSessionID);
64
+ function _createAnalyticsEvent() {
65
+ return {
66
+ schemaVersion: 1,
67
+ accountID: accountID,
68
+ appName: appName,
69
+ uuid: userID,
70
+ sessionID: sessionID,
71
+ unixTimestampUTC: +new Date(),
72
+ numEventsTotal: 0,
73
+ events: {}
74
+ };
80
75
  }
81
- return localSessionID;
82
- }
83
76
 
84
- function _setupIDs() {
85
- userID = _getOrCreateUserID();
86
- sessionID = _getOrCreateSessionID();
87
- }
77
+ function _validateCurrentState() {
78
+ if(!currentAnalyticsEvent){
79
+ throw new Error("Please call initSession before using any analytics event");
80
+ }
81
+ }
88
82
 
89
- function _retryPost(eventToSend) {
90
- eventToSend.backoffCount = (eventToSend.backoffCount || 0) + 1;
91
- debugLog(`Failed to call core analytics server. Will retry in ${
92
- DEFAULT_RETRY_TIME_IN_SECONDS * eventToSend.backoffCount}s: `);
93
- setTimeout(()=>{
94
- _postCurrentAnalyticsEvent(eventToSend);
95
- }, DEFAULT_RETRY_TIME_IN_SECONDS * 1000 * eventToSend.backoffCount);
96
- }
83
+ function _getCurrentAnalyticsEvent() {
84
+ _validateCurrentState();
85
+ // return a clone
86
+ return JSON.parse(JSON.stringify(currentAnalyticsEvent));
87
+ }
97
88
 
98
- function _postCurrentAnalyticsEvent(eventToSend) {
99
- if(disabled){
100
- return;
89
+ function _getOrCreateUserID() {
90
+ let localUserID = localStorage.getItem(USERID_LOCAL_STORAGE_KEY);
91
+ if(!localUserID){
92
+ localUserID = crypto.randomUUID();
93
+ localStorage.setItem(USERID_LOCAL_STORAGE_KEY, localUserID);
94
+ }
95
+ return localUserID;
101
96
  }
102
- if(!eventToSend){
103
- eventToSend = currentAnalyticsEvent;
104
- currentQuantisedTime = 0;
105
- _resetGranularityTimer();
106
- currentAnalyticsEvent = _createAnalyticsEvent();
97
+
98
+ function _getOrCreateSessionID() {
99
+ let localSessionID = sessionStorage.getItem(SESSION_ID_LOCAL_STORAGE_KEY);
100
+ if(!localSessionID){
101
+ localSessionID = Math.random().toString(36).substr(2, 10);
102
+ sessionStorage.setItem(SESSION_ID_LOCAL_STORAGE_KEY, localSessionID);
103
+ }
104
+ return localSessionID;
107
105
  }
108
- if(eventToSend.numEventsTotal === 0 ){
109
- return;
106
+
107
+ function _setupIDs() {
108
+ userID = _getOrCreateUserID();
109
+ sessionID = _getOrCreateSessionID();
110
110
  }
111
- let textToSend = JSON.stringify(eventToSend);
112
- if(textToSend.length > POST_LARGE_DATA_THRESHOLD_BYTES){
113
- console.warn(`Analytics event generated is very large at greater than ${textToSend.length}B. This
114
- typically means that you may be sending too many value events? .`);
111
+
112
+ function _retryPost(eventToSend) {
113
+ eventToSend.backoffCount = (eventToSend.backoffCount || 0) + 1;
114
+ debugLog(`Failed to call core analytics server. Will retry in ${
115
+ DEFAULT_RETRY_TIME_IN_SECONDS * eventToSend.backoffCount}s: `);
116
+ setTimeout(()=>{
117
+ _postCurrentAnalyticsEvent(eventToSend);
118
+ }, DEFAULT_RETRY_TIME_IN_SECONDS * 1000 * eventToSend.backoffCount);
115
119
  }
116
- debugLog("Sending Analytics data of length: ", textToSend.length, "B");
117
- window.fetch(postURL, {
118
- method: "POST",
119
- headers: {'Content-Type': 'application/json'},
120
- body: textToSend
121
- }).then(res=>{
122
- if(res.status === 200){
120
+
121
+ function _postCurrentAnalyticsEvent(eventToSend) {
122
+ if(disabled){
123
123
  return;
124
124
  }
125
- if(res.status !== 400){ // we don't retry bad requests
126
- _retryPost(eventToSend);
127
- } else {
128
- console.error("Analytics client: " +
129
- "Bad Request, this is most likely a problem with the library, update to latest version.");
125
+ if(!eventToSend){
126
+ eventToSend = currentAnalyticsEvent;
127
+ currentQuantisedTime = 0;
128
+ _resetGranularityTimer();
129
+ currentAnalyticsEvent = _createAnalyticsEvent();
130
130
  }
131
- }).catch(res => {
132
- debugError(res);
133
- _retryPost(eventToSend);
134
- });
135
- }
131
+ if(eventToSend.numEventsTotal === 0 ){
132
+ return;
133
+ }
134
+ let textToSend = JSON.stringify(eventToSend);
135
+ if(textToSend.length > POST_LARGE_DATA_THRESHOLD_BYTES){
136
+ console.warn(`Analytics event generated is very large at greater than ${textToSend.length}B. This
137
+ typically means that you may be sending too many value events? .`);
138
+ }
139
+ debugLog("Sending Analytics data of length: ", textToSend.length, "B");
140
+ window.fetch(postURL, {
141
+ method: "POST",
142
+ headers: {'Content-Type': 'application/json'},
143
+ body: textToSend
144
+ }).then(res=>{
145
+ if(res.status === 200){
146
+ return;
147
+ }
148
+ if(res.status !== 400){ // we don't retry bad requests
149
+ _retryPost(eventToSend);
150
+ } else {
151
+ console.error("Analytics client: " +
152
+ "Bad Request, this is most likely a problem with the library, update to latest version.");
153
+ }
154
+ }).catch(res => {
155
+ debugError(res);
156
+ _retryPost(eventToSend);
157
+ });
158
+ }
136
159
 
137
- function _resetGranularityTimer(disable) {
138
- if(granularityTimer){
139
- clearInterval(granularityTimer);
140
- granularityTimer = null;
160
+ function _resetGranularityTimer(disable) {
161
+ if(granularityTimer){
162
+ clearInterval(granularityTimer);
163
+ granularityTimer = null;
164
+ }
165
+ if(disable){
166
+ return;
167
+ }
168
+ granularityTimer = setInterval(()=>{
169
+ currentQuantisedTime = currentQuantisedTime + granularitySec;
170
+ }, granularitySec*1000);
141
171
  }
142
- if(disable){
143
- return;
172
+
173
+ function _setupTimers(disable) {
174
+ _resetGranularityTimer(disable);
175
+ if(postTimer){
176
+ clearInterval(postTimer);
177
+ postTimer = null;
178
+ }
179
+ if(disable){
180
+ return;
181
+ }
182
+ postTimer = setInterval(_postCurrentAnalyticsEvent, postIntervalSeconds*1000);
144
183
  }
145
- granularityTimer = setInterval(()=>{
146
- currentQuantisedTime = currentQuantisedTime + granularitySec;
147
- }, granularitySec*1000);
148
- }
149
184
 
150
- function _setupTimers(disable) {
151
- _resetGranularityTimer(disable);
152
- if(postTimer){
153
- clearInterval(postTimer);
154
- postTimer = null;
185
+ async function _getServerConfig() {
186
+ return new Promise((resolve, reject)=>{
187
+ let configURL = analyticsURL + `/getAppConfig?accountID=${accountID}&appName=${appName}`;
188
+ window.fetch(configURL).then(async res=>{
189
+ switch (res.status) {
190
+ case 200:
191
+ let serverResponse = await res.json();
192
+ resolve(serverResponse);
193
+ return;
194
+ case 400:
195
+ reject("Bad Request, check library version compatible?", res);
196
+ break;
197
+ default:
198
+ reject("analytics client: Could not update from remote config. Continuing with defaults.", res);
199
+ }
200
+ }).catch(err => {
201
+ reject("analytics client: Could not update from remote config. Continuing with defaults.", err);
202
+ });
203
+ });
155
204
  }
156
- if(disable){
157
- return;
205
+
206
+ /**
207
+ * Returns the analytics config for the app
208
+ * @returns {Object}
209
+ */
210
+ function _getAppConfig() {
211
+ return {
212
+ accountID, appName, disabled,
213
+ uuid: userID, sessionID,
214
+ postIntervalSeconds, granularitySec, analyticsURL, serverConfig
215
+ };
158
216
  }
159
- postTimer = setInterval(_postCurrentAnalyticsEvent, postIntervalSeconds*1000);
160
- }
161
217
 
162
- async function _getServerConfig() {
163
- return new Promise((resolve, reject)=>{
164
- let configURL = analyticsURL + `/getAppConfig?accountID=${accountID}&appName=${appName}`;
165
- window.fetch(configURL).then(async res=>{
166
- switch (res.status) {
167
- case 200:
168
- let serverResponse = await res.json();
169
- resolve(serverResponse);
170
- return;
171
- case 400:
172
- reject("Bad Request, check library version compatible?", res);
173
- break;
174
- default:
175
- reject("analytics client: Could not update from remote config. Continuing with defaults.", res);
218
+ async function _initFromRemoteConfig(postIntervalSecondsInitial, granularitySecInitial) {
219
+ serverConfig = await _getServerConfig();
220
+ if(serverConfig !== {}){
221
+ // User init overrides takes precedence over server overrides
222
+ postIntervalSeconds = postIntervalSecondsInitial ||
223
+ serverConfig["postIntervalSecondsInit"] || DEFAULT_POST_INTERVAL_SECONDS;
224
+ granularitySec = granularitySecInitial || serverConfig["granularitySecInit"] || DEFAULT_GRANULARITY_IN_SECONDS;
225
+ // For URLs, the server suggested URL takes precedence over user init values
226
+ analyticsURL = serverConfig["analyticsURLInit"] || analyticsURL || DEFAULT_BASE_URL;
227
+ disabled = serverConfig["disabled"] === true;
228
+ _setupTimers(disabled);
229
+ debugLog(`Init analytics Config from remote. disabled: ${disabled}
230
+ postIntervalSeconds:${postIntervalSeconds}, granularitySec: ${granularitySec} ,URL: ${analyticsURL}`);
231
+ if(disabled){
232
+ console.warn(`Core Analytics is disabled from the server for app: ${accountID}:${appName}`);
176
233
  }
177
- }).catch(err => {
178
- reject("analytics client: Could not update from remote config. Continuing with defaults.", err);
179
- });
180
- });
181
- }
234
+ }
235
+ }
182
236
 
183
- /**
184
- * Returns the analytics config for the app
185
- * @returns {Object}
186
- */
187
- function getAppConfig() {
188
- return {
189
- accountID, appName, disabled,
190
- uuid: userID, sessionID,
191
- postIntervalSeconds, granularitySec, analyticsURL, serverConfig
192
- };
193
- }
237
+ function _stripTrailingSlash(url) {
238
+ return url.replace(/\/$/, "");
239
+ }
194
240
 
195
- async function _initFromRemoteConfig(postIntervalSecondsInit, granularitySecInit) {
196
- serverConfig = await _getServerConfig();
197
- if(serverConfig !== {}){
198
- // User init overrides takes precedence over server overrides
199
- postIntervalSeconds = postIntervalSecondsInit ||
200
- serverConfig["postIntervalSecondsInit"] || DEFAULT_POST_INTERVAL_SECONDS;
201
- granularitySec = granularitySecInit || serverConfig["granularitySecInit"] || DEFAULT_GRANULARITY_IN_SECONDS;
202
- // For URLs, the server suggested URL takes precedence over user init values
203
- analyticsURL = serverConfig["analyticsURLInit"] || analyticsURL || DEFAULT_BASE_URL;
204
- disabled = serverConfig["disabled"] === true;
205
- _setupTimers(disabled);
206
- debugLog(`Init analytics Config from remote. disabled: ${disabled}
207
- postIntervalSeconds:${postIntervalSeconds}, granularitySec: ${granularitySec} ,URL: ${analyticsURL}`);
208
- if(disabled){
209
- console.warn(`Core Analytics is disabled from the server for app: ${accountID}:${appName}`);
241
+ function _ensureAnalyticsEventExists(eventType, category, subCategory) {
242
+ let events = currentAnalyticsEvent.events;
243
+ events[eventType] = events[eventType] || {};
244
+ events[eventType][category] = events[eventType][category] || {};
245
+ events[eventType][category][subCategory] = events[eventType][category][subCategory] || {
246
+ time: [], // quantised time
247
+ valueCount: [] // value and count array, If a single value, then it is count, else object {"val1":count1, ...}
248
+ };
249
+ }
250
+
251
+ function _validateEvent(eventType, category, subCategory, count, value) {
252
+ _validateCurrentState();
253
+ if(!eventType || !category || !subCategory){
254
+ throw new Error("missing eventType or category or subCategory");
255
+ }
256
+ if(typeof(count)!== 'number' || count <0){
257
+ throw new Error("invalid count, count should be a positive number");
258
+ }
259
+ if(typeof(value)!== 'number'){
260
+ throw new Error("invalid value, value should be a number");
210
261
  }
211
262
  }
212
- }
213
263
 
214
- function _stripTrailingSlash(url) {
215
- return url.replace(/\/$/, "");
216
- }
264
+ function _updateExistingAnalyticsEvent(index, eventType, category, subCategory, count, newValue) {
265
+ let events = currentAnalyticsEvent.events;
266
+ const storedValueIsCount = typeof(events[eventType][category][subCategory]["valueCount"][index]) === 'number';
267
+ if(storedValueIsCount && newValue === 0){
268
+ events[eventType][category][subCategory]["valueCount"][index] += count;
269
+ } else if(storedValueIsCount && newValue !== 0){
270
+ let newValueCount = {};
271
+ newValueCount[newValue] = count;
272
+ newValueCount[0] = events[eventType][category][subCategory]["valueCount"][index];
273
+ events[eventType][category][subCategory]["valueCount"][index] = newValueCount;
274
+ } else if(!storedValueIsCount){
275
+ let storedValueObject = events[eventType][category][subCategory]["valueCount"][index];
276
+ storedValueObject[newValue] = (storedValueObject[newValue] || 0) + count;
277
+ }
278
+ currentAnalyticsEvent.numEventsTotal += 1;
279
+ }
217
280
 
218
- /**
219
- * Initialize the analytics session
220
- * @param accountIDInit Your analytics account id as configured in the server or core.ai analytics
221
- * @param appNameInit The app name to log the events against.
222
- * @param analyticsURLInit Optional: Provide your own analytics server address if you self-hosted the server
223
- * @param postIntervalSecondsInit Optional: This defines the interval between sending analytics events to the server.
224
- * Default is 10 minutes
225
- * @param granularitySecInit Optional: The smallest time period under which the events can be distinguished. Multiple
226
- * events happening during this time period is aggregated to a count. The default granularity is 3 Seconds, which means
227
- * that any events that happen within 3 seconds cannot be distinguished in ordering.
228
- * @param debug set to true if you want to see detailed debug logs.
229
- */
230
- function initSession(accountIDInit, appNameInit, analyticsURLInit, postIntervalSecondsInit, granularitySecInit, debug) {
281
+ /**
282
+ * Register an analytics event. The events will be aggregated and send to the analytics server periodically.
283
+ * @param eventType - String, required
284
+ * @param eventCategory - String, required
285
+ * @param subCategory - String, required
286
+ * @param eventCount (Optional) : A non-negative number indicating the number of times the event (or an event with a
287
+ * particular value if a value is specified) happened. defaults to 1.
288
+ * @param eventValue (Optional) : A number value associated with the event. defaults to 0
289
+ */
290
+ function event(eventType, eventCategory, subCategory, eventCount=1, eventValue=0) {
291
+ if(disabled){
292
+ return;
293
+ }
294
+ _validateEvent(eventType, eventCategory, subCategory, eventCount, eventValue);
295
+ _ensureAnalyticsEventExists(eventType, eventCategory, subCategory);
296
+ let events = currentAnalyticsEvent.events;
297
+ let timeArray = events[eventType][eventCategory][subCategory]["time"];
298
+ let lastTime = timeArray.length>0? timeArray[timeArray.length-1] : null;
299
+ if(lastTime !== currentQuantisedTime){
300
+ events[eventType][eventCategory][subCategory]["time"].push(currentQuantisedTime);
301
+ if(eventValue===0){
302
+ events[eventType][eventCategory][subCategory]["valueCount"].push(eventCount);
303
+ } else {
304
+ let valueCount = {};
305
+ valueCount[eventValue] = eventCount;
306
+ events[eventType][eventCategory][subCategory]["valueCount"].push(valueCount);
307
+ }
308
+ currentAnalyticsEvent.numEventsTotal += 1;
309
+ return;
310
+ }
311
+ let modificationIndex = events[eventType][eventCategory][subCategory]["valueCount"].length -1;
312
+ _updateExistingAnalyticsEvent(modificationIndex, eventType, eventCategory, subCategory, eventCount, eventValue);
313
+ }
314
+
315
+ // Init Analytics
231
316
  if(!accountIDInit || !appNameInit){
232
317
  throw new Error("accountID and appName must exist for init");
233
318
  }
@@ -242,85 +327,20 @@ function initSession(accountIDInit, appNameInit, analyticsURLInit, postIntervalS
242
327
  currentAnalyticsEvent = _createAnalyticsEvent();
243
328
  _setupTimers();
244
329
  _initFromRemoteConfig(postIntervalSecondsInit, granularitySecInit);
245
- }
246
330
 
247
- function _ensureAnalyticsEventExists(eventType, category, subCategory) {
248
- let events = currentAnalyticsEvent.events;
249
- events[eventType] = events[eventType] || {};
250
- events[eventType][category] = events[eventType][category] || {};
251
- events[eventType][category][subCategory] = events[eventType][category][subCategory] || {
252
- time: [], // quantised time
253
- valueCount: [] // value and count array, If a single value, then it is count, else object {"val1":count1, ...}
254
- };
255
- }
256
-
257
- function _validateEvent(eventType, category, subCategory, count, value) {
258
- _validateCurrentState();
259
- if(!eventType || !category || !subCategory){
260
- throw new Error("missing eventType or category or subCategory");
261
- }
262
- if(typeof(count)!== 'number' || count <0){
263
- throw new Error("invalid count");
331
+ // As analytics lib load is async, our loading scripts will push event data into initData array till the lib load
332
+ // is complete. Now as load is done, we need to push these pending analytics events. Assuming that the async load of
333
+ // the lib should mostly happen under a second, we should not lose any accuracy of event times within the initial
334
+ // 3-second granularity. For more precision use cases, load the lib sync.
335
+ for(let eventData of analytics._initData){
336
+ event(...eventData);
264
337
  }
265
- if(typeof(value)!== 'number'){
266
- throw new Error("invalid value");
267
- }
268
- }
338
+ analytics._initData = [];
269
339
 
270
- function _updateExistingAnalyticsEvent(index, eventType, category, subCategory, count, newValue) {
271
- let events = currentAnalyticsEvent.events;
272
- const storedValueIsCount = typeof(events[eventType][category][subCategory]["valueCount"][index]) === 'number';
273
- if(storedValueIsCount && newValue === 0){
274
- events[eventType][category][subCategory]["valueCount"][index] += count;
275
- } else if(storedValueIsCount && newValue !== 0){
276
- let newValueCount = {};
277
- newValueCount[newValue] = count;
278
- newValueCount[0] = events[eventType][category][subCategory]["valueCount"][index];
279
- events[eventType][category][subCategory]["valueCount"][index] = newValueCount;
280
- } else if(!storedValueIsCount){
281
- let storedValueObject = events[eventType][category][subCategory]["valueCount"][index];
282
- storedValueObject[newValue] = (storedValueObject[newValue] || 0) + count;
283
- }
284
- currentAnalyticsEvent.numEventsTotal += 1;
285
- }
340
+ // Private API for tests
341
+ analytics._getCurrentAnalyticsEvent = _getCurrentAnalyticsEvent;
342
+ analytics._getAppConfig = _getAppConfig;
286
343
 
287
- /**
288
- * Register an analytics event. The events will be aggregated and send to the analytics server periodically.
289
- * @param eventType - String, required
290
- * @param eventCategory - String, required
291
- * @param subCategory - String, required
292
- * @param eventCount (Optional) : A non-negative number indicating the number of times the event (or an event with a
293
- * particular value if a value is specified) happened. defaults to 1.
294
- * @param eventValue (Optional) : A number value associated with the event. defaults to 0
295
- */
296
- function analyticsEvent(eventType, eventCategory, subCategory, eventCount=1, eventValue=0) {
297
- if(disabled){
298
- return;
299
- }
300
- _validateEvent(eventType, eventCategory, subCategory, eventCount, eventValue);
301
- _ensureAnalyticsEventExists(eventType, eventCategory, subCategory);
302
- let events = currentAnalyticsEvent.events;
303
- let timeArray = events[eventType][eventCategory][subCategory]["time"];
304
- let lastTime = timeArray.length>0? timeArray[timeArray.length-1] : null;
305
- if(lastTime !== currentQuantisedTime){
306
- events[eventType][eventCategory][subCategory]["time"].push(currentQuantisedTime);
307
- if(eventValue===0){
308
- events[eventType][eventCategory][subCategory]["valueCount"].push(eventCount);
309
- } else {
310
- let valueCount = {};
311
- valueCount[eventValue] = eventCount;
312
- events[eventType][eventCategory][subCategory]["valueCount"].push(valueCount);
313
- }
314
- currentAnalyticsEvent.numEventsTotal += 1;
315
- return;
316
- }
317
- let modificationIndex = events[eventType][eventCategory][subCategory]["valueCount"].length -1;
318
- _updateExistingAnalyticsEvent(modificationIndex, eventType, eventCategory, subCategory, eventCount, eventValue);
344
+ // Public API
345
+ analytics.event = event;
319
346
  }
320
-
321
- export {
322
- initSession,
323
- getCurrentAnalyticsEvent,
324
- analyticsEvent,
325
- getAppConfig
326
- };