@sharadtech/infralytiqs-sdk 1.0.0 → 1.0.2

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.
@@ -1,4 +1,4 @@
1
- /*! infralytiqs-sdk v1.0.0 | (c) 2026 sharadtech | License: See LICENSE | Built: 2026-05-24T02:39:05.253Z */
1
+ /*! infralytiqs-sdk v1.0.2 | (c) 2026 sharadtech | License: See LICENSE | Built: 2026-06-07T21:38:38.343Z */
2
2
  var Infralytiqs = (function (exports) {
3
3
  'use strict';
4
4
 
@@ -820,6 +820,164 @@ var Infralytiqs = (function (exports) {
820
820
  }
821
821
  }
822
822
 
823
+ /**
824
+ * Client-bootstrap auto-loader.
825
+ *
826
+ * When the SDK script first executes on a host page, it looks for a
827
+ * `window.IL_CLIENT_BOOTSTRAP_LIB` global declared by the host (in AEM this
828
+ * is injected by the `Infralytiqs.html` Sightly fragment). If present, the
829
+ * SDK fetches that client-specific bootstrap JavaScript from the CDN and
830
+ * appends it to <head>. The bootstrap is then responsible for calling
831
+ * `Infralytiqs.init({...})` with tenant/site configuration and wiring any
832
+ * site-specific event hooks.
833
+ *
834
+ * Path resolution
835
+ * ---------------
836
+ * `IL_CLIENT_BOOTSTRAP_LIB` may be either:
837
+ * • A fully qualified URL ("https://…/bootstrap.min.js") — used as-is.
838
+ * • A path starting with "/" (e.g. "/cl/publicis/ps/bootstrap.min.js") —
839
+ * resolved against the SDK's own origin (the CDN host that served this
840
+ * script). This lets every client bootstrap live in the same S3 bucket
841
+ * as the SDK without the host page needing to know the CDN hostname.
842
+ * • A relative path — resolved against the SDK's own URL.
843
+ *
844
+ * The SDK script URL is captured at module-evaluation time via
845
+ * `document.currentScript`, which is only reliable during the SDK's
846
+ * synchronous IIFE execution. A defensive fallback scans existing <script>
847
+ * tags for one whose src matches the SDK bundle naming convention.
848
+ */
849
+ const SDK_SCRIPT_URL = (() => {
850
+ try {
851
+ if (typeof document === 'undefined')
852
+ return '';
853
+ const current = document.currentScript;
854
+ if (current && current.src)
855
+ return current.src;
856
+ const scripts = document.getElementsByTagName('script');
857
+ for (let i = scripts.length - 1; i >= 0; i--) {
858
+ const src = scripts[i].src;
859
+ if (src && /infralytiqs(\.min)?\.js(\?.*)?$/.test(src))
860
+ return src;
861
+ }
862
+ }
863
+ catch (_a) {
864
+ /* noop — fall through to empty */
865
+ }
866
+ return '';
867
+ })();
868
+ const BOOTSTRAP_FLAG = '__il_bootstrap_loaded__';
869
+ function resolveBootstrapUrl(rawPath) {
870
+ if (/^https?:\/\//i.test(rawPath))
871
+ return rawPath;
872
+ if (!SDK_SCRIPT_URL)
873
+ return rawPath;
874
+ try {
875
+ return new URL(rawPath, SDK_SCRIPT_URL).href;
876
+ }
877
+ catch (_a) {
878
+ return rawPath;
879
+ }
880
+ }
881
+ /**
882
+ * Injects a <script src="…"> tag for the client bootstrap declared on the
883
+ * host page. Idempotent — a window sentinel guards against double injection
884
+ * if the SDK is somehow evaluated twice.
885
+ */
886
+ function loadClientBootstrap() {
887
+ if (typeof window === 'undefined' || typeof document === 'undefined')
888
+ return;
889
+ const w = window;
890
+ if (w[BOOTSTRAP_FLAG])
891
+ return;
892
+ const lib = w.IL_CLIENT_BOOTSTRAP_LIB;
893
+ if (!lib || typeof lib !== 'string')
894
+ return;
895
+ const absoluteUrl = resolveBootstrapUrl(lib);
896
+ w[BOOTSTRAP_FLAG] = true;
897
+ const s = document.createElement('script');
898
+ s.src = absoluteUrl;
899
+ s.async = true;
900
+ s.setAttribute('data-il-bootstrap', 'client');
901
+ s.onerror = () => {
902
+ if (typeof console !== 'undefined') {
903
+ console.error('[Infralytiqs] failed to load client bootstrap from', absoluteUrl);
904
+ }
905
+ };
906
+ const parent = document.head || document.documentElement;
907
+ if (parent) {
908
+ parent.appendChild(s);
909
+ }
910
+ }
911
+
912
+ /**
913
+ * Infralytiqs token sync.
914
+ *
915
+ * The host page (e.g. the AEM Infralytiqs.html HTL fragment) renders the
916
+ * tenant's current Infralytiqs token id into a global:
917
+ *
918
+ * <script>window.IL_TOKEN = "....";</script>
919
+ *
920
+ * On SDK load we copy that value into sessionStorage so the rest of the page
921
+ * (and any embedded Infralytiqs widgets — e.g. the "Infralytiqs SDK" report
922
+ * snippet) can read a single, tab-scoped source of truth. The token is
923
+ * tab-scoped on purpose: it lives only for the current session/tab, mirroring
924
+ * how the host page re-emits a fresh `window.IL_TOKEN` on every render.
925
+ *
926
+ * Update semantics: if a token is already stored and the markup provides a
927
+ * different (non-empty) value, the stored token is replaced with the markup
928
+ * value so the freshest server-issued token always wins.
929
+ */
930
+ /** sessionStorage key holding the Infralytiqs token id. */
931
+ const TOKEN_STORAGE_KEY = `${ENV.STORAGE_PREFIX}token`;
932
+ /**
933
+ * Reads `window.IL_TOKEN` and stores it in sessionStorage, updating the
934
+ * stored value when the markup token differs from what is already cached.
935
+ *
936
+ * @returns the token value now held in sessionStorage, or `null` when no
937
+ * valid token is available.
938
+ */
939
+ function syncToken() {
940
+ if (typeof window === 'undefined') {
941
+ return null;
942
+ }
943
+ const w = window;
944
+ const markupToken = typeof w.IL_TOKEN === 'string' ? w.IL_TOKEN.trim() : '';
945
+ let stored = null;
946
+ try {
947
+ stored = sessionStorage.getItem(TOKEN_STORAGE_KEY);
948
+ }
949
+ catch (_a) {
950
+ // sessionStorage unavailable (e.g. privacy mode) — nothing we can do.
951
+ return markupToken || null;
952
+ }
953
+ // No usable markup token: keep whatever is already stored (if anything).
954
+ if (!markupToken) {
955
+ return stored;
956
+ }
957
+ // Store on first sight or whenever the markup token has changed.
958
+ if (stored !== markupToken) {
959
+ try {
960
+ sessionStorage.setItem(TOKEN_STORAGE_KEY, markupToken);
961
+ }
962
+ catch (_b) {
963
+ /* storage write failed — return the markup value regardless */
964
+ }
965
+ }
966
+ return markupToken;
967
+ }
968
+ /**
969
+ * @returns the Infralytiqs token id currently held in sessionStorage, or
970
+ * `null` if none is stored / storage is unavailable.
971
+ */
972
+ function getStoredToken() {
973
+ try {
974
+ return sessionStorage.getItem(TOKEN_STORAGE_KEY);
975
+ }
976
+ catch (_a) {
977
+ return null;
978
+ }
979
+ }
980
+
823
981
  /**
824
982
  * st-ck-server license module id for Infralytiqs (Companies.productPlans[].module,
825
983
  * Users.moduleAndRole[].module). Kept here for documentation and optional host-app use.
@@ -896,9 +1054,51 @@ var Infralytiqs = (function (exports) {
896
1054
  destroy() {
897
1055
  tracker.destroy();
898
1056
  },
1057
+ /**
1058
+ * Re-read `window.IL_TOKEN` and sync it into sessionStorage. Runs once
1059
+ * automatically on SDK load; can be called again after the host page
1060
+ * refreshes the token global.
1061
+ *
1062
+ * @returns the token now held in sessionStorage, or `null` if none.
1063
+ */
1064
+ syncToken() {
1065
+ return syncToken();
1066
+ },
1067
+ /**
1068
+ * @returns the Infralytiqs token id currently held in sessionStorage.
1069
+ */
1070
+ getToken() {
1071
+ return getStoredToken();
1072
+ },
899
1073
  };
1074
+ // ─── Sync the Infralytiqs token into sessionStorage ─────────────────────
1075
+ // The host page renders the tenant's current token id as `window.IL_TOKEN`
1076
+ // (see AEM Infralytiqs.html). Copy it into sessionStorage on load so any
1077
+ // embedded report widget can pick it up, updating the stored value whenever
1078
+ // the markup token changes.
1079
+ try {
1080
+ syncToken();
1081
+ }
1082
+ catch (_a) {
1083
+ /* never throw out of SDK script-tag evaluation */
1084
+ }
1085
+ // ─── Auto-load the client-specific bootstrap ────────────────────────────
1086
+ // When the SDK script tag executes, look for `window.IL_CLIENT_BOOTSTRAP_LIB`
1087
+ // declared by the host page (e.g. by the AEM Infralytiqs.html Sightly
1088
+ // fragment) and inject a <script> tag for it. The bootstrap is then
1089
+ // responsible for calling `Infralytiqs.init({...})` and wiring up any
1090
+ // site-specific event hooks. Resolution against the SDK's own CDN origin
1091
+ // is handled inside the loader, so host pages can use absolute-path
1092
+ // shortcuts like "/cl/publicis/ps/infralytiqs-bootstrap.min.js".
1093
+ try {
1094
+ loadClientBootstrap();
1095
+ }
1096
+ catch (_b) {
1097
+ /* never throw out of SDK script-tag evaluation */
1098
+ }
900
1099
 
901
1100
  exports.LICENSE_MODULE_ID = LICENSE_MODULE_ID;
1101
+ exports.TOKEN_STORAGE_KEY = TOKEN_STORAGE_KEY;
902
1102
  exports.default = Infralytiqs;
903
1103
 
904
1104
  Object.defineProperty(exports, '__esModule', { value: true });
@@ -1,2 +1,2 @@
1
- /*! infralytiqs-sdk v1.0.0 | (c) 2026 sharadtech | License: See LICENSE | Built: 2026-05-24T02:39:05.253Z */
2
- var Infralytiqs=function(t){"use strict";const e={ANALYTICS_API_BASE_URL:"",INGEST_PATH:"/il/analytics/:tenant_id/:site_id/events",BATCH_SIZE:20,FLUSH_INTERVAL_MS:5e3,SESSION_TIMEOUT_MS:18e5,STORAGE_PREFIX:"_il_",SDK_VERSION:"1.0.0",MAX_RETRIES:2,DEBUG:!1},n=`${e.STORAGE_PREFIX}anon_id`,i=`${e.STORAGE_PREFIX}session_id`,o=`${e.STORAGE_PREFIX}session_ts`;function s(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{const e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)})}function r(t){try{return localStorage.getItem(t)}catch(t){return null}}function a(t,e){try{localStorage.setItem(t,e)}catch(t){}}function u(){let t=r(n);return t||(t=s(),a(n,t)),t}function c(t){const e=Date.now(),n=parseInt(r(o)||"0",10);let u=r(i);return(!u||e-n>t)&&(u=s(),a(i,u)),a(o,String(e)),u}let l="";function d(t){l=t;try{sessionStorage.setItem(`${e.STORAGE_PREFIX}user_id`,t)}catch(t){}}function f(){if(l)return l;try{l=sessionStorage.getItem(`${e.STORAGE_PREFIX}user_id`)||""}catch(t){}return l}function g(){const t=navigator.userAgent||"";return/tablet|ipad|playbook|silk/i.test(t)?"tablet":/mobile|iphone|ipod|android.*mobile|windows phone|blackberry/i.test(t)?"mobile":"desktop"}function h(){const t=navigator.userAgent||"",e=navigator.platform||"",n=navigator.maxTouchPoints||0;return/iPhone|iPod/i.test(t)||/iPad/i.test(t)||/Mac/.test(e)&&n>1?"iOS":/Android/i.test(t)?"Android":/CrOS/i.test(t)?"ChromeOS":/Windows/i.test(t)?"Windows":/Mac OS X|Macintosh/i.test(t)?"macOS":/Linux/i.test(t)?"Linux":"Other"}function m(){const t=(navigator.language||"").split("-");return t.length>1?t[1].toUpperCase():""}const p=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"];function _(t){return`${t.serverUrl.replace(/\/+$/,"")}${e.INGEST_PATH.replace(":tenant_id",encodeURIComponent(t.tenantId)).replace(":site_id",encodeURIComponent(t.siteId))}`}function v(t,...e){t&&"undefined"!=typeof console&&console.log("[Infralytiqs]",...e)}function I(t,e){const n=[];if(!t.disableAutoPageView){e("page_view",null,{referrer:document.referrer||""},{});const t=()=>{e("page_view","spa_navigation",{referrer:document.referrer||""},{})};window.addEventListener("popstate",t),n.push(()=>window.removeEventListener("popstate",t));const i=history.pushState.bind(history);history.pushState=function(...t){i(...t),e("page_view","spa_navigation",{referrer:document.referrer||""},{})},n.push(()=>{history.pushState=i})}if(!t.disableAutoClick){const i=t.clickSelector||'a, button, [data-il-track], input[type="submit"]',o=n=>{const o=n.target;if(!o)return;const s=o.closest(i);if(!s)return;const r=Object.assign(Object.assign({},function(t){var e,n,i;const o={},s=(null===(e=t.tagName)||void 0===e?void 0:e.toLowerCase())||"";o.element_tag=s,t.id&&(o.element_id=t.id);const r=t.className;if("string"==typeof r&&r&&(o.element_class=r.split(/\s+/).slice(0,3).join(" ")),"a"===s){const e=t.href;e&&(o.link_url=e);const i=null===(n=t.textContent)||void 0===n?void 0:n.trim();i&&(o.link_text=i.substring(0,120))}else if("button"===s||"button"===t.getAttribute("role")){const e=null===(i=t.textContent)||void 0===i?void 0:i.trim();e&&(o.button_text=e.substring(0,120))}const a=t.getAttribute("data-il-track");return a&&(o.track_label=a),o}(s)),function(t,e){var n;const i={};if(!e)return i;for(const[o,s]of Object.entries(e))if("function"==typeof s)i[o]=s(t);else if("string"==typeof s){const e=t.closest(s)||t.querySelector(s);e&&(i[o]=e.getAttribute(`data-${o}`)||(null===(n=e.textContent)||void 0===n?void 0:n.trim())||"")}return i}(s,t.evarMap)),a=function(t,e){const n={};if(!e)return n;for(const[i,o]of Object.entries(e))n[i]=o(t);return n}(s,t.propMap);e("click",null,r,a)};document.addEventListener("click",o,{capture:!0,passive:!0}),n.push(()=>document.removeEventListener("click",o,!0))}if(!t.disableAutoPageLeave){let t=Date.now();const i=()=>{if("hidden"===document.visibilityState){const n=Math.round((Date.now()-t)/1e3);e("page_leave",null,{},{time_on_page_sec:n})}else t=Date.now()};document.addEventListener("visibilitychange",i),n.push(()=>document.removeEventListener("visibilitychange",i));const o=()=>{const n=Math.round((Date.now()-t)/1e3);e("page_leave","unload",{},{time_on_page_sec:n})};window.addEventListener("beforeunload",o),n.push(()=>window.removeEventListener("beforeunload",o))}return()=>n.forEach(t=>t())}const y="il_geo_v1",S="il_geo_deny_v1",b=8e3,w=()=>{try{if("undefined"!=typeof window&&window.localStorage){const t="__il_geo_probe__";return window.localStorage.setItem(t,"1"),window.localStorage.removeItem(t),window.localStorage}}catch(t){}return null};let E=null,T=null;const x=()=>{if(E)return;const t=(()=>{const t=w();if(!t)return null;try{const e=t.getItem(y);if(!e)return null;const n=JSON.parse(e);if("number"==typeof n.latitude&&"number"==typeof n.longitude&&"number"==typeof n.capturedAt&&Date.now()-n.capturedAt<6048e5)return n;t.removeItem(y)}catch(e){try{t.removeItem(y)}catch(t){}}return null})();t&&(E=t)},A=t=>{var n;return"undefined"==typeof window||"undefined"==typeof navigator?Promise.resolve(null):(x(),E?Promise.resolve(E):(()=>{const t=w();if(!t)return!1;try{const e=t.getItem(S);if(!e)return!1;const n=Number(e);if(Number.isFinite(n)&&Date.now()-n<864e5)return!0;t.removeItem(S)}catch(t){}return!1})()?(t&&console.log("[Infralytiqs] geolocation previously denied — skipping prompt"),Promise.resolve(null)):"geolocation"in navigator&&"function"==typeof(null===(n=navigator.geolocation)||void 0===n?void 0:n.getCurrentPosition)?T||(T=new Promise(n=>{let i=!1;const o=t=>{i||(i=!0,T=null,n(t))},s=window.setTimeout(()=>{t&&console.log("[Infralytiqs] geolocation prompt timed out after 8000ms"),o(null)},9e3);try{navigator.geolocation.getCurrentPosition(n=>{window.clearTimeout(s);const i={latitude:n.coords.latitude,longitude:n.coords.longitude,accuracy:n.coords.accuracy,capturedAt:Date.now()};E=i,(t=>{const e=w();if(e)try{e.setItem(y,JSON.stringify(t))}catch(t){}})(i),t&&console.log(`[Infralytiqs] geolocation granted (sdk=${e.SDK_VERSION}, acc=${Math.round(i.accuracy)}m)`),o(i)},e=>{window.clearTimeout(s),e&&1===e.code?((()=>{const t=w();if(t)try{t.setItem(S,String(Date.now()))}catch(t){}})(),t&&console.log("[Infralytiqs] geolocation permission denied")):t&&console.log(`[Infralytiqs] geolocation error (code=${null==e?void 0:e.code}): ${null==e?void 0:e.message}`),o(null)},{enableHighAccuracy:!1,timeout:b,maximumAge:36e5})}catch(t){window.clearTimeout(s),o(null)}}),T):Promise.resolve(null))};function O(){try{const t=window.location,e=t.hash||"";if(!e.startsWith("#/"))return t.href;const n=e.slice(1),i=n.indexOf("?"),o=i>=0?n.slice(0,i):n,s=i>=0?n.slice(i+1):"",r=[(t.search||"").replace(/^\?/,""),s].filter(Boolean).join("&");return t.origin+o+(r?"?"+r:"")}catch(t){return"undefined"!=typeof window&&window.location?window.location.href:""}}const R=new class{constructor(){this.queue=[],this.flushTimer=null,this.teardownAutoCapture=null,this.initialized=!1,this.preInitBuffer=[],this.preInitUserId=null}init(t){var n,i;if(this.initialized)return void this.log("Already initialized — ignoring duplicate init()");if(!t.serverUrl||!t.tenantId||!t.siteId)return void console.error("[Infralytiqs] init() requires serverUrl, tenantId, and siteId");const o=Object.assign(Object.assign({},t.dbName?{ch_db_name:t.dbName}:{}),null!==(n=t.globalDimensions)&&void 0!==n?n:{});if(this.config=Object.assign(Object.assign({batchSize:e.BATCH_SIZE,flushIntervalMs:e.FLUSH_INTERVAL_MS,sessionTimeoutMs:e.SESSION_TIMEOUT_MS,debug:e.DEBUG,clickSelector:'a, button, [data-il-track], input[type="submit"]'},t),{globalDimensions:o}),this.transportCfg={serverUrl:this.config.serverUrl,tenantId:this.config.tenantId,siteId:this.config.siteId,debug:null!==(i=this.config.debug)&&void 0!==i&&i},this.preInitUserId&&(d(this.preInitUserId),this.preInitUserId=null),this.config.userId&&d(this.config.userId),this.startFlushTimer(),this.teardownAutoCapture=I(this.config,(t,e,n,i)=>{this.trackRaw(t,e,n,i)}),this.initialized=!0,this.config.captureLocation&&A(this.config.debug).catch(()=>{}),this.preInitBuffer.length>0){const t=this.preInitBuffer.splice(0);this.log(`Draining pre-init buffer (${t.length} event(s))`);for(const e of t)this.trackRaw(e.eventType,e.eventSubtype,e.dims,e.metrics)}this.log("Initialized",{tenantId:t.tenantId,siteId:t.siteId,dbName:t.dbName,captureLocation:!!t.captureLocation})}track(t,e,n,i){if(!this.initialized)return this.preInitBuffer.length>=100&&this.preInitBuffer.shift(),void this.preInitBuffer.push({eventType:t,eventSubtype:null!=i?i:null,dims:null!=e?e:{},metrics:null!=n?n:{}});this.trackRaw(t,null!=i?i:null,null!=e?e:{},null!=n?n:{})}identify(t){this.initialized?(d(t),this.log("User identified",t)):this.preInitUserId=t}async flush(){await this.flushQueue(!1)}destroy(){this.flushQueue(!0),this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.teardownAutoCapture&&(this.teardownAutoCapture(),this.teardownAutoCapture=null),this.initialized=!1,this.log("Destroyed")}trackRaw(t,n,i,o){var s,r,a,l;const d=function(){const t={},e="_il_utm_";try{const n=new URLSearchParams(window.location.search);let i=!1;for(const o of p){const s=n.get(o);s&&(t[o]=s,sessionStorage.setItem(`${e}${o}`,s),i=!0)}if(!i)for(const n of p){const i=sessionStorage.getItem(`${e}${n}`);i&&(t[n]=i)}}catch(t){}return t}(),_={language_iso_code:navigator.language||navigator.userLanguage||"",user_id:f(),anonymous_id:u(),session_id:c(null!==(s=this.config.sessionTimeoutMs)&&void 0!==s?s:e.SESSION_TIMEOUT_MS),event_type:t,event_subtype:n,custom_dimensions:Object.assign(Object.assign(Object.assign({},null!==(r=this.config.globalDimensions)&&void 0!==r?r:{}),i),{sdk_version:e.SDK_VERSION}),custom_metrics:o,page_url:O(),country_code:m(),device_type:g(),device_os:h(),utm_source:null!==(a=d.utm_source)&&void 0!==a?a:null};if(d.utm_medium&&(_.custom_dimensions.utm_medium=d.utm_medium),d.utm_campaign&&(_.custom_dimensions.utm_campaign=d.utm_campaign),d.utm_term&&(_.custom_dimensions.utm_term=d.utm_term),d.utm_content&&(_.custom_dimensions.utm_content=d.utm_content),this.config.captureLocation){const t=E||(x(),E);t&&(_.latitude=t.latitude,_.longitude=t.longitude,_.location_accuracy=t.accuracy)}this.queue.push(_),this.log("Queued",t,n,`(${this.queue.length}/${this.config.batchSize})`),this.queue.length>=(null!==(l=this.config.batchSize)&&void 0!==l?l:e.BATCH_SIZE)&&this.flushQueue(!1)}startFlushTimer(){var t;const n=null!==(t=this.config.flushIntervalMs)&&void 0!==t?t:e.FLUSH_INTERVAL_MS;this.flushTimer=setInterval(()=>this.flushQueue(!1),n)}async flushQueue(t){if(0===this.queue.length)return;const n=this.queue.splice(0,this.queue.length);if(t)return void function(t,e){if("undefined"==typeof navigator||!navigator.sendBeacon)return!1;const n=_(t),i=JSON.stringify(1===e.length?e[0]:e),o=new Blob([i],{type:"application/json"}),s=navigator.sendBeacon(n,o);v(t.debug,`Beacon ${s?"accepted":"rejected"} ${e.length} event(s)`)}(this.transportCfg,n);await async function(t,n,i=e.MAX_RETRIES){const o=_(t),s=JSON.stringify(1===n.length?n[0]:n);for(let e=0;e<=i;e++)try{const i=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:s,keepalive:!0});if(i.ok)return v(t.debug,`Flushed ${n.length} event(s) — HTTP ${i.status}`),!0;v(t.debug,`Flush attempt ${e+1} failed — HTTP ${i.status}`)}catch(n){v(t.debug,`Flush attempt ${e+1} error`,n)}return!1}(this.transportCfg,n)||this.log("Flush failed — events dropped",n.length)}log(...t){var e;(null===(e=this.config)||void 0===e?void 0:e.debug)&&"undefined"!=typeof console&&console.log("[Infralytiqs]",...t)}},U={init(t){R.init(t)},track(t,e,n,i){R.track(t,e,n,i)},identify(t){R.identify(t)},flush:()=>R.flush(),destroy(){R.destroy()}};return t.LICENSE_MODULE_ID="infralytiqs.com",t.default=U,Object.defineProperty(t,"__esModule",{value:!0}),t}({});
1
+ /*! infralytiqs-sdk v1.0.2 | (c) 2026 sharadtech | License: See LICENSE | Built: 2026-06-07T21:38:38.343Z */
2
+ var Infralytiqs=function(t){"use strict";const e={ANALYTICS_API_BASE_URL:"",INGEST_PATH:"/il/analytics/:tenant_id/:site_id/events",BATCH_SIZE:20,FLUSH_INTERVAL_MS:5e3,SESSION_TIMEOUT_MS:18e5,STORAGE_PREFIX:"_il_",SDK_VERSION:"1.0.0",MAX_RETRIES:2,DEBUG:!1},n=`${e.STORAGE_PREFIX}anon_id`,i=`${e.STORAGE_PREFIX}session_id`,o=`${e.STORAGE_PREFIX}session_ts`;function r(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{const e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)})}function s(t){try{return localStorage.getItem(t)}catch(t){return null}}function a(t,e){try{localStorage.setItem(t,e)}catch(t){}}function u(){let t=s(n);return t||(t=r(),a(n,t)),t}function c(t){const e=Date.now(),n=parseInt(s(o)||"0",10);let u=s(i);return(!u||e-n>t)&&(u=r(),a(i,u)),a(o,String(e)),u}let l="";function d(t){l=t;try{sessionStorage.setItem(`${e.STORAGE_PREFIX}user_id`,t)}catch(t){}}function f(){if(l)return l;try{l=sessionStorage.getItem(`${e.STORAGE_PREFIX}user_id`)||""}catch(t){}return l}function g(){const t=navigator.userAgent||"";return/tablet|ipad|playbook|silk/i.test(t)?"tablet":/mobile|iphone|ipod|android.*mobile|windows phone|blackberry/i.test(t)?"mobile":"desktop"}function h(){const t=navigator.userAgent||"",e=navigator.platform||"",n=navigator.maxTouchPoints||0;return/iPhone|iPod/i.test(t)||/iPad/i.test(t)||/Mac/.test(e)&&n>1?"iOS":/Android/i.test(t)?"Android":/CrOS/i.test(t)?"ChromeOS":/Windows/i.test(t)?"Windows":/Mac OS X|Macintosh/i.test(t)?"macOS":/Linux/i.test(t)?"Linux":"Other"}function m(){const t=(navigator.language||"").split("-");return t.length>1?t[1].toUpperCase():""}const p=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"];function _(t){return`${t.serverUrl.replace(/\/+$/,"")}${e.INGEST_PATH.replace(":tenant_id",encodeURIComponent(t.tenantId)).replace(":site_id",encodeURIComponent(t.siteId))}`}function y(t,...e){t&&"undefined"!=typeof console&&console.log("[Infralytiqs]",...e)}function v(t,e){const n=[];if(!t.disableAutoPageView){e("page_view",null,{referrer:document.referrer||""},{});const t=()=>{e("page_view","spa_navigation",{referrer:document.referrer||""},{})};window.addEventListener("popstate",t),n.push(()=>window.removeEventListener("popstate",t));const i=history.pushState.bind(history);history.pushState=function(...t){i(...t),e("page_view","spa_navigation",{referrer:document.referrer||""},{})},n.push(()=>{history.pushState=i})}if(!t.disableAutoClick){const i=t.clickSelector||'a, button, [data-il-track], input[type="submit"]',o=n=>{const o=n.target;if(!o)return;const r=o.closest(i);if(!r)return;const s=Object.assign(Object.assign({},function(t){var e,n,i;const o={},r=(null===(e=t.tagName)||void 0===e?void 0:e.toLowerCase())||"";o.element_tag=r,t.id&&(o.element_id=t.id);const s=t.className;if("string"==typeof s&&s&&(o.element_class=s.split(/\s+/).slice(0,3).join(" ")),"a"===r){const e=t.href;e&&(o.link_url=e);const i=null===(n=t.textContent)||void 0===n?void 0:n.trim();i&&(o.link_text=i.substring(0,120))}else if("button"===r||"button"===t.getAttribute("role")){const e=null===(i=t.textContent)||void 0===i?void 0:i.trim();e&&(o.button_text=e.substring(0,120))}const a=t.getAttribute("data-il-track");return a&&(o.track_label=a),o}(r)),function(t,e){var n;const i={};if(!e)return i;for(const[o,r]of Object.entries(e))if("function"==typeof r)i[o]=r(t);else if("string"==typeof r){const e=t.closest(r)||t.querySelector(r);e&&(i[o]=e.getAttribute(`data-${o}`)||(null===(n=e.textContent)||void 0===n?void 0:n.trim())||"")}return i}(r,t.evarMap)),a=function(t,e){const n={};if(!e)return n;for(const[i,o]of Object.entries(e))n[i]=o(t);return n}(r,t.propMap);e("click",null,s,a)};document.addEventListener("click",o,{capture:!0,passive:!0}),n.push(()=>document.removeEventListener("click",o,!0))}if(!t.disableAutoPageLeave){let t=Date.now();const i=()=>{if("hidden"===document.visibilityState){const n=Math.round((Date.now()-t)/1e3);e("page_leave",null,{},{time_on_page_sec:n})}else t=Date.now()};document.addEventListener("visibilitychange",i),n.push(()=>document.removeEventListener("visibilitychange",i));const o=()=>{const n=Math.round((Date.now()-t)/1e3);e("page_leave","unload",{},{time_on_page_sec:n})};window.addEventListener("beforeunload",o),n.push(()=>window.removeEventListener("beforeunload",o))}return()=>n.forEach(t=>t())}const I="il_geo_v1",S="il_geo_deny_v1",w=8e3,b=()=>{try{if("undefined"!=typeof window&&window.localStorage){const t="__il_geo_probe__";return window.localStorage.setItem(t,"1"),window.localStorage.removeItem(t),window.localStorage}}catch(t){}return null};let E=null,T=null;const O=()=>{if(E)return;const t=(()=>{const t=b();if(!t)return null;try{const e=t.getItem(I);if(!e)return null;const n=JSON.parse(e);if("number"==typeof n.latitude&&"number"==typeof n.longitude&&"number"==typeof n.capturedAt&&Date.now()-n.capturedAt<6048e5)return n;t.removeItem(I)}catch(e){try{t.removeItem(I)}catch(t){}}return null})();t&&(E=t)},A=t=>{var n;return"undefined"==typeof window||"undefined"==typeof navigator?Promise.resolve(null):(O(),E?Promise.resolve(E):(()=>{const t=b();if(!t)return!1;try{const e=t.getItem(S);if(!e)return!1;const n=Number(e);if(Number.isFinite(n)&&Date.now()-n<864e5)return!0;t.removeItem(S)}catch(t){}return!1})()?(t&&console.log("[Infralytiqs] geolocation previously denied — skipping prompt"),Promise.resolve(null)):"geolocation"in navigator&&"function"==typeof(null===(n=navigator.geolocation)||void 0===n?void 0:n.getCurrentPosition)?T||(T=new Promise(n=>{let i=!1;const o=t=>{i||(i=!0,T=null,n(t))},r=window.setTimeout(()=>{t&&console.log("[Infralytiqs] geolocation prompt timed out after 8000ms"),o(null)},9e3);try{navigator.geolocation.getCurrentPosition(n=>{window.clearTimeout(r);const i={latitude:n.coords.latitude,longitude:n.coords.longitude,accuracy:n.coords.accuracy,capturedAt:Date.now()};E=i,(t=>{const e=b();if(e)try{e.setItem(I,JSON.stringify(t))}catch(t){}})(i),t&&console.log(`[Infralytiqs] geolocation granted (sdk=${e.SDK_VERSION}, acc=${Math.round(i.accuracy)}m)`),o(i)},e=>{window.clearTimeout(r),e&&1===e.code?((()=>{const t=b();if(t)try{t.setItem(S,String(Date.now()))}catch(t){}})(),t&&console.log("[Infralytiqs] geolocation permission denied")):t&&console.log(`[Infralytiqs] geolocation error (code=${null==e?void 0:e.code}): ${null==e?void 0:e.message}`),o(null)},{enableHighAccuracy:!1,timeout:w,maximumAge:36e5})}catch(t){window.clearTimeout(r),o(null)}}),T):Promise.resolve(null))};function x(){try{const t=window.location,e=t.hash||"";if(!e.startsWith("#/"))return t.href;const n=e.slice(1),i=n.indexOf("?"),o=i>=0?n.slice(0,i):n,r=i>=0?n.slice(i+1):"",s=[(t.search||"").replace(/^\?/,""),r].filter(Boolean).join("&");return t.origin+o+(s?"?"+s:"")}catch(t){return"undefined"!=typeof window&&window.location?window.location.href:""}}const R=(()=>{try{if("undefined"==typeof document)return"";const t=document.currentScript;if(t&&t.src)return t.src;const e=document.getElementsByTagName("script");for(let t=e.length-1;t>=0;t--){const n=e[t].src;if(n&&/infralytiqs(\.min)?\.js(\?.*)?$/.test(n))return n}}catch(t){}return""})(),L="__il_bootstrap_loaded__";const k=`${e.STORAGE_PREFIX}token`;function N(){if("undefined"==typeof window)return null;const t=window,e="string"==typeof t.IL_TOKEN?t.IL_TOKEN.trim():"";let n=null;try{n=sessionStorage.getItem(k)}catch(t){return e||null}if(!e)return n;if(n!==e)try{sessionStorage.setItem(k,e)}catch(t){}return e}const U=new class{constructor(){this.queue=[],this.flushTimer=null,this.teardownAutoCapture=null,this.initialized=!1,this.preInitBuffer=[],this.preInitUserId=null}init(t){var n,i;if(this.initialized)return void this.log("Already initialized — ignoring duplicate init()");if(!t.serverUrl||!t.tenantId||!t.siteId)return void console.error("[Infralytiqs] init() requires serverUrl, tenantId, and siteId");const o=Object.assign(Object.assign({},t.dbName?{ch_db_name:t.dbName}:{}),null!==(n=t.globalDimensions)&&void 0!==n?n:{});if(this.config=Object.assign(Object.assign({batchSize:e.BATCH_SIZE,flushIntervalMs:e.FLUSH_INTERVAL_MS,sessionTimeoutMs:e.SESSION_TIMEOUT_MS,debug:e.DEBUG,clickSelector:'a, button, [data-il-track], input[type="submit"]'},t),{globalDimensions:o}),this.transportCfg={serverUrl:this.config.serverUrl,tenantId:this.config.tenantId,siteId:this.config.siteId,debug:null!==(i=this.config.debug)&&void 0!==i&&i},this.preInitUserId&&(d(this.preInitUserId),this.preInitUserId=null),this.config.userId&&d(this.config.userId),this.startFlushTimer(),this.teardownAutoCapture=v(this.config,(t,e,n,i)=>{this.trackRaw(t,e,n,i)}),this.initialized=!0,this.config.captureLocation&&A(this.config.debug).catch(()=>{}),this.preInitBuffer.length>0){const t=this.preInitBuffer.splice(0);this.log(`Draining pre-init buffer (${t.length} event(s))`);for(const e of t)this.trackRaw(e.eventType,e.eventSubtype,e.dims,e.metrics)}this.log("Initialized",{tenantId:t.tenantId,siteId:t.siteId,dbName:t.dbName,captureLocation:!!t.captureLocation})}track(t,e,n,i){if(!this.initialized)return this.preInitBuffer.length>=100&&this.preInitBuffer.shift(),void this.preInitBuffer.push({eventType:t,eventSubtype:null!=i?i:null,dims:null!=e?e:{},metrics:null!=n?n:{}});this.trackRaw(t,null!=i?i:null,null!=e?e:{},null!=n?n:{})}identify(t){this.initialized?(d(t),this.log("User identified",t)):this.preInitUserId=t}async flush(){await this.flushQueue(!1)}destroy(){this.flushQueue(!0),this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.teardownAutoCapture&&(this.teardownAutoCapture(),this.teardownAutoCapture=null),this.initialized=!1,this.log("Destroyed")}trackRaw(t,n,i,o){var r,s,a,l;const d=function(){const t={},e="_il_utm_";try{const n=new URLSearchParams(window.location.search);let i=!1;for(const o of p){const r=n.get(o);r&&(t[o]=r,sessionStorage.setItem(`${e}${o}`,r),i=!0)}if(!i)for(const n of p){const i=sessionStorage.getItem(`${e}${n}`);i&&(t[n]=i)}}catch(t){}return t}(),_={language_iso_code:navigator.language||navigator.userLanguage||"",user_id:f(),anonymous_id:u(),session_id:c(null!==(r=this.config.sessionTimeoutMs)&&void 0!==r?r:e.SESSION_TIMEOUT_MS),event_type:t,event_subtype:n,custom_dimensions:Object.assign(Object.assign(Object.assign({},null!==(s=this.config.globalDimensions)&&void 0!==s?s:{}),i),{sdk_version:e.SDK_VERSION}),custom_metrics:o,page_url:x(),country_code:m(),device_type:g(),device_os:h(),utm_source:null!==(a=d.utm_source)&&void 0!==a?a:null};if(d.utm_medium&&(_.custom_dimensions.utm_medium=d.utm_medium),d.utm_campaign&&(_.custom_dimensions.utm_campaign=d.utm_campaign),d.utm_term&&(_.custom_dimensions.utm_term=d.utm_term),d.utm_content&&(_.custom_dimensions.utm_content=d.utm_content),this.config.captureLocation){const t=E||(O(),E);t&&(_.latitude=t.latitude,_.longitude=t.longitude,_.location_accuracy=t.accuracy)}this.queue.push(_),this.log("Queued",t,n,`(${this.queue.length}/${this.config.batchSize})`),this.queue.length>=(null!==(l=this.config.batchSize)&&void 0!==l?l:e.BATCH_SIZE)&&this.flushQueue(!1)}startFlushTimer(){var t;const n=null!==(t=this.config.flushIntervalMs)&&void 0!==t?t:e.FLUSH_INTERVAL_MS;this.flushTimer=setInterval(()=>this.flushQueue(!1),n)}async flushQueue(t){if(0===this.queue.length)return;const n=this.queue.splice(0,this.queue.length);if(t)return void function(t,e){if("undefined"==typeof navigator||!navigator.sendBeacon)return!1;const n=_(t),i=JSON.stringify(1===e.length?e[0]:e),o=new Blob([i],{type:"application/json"}),r=navigator.sendBeacon(n,o);y(t.debug,`Beacon ${r?"accepted":"rejected"} ${e.length} event(s)`)}(this.transportCfg,n);await async function(t,n,i=e.MAX_RETRIES){const o=_(t),r=JSON.stringify(1===n.length?n[0]:n);for(let e=0;e<=i;e++)try{const i=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:r,keepalive:!0});if(i.ok)return y(t.debug,`Flushed ${n.length} event(s) — HTTP ${i.status}`),!0;y(t.debug,`Flush attempt ${e+1} failed — HTTP ${i.status}`)}catch(n){y(t.debug,`Flush attempt ${e+1} error`,n)}return!1}(this.transportCfg,n)||this.log("Flush failed — events dropped",n.length)}log(...t){var e;(null===(e=this.config)||void 0===e?void 0:e.debug)&&"undefined"!=typeof console&&console.log("[Infralytiqs]",...t)}},P={init(t){U.init(t)},track(t,e,n,i){U.track(t,e,n,i)},identify(t){U.identify(t)},flush:()=>U.flush(),destroy(){U.destroy()},syncToken:()=>N(),getToken:()=>function(){try{return sessionStorage.getItem(k)}catch(t){return null}}()};try{N()}catch(t){}try{!function(){if("undefined"==typeof window||"undefined"==typeof document)return;const t=window;if(t[L])return;const e=t.IL_CLIENT_BOOTSTRAP_LIB;if(!e||"string"!=typeof e)return;const n=function(t){if(/^https?:\/\//i.test(t))return t;if(!R)return t;try{return new URL(t,R).href}catch(e){return t}}(e);t[L]=!0;const i=document.createElement("script");i.src=n,i.async=!0,i.setAttribute("data-il-bootstrap","client"),i.onerror=()=>{"undefined"!=typeof console&&console.error("[Infralytiqs] failed to load client bootstrap from",n)};const o=document.head||document.documentElement;o&&o.appendChild(i)}()}catch(t){}return t.LICENSE_MODULE_ID="infralytiqs.com",t.TOKEN_STORAGE_KEY=k,t.default=P,Object.defineProperty(t,"__esModule",{value:!0}),t}({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sharadtech/infralytiqs-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "Lightweight website analytics tracker SDK for Infralytiqs (ClickHouse backend)",
6
6
  "main": "dist/infralytiqs.min.js",
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Client-bootstrap auto-loader.
3
+ *
4
+ * When the SDK script first executes on a host page, it looks for a
5
+ * `window.IL_CLIENT_BOOTSTRAP_LIB` global declared by the host (in AEM this
6
+ * is injected by the `Infralytiqs.html` Sightly fragment). If present, the
7
+ * SDK fetches that client-specific bootstrap JavaScript from the CDN and
8
+ * appends it to <head>. The bootstrap is then responsible for calling
9
+ * `Infralytiqs.init({...})` with tenant/site configuration and wiring any
10
+ * site-specific event hooks.
11
+ *
12
+ * Path resolution
13
+ * ---------------
14
+ * `IL_CLIENT_BOOTSTRAP_LIB` may be either:
15
+ * • A fully qualified URL ("https://…/bootstrap.min.js") — used as-is.
16
+ * • A path starting with "/" (e.g. "/cl/publicis/ps/bootstrap.min.js") —
17
+ * resolved against the SDK's own origin (the CDN host that served this
18
+ * script). This lets every client bootstrap live in the same S3 bucket
19
+ * as the SDK without the host page needing to know the CDN hostname.
20
+ * • A relative path — resolved against the SDK's own URL.
21
+ *
22
+ * The SDK script URL is captured at module-evaluation time via
23
+ * `document.currentScript`, which is only reliable during the SDK's
24
+ * synchronous IIFE execution. A defensive fallback scans existing <script>
25
+ * tags for one whose src matches the SDK bundle naming convention.
26
+ */
27
+
28
+ const SDK_SCRIPT_URL: string = (() => {
29
+ try {
30
+ if (typeof document === 'undefined') return '';
31
+ const current = document.currentScript as HTMLScriptElement | null;
32
+ if (current && current.src) return current.src;
33
+
34
+ const scripts = document.getElementsByTagName('script');
35
+ for (let i = scripts.length - 1; i >= 0; i--) {
36
+ const src = scripts[i].src;
37
+ if (src && /infralytiqs(\.min)?\.js(\?.*)?$/.test(src)) return src;
38
+ }
39
+ } catch {
40
+ /* noop — fall through to empty */
41
+ }
42
+ return '';
43
+ })();
44
+
45
+ const BOOTSTRAP_FLAG = '__il_bootstrap_loaded__';
46
+
47
+ interface WindowWithBootstrap {
48
+ IL_CLIENT_BOOTSTRAP_LIB?: string;
49
+ [BOOTSTRAP_FLAG]?: boolean;
50
+ }
51
+
52
+ function resolveBootstrapUrl(rawPath: string): string {
53
+ if (/^https?:\/\//i.test(rawPath)) return rawPath;
54
+ if (!SDK_SCRIPT_URL) return rawPath;
55
+ try {
56
+ return new URL(rawPath, SDK_SCRIPT_URL).href;
57
+ } catch {
58
+ return rawPath;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Injects a <script src="…"> tag for the client bootstrap declared on the
64
+ * host page. Idempotent — a window sentinel guards against double injection
65
+ * if the SDK is somehow evaluated twice.
66
+ */
67
+ export function loadClientBootstrap(): void {
68
+ if (typeof window === 'undefined' || typeof document === 'undefined') return;
69
+
70
+ const w = window as unknown as WindowWithBootstrap;
71
+ if (w[BOOTSTRAP_FLAG]) return;
72
+
73
+ const lib = w.IL_CLIENT_BOOTSTRAP_LIB;
74
+ if (!lib || typeof lib !== 'string') return;
75
+
76
+ const absoluteUrl = resolveBootstrapUrl(lib);
77
+
78
+ w[BOOTSTRAP_FLAG] = true;
79
+
80
+ const s = document.createElement('script');
81
+ s.src = absoluteUrl;
82
+ s.async = true;
83
+ s.setAttribute('data-il-bootstrap', 'client');
84
+ s.onerror = (): void => {
85
+ if (typeof console !== 'undefined') {
86
+ console.error('[Infralytiqs] failed to load client bootstrap from', absoluteUrl);
87
+ }
88
+ };
89
+
90
+ const parent = document.head || document.documentElement;
91
+ if (parent) {
92
+ parent.appendChild(s);
93
+ }
94
+ }
package/src/index.ts CHANGED
@@ -33,8 +33,11 @@
33
33
 
34
34
  import { InfralytiqsTracker } from './tracker';
35
35
  import type { InfralytiqsConfig } from './types';
36
+ import { loadClientBootstrap } from './bootstrapLoader';
37
+ import { syncToken, getStoredToken } from './token';
36
38
 
37
39
  export { LICENSE_MODULE_ID } from './licenseModuleId';
40
+ export { TOKEN_STORAGE_KEY } from './token';
38
41
  export type { InfralytiqsConfig };
39
42
 
40
43
  const tracker = new InfralytiqsTracker();
@@ -85,7 +88,50 @@ const Infralytiqs = {
85
88
  destroy(): void {
86
89
  tracker.destroy();
87
90
  },
91
+
92
+ /**
93
+ * Re-read `window.IL_TOKEN` and sync it into sessionStorage. Runs once
94
+ * automatically on SDK load; can be called again after the host page
95
+ * refreshes the token global.
96
+ *
97
+ * @returns the token now held in sessionStorage, or `null` if none.
98
+ */
99
+ syncToken(): string | null {
100
+ return syncToken();
101
+ },
102
+
103
+ /**
104
+ * @returns the Infralytiqs token id currently held in sessionStorage.
105
+ */
106
+ getToken(): string | null {
107
+ return getStoredToken();
108
+ },
88
109
  };
89
110
 
90
111
  export default Infralytiqs;
91
112
 
113
+ // ─── Sync the Infralytiqs token into sessionStorage ─────────────────────
114
+ // The host page renders the tenant's current token id as `window.IL_TOKEN`
115
+ // (see AEM Infralytiqs.html). Copy it into sessionStorage on load so any
116
+ // embedded report widget can pick it up, updating the stored value whenever
117
+ // the markup token changes.
118
+ try {
119
+ syncToken();
120
+ } catch {
121
+ /* never throw out of SDK script-tag evaluation */
122
+ }
123
+
124
+ // ─── Auto-load the client-specific bootstrap ────────────────────────────
125
+ // When the SDK script tag executes, look for `window.IL_CLIENT_BOOTSTRAP_LIB`
126
+ // declared by the host page (e.g. by the AEM Infralytiqs.html Sightly
127
+ // fragment) and inject a <script> tag for it. The bootstrap is then
128
+ // responsible for calling `Infralytiqs.init({...})` and wiring up any
129
+ // site-specific event hooks. Resolution against the SDK's own CDN origin
130
+ // is handled inside the loader, so host pages can use absolute-path
131
+ // shortcuts like "/cl/publicis/ps/infralytiqs-bootstrap.min.js".
132
+ try {
133
+ loadClientBootstrap();
134
+ } catch {
135
+ /* never throw out of SDK script-tag evaluation */
136
+ }
137
+
package/src/token.ts ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Infralytiqs token sync.
3
+ *
4
+ * The host page (e.g. the AEM Infralytiqs.html HTL fragment) renders the
5
+ * tenant's current Infralytiqs token id into a global:
6
+ *
7
+ * <script>window.IL_TOKEN = "....";</script>
8
+ *
9
+ * On SDK load we copy that value into sessionStorage so the rest of the page
10
+ * (and any embedded Infralytiqs widgets — e.g. the "Infralytiqs SDK" report
11
+ * snippet) can read a single, tab-scoped source of truth. The token is
12
+ * tab-scoped on purpose: it lives only for the current session/tab, mirroring
13
+ * how the host page re-emits a fresh `window.IL_TOKEN` on every render.
14
+ *
15
+ * Update semantics: if a token is already stored and the markup provides a
16
+ * different (non-empty) value, the stored token is replaced with the markup
17
+ * value so the freshest server-issued token always wins.
18
+ */
19
+
20
+ import { ENV } from './envConfig';
21
+
22
+ /** sessionStorage key holding the Infralytiqs token id. */
23
+ export const TOKEN_STORAGE_KEY = `${ENV.STORAGE_PREFIX}token`;
24
+
25
+ interface WindowWithToken extends Window {
26
+ IL_TOKEN?: unknown;
27
+ }
28
+
29
+ /**
30
+ * Reads `window.IL_TOKEN` and stores it in sessionStorage, updating the
31
+ * stored value when the markup token differs from what is already cached.
32
+ *
33
+ * @returns the token value now held in sessionStorage, or `null` when no
34
+ * valid token is available.
35
+ */
36
+ export function syncToken(): string | null {
37
+ if (typeof window === 'undefined') {
38
+ return null;
39
+ }
40
+
41
+ const w = window as WindowWithToken;
42
+ const markupToken = typeof w.IL_TOKEN === 'string' ? w.IL_TOKEN.trim() : '';
43
+
44
+ let stored: string | null = null;
45
+ try {
46
+ stored = sessionStorage.getItem(TOKEN_STORAGE_KEY);
47
+ } catch {
48
+ // sessionStorage unavailable (e.g. privacy mode) — nothing we can do.
49
+ return markupToken || null;
50
+ }
51
+
52
+ // No usable markup token: keep whatever is already stored (if anything).
53
+ if (!markupToken) {
54
+ return stored;
55
+ }
56
+
57
+ // Store on first sight or whenever the markup token has changed.
58
+ if (stored !== markupToken) {
59
+ try {
60
+ sessionStorage.setItem(TOKEN_STORAGE_KEY, markupToken);
61
+ } catch {
62
+ /* storage write failed — return the markup value regardless */
63
+ }
64
+ }
65
+
66
+ return markupToken;
67
+ }
68
+
69
+ /**
70
+ * @returns the Infralytiqs token id currently held in sessionStorage, or
71
+ * `null` if none is stored / storage is unavailable.
72
+ */
73
+ export function getStoredToken(): string | null {
74
+ try {
75
+ return sessionStorage.getItem(TOKEN_STORAGE_KEY);
76
+ } catch {
77
+ return null;
78
+ }
79
+ }