@sharadtech/infralytiqs-sdk 1.0.1 → 1.0.3
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/buildScripts/Jenkinsfile.deploy +241 -125
- package/clients/publicis/arc/README.md +212 -0
- package/clients/publicis/arc/package-lock.json +808 -0
- package/clients/publicis/arc/package.json +23 -0
- package/clients/publicis/arc/rollup.config.mjs +28 -0
- package/clients/publicis/arc/src/index.js +2900 -0
- package/clients/publicis/atl/README.md +203 -0
- package/clients/publicis/atl/package-lock.json +808 -0
- package/clients/publicis/atl/package.json +23 -0
- package/clients/publicis/atl/rollup.config.mjs +28 -0
- package/clients/publicis/atl/src/index.js +2902 -0
- package/clients/publicis/colab/README.md +213 -0
- package/clients/publicis/colab/package-lock.json +808 -0
- package/clients/publicis/colab/package.json +23 -0
- package/clients/publicis/colab/rollup.config.mjs +28 -0
- package/clients/publicis/colab/src/index.js +2901 -0
- package/clients/publicis/fnacdarty/README.md +210 -0
- package/clients/publicis/fnacdarty/package-lock.json +808 -0
- package/clients/publicis/fnacdarty/package.json +23 -0
- package/clients/publicis/fnacdarty/rollup.config.mjs +28 -0
- package/clients/publicis/fnacdarty/src/index.js +2900 -0
- package/clients/publicis/garnier/README.md +206 -0
- package/clients/publicis/garnier/package-lock.json +808 -0
- package/clients/publicis/garnier/package.json +23 -0
- package/clients/publicis/garnier/rollup.config.mjs +28 -0
- package/clients/publicis/garnier/src/index.js +2894 -0
- package/clients/publicis/pmigtr/README.md +212 -0
- package/clients/publicis/pmigtr/package-lock.json +808 -0
- package/clients/publicis/pmigtr/package.json +23 -0
- package/clients/publicis/pmigtr/rollup.config.mjs +28 -0
- package/clients/publicis/pmigtr/src/index.js +2903 -0
- package/clients/publicis/ps/README.md +105 -5
- package/clients/publicis/ps/package-lock.json +2 -2
- package/clients/publicis/ps/package.json +1 -1
- package/clients/publicis/ps/src/index.js +2473 -70
- package/clients/publicis/px/README.md +209 -0
- package/clients/publicis/px/package-lock.json +808 -0
- package/clients/publicis/px/package.json +23 -0
- package/clients/publicis/px/rollup.config.mjs +28 -0
- package/clients/publicis/px/src/index.js +2899 -0
- package/clients/publicis/pxp/README.md +212 -0
- package/clients/publicis/pxp/package-lock.json +808 -0
- package/clients/publicis/pxp/package.json +23 -0
- package/clients/publicis/pxp/rollup.config.mjs +28 -0
- package/clients/publicis/pxp/src/index.js +2900 -0
- package/clients/publicis/razorfish/README.md +210 -0
- package/clients/publicis/razorfish/package-lock.json +808 -0
- package/clients/publicis/razorfish/package.json +23 -0
- package/clients/publicis/razorfish/rollup.config.mjs +28 -0
- package/clients/publicis/razorfish/src/index.js +2900 -0
- package/clients/publicis/stellantis/README.md +208 -0
- package/clients/publicis/stellantis/package-lock.json +808 -0
- package/clients/publicis/stellantis/package.json +23 -0
- package/clients/publicis/stellantis/rollup.config.mjs +28 -0
- package/clients/publicis/stellantis/src/index.js +2895 -0
- package/clients/publicis/visa/README.md +208 -0
- package/clients/publicis/visa/package-lock.json +808 -0
- package/clients/publicis/visa/package.json +23 -0
- package/clients/publicis/visa/rollup.config.mjs +28 -0
- package/clients/publicis/visa/src/index.js +2894 -0
- package/dist/infralytiqs.js +272 -3
- package/dist/infralytiqs.min.js +2 -2
- package/package.json +1 -1
- package/src/envConfig.ts +1 -1
- package/src/index.ts +31 -0
- package/src/remoteConfig.ts +164 -0
- package/src/token.ts +79 -0
- package/src/tracker.ts +30 -0
- package/src/types.ts +10 -2
package/dist/infralytiqs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! infralytiqs-sdk v1.0.
|
|
1
|
+
/*! infralytiqs-sdk v1.0.3 | (c) 2026 sharadtech | License: See LICENSE | Built: 2026-06-09T23:55:14.571Z */
|
|
2
2
|
var Infralytiqs = (function (exports) {
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -22,7 +22,7 @@ var Infralytiqs = (function (exports) {
|
|
|
22
22
|
/** LocalStorage key prefix for tracker state */
|
|
23
23
|
STORAGE_PREFIX: '_il_',
|
|
24
24
|
/** SDK version — injected into every event payload for debugging */
|
|
25
|
-
SDK_VERSION: '1.0.
|
|
25
|
+
SDK_VERSION: '1.0.3',
|
|
26
26
|
/** Maximum retry attempts for failed flushes */
|
|
27
27
|
MAX_RETRIES: 2,
|
|
28
28
|
/** Enable debug logging to browser console (overridden by init config) */
|
|
@@ -572,6 +572,223 @@ var Infralytiqs = (function (exports) {
|
|
|
572
572
|
return memoryCoords;
|
|
573
573
|
};
|
|
574
574
|
|
|
575
|
+
/**
|
|
576
|
+
* Infralytiqs token sync.
|
|
577
|
+
*
|
|
578
|
+
* The host page (e.g. the AEM Infralytiqs.html HTL fragment) renders the
|
|
579
|
+
* tenant's current Infralytiqs token id into a global:
|
|
580
|
+
*
|
|
581
|
+
* <script>window.IL_TOKEN = "....";</script>
|
|
582
|
+
*
|
|
583
|
+
* On SDK load we copy that value into sessionStorage so the rest of the page
|
|
584
|
+
* (and any embedded Infralytiqs widgets — e.g. the "Infralytiqs SDK" report
|
|
585
|
+
* snippet) can read a single, tab-scoped source of truth. The token is
|
|
586
|
+
* tab-scoped on purpose: it lives only for the current session/tab, mirroring
|
|
587
|
+
* how the host page re-emits a fresh `window.IL_TOKEN` on every render.
|
|
588
|
+
*
|
|
589
|
+
* Update semantics: if a token is already stored and the markup provides a
|
|
590
|
+
* different (non-empty) value, the stored token is replaced with the markup
|
|
591
|
+
* value so the freshest server-issued token always wins.
|
|
592
|
+
*/
|
|
593
|
+
/** sessionStorage key holding the Infralytiqs token id. */
|
|
594
|
+
const TOKEN_STORAGE_KEY = `${ENV.STORAGE_PREFIX}token`;
|
|
595
|
+
/**
|
|
596
|
+
* Reads `window.IL_TOKEN` and stores it in sessionStorage, updating the
|
|
597
|
+
* stored value when the markup token differs from what is already cached.
|
|
598
|
+
*
|
|
599
|
+
* @returns the token value now held in sessionStorage, or `null` when no
|
|
600
|
+
* valid token is available.
|
|
601
|
+
*/
|
|
602
|
+
function syncToken() {
|
|
603
|
+
if (typeof window === 'undefined') {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
const w = window;
|
|
607
|
+
const markupToken = typeof w.IL_TOKEN === 'string' ? w.IL_TOKEN.trim() : '';
|
|
608
|
+
let stored = null;
|
|
609
|
+
try {
|
|
610
|
+
stored = sessionStorage.getItem(TOKEN_STORAGE_KEY);
|
|
611
|
+
}
|
|
612
|
+
catch (_a) {
|
|
613
|
+
// sessionStorage unavailable (e.g. privacy mode) — nothing we can do.
|
|
614
|
+
return markupToken || null;
|
|
615
|
+
}
|
|
616
|
+
// No usable markup token: keep whatever is already stored (if anything).
|
|
617
|
+
if (!markupToken) {
|
|
618
|
+
return stored;
|
|
619
|
+
}
|
|
620
|
+
// Store on first sight or whenever the markup token has changed.
|
|
621
|
+
if (stored !== markupToken) {
|
|
622
|
+
try {
|
|
623
|
+
sessionStorage.setItem(TOKEN_STORAGE_KEY, markupToken);
|
|
624
|
+
}
|
|
625
|
+
catch (_b) {
|
|
626
|
+
/* storage write failed — return the markup value regardless */
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return markupToken;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* @returns the Infralytiqs token id currently held in sessionStorage, or
|
|
633
|
+
* `null` if none is stored / storage is unavailable.
|
|
634
|
+
*/
|
|
635
|
+
function getStoredToken() {
|
|
636
|
+
try {
|
|
637
|
+
return sessionStorage.getItem(TOKEN_STORAGE_KEY);
|
|
638
|
+
}
|
|
639
|
+
catch (_a) {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Remote tenant configuration fetch for the Infralytiqs SDK.
|
|
646
|
+
*
|
|
647
|
+
* After `init()`, the SDK calls the public st-ck-server endpoint
|
|
648
|
+
*
|
|
649
|
+
* GET {serverUrl}/il/analytics/{tenantId}/{siteId}/client-config?db_name={dbName}
|
|
650
|
+
* headers: { 'x-il-token': <window.IL_TOKEN> }
|
|
651
|
+
*
|
|
652
|
+
* which returns browser-safe behaviour flags configured on the tenant's
|
|
653
|
+
* ClickHouse server configuration in the Infralytiqs Settings UI
|
|
654
|
+
* ("Data Sources" → "Configured Servers"). Today that is:
|
|
655
|
+
*
|
|
656
|
+
* precise_visitor_location — when true, the SDK should request precise
|
|
657
|
+
* browser geolocation (visitor-consented) and attach lat/lng to events.
|
|
658
|
+
*
|
|
659
|
+
* Failure model — IMPORTANT: this endpoint may not exist yet on older
|
|
660
|
+
* server deployments, the token may be missing/expired, or the network may
|
|
661
|
+
* be down. None of that may ever break the host site or tracking, so:
|
|
662
|
+
*
|
|
663
|
+
* • No token available → skip the call entirely, resolve null.
|
|
664
|
+
* • Non-2xx (401/403/404/5xx) → resolve null silently.
|
|
665
|
+
* • Network error / timeout → resolve null silently.
|
|
666
|
+
* • Malformed JSON → resolve null silently.
|
|
667
|
+
*
|
|
668
|
+
* A successful response is cached in sessionStorage for the rest of the
|
|
669
|
+
* tab session so SPA navigations / repeat page loads within the tab don't
|
|
670
|
+
* re-hit the endpoint.
|
|
671
|
+
*/
|
|
672
|
+
/** Endpoint pattern — :tenant_id and :site_id are replaced at runtime. */
|
|
673
|
+
const CLIENT_CONFIG_PATH = '/il/analytics/:tenant_id/:site_id/client-config';
|
|
674
|
+
/** Abort the config fetch if the server hasn't answered within this window. */
|
|
675
|
+
const FETCH_TIMEOUT_MS = 6000;
|
|
676
|
+
/** sessionStorage key for the per-tab remote-config cache. */
|
|
677
|
+
const CACHE_KEY = `${ENV.STORAGE_PREFIX}client_cfg_v1`;
|
|
678
|
+
const scopeKey = (tenantId, siteId) => `${tenantId}::${siteId}`;
|
|
679
|
+
const readCache = (tenantId, siteId) => {
|
|
680
|
+
try {
|
|
681
|
+
const raw = sessionStorage.getItem(CACHE_KEY);
|
|
682
|
+
if (!raw)
|
|
683
|
+
return null;
|
|
684
|
+
const parsed = JSON.parse(raw);
|
|
685
|
+
if (parsed && parsed.scope === scopeKey(tenantId, siteId) && parsed.cfg) {
|
|
686
|
+
return parsed.cfg;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
catch (_a) {
|
|
690
|
+
/* unavailable / corrupted cache — fall through to a live fetch */
|
|
691
|
+
}
|
|
692
|
+
return null;
|
|
693
|
+
};
|
|
694
|
+
const writeCache = (tenantId, siteId, cfg) => {
|
|
695
|
+
try {
|
|
696
|
+
const envelope = { scope: scopeKey(tenantId, siteId), cfg };
|
|
697
|
+
sessionStorage.setItem(CACHE_KEY, JSON.stringify(envelope));
|
|
698
|
+
}
|
|
699
|
+
catch (_a) {
|
|
700
|
+
/* ignore — cache is best-effort */
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
/** Resolve the freshest available IL token (markup global wins over cache). */
|
|
704
|
+
const resolveToken = () => {
|
|
705
|
+
try {
|
|
706
|
+
return syncToken() || getStoredToken();
|
|
707
|
+
}
|
|
708
|
+
catch (_a) {
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
/**
|
|
713
|
+
* Fetches the tenant's remote client configuration.
|
|
714
|
+
*
|
|
715
|
+
* Resolves with the parsed flags, or `null` when the config could not be
|
|
716
|
+
* obtained for ANY reason (no token, endpoint missing, invalid token,
|
|
717
|
+
* network failure). Never rejects and never throws.
|
|
718
|
+
*/
|
|
719
|
+
function fetchRemoteClientConfig(serverUrl, tenantId, siteId, dbName, debug) {
|
|
720
|
+
try {
|
|
721
|
+
if (typeof window === 'undefined' || typeof fetch !== 'function') {
|
|
722
|
+
return Promise.resolve(null);
|
|
723
|
+
}
|
|
724
|
+
const cached = readCache(tenantId, siteId);
|
|
725
|
+
if (cached) {
|
|
726
|
+
if (debug)
|
|
727
|
+
console.log('[Infralytiqs] remote client-config (cached):', cached);
|
|
728
|
+
return Promise.resolve(cached);
|
|
729
|
+
}
|
|
730
|
+
const token = resolveToken();
|
|
731
|
+
if (!token) {
|
|
732
|
+
// Without a token the server would reject the call anyway — skip the
|
|
733
|
+
// round-trip entirely. Local init() config remains in effect.
|
|
734
|
+
if (debug)
|
|
735
|
+
console.log('[Infralytiqs] no IL token — skipping remote client-config fetch');
|
|
736
|
+
return Promise.resolve(null);
|
|
737
|
+
}
|
|
738
|
+
const path = CLIENT_CONFIG_PATH
|
|
739
|
+
.replace(':tenant_id', encodeURIComponent(tenantId))
|
|
740
|
+
.replace(':site_id', encodeURIComponent(siteId));
|
|
741
|
+
const qs = dbName ? `?db_name=${encodeURIComponent(dbName)}` : '';
|
|
742
|
+
const url = `${serverUrl.replace(/\/$/, '')}${path}${qs}`;
|
|
743
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
744
|
+
const timer = controller
|
|
745
|
+
? window.setTimeout(() => { try {
|
|
746
|
+
controller.abort();
|
|
747
|
+
}
|
|
748
|
+
catch ( /* noop */_a) { /* noop */ } }, FETCH_TIMEOUT_MS)
|
|
749
|
+
: null;
|
|
750
|
+
return fetch(url, {
|
|
751
|
+
method: 'GET',
|
|
752
|
+
headers: { 'x-il-token': token },
|
|
753
|
+
signal: controller ? controller.signal : undefined,
|
|
754
|
+
})
|
|
755
|
+
.then((res) => {
|
|
756
|
+
if (timer !== null)
|
|
757
|
+
window.clearTimeout(timer);
|
|
758
|
+
if (!res.ok) {
|
|
759
|
+
// 403 = invalid/expired token, 404 = endpoint not deployed yet.
|
|
760
|
+
// Both are expected states — degrade silently to local config.
|
|
761
|
+
if (debug)
|
|
762
|
+
console.log(`[Infralytiqs] remote client-config unavailable (HTTP ${res.status})`);
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
return res.json().then((body) => {
|
|
766
|
+
var _a;
|
|
767
|
+
const data = body && typeof body === 'object' ? ((_a = body.data) !== null && _a !== void 0 ? _a : body) : null;
|
|
768
|
+
if (!data || typeof data !== 'object')
|
|
769
|
+
return null;
|
|
770
|
+
const cfg = {
|
|
771
|
+
preciseVisitorLocation: data.precise_visitor_location === true,
|
|
772
|
+
};
|
|
773
|
+
writeCache(tenantId, siteId, cfg);
|
|
774
|
+
if (debug)
|
|
775
|
+
console.log('[Infralytiqs] remote client-config:', cfg);
|
|
776
|
+
return cfg;
|
|
777
|
+
}).catch(() => null);
|
|
778
|
+
})
|
|
779
|
+
.catch(() => {
|
|
780
|
+
if (timer !== null)
|
|
781
|
+
window.clearTimeout(timer);
|
|
782
|
+
if (debug)
|
|
783
|
+
console.log('[Infralytiqs] remote client-config fetch failed (network) — using local config');
|
|
784
|
+
return null;
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
catch (_a) {
|
|
788
|
+
return Promise.resolve(null);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
575
792
|
/** Hard cap on the pre-init buffer to avoid unbounded memory growth. */
|
|
576
793
|
const PRE_INIT_BUFFER_LIMIT = 100;
|
|
577
794
|
/**
|
|
@@ -673,6 +890,30 @@ var Infralytiqs = (function (exports) {
|
|
|
673
890
|
if (this.config.captureLocation) {
|
|
674
891
|
requestLocation(this.config.debug).catch(() => { });
|
|
675
892
|
}
|
|
893
|
+
// Fire-and-forget remote tenant configuration. The server's ClickHouse
|
|
894
|
+
// module configuration (Infralytiqs Settings → Data Sources) carries
|
|
895
|
+
// browser-safe behaviour flags — today "Capture Precise Visitor
|
|
896
|
+
// Location". When the fetch succeeds the remote flag is authoritative:
|
|
897
|
+
// • remote true → enable captureLocation and kick off the (consented)
|
|
898
|
+
// geolocation prompt, even if init() left it off.
|
|
899
|
+
// • remote false → disable captureLocation so subsequent events stop
|
|
900
|
+
// attaching cached coords.
|
|
901
|
+
// When the fetch fails for any reason (no token, endpoint not deployed
|
|
902
|
+
// yet, expired token, network down) it resolves null and the local
|
|
903
|
+
// init() config stays in effect — tracking is never disrupted.
|
|
904
|
+
fetchRemoteClientConfig(this.config.serverUrl, this.config.tenantId, this.config.siteId, this.config.dbName, this.config.debug).then((remote) => {
|
|
905
|
+
if (!remote)
|
|
906
|
+
return;
|
|
907
|
+
if (remote.preciseVisitorLocation && !this.config.captureLocation) {
|
|
908
|
+
this.config.captureLocation = true;
|
|
909
|
+
this.log('Remote config enabled precise visitor location');
|
|
910
|
+
requestLocation(this.config.debug).catch(() => { });
|
|
911
|
+
}
|
|
912
|
+
else if (!remote.preciseVisitorLocation && this.config.captureLocation) {
|
|
913
|
+
this.config.captureLocation = false;
|
|
914
|
+
this.log('Remote config disabled precise visitor location');
|
|
915
|
+
}
|
|
916
|
+
}).catch(() => { });
|
|
676
917
|
// Drain anything that arrived during the async bootstrap window.
|
|
677
918
|
if (this.preInitBuffer.length > 0) {
|
|
678
919
|
const buffered = this.preInitBuffer.splice(0);
|
|
@@ -985,7 +1226,34 @@ var Infralytiqs = (function (exports) {
|
|
|
985
1226
|
destroy() {
|
|
986
1227
|
tracker.destroy();
|
|
987
1228
|
},
|
|
1229
|
+
/**
|
|
1230
|
+
* Re-read `window.IL_TOKEN` and sync it into sessionStorage. Runs once
|
|
1231
|
+
* automatically on SDK load; can be called again after the host page
|
|
1232
|
+
* refreshes the token global.
|
|
1233
|
+
*
|
|
1234
|
+
* @returns the token now held in sessionStorage, or `null` if none.
|
|
1235
|
+
*/
|
|
1236
|
+
syncToken() {
|
|
1237
|
+
return syncToken();
|
|
1238
|
+
},
|
|
1239
|
+
/**
|
|
1240
|
+
* @returns the Infralytiqs token id currently held in sessionStorage.
|
|
1241
|
+
*/
|
|
1242
|
+
getToken() {
|
|
1243
|
+
return getStoredToken();
|
|
1244
|
+
},
|
|
988
1245
|
};
|
|
1246
|
+
// ─── Sync the Infralytiqs token into sessionStorage ─────────────────────
|
|
1247
|
+
// The host page renders the tenant's current token id as `window.IL_TOKEN`
|
|
1248
|
+
// (see AEM Infralytiqs.html). Copy it into sessionStorage on load so any
|
|
1249
|
+
// embedded report widget can pick it up, updating the stored value whenever
|
|
1250
|
+
// the markup token changes.
|
|
1251
|
+
try {
|
|
1252
|
+
syncToken();
|
|
1253
|
+
}
|
|
1254
|
+
catch (_a) {
|
|
1255
|
+
/* never throw out of SDK script-tag evaluation */
|
|
1256
|
+
}
|
|
989
1257
|
// ─── Auto-load the client-specific bootstrap ────────────────────────────
|
|
990
1258
|
// When the SDK script tag executes, look for `window.IL_CLIENT_BOOTSTRAP_LIB`
|
|
991
1259
|
// declared by the host page (e.g. by the AEM Infralytiqs.html Sightly
|
|
@@ -997,11 +1265,12 @@ var Infralytiqs = (function (exports) {
|
|
|
997
1265
|
try {
|
|
998
1266
|
loadClientBootstrap();
|
|
999
1267
|
}
|
|
1000
|
-
catch (
|
|
1268
|
+
catch (_b) {
|
|
1001
1269
|
/* never throw out of SDK script-tag evaluation */
|
|
1002
1270
|
}
|
|
1003
1271
|
|
|
1004
1272
|
exports.LICENSE_MODULE_ID = LICENSE_MODULE_ID;
|
|
1273
|
+
exports.TOKEN_STORAGE_KEY = TOKEN_STORAGE_KEY;
|
|
1005
1274
|
exports.default = Infralytiqs;
|
|
1006
1275
|
|
|
1007
1276
|
Object.defineProperty(exports, '__esModule', { value: true });
|
package/dist/infralytiqs.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! infralytiqs-sdk v1.0.
|
|
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 v(t,...e){t&&"undefined"!=typeof console&&console.log("[Infralytiqs]",...e)}function y(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",b="il_geo_deny_v1",S=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 A=()=>{if(E)return;const t=(()=>{const t=w();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)},x=t=>{var n;return"undefined"==typeof window||"undefined"==typeof navigator?Promise.resolve(null):(A(),E?Promise.resolve(E):(()=>{const t=w();if(!t)return!1;try{const e=t.getItem(b);if(!e)return!1;const n=Number(e);if(Number.isFinite(n)&&Date.now()-n<864e5)return!0;t.removeItem(b)}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=w();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=w();if(t)try{t.setItem(b,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:S,maximumAge:36e5})}catch(t){window.clearTimeout(r),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,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 L=(()=>{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""})(),R="__il_bootstrap_loaded__";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=y(this.config,(t,e,n,i)=>{this.trackRaw(t,e,n,i)}),this.initialized=!0,this.config.captureLocation&&x(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: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||(A(),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);v(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 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)}},k={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()}};try{!function(){if("undefined"==typeof window||"undefined"==typeof document)return;const t=window;if(t[R])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(!L)return t;try{return new URL(t,L).href}catch(e){return t}}(e);t[R]=!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.default=k,Object.defineProperty(t,"__esModule",{value:!0}),t}({});
|
|
1
|
+
/*! infralytiqs-sdk v1.0.3 | (c) 2026 sharadtech | License: See LICENSE | Built: 2026-06-09T23:55:14.571Z */
|
|
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.3",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 c(t,e){try{localStorage.setItem(t,e)}catch(t){}}function a(){let t=s(n);return t||(t=r(),c(n,t)),t}function l(t){const e=Date.now(),n=parseInt(s(o)||"0",10);let a=s(i);return(!a||e-n>t)&&(a=r(),c(i,a)),c(o,String(e)),a}let u="";function d(t){u=t;try{sessionStorage.setItem(`${e.STORAGE_PREFIX}user_id`,t)}catch(t){}}function f(){if(u)return u;try{u=sessionStorage.getItem(`${e.STORAGE_PREFIX}user_id`)||""}catch(t){}return u}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 c=t.getAttribute("data-il-track");return c&&(o.track_label=c),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)),c=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,c)};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",b="il_geo_deny_v1",w=8e3,S=()=>{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 T=null,E=null;const O=()=>{if(T)return;const t=(()=>{const t=S();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&&(T=t)},A=t=>{var n;return"undefined"==typeof window||"undefined"==typeof navigator?Promise.resolve(null):(O(),T?Promise.resolve(T):(()=>{const t=S();if(!t)return!1;try{const e=t.getItem(b);if(!e)return!1;const n=Number(e);if(Number.isFinite(n)&&Date.now()-n<864e5)return!0;t.removeItem(b)}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)?E||(E=new Promise(n=>{let i=!1;const o=t=>{i||(i=!0,E=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()};T=i,(t=>{const e=S();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=S();if(t)try{t.setItem(b,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)}}),E):Promise.resolve(null))},x=`${e.STORAGE_PREFIX}token`;function L(){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(x)}catch(t){return e||null}if(!e)return n;if(n!==e)try{sessionStorage.setItem(x,e)}catch(t){}return e}function R(){try{return sessionStorage.getItem(x)}catch(t){return null}}const $=`${e.STORAGE_PREFIX}client_cfg_v1`,k=(t,e)=>`${t}::${e}`;function P(t,e,n,i,o){try{if("undefined"==typeof window||"function"!=typeof fetch)return Promise.resolve(null);const r=((t,e)=>{try{const n=sessionStorage.getItem($);if(!n)return null;const i=JSON.parse(n);if(i&&i.scope===k(t,e)&&i.cfg)return i.cfg}catch(t){}return null})(e,n);if(r)return o&&console.log("[Infralytiqs] remote client-config (cached):",r),Promise.resolve(r);const s=(()=>{try{return L()||R()}catch(t){return null}})();if(!s)return o&&console.log("[Infralytiqs] no IL token — skipping remote client-config fetch"),Promise.resolve(null);const c="/il/analytics/:tenant_id/:site_id/client-config".replace(":tenant_id",encodeURIComponent(e)).replace(":site_id",encodeURIComponent(n)),a=i?`?db_name=${encodeURIComponent(i)}`:"",l=`${t.replace(/\/$/,"")}${c}${a}`,u="undefined"!=typeof AbortController?new AbortController:null,d=u?window.setTimeout(()=>{try{u.abort()}catch(t){}},6e3):null;return fetch(l,{method:"GET",headers:{"x-il-token":s},signal:u?u.signal:void 0}).then(t=>(null!==d&&window.clearTimeout(d),t.ok?t.json().then(t=>{var i;const r=t&&"object"==typeof t?null!==(i=t.data)&&void 0!==i?i:t:null;if(!r||"object"!=typeof r)return null;const s={preciseVisitorLocation:!0===r.precise_visitor_location};return((t,e,n)=>{try{const i={scope:k(t,e),cfg:n};sessionStorage.setItem($,JSON.stringify(i))}catch(t){}})(e,n,s),o&&console.log("[Infralytiqs] remote client-config:",s),s}).catch(()=>null):(o&&console.log(`[Infralytiqs] remote client-config unavailable (HTTP ${t.status})`),null))).catch(()=>(null!==d&&window.clearTimeout(d),o&&console.log("[Infralytiqs] remote client-config fetch failed (network) — using local config"),null))}catch(t){return Promise.resolve(null)}}function U(){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 C=(()=>{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""})(),N="__il_bootstrap_loaded__";const q=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(()=>{}),P(this.config.serverUrl,this.config.tenantId,this.config.siteId,this.config.dbName,this.config.debug).then(t=>{t&&(t.preciseVisitorLocation&&!this.config.captureLocation?(this.config.captureLocation=!0,this.log("Remote config enabled precise visitor location"),A(this.config.debug).catch(()=>{})):!t.preciseVisitorLocation&&this.config.captureLocation&&(this.config.captureLocation=!1,this.log("Remote config disabled precise visitor location")))}).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,c,u;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:a(),session_id:l(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:U(),country_code:m(),device_type:g(),device_os:h(),utm_source:null!==(c=d.utm_source)&&void 0!==c?c: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=T||(O(),T);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!==(u=this.config.batchSize)&&void 0!==u?u: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)}},M={init(t){q.init(t)},track(t,e,n,i){q.track(t,e,n,i)},identify(t){q.identify(t)},flush:()=>q.flush(),destroy(){q.destroy()},syncToken:()=>L(),getToken:()=>R()};try{L()}catch(t){}try{!function(){if("undefined"==typeof window||"undefined"==typeof document)return;const t=window;if(t[N])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(!C)return t;try{return new URL(t,C).href}catch(e){return t}}(e);t[N]=!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=x,t.default=M,Object.defineProperty(t,"__esModule",{value:!0}),t}({});
|
package/package.json
CHANGED
package/src/envConfig.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -34,8 +34,10 @@
|
|
|
34
34
|
import { InfralytiqsTracker } from './tracker';
|
|
35
35
|
import type { InfralytiqsConfig } from './types';
|
|
36
36
|
import { loadClientBootstrap } from './bootstrapLoader';
|
|
37
|
+
import { syncToken, getStoredToken } from './token';
|
|
37
38
|
|
|
38
39
|
export { LICENSE_MODULE_ID } from './licenseModuleId';
|
|
40
|
+
export { TOKEN_STORAGE_KEY } from './token';
|
|
39
41
|
export type { InfralytiqsConfig };
|
|
40
42
|
|
|
41
43
|
const tracker = new InfralytiqsTracker();
|
|
@@ -86,10 +88,39 @@ const Infralytiqs = {
|
|
|
86
88
|
destroy(): void {
|
|
87
89
|
tracker.destroy();
|
|
88
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
|
+
},
|
|
89
109
|
};
|
|
90
110
|
|
|
91
111
|
export default Infralytiqs;
|
|
92
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
|
+
|
|
93
124
|
// ─── Auto-load the client-specific bootstrap ────────────────────────────
|
|
94
125
|
// When the SDK script tag executes, look for `window.IL_CLIENT_BOOTSTRAP_LIB`
|
|
95
126
|
// declared by the host page (e.g. by the AEM Infralytiqs.html Sightly
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote tenant configuration fetch for the Infralytiqs SDK.
|
|
3
|
+
*
|
|
4
|
+
* After `init()`, the SDK calls the public st-ck-server endpoint
|
|
5
|
+
*
|
|
6
|
+
* GET {serverUrl}/il/analytics/{tenantId}/{siteId}/client-config?db_name={dbName}
|
|
7
|
+
* headers: { 'x-il-token': <window.IL_TOKEN> }
|
|
8
|
+
*
|
|
9
|
+
* which returns browser-safe behaviour flags configured on the tenant's
|
|
10
|
+
* ClickHouse server configuration in the Infralytiqs Settings UI
|
|
11
|
+
* ("Data Sources" → "Configured Servers"). Today that is:
|
|
12
|
+
*
|
|
13
|
+
* precise_visitor_location — when true, the SDK should request precise
|
|
14
|
+
* browser geolocation (visitor-consented) and attach lat/lng to events.
|
|
15
|
+
*
|
|
16
|
+
* Failure model — IMPORTANT: this endpoint may not exist yet on older
|
|
17
|
+
* server deployments, the token may be missing/expired, or the network may
|
|
18
|
+
* be down. None of that may ever break the host site or tracking, so:
|
|
19
|
+
*
|
|
20
|
+
* • No token available → skip the call entirely, resolve null.
|
|
21
|
+
* • Non-2xx (401/403/404/5xx) → resolve null silently.
|
|
22
|
+
* • Network error / timeout → resolve null silently.
|
|
23
|
+
* • Malformed JSON → resolve null silently.
|
|
24
|
+
*
|
|
25
|
+
* A successful response is cached in sessionStorage for the rest of the
|
|
26
|
+
* tab session so SPA navigations / repeat page loads within the tab don't
|
|
27
|
+
* re-hit the endpoint.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { ENV } from './envConfig';
|
|
31
|
+
import { getStoredToken, syncToken } from './token';
|
|
32
|
+
|
|
33
|
+
/** Endpoint pattern — :tenant_id and :site_id are replaced at runtime. */
|
|
34
|
+
const CLIENT_CONFIG_PATH = '/il/analytics/:tenant_id/:site_id/client-config';
|
|
35
|
+
|
|
36
|
+
/** Abort the config fetch if the server hasn't answered within this window. */
|
|
37
|
+
const FETCH_TIMEOUT_MS = 6000;
|
|
38
|
+
|
|
39
|
+
/** sessionStorage key for the per-tab remote-config cache. */
|
|
40
|
+
const CACHE_KEY = `${ENV.STORAGE_PREFIX}client_cfg_v1`;
|
|
41
|
+
|
|
42
|
+
/** Browser-safe behaviour flags delivered by the server. */
|
|
43
|
+
export interface RemoteClientConfig {
|
|
44
|
+
/** Tenant may capture precise (consented) visitor geolocation. */
|
|
45
|
+
preciseVisitorLocation: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface CacheEnvelope {
|
|
49
|
+
/** Cache is scoped to tenant/site so a SPA can't reuse a stale scope. */
|
|
50
|
+
scope: string;
|
|
51
|
+
cfg: RemoteClientConfig;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const scopeKey = (tenantId: string, siteId: string): string => `${tenantId}::${siteId}`;
|
|
55
|
+
|
|
56
|
+
const readCache = (tenantId: string, siteId: string): RemoteClientConfig | null => {
|
|
57
|
+
try {
|
|
58
|
+
const raw = sessionStorage.getItem(CACHE_KEY);
|
|
59
|
+
if (!raw) return null;
|
|
60
|
+
const parsed = JSON.parse(raw) as CacheEnvelope;
|
|
61
|
+
if (parsed && parsed.scope === scopeKey(tenantId, siteId) && parsed.cfg) {
|
|
62
|
+
return parsed.cfg;
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
/* unavailable / corrupted cache — fall through to a live fetch */
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const writeCache = (tenantId: string, siteId: string, cfg: RemoteClientConfig): void => {
|
|
71
|
+
try {
|
|
72
|
+
const envelope: CacheEnvelope = { scope: scopeKey(tenantId, siteId), cfg };
|
|
73
|
+
sessionStorage.setItem(CACHE_KEY, JSON.stringify(envelope));
|
|
74
|
+
} catch {
|
|
75
|
+
/* ignore — cache is best-effort */
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** Resolve the freshest available IL token (markup global wins over cache). */
|
|
80
|
+
const resolveToken = (): string | null => {
|
|
81
|
+
try {
|
|
82
|
+
return syncToken() || getStoredToken();
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Fetches the tenant's remote client configuration.
|
|
90
|
+
*
|
|
91
|
+
* Resolves with the parsed flags, or `null` when the config could not be
|
|
92
|
+
* obtained for ANY reason (no token, endpoint missing, invalid token,
|
|
93
|
+
* network failure). Never rejects and never throws.
|
|
94
|
+
*/
|
|
95
|
+
export function fetchRemoteClientConfig(
|
|
96
|
+
serverUrl: string,
|
|
97
|
+
tenantId: string,
|
|
98
|
+
siteId: string,
|
|
99
|
+
dbName?: string,
|
|
100
|
+
debug?: boolean,
|
|
101
|
+
): Promise<RemoteClientConfig | null> {
|
|
102
|
+
try {
|
|
103
|
+
if (typeof window === 'undefined' || typeof fetch !== 'function') {
|
|
104
|
+
return Promise.resolve(null);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const cached = readCache(tenantId, siteId);
|
|
108
|
+
if (cached) {
|
|
109
|
+
if (debug) console.log('[Infralytiqs] remote client-config (cached):', cached);
|
|
110
|
+
return Promise.resolve(cached);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const token = resolveToken();
|
|
114
|
+
if (!token) {
|
|
115
|
+
// Without a token the server would reject the call anyway — skip the
|
|
116
|
+
// round-trip entirely. Local init() config remains in effect.
|
|
117
|
+
if (debug) console.log('[Infralytiqs] no IL token — skipping remote client-config fetch');
|
|
118
|
+
return Promise.resolve(null);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const path = CLIENT_CONFIG_PATH
|
|
122
|
+
.replace(':tenant_id', encodeURIComponent(tenantId))
|
|
123
|
+
.replace(':site_id', encodeURIComponent(siteId));
|
|
124
|
+
const qs = dbName ? `?db_name=${encodeURIComponent(dbName)}` : '';
|
|
125
|
+
const url = `${serverUrl.replace(/\/$/, '')}${path}${qs}`;
|
|
126
|
+
|
|
127
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
128
|
+
const timer = controller
|
|
129
|
+
? window.setTimeout(() => { try { controller.abort(); } catch { /* noop */ } }, FETCH_TIMEOUT_MS)
|
|
130
|
+
: null;
|
|
131
|
+
|
|
132
|
+
return fetch(url, {
|
|
133
|
+
method: 'GET',
|
|
134
|
+
headers: { 'x-il-token': token },
|
|
135
|
+
signal: controller ? controller.signal : undefined,
|
|
136
|
+
})
|
|
137
|
+
.then((res) => {
|
|
138
|
+
if (timer !== null) window.clearTimeout(timer);
|
|
139
|
+
if (!res.ok) {
|
|
140
|
+
// 403 = invalid/expired token, 404 = endpoint not deployed yet.
|
|
141
|
+
// Both are expected states — degrade silently to local config.
|
|
142
|
+
if (debug) console.log(`[Infralytiqs] remote client-config unavailable (HTTP ${res.status})`);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return res.json().then((body: any) => {
|
|
146
|
+
const data = body && typeof body === 'object' ? (body.data ?? body) : null;
|
|
147
|
+
if (!data || typeof data !== 'object') return null;
|
|
148
|
+
const cfg: RemoteClientConfig = {
|
|
149
|
+
preciseVisitorLocation: data.precise_visitor_location === true,
|
|
150
|
+
};
|
|
151
|
+
writeCache(tenantId, siteId, cfg);
|
|
152
|
+
if (debug) console.log('[Infralytiqs] remote client-config:', cfg);
|
|
153
|
+
return cfg;
|
|
154
|
+
}).catch(() => null);
|
|
155
|
+
})
|
|
156
|
+
.catch(() => {
|
|
157
|
+
if (timer !== null) window.clearTimeout(timer);
|
|
158
|
+
if (debug) console.log('[Infralytiqs] remote client-config fetch failed (network) — using local config');
|
|
159
|
+
return null;
|
|
160
|
+
});
|
|
161
|
+
} catch {
|
|
162
|
+
return Promise.resolve(null);
|
|
163
|
+
}
|
|
164
|
+
}
|