From 63d4c3ea869e4271b93018411ac5854ca14f6d2c Mon Sep 17 00:00:00 2001 From: turtledreams <62231246+turtledreams@users.noreply.github.com> Date: Fri, 18 Apr 2025 22:26:36 +0900 Subject: [PATCH 1/3] Version 25.4 --- CHANGELOG.md | 16 + cypress/e2e/bridged_utils.cy.js | 2 +- cypress/e2e/device_id_init_scenarios.cy.js | 171 +++--- cypress/e2e/integration.cy.js | 39 +- cypress/e2e/sdk_behavior.cy.js | 233 ++++++++ cypress/support/helper.js | 178 +++++- lib/countly.d.ts | 5 + lib/countly.js | 652 ++++++++++++++------- lib/countly.min.js | 395 +++++++------ 9 files changed, 1166 insertions(+), 525 deletions(-) create mode 100644 cypress/e2e/sdk_behavior.cy.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e1bcf68c..a08a07b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## 25.4.0 + +- ! Minor Breaking Change ! SDK now has Server Configuration feature and it is enabled by default. Changes made on SDK Manager > SDK Configuration on your server will affect SDK behavior directly. + +- Mitigated an issue about orientation detection in Safari + +- Improved init time Content Zone logic +- Improved error handler to include script loading issues +- Improved the wrapper of Feedback Widgets + +- Added `refreshContentZone` method to Content interface for refreshing Content Zone requests +- Added `behavior_settings` init time method for providing server configuration during first initialization +- Added `content_whitelist` init time method that lets you whitelist your other domains for displaying Content + +- `max_logs` config option value will not be used anymore (use `max_breadcrumb_count` instead) + ## 25.1.0 - Improved orientation reporting precision. diff --git a/cypress/e2e/bridged_utils.cy.js b/cypress/e2e/bridged_utils.cy.js index 9c29ecc4..ae8d4315 100644 --- a/cypress/e2e/bridged_utils.cy.js +++ b/cypress/e2e/bridged_utils.cy.js @@ -15,7 +15,7 @@ function initMain(name, version) { } const SDK_NAME = "javascript_native_web"; -const SDK_VERSION = "25.1.0"; +const SDK_VERSION = "25.4.0"; // tests describe("Bridged SDK Utilities Tests", () => { diff --git a/cypress/e2e/device_id_init_scenarios.cy.js b/cypress/e2e/device_id_init_scenarios.cy.js index 8cc0ce90..adfc787c 100644 --- a/cypress/e2e/device_id_init_scenarios.cy.js +++ b/cypress/e2e/device_id_init_scenarios.cy.js @@ -94,7 +94,7 @@ function initMain(deviceId, offline, searchQuery, clear) { device_id: deviceId, debug: true, clear_stored_id: clear, - getSearchQuery: function() { + getSearchQuery: function () { return searchQuery; }, offline_mode: offline @@ -115,14 +115,19 @@ function checkRequestsForT(queue, expectedInternalType) { expect(queue[i].t).to.eq(expectedInternalType); } } -function checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType, temp) { +function checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType, temp, afterOffline) { var directReqs = Countly._internals.testingGetRequests(); // get direct requests cy.log("Requests: " + JSON.stringify(directReqs)); - expect(directReqs.length).to.eq(temp ? 0 : 2); + expect(directReqs.length).to.eq(temp ? 0 : afterOffline ? 4 : 3); for (var i = 0; i < directReqs.length; i++) { - expect(directReqs[i].params.device_id).to.eq(afterInitDeviceId); - expect(directReqs[i].params.t).to.eq(afterInitDeviceIdType); + if (afterOffline && directReqs[i].functionName == "server_config" && i == directReqs.length - 1) { + expect(directReqs[i].params.device_id).to.be.oneOf(["id_2", "storedID", "newID"]); + expect(directReqs[i].params.t).to.eq(DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED); + } else { + expect(directReqs[i].params.device_id).to.eq(afterInitDeviceId); + expect(directReqs[i].params.t).to.eq(afterInitDeviceIdType); + } } } function checkEachStoredReqForIDandT(afterInitDeviceId, afterInitDeviceIdType) { @@ -170,7 +175,7 @@ function generateSomeEvents() { // some events/requests Countly.begin_session(); Countly.track_pageview(); - Countly.add_event({key: "test", segmentation: {"segment": "segment"}}); + Countly.add_event({ key: "test", segmentation: { "segment": "segment" } }); } function setURLCheck(deviceID) { @@ -253,10 +258,10 @@ function changeIDTests(afterInitDeviceId, afterInitDeviceIdType, afterOffline) { // wait for things to resolve cy.wait(550).then(() => { // direct requests would have the old device id (hc and session) - checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType); + checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType, false, true); // after ID events - checkStoredReqQueueAfterIDChange(changedID2, changedIDType2, afterOffline? 3 : 2); // no end and begin session in offline mode => device id change scenario + checkStoredReqQueueAfterIDChange(changedID2, changedIDType2, afterOffline ? 3 : 2); // no end and begin session in offline mode => device id change scenario }); }); @@ -275,17 +280,17 @@ var DeviceIdTypeInternalEnumsTest = { TEMPORARY_ID: 2, URL_PROVIDED: 3 }; -describe("Device Id tests during first init", ()=>{ +describe("Device Id tests during first init", () => { // sdk is initialized w/o custom device id, w/o offline mode, w/o utm device id // we provide no device id information sdk should generate the id - it("1-SDK is initialized without custom device id, without offline mode, without utm device id", ()=>{ + it("1-SDK is initialized without custom device id, without offline mode, without utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); - + const afterInitDeviceId = Countly.get_device_id(); const afterInitDeviceIdType = Countly.get_device_id_type(); - + expect(afterInitDeviceIdType).to.eq(Countly.DeviceIdType.SDK_GENERATED); validateSdkGeneratedId(afterInitDeviceId); validateInternalDeviceIdType(DeviceIdTypeInternalEnumsTest.SDK_GENERATED); @@ -301,17 +306,17 @@ describe("Device Id tests during first init", ()=>{ }); }); // we provide device id information sdk should use it - it("2-SDK is initialized with custom device id, without offline mode, without utm device id", ()=>{ + it("2-SDK is initialized with custom device id, without offline mode, without utm device id", () => { hp.haltAndClearStorage(() => { initMain("customID", false, undefined); const afterInitDeviceId = Countly.get_device_id(); const afterInitDeviceIdType = Countly.get_device_id_type(); - + expect(afterInitDeviceIdType).to.equal(Countly.DeviceIdType.DEVELOPER_SUPPLIED); expect(afterInitDeviceId).to.eq("customID"); validateInternalDeviceIdType(DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED); - + generateSomeEvents(); // wait for things to resolve @@ -322,9 +327,9 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - + // we provide no device id information sdk should generate the id - it("3-SDK is initialized without custom device id, with offline mode, without utm device id", ()=>{ + it("3-SDK is initialized without custom device id, with offline mode, without utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, true, undefined); @@ -345,13 +350,13 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("4-SDK is initialized without custom device id, without offline mode, with utm device id", ()=>{ + it("4-SDK is initialized without custom device id, without offline mode, with utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, "?cly_device_id=someID"); setURLCheck("someID"); }); }); - it("5-SDK is initialized with custom device id, with offline mode, without utm device id", ()=>{ + it("5-SDK is initialized with custom device id, with offline mode, without utm device id", () => { hp.haltAndClearStorage(() => { initMain("customID", true, undefined); @@ -372,19 +377,19 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("6-SDK is initialized with custom device id, without offline mode, with utm device id", ()=>{ + it("6-SDK is initialized with custom device id, without offline mode, with utm device id", () => { hp.haltAndClearStorage(() => { initMain("customID2", false, "?cly_device_id=someID1"); setURLCheck("someID1"); }); }); - it("7-SDK is initialized without custom device id, with offline mode, with utm device id", ()=>{ + it("7-SDK is initialized without custom device id, with offline mode, with utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, true, "?cly_device_id=someID2"); setURLCheck("someID2"); }); }); - it("8-SDK is initialized with custom device id, with offline mode, with utm device id", ()=>{ + it("8-SDK is initialized with custom device id, with offline mode, with utm device id", () => { hp.haltAndClearStorage(() => { initMain("customID3", true, "?cly_device_id=someID3"); setURLCheck("someID3"); @@ -393,7 +398,7 @@ describe("Device Id tests during first init", ()=>{ // Here tests focus the device id change and offline mode // first pair - it("9-SDK is initialized with no device id, not offline mode, not utm device id", ()=>{ + it("9-SDK is initialized with no device id, not offline mode, not utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); @@ -430,7 +435,7 @@ describe("Device Id tests during first init", ()=>{ }); }); - it("10-SDK is initialized with no device id, not offline mode, not utm device id, but then offline", ()=>{ + it("10-SDK is initialized with no device id, not offline mode, not utm device id, but then offline", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); @@ -459,7 +464,7 @@ describe("Device Id tests during first init", ()=>{ // wait for things to resolve cy.wait(550).then(() => { // direct requests would have the old device id (hc and session) - checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType); + checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType, false, true); // after ID events checkStoredReqQueueAfterIDChange(changedID, changedIDType, true); // no end and begin session in offline mode => device id change scenario @@ -468,7 +473,7 @@ describe("Device Id tests during first init", ()=>{ }); }); // second pair - it("11-SDK is initialized with user defined device id, not offline mode, not utm device id", ()=>{ + it("11-SDK is initialized with user defined device id, not offline mode, not utm device id", () => { hp.haltAndClearStorage(() => { initMain("initID", false, undefined); @@ -505,7 +510,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("12-SDK is initialized with user defined device id, not offline mode, not utm device id, but then offline", ()=>{ + it("12-SDK is initialized with user defined device id, not offline mode, not utm device id, but then offline", () => { hp.haltAndClearStorage(() => { initMain("initID", false, undefined); @@ -535,7 +540,7 @@ describe("Device Id tests during first init", ()=>{ // wait for things to resolve cy.wait(550).then(() => { // direct requests would have the old device id (hc and session) - checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType); + checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType, false, true); // after ID events checkStoredReqQueueAfterIDChange(changedID, changedIDType, true); @@ -544,7 +549,7 @@ describe("Device Id tests during first init", ()=>{ }); }); // third pair - it("13-SDK is initialized with no device id, offline mode, no utm device id", ()=>{ + it("13-SDK is initialized with no device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, true, undefined); @@ -581,7 +586,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("14-SDK is initialized with no device id, offline mode, no utm device id, but then offline", ()=>{ + it("14-SDK is initialized with no device id, offline mode, no utm device id, but then offline", () => { hp.haltAndClearStorage(() => { initMain(undefined, true, undefined); @@ -620,7 +625,7 @@ describe("Device Id tests during first init", ()=>{ }); }); // fourth pair - it("15-SDK is initialized with no device id, no offline mode, utm device id", ()=>{ + it("15-SDK is initialized with no device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, "?cly_device_id=someID"); @@ -657,7 +662,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("16-SDK is initialized with no device id, no offline mode, utm device id, but then offline", ()=>{ + it("16-SDK is initialized with no device id, no offline mode, utm device id, but then offline", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, "?cly_device_id=someID"); @@ -687,7 +692,7 @@ describe("Device Id tests during first init", ()=>{ // wait for things to resolve cy.wait(550).then(() => { // direct requests would have the old device id (hc and session) - checkEachDirectReqForIDandT(afterInitDeviceId, DeviceIdTypeInternalEnumsTest.URL_PROVIDED); + checkEachDirectReqForIDandT(afterInitDeviceId, DeviceIdTypeInternalEnumsTest.URL_PROVIDED, false, true); // after ID events checkStoredReqQueueAfterIDChange(changedID, changedIDType, true); @@ -700,30 +705,30 @@ describe("Device Id tests during first init", ()=>{ it("17-Stored ID precedence, SDK is initialized with no device id, not offline mode, no utm device id", () => { storedIDUsingTests(undefined, undefined, undefined); }); - it("18-Stored ID precedence, SDK is initialized with device id, not offline mode, no utm device id", ()=>{ + it("18-Stored ID precedence, SDK is initialized with device id, not offline mode, no utm device id", () => { storedIDUsingTests("counterID", undefined, undefined); }); - it("19-Stored ID precedence, SDK is initialized with no device id, offline mode, no utm device id", ()=>{ + it("19-Stored ID precedence, SDK is initialized with no device id, offline mode, no utm device id", () => { storedIDUsingTests(undefined, true, undefined); }); - it("20-Stored ID precedence, SDK is initialized with no device id, no offline mode, utm device id", ()=>{ + it("20-Stored ID precedence, SDK is initialized with no device id, no offline mode, utm device id", () => { storedIDUsingTests(undefined, undefined, "?cly_device_id=abab"); }); - it("21-Stored ID precedence, SDK is initialized with device id, offline mode, no utm device id", ()=>{ + it("21-Stored ID precedence, SDK is initialized with device id, offline mode, no utm device id", () => { storedIDUsingTests("counterID", true, undefined); }); - it("22-Stored ID precedence, SDK is initialized with device id, no offline mode, utm device id", ()=>{ + it("22-Stored ID precedence, SDK is initialized with device id, no offline mode, utm device id", () => { storedIDUsingTests("counterID", undefined, "?cly_device_id=abab"); }); - it("23-Stored ID precedence, SDK is initialized no device id, offline mode, utm device id", ()=>{ + it("23-Stored ID precedence, SDK is initialized no device id, offline mode, utm device id", () => { storedIDUsingTests(undefined, true, "?cly_device_id=abab"); }); - it("24-Stored ID precedence, SDK is initialized with device id, offline mode, utm device id", ()=>{ + it("24-Stored ID precedence, SDK is initialized with device id, offline mode, utm device id", () => { storedIDUsingTests("counterID", true, "?cly_device_id=abab"); }); // Temporary ID was present in the local storage before initialization - it("25-Stored temp ID precedence, SDK is initialized with no device id, not offline mode, no utm device id", ()=>{ + it("25-Stored temp ID precedence, SDK is initialized with no device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -748,7 +753,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("26-Stored temp ID precedence, SDK is initialized with device id, not offline mode, no utm device id", ()=>{ + it("26-Stored temp ID precedence, SDK is initialized with device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -773,7 +778,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("27-Stored temp ID precedence, SDK is initialized with no device id, offline mode, no utm device id", ()=>{ + it("27-Stored temp ID precedence, SDK is initialized with no device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -798,7 +803,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("28-Stored temp ID precedence, SDK is initialized with no device id, no offline mode, utm device id", ()=>{ + it("28-Stored temp ID precedence, SDK is initialized with no device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -823,7 +828,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("29-Stored temp ID precedence, SDK is initialized with device id, offline mode, no utm device id", ()=>{ + it("29-Stored temp ID precedence, SDK is initialized with device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -848,7 +853,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("30-Stored temp ID precedence, SDK is initialized with device id, no offline mode, utm device id", ()=>{ + it("30-Stored temp ID precedence, SDK is initialized with device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -873,7 +878,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("31-Stored temp ID precedence, SDK is initialized with no device id, offline mode, utm device id", ()=>{ + it("31-Stored temp ID precedence, SDK is initialized with no device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -898,7 +903,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("32-Stored temp ID precedence, SDK is initialized with device id, offline mode, utm device id", ()=>{ + it("32-Stored temp ID precedence, SDK is initialized with device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -926,7 +931,7 @@ describe("Device Id tests during first init", ()=>{ // Same tests with clear device ID flag set to true // Auto generated or developer set device ID was present in the local storage before initialization - it("33-Cleared ID precedence, SDK is initialized with no device id, not offline mode, no utm device id", ()=>{ + it("33-Cleared ID precedence, SDK is initialized with no device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -951,7 +956,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("34-Cleared ID precedence, SDK is initialized with device id, not offline mode, no utm device id", ()=>{ + it("34-Cleared ID precedence, SDK is initialized with device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -976,7 +981,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("35-Cleared ID precedence, SDK is initialized with no device id, offline mode, no utm device id", ()=>{ + it("35-Cleared ID precedence, SDK is initialized with no device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -1001,7 +1006,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("36-Cleared ID precedence, SDK is initialized with no device id, no offline mode, utm device id", ()=>{ + it("36-Cleared ID precedence, SDK is initialized with no device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -1026,7 +1031,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("37-Cleared ID precedence, SDK is initialized with device id, offline mode, no utm device id", ()=>{ + it("37-Cleared ID precedence, SDK is initialized with device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -1051,7 +1056,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("38-Cleared ID precedence, SDK is initialized with device id, no offline mode, utm device id", ()=>{ + it("38-Cleared ID precedence, SDK is initialized with device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -1076,7 +1081,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("39-Cleared ID precedence, SDK is initialized with no device id, offline mode, utm device id", ()=>{ + it("39-Cleared ID precedence, SDK is initialized with no device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -1101,7 +1106,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("40-Cleared ID precedence, SDK is initialized with device id, offline mode, utm device id", ()=>{ + it("40-Cleared ID precedence, SDK is initialized with device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "storedID"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.DEVELOPER_SUPPLIED).then(() => { @@ -1128,7 +1133,7 @@ describe("Device Id tests during first init", ()=>{ }); // Temporary ID was present in the local storage before initialization - it("41-Cleared temp ID precedence, SDK is initialized with no device id, not offline mode, no utm device id", ()=>{ + it("41-Cleared temp ID precedence, SDK is initialized with no device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1153,7 +1158,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("42-Cleared temp ID precedence, SDK is initialized with device id, not offline mode, no utm device id", ()=>{ + it("42-Cleared temp ID precedence, SDK is initialized with device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1178,7 +1183,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("43-Cleared temp ID precedence, SDK is initialized with no device id, offline mode, no utm device id", ()=>{ + it("43-Cleared temp ID precedence, SDK is initialized with no device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1203,7 +1208,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("44-Cleared temp ID precedence, SDK is initialized with no device id, no offline mode, utm device id", ()=>{ + it("44-Cleared temp ID precedence, SDK is initialized with no device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1228,7 +1233,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("45-Cleared temp ID precedence, SDK is initialized with device id, offline mode, no utm device id", ()=>{ + it("45-Cleared temp ID precedence, SDK is initialized with device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1253,7 +1258,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("46-Cleared temp ID precedence, SDK is initialized with device id, no offline mode, utm device id", ()=>{ + it("46-Cleared temp ID precedence, SDK is initialized with device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1278,7 +1283,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("47-Cleared temp ID precedence, SDK is initialized with no device id, offline mode, utm device id", ()=>{ + it("47-Cleared temp ID precedence, SDK is initialized with no device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1303,7 +1308,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("48-Cleared temp ID precedence, SDK is initialized with device id, offline mode, utm device id", ()=>{ + it("48-Cleared temp ID precedence, SDK is initialized with device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { cy.setLocalStorage("YOUR_APP_KEY/cly_id", "[CLY]_temp_id"); cy.setLocalStorage("YOUR_APP_KEY/cly_id_type", DeviceIdTypeInternalEnumsTest.TEMPORARY_ID).then(() => { @@ -1330,7 +1335,7 @@ describe("Device Id tests during first init", ()=>{ }); // SDK generated ID was present prior the second init - it("49-Stored UUID precedence, SDK is initialized with no device id, not offline mode, no utm device id", ()=>{ + it("49-Stored UUID precedence, SDK is initialized with no device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1346,7 +1351,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("50-Stored UUID precedence, SDK is initialized with device id, not offline mode, no utm device id", ()=>{ + it("50-Stored UUID precedence, SDK is initialized with device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1362,7 +1367,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("51-Stored UUID precedence, SDK is initialized with no device id, offline mode, no utm device id", ()=>{ + it("51-Stored UUID precedence, SDK is initialized with no device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1378,7 +1383,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("52-Stored UUID precedence, SDK is initialized with no device id, no offline mode, utm device id", ()=>{ + it("52-Stored UUID precedence, SDK is initialized with no device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1394,7 +1399,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("53-Stored UUID precedence, SDK is initialized with device id, offline mode, no utm device id", ()=>{ + it("53-Stored UUID precedence, SDK is initialized with device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1410,7 +1415,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("54-Stored UUID precedence, SDK is initialized with device id, no offline mode, utm device id", ()=>{ + it("54-Stored UUID precedence, SDK is initialized with device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1426,7 +1431,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("55-Stored UUID precedence, SDK is initialized no device id, offline mode, utm device id", ()=>{ + it("55-Stored UUID precedence, SDK is initialized no device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1442,7 +1447,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("56-Stored UUID precedence, SDK is initialized with device id, offline mode, utm device id", ()=>{ + it("56-Stored UUID precedence, SDK is initialized with device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1460,7 +1465,7 @@ describe("Device Id tests during first init", ()=>{ }); // SDK generated ID was present prior the second init (same tests with flag set to true) - it("57-Stored UUID precedence, SDK is initialized with no device id, not offline mode, no utm device id", ()=>{ + it("57-Stored UUID precedence, SDK is initialized with no device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1476,7 +1481,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("58-Stored UUID precedence, SDK is initialized with device id, not offline mode, no utm device id", ()=>{ + it("58-Stored UUID precedence, SDK is initialized with device id, not offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1491,7 +1496,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("59-Stored UUID precedence, SDK is initialized with no device id, offline mode, no utm device id", ()=>{ + it("59-Stored UUID precedence, SDK is initialized with no device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1506,7 +1511,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("60-Stored UUID precedence, SDK is initialized with no device id, no offline mode, utm device id", ()=>{ + it("60-Stored UUID precedence, SDK is initialized with no device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1521,7 +1526,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("61-Stored UUID precedence, SDK is initialized with device id, offline mode, no utm device id", ()=>{ + it("61-Stored UUID precedence, SDK is initialized with device id, offline mode, no utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1536,7 +1541,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("62-Stored UUID precedence, SDK is initialized with device id, no offline mode, utm device id", ()=>{ + it("62-Stored UUID precedence, SDK is initialized with device id, no offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1551,7 +1556,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("63-Stored UUID precedence, SDK is initialized no device id, offline mode, utm device id", ()=>{ + it("63-Stored UUID precedence, SDK is initialized no device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1566,7 +1571,7 @@ describe("Device Id tests during first init", ()=>{ }); }); }); - it("64-Stored UUID precedence, SDK is initialized with device id, offline mode, utm device id", ()=>{ + it("64-Stored UUID precedence, SDK is initialized with device id, offline mode, utm device id", () => { hp.haltAndClearStorage(() => { initMain(undefined, false, undefined); var oldUUID = Countly.get_device_id(); @@ -1756,7 +1761,7 @@ describe("Device Id tests during first init", ()=>{ // wait for things to resolve cy.wait(550).then(() => { // direct requests would have the old device id (hc and session) - checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType); + checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType, false, true); // after ID events checkStoredReqQueueAfterIDChange(changedID, changedIDType, true); // no end and begin session in offline mode => device id change scenario @@ -1832,7 +1837,7 @@ describe("Device Id tests during first init", ()=>{ // wait for things to resolve cy.wait(550).then(() => { // direct requests would have the old device id (hc and session) - checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType); + checkEachDirectReqForIDandT(afterInitDeviceId, afterInitDeviceIdType, false, true); // after ID events checkStoredReqQueueAfterIDChange(changedID, changedIDType, true); @@ -1984,7 +1989,7 @@ describe("Device Id tests during first init", ()=>{ // wait for things to resolve cy.wait(550).then(() => { // direct requests would have the old device id (hc and session) - checkEachDirectReqForIDandT(afterInitDeviceId, DeviceIdTypeInternalEnumsTest.URL_PROVIDED); + checkEachDirectReqForIDandT(afterInitDeviceId, DeviceIdTypeInternalEnumsTest.URL_PROVIDED, false, true); // after ID events checkStoredReqQueueAfterIDChange(changedID, changedIDType, true); diff --git a/cypress/e2e/integration.cy.js b/cypress/e2e/integration.cy.js index 2273d158..eacff103 100644 --- a/cypress/e2e/integration.cy.js +++ b/cypress/e2e/integration.cy.js @@ -16,41 +16,14 @@ function initMain() { describe("Integration test", () => { it("int, no consent, no offline_mode", () => { initMain(); - const idType = Countly.get_device_id_type(); - const id = Countly.get_device_id(); - const consentStatus = Countly.check_any_consent(); - Countly.remove_consent(); - Countly.disable_offline_mode(); - Countly.add_event({ key: "test", count: 1, sum: 1, dur: 1, segmentation: { test: "test" } }); - Countly.start_event("test"); - Countly.cancel_event("gobbledygook"); - Countly.end_event("test"); - Countly.report_conversion("camp_id", "camp_user_id"); - Countly.recordDirectAttribution("camp_id", "camp_user_id"); - Countly.user_details({ name: "name" }); - Countly.userData.set("set", "set"); - Countly.userData.save(); - Countly.report_trace({ name: "name", stz: 1, type: "type" }); - Countly.log_error({ error: "error", stack: "stack" }); - Countly.add_log("error"); - Countly.fetch_remote_config(); - Countly.enrollUserToAb(); - const remote = Countly.get_remote_config(); - Countly.track_sessions(); - Countly.track_pageview(); - Countly.track_errors(); - Countly.track_clicks(); - Countly.track_scrolls(); - Countly.track_links(); - Countly.track_forms(); - Countly.collect_from_forms(); - Countly.collect_from_facebook(); - Countly.opt_in(); - // TODO: widgets - // TODO: make better + var consentStatus = Countly.check_any_consent(); + var remote = Countly.get_remote_config(); + var id = Countly.get_device_id(); + var idType = Countly.get_device_id_type(); + hp.integrationMethods(); cy.fetch_local_request_queue().then((rq) => { cy.log(rq); - hp.testNormalFlow(rq, "/__cypress/iframes/cypress%5Ce2e%5Cintegration.cy.js", hp.appKey); + hp.testNormalFlowInt(rq, "/__cypress/iframes/cypress%5Ce2e%5Cintegration.cy.js", hp.appKey); expect(consentStatus).to.equal(true); // no consent necessary expect(remote).to.eql({}); // deepEqual expect(rq[0].device_id).to.equal(id); diff --git a/cypress/e2e/sdk_behavior.cy.js b/cypress/e2e/sdk_behavior.cy.js new file mode 100644 index 00000000..f89bc6ae --- /dev/null +++ b/cypress/e2e/sdk_behavior.cy.js @@ -0,0 +1,233 @@ + +var Countly = require("../../lib/countly"); +var hp = require("../support/helper.js"); + +function initMain(val) { + Countly.init({ + app_key: "spp", + url: "https://hey.some.ly", + debug: true, + behavior_settings: val + }); +} + +function sentReqList(size, expectedKeywords, nonexistingKeywords) { + var directReqs = Countly._internals.testingGetRequests(); // get direct requests + var functionNames = directReqs.map((item) => item.functionName); + cy.log("Direct Requests: " + JSON.stringify(directReqs)); + + if (typeof size !== 'undefined') { + expect(directReqs.length).to.eq(size); + } + if (expectedKeywords) { + for (var i = 0; i < expectedKeywords.length; i++) { + expect(functionNames.includes(expectedKeywords[i])).to.be.true; + } + } + if (nonexistingKeywords) { + for (var j = 0; j < nonexistingKeywords.length; j++) { + expect(functionNames.includes(nonexistingKeywords[j])).to.be.false; + } + } +} +function queues(eqsize, rqsize, expectedKeywords, nonexistingKeywords) { + var queues = Countly._internals.getLocalQueues(); // get local queues + const allKeysE = queues.eventQ.flatMap(item => Object.keys(item)); + const allKeysQ = queues.requestQ.flatMap(item => Object.keys(item)); + const uniqueKeys = [...new Set(allKeysE), ...new Set(allKeysQ)]; + + const allValuesE = queues.eventQ.flatMap(item => Object.values(item)); + const allValuesQ = queues.requestQ.flatMap(item => Object.values(item)); + const uniqueValues = [...new Set(allValuesE), ...new Set(allValuesQ)]; + + cy.log("Unique Keys: " + JSON.stringify(uniqueKeys)); + cy.log("Queues: " + JSON.stringify(queues)); + + if (typeof eqsize !== 'undefined') { + expect(queues.eventQ.length).to.eq(eqsize); + } + if (typeof rqsize !== 'undefined') { + expect(queues.requestQ.length).to.eq(rqsize); + } + if (expectedKeywords) { + for (var i = 0; i < expectedKeywords.length; i++) { + expect(uniqueKeys.includes(expectedKeywords[i])).to.be.true; + } + } + if (nonexistingKeywords) { + for (var j = 0; j < nonexistingKeywords.length; j++) { + expect(uniqueValues.includes(nonexistingKeywords[j])).to.be.false; + } + } +} + +const waitT = 2000; + +describe("SDK Behavior test", () => { + it("Basic initialization with default config", () => { + hp.haltAndClearStorage(() => { + initMain(); + cy.wait(waitT).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(2, ["server_config", "[healthCheck]"]); + queues(0, 0); + }); + }); + }); + }); + + it("Initialization with default config and integration methods", () => { + hp.haltAndClearStorage(() => { + initMain(); + hp.integrationMethods(); + cy.wait(waitT).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(9, ["server_config", "[healthCheck]", "enrollUserToAb", "fetch_remote_config_explicit", "send_request_queue", "get_available_feedback_widgets,"]); + queues(0, 15); + }); + }); + }); + }); + + it("Config with networking disabled", () => { + hp.haltAndClearStorage(() => { + var settings = {}; + settings.c = { + networking: false + }; + initMain(settings); + hp.integrationMethods(); + cy.wait(waitT).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(1, ["server_config"]); + queues(0, 15); + }); + }); + }); + }); + + it("Config with tracking disabled", () => { + hp.haltAndClearStorage(() => { + var settings = {}; + settings.c = { + tracking: false + }; + initMain(settings); + hp.integrationMethods(); + cy.wait(waitT).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(8, ["server_config", "[healthCheck]", "enrollUserToAb", "fetch_remote_config_explicit", "get_available_feedback_widgets,"]); + queues(0, 0); + }); + }); + }); + }); + + it("Config with both tracking and networking disabled", () => { + hp.haltAndClearStorage(() => { + var settings = {}; + settings.c = { + tracking: false, + networking: false + }; + initMain(settings); + hp.integrationMethods(); + cy.wait(waitT).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(1, ["server_config"]); + queues(0, 0); + }); + }); + }); + }); + + it("Config with consent required true", () => { + hp.haltAndClearStorage(() => { + var settings = {}; + settings.c = { + cr: true + }; + initMain(settings); + hp.integrationMethods(); + cy.wait(waitT).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(4, ["server_config", "[healthCheck]", "enrollUserToAb", "send_request_queue"]); // device id change sent + queues(0, 2, ["old_device_id", "consent"]); + }); + }); + }); + }); + + it("Limited queue sizes with networking disabled", () => { + hp.haltAndClearStorage(() => { + var settings = {}; + settings.c = { + rqs: 1, + eqs: 1, + networking: false, + }; + initMain(settings); + Countly.add_event({ key: "test_1" }); + Countly.add_event({ key: "test_2" }); + Countly.add_event({ key: "test_3" }); + Countly.add_event({ key: "test_4" }); + Countly.add_event({ key: "test_5" }); + cy.wait(3000).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(1, ["server_config"]); + queues(0, 2, ["events"], ["test_1", "test_2", "test_3"]); // 1+1 + }); + }); + }); + }); + + it("Session update interval configuration", () => { + hp.haltAndClearStorage(() => { + var settings = {}; + settings.c = { + sui: 1, + }; + initMain(settings); + Countly.track_sessions(); + cy.wait(4000).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(3, ["server_config", "[healthCheck]", "send_request_queue"]); + queues(0, 4, ["session_duration", "begin_session"], ["session_end"]); + }); + }); + }); + }); + + it("Disabled tracking types configuration", () => { + hp.haltAndClearStorage(() => { + var settings = {}; + settings.c = { + st: false, + crt: false, + lt: false, + vt: false, + cet: false, + }; + initMain(settings); + Countly.track_sessions(); + Countly.add_event({ key: "test_1" }); + Countly.track_pageview(); + Countly.log_error({ message: "test" }); + cy.wait(4000).then(() => { + cy.fetch_local_request_queue().then((rq) => { + cy.log("Request Queue: " + JSON.stringify(rq)); + sentReqList(2, ["server_config", "[healthCheck]"]); + queues(0, 0); + }); + }); + }); + }); +}); diff --git a/cypress/support/helper.js b/cypress/support/helper.js index 94c49967..91c816db 100644 --- a/cypress/support/helper.js +++ b/cypress/support/helper.js @@ -183,6 +183,120 @@ function events(omitList) { } } +// TODO: this validator is so rigid. Must be modified to be more flexible (accepting more variables) +/** + * Validates requests in the request queue for normal flow test + * @param {Array} rq - request queue + * @param {string} viewName - name of the view + * @param {string} countlyAppKey - app key +*/ +function testNormalFlowInt(rq, viewName, countlyAppKey) { + cy.log(JSON.stringify(rq)); + expect(rq.length).to.equal(14); + const idType = rq[0].t; + const id = rq[0].device_id; + + // 1 - 2 + expect(rq[0].campaign_id).to.equal("camp_id"); + expect(rq[0].campaign_user).to.equal("camp_user_id"); + expect(rq[1].campaign_id).to.equal("camp_id"); + expect(rq[1].campaign_user).to.equal("camp_user_id"); + + // 3 + const thirdRequest = JSON.parse(rq[2].events); + expect(thirdRequest.length).to.equal(2); + cy.check_event(thirdRequest[0], { key: "test", count: 1, sum: 1, dur: 1, segmentation: { test: "test" } }, undefined, ""); + cy.check_event(thirdRequest[0], { key: "test", count: 1, sum: 1, dur: 1, segmentation: {} }, undefined, ""); + + // 4 + const fourthRequest = JSON.parse(rq[3].user_details); + expect(fourthRequest.name).to.equal("Test User"); + expect(fourthRequest.custom).to.eql({}); + + // 5 + const fifthRequest = JSON.parse(rq[4].user_details); + // Instead of expecting a simple object, check for the presence of all the properties + expect(fifthRequest).to.have.property('custom'); + expect(fifthRequest.custom).to.have.property('custom-property'); + expect(fifthRequest.custom).to.have.property('unique-property'); + expect(fifthRequest.custom['unique-property']).to.have.property('$setOnce', 'unique-value'); + expect(fifthRequest.custom).to.have.property('counter'); + expect(fifthRequest.custom.counter).to.have.property('$inc', 5); + expect(fifthRequest.custom).to.have.property('value'); + expect(fifthRequest.custom.value).to.have.property('$mul', 2); + expect(fifthRequest.custom).to.have.property('max-value'); + expect(fifthRequest.custom['max-value']).to.have.property('$max', 100); + expect(fifthRequest.custom).to.have.property('min-value'); + expect(fifthRequest.custom['min-value']).to.have.property('$min', 1); + expect(fifthRequest.custom).to.have.property('array-property'); + expect(fifthRequest.custom['array-property']).to.have.property('$push').to.be.an('array').that.includes('new-value'); + expect(fifthRequest.custom['array-property']).to.have.property('$pull').to.be.an('array').that.includes('value-to-remove'); + expect(fifthRequest.custom).to.have.property('unique-array'); + expect(fifthRequest.custom['unique-array']).to.have.property('$addToSet').to.be.an('array').that.includes('unique-item'); + + // 6 + const sixthRequest = JSON.parse(rq[5].crash); + expect(sixthRequest._error).to.equal("stack"); + + // 7 + expect(rq[6].begin_session).to.equal(1); + + // 8 + const eighthRequest = JSON.parse(rq[7].events); + expect(eighthRequest.length).to.equal(2); + cy.check_event(eighthRequest[0], { key: "[CLY]_orientation" }, undefined, ""); + cy.check_view_event(eighthRequest[1], viewName, undefined, false); + + // 9 - Session duration check + expect(rq[8].session_duration).to.equal(30); + + // 10 - End session duration check + expect(rq[9].session_duration).to.equal(0); + + // 11 - View event end + const eleventhRequest = JSON.parse(rq[10].events); + expect(eleventhRequest.length).to.equal(1); + cy.check_view_event(eleventhRequest[0], viewName, 0, false); + + // 12 - Device ID change + expect(rq[11].old_device_id).to.equal(id); + expect(rq[11].device_id).to.equal("new-device-id"); + + // 13 - New session with custom device ID + expect(rq[12].begin_session).to.equal(1); + expect(rq[12].device_id).to.equal("custom-device-id"); + + // 14 - Star rating events + const fourteenthRequest = JSON.parse(rq[13].events); + expect(fourteenthRequest.length).to.equal(3); + cy.check_event(fourteenthRequest[0], { key: "[CLY]_orientation" }, undefined, true); + cy.check_event(fourteenthRequest[1], { key: "[CLY]_star_rating", segmentation: { widget_id: "test-id", rating: 5 } }, undefined, true); + cy.check_event(fourteenthRequest[2], { key: "[CLY]_star_rating", segmentation: { widget_id: "test-id", rating: 5 } }, undefined, true); + + // each request should have same device id, device id type and app key + rq.forEach((element, index) => { + expect(element.app_key).to.equal(countlyAppKey); + expect(element.metrics).to.be.ok; + expect(element.dow).to.exist; + expect(element.hour).to.exist; + expect(element.sdk_name).to.be.ok; + expect(element.sdk_version).to.be.ok; + expect(element.timestamp).to.be.ok; + + // Device ID and type checks (accounting for ID changes) + if (index < 11) { + expect(element.device_id).to.equal(id); + expect(element.t).to.equal(idType); + } else if (index === 11) { + expect(element.device_id).to.equal("new-device-id"); + expect(element.t).to.equal(0); + } else { + expect(element.device_id).to.equal("custom-device-id"); + expect(element.t).to.equal(0); + } + }); +} + // TODO: this validator is so rigid. Must be modified to be more flexible (accepting more variables) /** * Validates requests in the request queue for normal flow test @@ -328,6 +442,66 @@ function turnSearchStringToObject(searchString) { return paramsObject; } +function integrationMethods() { + const idType = Countly.get_device_id_type(); + const id = Countly.get_device_id(); + Countly.add_consent("events"); + Countly.check_any_consent(); + Countly.check_consent("events"); + Countly.group_features({ all_features: ["events", "views", "crashes"] }); + Countly.remove_consent("events"); + Countly.disable_offline_mode(); + Countly.add_event({ key: "test", count: 1, sum: 1, dur: 1, segmentation: { test: "test" } }); + Countly.start_event("test"); + Countly.cancel_event("gobbledygook"); + Countly.end_event("test"); + Countly.report_conversion("camp_id", "camp_user_id"); + Countly.recordDirectAttribution("camp_id", "camp_user_id"); + Countly.user_details({ name: "Test User", email: "test@example.com" }); + Countly.userData.set("custom-property", "custom-value"); + Countly.userData.unset("custom-property"); + Countly.userData.set_once("unique-property", "unique-value"); + Countly.userData.increment("counter"); + Countly.userData.increment_by("counter", 5); + Countly.userData.multiply("value", 2); + Countly.userData.max("max-value", 100); + Countly.userData.min("min-value", 1); + Countly.userData.push("array-property", "new-value"); + Countly.userData.push_unique("unique-array", "unique-item"); + Countly.userData.pull("array-property", "value-to-remove"); + Countly.userData.save(); + Countly.report_trace({ name: "name", stz: 1, type: "type" }); + Countly.log_error({ error: "error", stack: "stack" }); + Countly.add_log("error"); + Countly.enrollUserToAb(["test-key"]); + Countly.fetch_remote_config(["test-key"], [], (err, config) => console.log(config)); + const remote = Countly.get_remote_config(); + Countly.track_sessions(); + Countly.track_pageview(); + Countly.track_errors(); + Countly.track_clicks(); + Countly.track_scrolls(); + Countly.track_links(); + Countly.track_forms(); + Countly.collect_from_forms(); + Countly.collect_from_facebook(); + Countly.opt_in(); + Countly.begin_session(); + Countly.session_duration(30); + Countly.end_session(); + Countly.content.enterContentZone(); + Countly.content.refreshContentZone(); + Countly.content.exitContentZone(); + Countly.change_id("new-device-id", true); + Countly.set_id("custom-device-id"); + Countly.feedback.showRating(); + Countly.feedback.showNPS(); + Countly.feedback.showSurvey(); + Countly.recordRatingWidgetWithID({ widget_id: "test-id", rating: 5 }); + Countly.reportFeedbackWidgetManually({ _id: "test-id", type: "rating" }, {}, { rating: 5 }); + Countly.get_available_feedback_widgets((widgets) => console.log(widgets)); +} + module.exports = { haltAndClearStorage, sWait, @@ -344,5 +518,7 @@ module.exports = { validateDefaultUtmTags, userDetailObj, check_commons, - turnSearchStringToObject + turnSearchStringToObject, + integrationMethods, + testNormalFlowInt, }; \ No newline at end of file diff --git a/lib/countly.d.ts b/lib/countly.d.ts index 52fcca85..41ad7f61 100644 --- a/lib/countly.d.ts +++ b/lib/countly.d.ts @@ -486,6 +486,7 @@ declare module "countly-sdk-web" { /** * Content interface with convenience methods for content zones: * - enterContentZone() - enters a content zone + * - refreshContentZone() - refreshes the content zone * - exitContentZone() - exits a content zone */ const content: Content; @@ -494,6 +495,10 @@ declare module "countly-sdk-web" { * Enters content zone and checks and displays available content regularly */ enterContentZone(): void; + /** + * Refreshes content zone + */ + refreshContentZone(): void; /** * Exits content zone */ diff --git a/lib/countly.js b/lib/countly.js index caa7035d..012eb299 100644 --- a/lib/countly.js +++ b/lib/countly.js @@ -209,7 +209,7 @@ statusCode: "cly_hc_status_code", errorMessage: "cly_hc_error_message" }); - var SDK_VERSION = "25.1.0"; + var SDK_VERSION = "25.4.0"; var SDK_NAME = "javascript_native_web"; // Using this on document.referrer would return an array with 17 elements in it. The 12th element (array[11]) would be the path we are looking for. Others would be things like password and such (use https://regex101.com/ to check more) @@ -852,7 +852,6 @@ var _apiPath = /*#__PURE__*/new WeakMap(); var _readPath = /*#__PURE__*/new WeakMap(); var _beatInterval = /*#__PURE__*/new WeakMap(); - var _queueSize = /*#__PURE__*/new WeakMap(); var _requestQueue = /*#__PURE__*/new WeakMap(); var _eventQueue = /*#__PURE__*/new WeakMap(); var _remoteConfigs = /*#__PURE__*/new WeakMap(); @@ -870,9 +869,6 @@ var _failTimeoutAmount = /*#__PURE__*/new WeakMap(); var _inactivityTime = /*#__PURE__*/new WeakMap(); var _inactivityCounter = /*#__PURE__*/new WeakMap(); - var _sessionUpdate = /*#__PURE__*/new WeakMap(); - var _maxEventBatch = /*#__PURE__*/new WeakMap(); - var _maxCrashLogs = /*#__PURE__*/new WeakMap(); var _useSessionCookie = /*#__PURE__*/new WeakMap(); var _sessionCookieTimeout = /*#__PURE__*/new WeakMap(); var _readyToProcess = /*#__PURE__*/new WeakMap(); @@ -895,13 +891,37 @@ var _shouldSendHC = /*#__PURE__*/new WeakMap(); var _consents = /*#__PURE__*/new WeakMap(); var _generatedRequests = /*#__PURE__*/new WeakMap(); - var _contentTimeInterval = /*#__PURE__*/new WeakMap(); var _contentEndPoint = /*#__PURE__*/new WeakMap(); var _inContentZone = /*#__PURE__*/new WeakMap(); var _contentZoneTimer = /*#__PURE__*/new WeakMap(); - var _contentZoneTimerInterval = /*#__PURE__*/new WeakMap(); var _contentIframeID = /*#__PURE__*/new WeakMap(); var _crashFilterCallback = /*#__PURE__*/new WeakMap(); + var _serverConfigCache = /*#__PURE__*/new WeakMap(); + var _SCNetwork = /*#__PURE__*/new WeakMap(); + var _SCSizeReqQueue = /*#__PURE__*/new WeakMap(); + var _SCSizeEventBatch = /*#__PURE__*/new WeakMap(); + var _SCIntervalSessionUpdate = /*#__PURE__*/new WeakMap(); + var _SCIntervalContent = /*#__PURE__*/new WeakMap(); + var _SCInterval = /*#__PURE__*/new WeakMap(); + var _SCTrackingAll = /*#__PURE__*/new WeakMap(); + var _SCTrackingSession = /*#__PURE__*/new WeakMap(); + var _SCTrackingViews = /*#__PURE__*/new WeakMap(); + var _SCTrackingCrashes = /*#__PURE__*/new WeakMap(); + var _SCTrackingEvents = /*#__PURE__*/new WeakMap(); + var _SCTrackingLocation = /*#__PURE__*/new WeakMap(); + var _SCEnableContent = /*#__PURE__*/new WeakMap(); + var _SCEnableConsentRequired = /*#__PURE__*/new WeakMap(); + var _SCEnableRefreshContentZone = /*#__PURE__*/new WeakMap(); + var _SCLimitKeyLength = /*#__PURE__*/new WeakMap(); + var _SCLimitValueSize = /*#__PURE__*/new WeakMap(); + var _SCLimitSegmentationValues = /*#__PURE__*/new WeakMap(); + var _SCLimitBreadcrumbCount = /*#__PURE__*/new WeakMap(); + var _SCLimitStackTraceLinesPerThread = /*#__PURE__*/new WeakMap(); + var _SCLimitStackTraceLineLength = /*#__PURE__*/new WeakMap(); + var _initContentSent = /*#__PURE__*/new WeakMap(); + var _initTimestamp = /*#__PURE__*/new WeakMap(); + var _getAndSetServerConfig = /*#__PURE__*/new WeakMap(); + var _populateServerConfig = /*#__PURE__*/new WeakMap(); var _initialize = /*#__PURE__*/new WeakMap(); var _updateConsent = /*#__PURE__*/new WeakMap(); var _add_cly_events = /*#__PURE__*/new WeakMap(); @@ -914,6 +934,8 @@ var _showWidgetInternal = /*#__PURE__*/new WeakMap(); var _checkIgnore = /*#__PURE__*/new WeakMap(); var _enterContentZoneInternal = /*#__PURE__*/new WeakMap(); + var _refreshContentZoneInternal = /*#__PURE__*/new WeakMap(); + var _exitContentZoneInternal = /*#__PURE__*/new WeakMap(); var _prepareContentRequest = /*#__PURE__*/new WeakMap(); var _sendContentRequest = /*#__PURE__*/new WeakMap(); var _displayContent = /*#__PURE__*/new WeakMap(); @@ -969,7 +991,6 @@ _classPrivateFieldInitSpec(this, _apiPath, void 0); _classPrivateFieldInitSpec(this, _readPath, void 0); _classPrivateFieldInitSpec(this, _beatInterval, void 0); - _classPrivateFieldInitSpec(this, _queueSize, void 0); _classPrivateFieldInitSpec(this, _requestQueue, void 0); _classPrivateFieldInitSpec(this, _eventQueue, void 0); _classPrivateFieldInitSpec(this, _remoteConfigs, void 0); @@ -987,9 +1008,6 @@ _classPrivateFieldInitSpec(this, _failTimeoutAmount, void 0); _classPrivateFieldInitSpec(this, _inactivityTime, void 0); _classPrivateFieldInitSpec(this, _inactivityCounter, void 0); - _classPrivateFieldInitSpec(this, _sessionUpdate, void 0); - _classPrivateFieldInitSpec(this, _maxEventBatch, void 0); - _classPrivateFieldInitSpec(this, _maxCrashLogs, void 0); _classPrivateFieldInitSpec(this, _useSessionCookie, void 0); _classPrivateFieldInitSpec(this, _sessionCookieTimeout, void 0); _classPrivateFieldInitSpec(this, _readyToProcess, void 0); @@ -1012,28 +1030,167 @@ _classPrivateFieldInitSpec(this, _shouldSendHC, void 0); _classPrivateFieldInitSpec(this, _consents, void 0); _classPrivateFieldInitSpec(this, _generatedRequests, void 0); - _classPrivateFieldInitSpec(this, _contentTimeInterval, void 0); _classPrivateFieldInitSpec(this, _contentEndPoint, void 0); _classPrivateFieldInitSpec(this, _inContentZone, void 0); _classPrivateFieldInitSpec(this, _contentZoneTimer, void 0); - _classPrivateFieldInitSpec(this, _contentZoneTimerInterval, void 0); _classPrivateFieldInitSpec(this, _contentIframeID, void 0); _classPrivateFieldInitSpec(this, _crashFilterCallback, void 0); + _classPrivateFieldInitSpec(this, _serverConfigCache, void 0); + _classPrivateFieldInitSpec(this, _SCNetwork, void 0); + _classPrivateFieldInitSpec(this, _SCSizeReqQueue, void 0); + _classPrivateFieldInitSpec(this, _SCSizeEventBatch, void 0); + _classPrivateFieldInitSpec(this, _SCIntervalSessionUpdate, void 0); + _classPrivateFieldInitSpec(this, _SCIntervalContent, void 0); + _classPrivateFieldInitSpec(this, _SCInterval, void 0); + _classPrivateFieldInitSpec(this, _SCTrackingAll, void 0); + _classPrivateFieldInitSpec(this, _SCTrackingSession, void 0); + _classPrivateFieldInitSpec(this, _SCTrackingViews, void 0); + _classPrivateFieldInitSpec(this, _SCTrackingCrashes, void 0); + _classPrivateFieldInitSpec(this, _SCTrackingEvents, void 0); + _classPrivateFieldInitSpec(this, _SCTrackingLocation, void 0); + _classPrivateFieldInitSpec(this, _SCEnableContent, void 0); + _classPrivateFieldInitSpec(this, _SCEnableConsentRequired, void 0); + _classPrivateFieldInitSpec(this, _SCEnableRefreshContentZone, void 0); + _classPrivateFieldInitSpec(this, _SCLimitKeyLength, void 0); + _classPrivateFieldInitSpec(this, _SCLimitValueSize, void 0); + _classPrivateFieldInitSpec(this, _SCLimitSegmentationValues, void 0); + _classPrivateFieldInitSpec(this, _SCLimitBreadcrumbCount, void 0); + _classPrivateFieldInitSpec(this, _SCLimitStackTraceLinesPerThread, void 0); + _classPrivateFieldInitSpec(this, _SCLimitStackTraceLineLength, void 0); + _classPrivateFieldInitSpec(this, _initContentSent, void 0); + _classPrivateFieldInitSpec(this, _initTimestamp, void 0); + _classPrivateFieldInitSpec(this, _getAndSetServerConfig, function () { + if (_this.device_id === "[CLY]_temp_id") { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "server_config, Device ID is temporary, not fetching server config"); + return; + } + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "server_config, Fetching server config"); + var params = {}; + params.app_key = _this.app_key; + params.device_id = _this.device_id; + params.sdk_version = _classPrivateFieldGet2(_sdkVersion, _this); + params.sdk_name = _classPrivateFieldGet2(_sdkName, _this); + params.t = _classPrivateFieldGet2(_deviceIdType, _this); + params.timestamp = getMsTimestamp(); + var date = new Date(); + params.hour = date.getHours(); + params.dow = date.getDay(); + params.av = _this.app_version; + params.method = "sc"; + _classPrivateFieldGet2(_makeNetworkRequest, _this).call(_this, "server_config", _this.url + _classPrivateFieldGet2(_readPath, _this), params, function (err, params, responseText) { + if (err) { + // error has been logged by the request function + return; + } + try { + var config = JSON.parse(responseText); + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "server_config, Config fetched successfully:[" + JSON.stringify(config) + "]"); + if (config) { + _classPrivateFieldGet2(_populateServerConfig, _this).call(_this, config); + } + _classPrivateFieldGet2(_setValueInStorage, _this).call(_this, "cly_config", JSON.stringify(config)); + } catch (ex) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.ERROR, "server_config, Had an issue while parsing the response: " + ex); + } + }, true, true); + setTimeout(function () { + _classPrivateFieldGet2(_getAndSetServerConfig, _this).call(_this); + }, _classPrivateFieldGet2(_SCInterval, _this) * 60 * 60 * 1000); + }); + _classPrivateFieldInitSpec(this, _populateServerConfig, function (mainCache) { + if (!mainCache || !mainCache.c || _typeof(mainCache.c) !== "object") { + return; + } + var cache = mainCache.c; + if (cache && cache.hasOwnProperty("networking")) { + _classPrivateFieldSet2(_SCNetwork, _this, cache.networking); + } + if (cache && cache.hasOwnProperty("tracking")) { + _classPrivateFieldSet2(_SCTrackingAll, _this, cache.tracking); + } + if (cache && cache.hasOwnProperty("rqs")) { + _classPrivateFieldSet2(_SCSizeReqQueue, _this, cache.rqs); + } + if (cache && cache.hasOwnProperty("eqs")) { + _classPrivateFieldSet2(_SCSizeEventBatch, _this, cache.eqs); + } + if (cache && cache.hasOwnProperty("sui")) { + _classPrivateFieldSet2(_SCIntervalSessionUpdate, _this, cache.sui); + } + if (cache && cache.hasOwnProperty("czi") && cache.czi > 14) { + _classPrivateFieldSet2(_SCIntervalContent, _this, cache.czi * 1000); + } + if (cache && cache.hasOwnProperty("ecz")) { + _classPrivateFieldSet2(_SCEnableContent, _this, cache.ecz); + if (!_classPrivateFieldGet2(_initContentSent, _this) && _classPrivateFieldGet2(_SCEnableContent, _this)) { + _classPrivateFieldGet2(_enterContentZoneInternal, _this).call(_this); + } + } + if (cache && cache.hasOwnProperty("cr")) { + _classPrivateFieldSet2(_SCEnableConsentRequired, _this, cache.cr); + } + if (cache && cache.hasOwnProperty("st")) { + _classPrivateFieldSet2(_SCTrackingSession, _this, cache.st); + } + if (cache && cache.hasOwnProperty("crt")) { + _classPrivateFieldSet2(_SCTrackingCrashes, _this, cache.crt); + } + if (cache && cache.hasOwnProperty("vt")) { + _classPrivateFieldSet2(_SCTrackingViews, _this, cache.vt); + } + if (cache && cache.hasOwnProperty("cet")) { + _classPrivateFieldSet2(_SCTrackingEvents, _this, cache.cet); + } + if (cache && cache.hasOwnProperty("lkl")) { + _classPrivateFieldSet2(_SCLimitKeyLength, _this, cache.lkl); + } + if (cache && cache.hasOwnProperty("lvs")) { + _classPrivateFieldSet2(_SCLimitValueSize, _this, cache.lvs); + } + if (cache && cache.hasOwnProperty("lsv")) { + _classPrivateFieldSet2(_SCLimitSegmentationValues, _this, cache.lsv); + } + if (cache && cache.hasOwnProperty("lbc")) { + _classPrivateFieldSet2(_SCLimitBreadcrumbCount, _this, cache.lbc); + } + if (cache && cache.hasOwnProperty("ltlpt")) { + _classPrivateFieldSet2(_SCLimitStackTraceLinesPerThread, _this, cache.ltlpt); + } + if (cache && cache.hasOwnProperty("ltl")) { + _classPrivateFieldSet2(_SCLimitStackTraceLineLength, _this, cache.ltl); + } + if (cache && cache.hasOwnProperty("scui")) { + _classPrivateFieldSet2(_SCInterval, _this, Math.max(cache.scui, 4)); + } + if (cache && cache.hasOwnProperty("lt")) { + _classPrivateFieldSet2(_SCTrackingLocation, _this, cache.lt); + } + // web does not have support for 'dort' parameter + if (cache && cache.hasOwnProperty("rcz")) { + _classPrivateFieldSet2(_SCEnableRefreshContentZone, _this, cache.rcz); + } + }); /** * Initialize the Countly * @param {Object} ob - config object * @returns */ _classPrivateFieldInitSpec(this, _initialize, function (ob) { - _this.serialize = getConfig("serialize", ob, Countly.serialize); - _this.deserialize = getConfig("deserialize", ob, Countly.deserialize); + _classPrivateFieldSet2(_ignoreReferrers, _this, getConfig("ignore_referrers", ob, [])); + _classPrivateFieldSet2(_failTimeoutAmount, _this, getConfig("fail_timeout", ob, configurationDefaultValues.FAIL_TIMEOUT_AMOUNT)); + _classPrivateFieldSet2(_inactivityTime, _this, getConfig("inactivity_time", ob, configurationDefaultValues.INACTIVITY_TIME)); + _classPrivateFieldSet2(_useSessionCookie, _this, getConfig("use_session_cookie", ob, true)); + _classPrivateFieldSet2(_sessionCookieTimeout, _this, getConfig("session_cookie_timeout", ob, configurationDefaultValues.SESSION_COOKIE_TIMEOUT)); + _classPrivateFieldSet2(_offlineMode, _this, getConfig("offline_mode", ob, false)); + _classPrivateFieldSet2(_sdkName, _this, getConfig("sdk_name", ob, SDK_NAME)); + _classPrivateFieldSet2(_sdkVersion, _this, getConfig("sdk_version", ob, SDK_VERSION)); + _classPrivateFieldSet2(_beatInterval, _this, getConfig("interval", ob, configurationDefaultValues.BEAT_INTERVAL)); _this.getViewName = getConfig("getViewName", ob, Countly.getViewName); _this.getViewUrl = getConfig("getViewUrl", ob, Countly.getViewUrl); _this.getSearchQuery = getConfig("getSearchQuery", ob, Countly.getSearchQuery); _this.DeviceIdType = Countly.DeviceIdType; // it is Countly device Id type Enums for clients to use _this.namespace = getConfig("namespace", ob, ""); _this.clearStoredId = getConfig("clear_stored_id", ob, false); - _this.app_key = getConfig("app_key", ob, null); _this.onload = getConfig("onload", ob, []); _this.utm = getConfig("utm", ob, { source: true, @@ -1050,7 +1207,6 @@ _this.test_mode_eq = getConfig("test_mode_eq", ob, false); _this.metrics = getConfig("metrics", ob, {}); _this.headers = getConfig("headers", ob, {}); - _this.url = stripTrailingSlash(getConfig("url", ob, "")); _this.app_version = getConfig("app_version", ob, "0.0"); _this.country_code = getConfig("country_code", ob, null); _this.city = getConfig("city", ob, null); @@ -1059,33 +1215,17 @@ _this.force_post = getConfig("force_post", ob, false); _this.remote_config = getConfig("remote_config", ob, false); _this.ignore_visitor = getConfig("ignore_visitor", ob, false); - _this.require_consent = getConfig("require_consent", ob, false); _this.track_domains = !isBrowser ? undefined : getConfig("track_domains", ob, true); _this.storage = getConfig("storage", ob, "default"); _this.enableOrientationTracking = !isBrowser ? undefined : getConfig("enable_orientation_tracking", ob, true); - _this.maxKeyLength = getConfig("max_key_length", ob, configurationDefaultValues.MAX_KEY_LENGTH); - _this.maxValueSize = getConfig("max_value_size", ob, configurationDefaultValues.MAX_VALUE_SIZE); - _this.maxSegmentationValues = getConfig("max_segmentation_values", ob, configurationDefaultValues.MAX_SEGMENTATION_VALUES); - _this.maxBreadcrumbCount = getConfig("max_breadcrumb_count", ob, null); - _this.maxStackTraceLinesPerThread = getConfig("max_stack_trace_lines_per_thread", ob, configurationDefaultValues.MAX_STACKTRACE_LINES_PER_THREAD); - _this.maxStackTraceLineLength = getConfig("max_stack_trace_line_length", ob, configurationDefaultValues.MAX_STACKTRACE_LINE_LENGTH); _this.heatmapWhitelist = getConfig("heatmap_whitelist", ob, []); + _this.contentWhitelist = getConfig("content_whitelist", ob, []); _this.salt = getConfig("salt", ob, null); _this.hcErrorCount = _classPrivateFieldGet2(_getValueFromStorage, _this).call(_this, healthCheckCounterEnum.errorCount) || 0; _this.hcWarningCount = _classPrivateFieldGet2(_getValueFromStorage, _this).call(_this, healthCheckCounterEnum.warningCount) || 0; _this.hcStatusCode = _classPrivateFieldGet2(_getValueFromStorage, _this).call(_this, healthCheckCounterEnum.statusCode) || -1; _this.hcErrorMessage = _classPrivateFieldGet2(_getValueFromStorage, _this).call(_this, healthCheckCounterEnum.errorMessage) || ""; - _classPrivateFieldSet2(_contentZoneTimerInterval, _this, getConfig("content_zone_timer_interval", ob, null)); _classPrivateFieldSet2(_crashFilterCallback, _this, getConfig("crash_filter_callback", ob, null)); - if (_classPrivateFieldGet2(_contentZoneTimerInterval, _this)) { - _classPrivateFieldSet2(_contentTimeInterval, _this, Math.max(_classPrivateFieldGet2(_contentZoneTimerInterval, _this), 15) * 1000); - } - if (_classPrivateFieldGet2(_maxCrashLogs, _this) && !_this.maxBreadcrumbCount) { - _this.maxBreadcrumbCount = _classPrivateFieldGet2(_maxCrashLogs, _this); - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "initialize, 'maxCrashLogs' is deprecated. Use 'maxBreadcrumbCount' instead!"); - } else if (!_classPrivateFieldGet2(_maxCrashLogs, _this) && !_this.maxBreadcrumbCount) { - _this.maxBreadcrumbCount = 100; - } if (_this.storage === "cookie") { _classPrivateFieldSet2(_lsSupport, _this, false); } @@ -1120,6 +1260,13 @@ } } } + if (Array.isArray(_this.contentWhitelist)) { + _this.contentWhitelist.push(_this.url); + _this.contentWhitelist = _this.contentWhitelist.map(function (e) { + // remove trailing slashes from the entries + return stripTrailingSlash(e); + }); + } if (_this.passed_data && _this.passed_data.app_key && _this.passed_data.app_key === _this.app_key || _this.passed_data && !_this.passed_data.app_key && _classPrivateFieldGet2(_global, _this)) { if (_this.passed_data.token && _this.passed_data.purpose) { if (_this.passed_data.token !== _classPrivateFieldGet2(_getValueFromStorage, _this).call(_this, "cly_old_token")) { @@ -1189,9 +1336,10 @@ } else { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, SDK name:[" + _classPrivateFieldGet2(_sdkName, _this) + "], version:[" + _classPrivateFieldGet2(_sdkVersion, _this) + "], default name:[" + SDK_NAME + "] and default version:[" + SDK_VERSION + "]"); } + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, stored server config:[" + JSON.stringify(_classPrivateFieldGet2(_serverConfigCache, _this)) + "]"); _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, app_key:[" + _this.app_key + "], url:[" + _this.url + "]"); _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, device_id:[" + getConfig("device_id", ob, undefined) + "]"); - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, require_consent is enabled:[" + _this.require_consent + "]"); + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, require_consent is enabled:[" + _classPrivateFieldGet2(_SCEnableConsentRequired, _this) + "]"); try { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, metric override:[" + JSON.stringify(_this.metrics) + "]"); _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, header override:[" + JSON.stringify(_this.headers) + "]"); @@ -1267,37 +1415,37 @@ if (_classPrivateFieldGet2(_remoteConfigs, _this)) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, stored remote configs:[" + JSON.stringify(_classPrivateFieldGet2(_remoteConfigs, _this)) + "]"); } - if (_classPrivateFieldGet2(_contentZoneTimerInterval, _this)) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, content_zone_timer_interval:[" + _classPrivateFieldGet2(_contentZoneTimerInterval, _this) + "]"); + if (_classPrivateFieldGet2(_SCIntervalContent, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, content_zone_timer_interval:[" + _classPrivateFieldGet2(_SCIntervalContent, _this) + "]"); } // functions, if provided, would be printed as true without revealing their content _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, 'getViewName' callback override provided:[" + (_this.getViewName !== Countly.getViewName) + "]"); _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, 'getSearchQuery' callback override provided:[" + (_this.getSearchQuery !== Countly.getSearchQuery) + "]"); // limits are printed here if they were modified - if (_this.maxKeyLength !== configurationDefaultValues.MAX_KEY_LENGTH) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxKeyLength set to:[" + _this.maxKeyLength + "] characters"); + if (_classPrivateFieldGet2(_SCLimitKeyLength, _this) !== configurationDefaultValues.MAX_KEY_LENGTH) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxKeyLength set to:[" + _classPrivateFieldGet2(_SCLimitKeyLength, _this) + "] characters"); } - if (_this.maxValueSize !== configurationDefaultValues.MAX_VALUE_SIZE) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxValueSize set to:[" + _this.maxValueSize + "] characters"); + if (_classPrivateFieldGet2(_SCLimitValueSize, _this) !== configurationDefaultValues.MAX_VALUE_SIZE) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxValueSize set to:[" + _classPrivateFieldGet2(_SCLimitValueSize, _this) + "] characters"); } - if (_this.maxSegmentationValues !== configurationDefaultValues.MAX_SEGMENTATION_VALUES) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxSegmentationValues set to:[" + _this.maxSegmentationValues + "] key/value pairs"); + if (_classPrivateFieldGet2(_SCLimitSegmentationValues, _this) !== configurationDefaultValues.MAX_SEGMENTATION_VALUES) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxSegmentationValues set to:[" + _classPrivateFieldGet2(_SCLimitSegmentationValues, _this) + "] key/value pairs"); } - if (_this.maxBreadcrumbCount !== configurationDefaultValues.MAX_BREADCRUMB_COUNT) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxBreadcrumbCount for custom logs set to:[" + _this.maxBreadcrumbCount + "] entries"); + if (_classPrivateFieldGet2(_SCLimitBreadcrumbCount, _this) !== configurationDefaultValues.MAX_BREADCRUMB_COUNT) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxBreadcrumbCount for custom logs set to:[" + _classPrivateFieldGet2(_SCLimitBreadcrumbCount, _this) + "] entries"); } - if (_this.maxStackTraceLinesPerThread !== configurationDefaultValues.MAX_STACKTRACE_LINES_PER_THREAD) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxStackTraceLinesPerThread set to:[" + _this.maxStackTraceLinesPerThread + "] lines"); + if (_classPrivateFieldGet2(_SCLimitStackTraceLinesPerThread, _this) !== configurationDefaultValues.MAX_STACKTRACE_LINES_PER_THREAD) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxStackTraceLinesPerThread set to:[" + _classPrivateFieldGet2(_SCLimitStackTraceLinesPerThread, _this) + "] lines"); } - if (_this.maxStackTraceLineLength !== configurationDefaultValues.MAX_STACKTRACE_LINE_LENGTH) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxStackTraceLineLength set to:[" + _this.maxStackTraceLineLength + "] characters"); + if (_classPrivateFieldGet2(_SCLimitStackTraceLineLength, _this) !== configurationDefaultValues.MAX_STACKTRACE_LINE_LENGTH) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, maxStackTraceLineLength set to:[" + _classPrivateFieldGet2(_SCLimitStackTraceLineLength, _this) + "] characters"); } if (_classPrivateFieldGet2(_beatInterval, _this) !== configurationDefaultValues.BEAT_INTERVAL) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, interval for heartbeats set to:[" + _classPrivateFieldGet2(_beatInterval, _this) + "] milliseconds"); } - if (_classPrivateFieldGet2(_queueSize, _this) !== configurationDefaultValues.QUEUE_SIZE) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, queue_size set to:[" + _classPrivateFieldGet2(_queueSize, _this) + "] items max"); + if (_classPrivateFieldGet2(_SCSizeReqQueue, _this) !== configurationDefaultValues.QUEUE_SIZE) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, queue_size set to:[" + _classPrivateFieldGet2(_SCSizeReqQueue, _this) + "] items max"); } if (_classPrivateFieldGet2(_failTimeoutAmount, _this) !== configurationDefaultValues.FAIL_TIMEOUT_AMOUNT) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, fail_timeout set to:[" + _classPrivateFieldGet2(_failTimeoutAmount, _this) + "] seconds of wait time after a failed connection to server"); @@ -1305,14 +1453,11 @@ if (_classPrivateFieldGet2(_inactivityTime, _this) !== configurationDefaultValues.INACTIVITY_TIME) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, inactivity_time set to:[" + _classPrivateFieldGet2(_inactivityTime, _this) + "] minutes to consider a user as inactive after no observable action"); } - if (_classPrivateFieldGet2(_sessionUpdate, _this) !== configurationDefaultValues.SESSION_UPDATE) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, session_update set to:[" + _classPrivateFieldGet2(_sessionUpdate, _this) + "] seconds to check if extending a session is needed while the user is active"); + if (_classPrivateFieldGet2(_SCIntervalSessionUpdate, _this) !== configurationDefaultValues.SESSION_UPDATE) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, session_update set to:[" + _classPrivateFieldGet2(_SCIntervalSessionUpdate, _this) + "] seconds to check if extending a session is needed while the user is active"); } - if (_classPrivateFieldGet2(_maxEventBatch, _this) !== configurationDefaultValues.MAX_EVENT_BATCH) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, max_events set to:[" + _classPrivateFieldGet2(_maxEventBatch, _this) + "] events to send in one batch"); - } - if (_classPrivateFieldGet2(_maxCrashLogs, _this)) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "initialize, max_logs set to:[" + _classPrivateFieldGet2(_maxCrashLogs, _this) + "] breadcrumbs to store for crash logs max, deprecated "); + if (_classPrivateFieldGet2(_SCSizeEventBatch, _this) !== configurationDefaultValues.MAX_EVENT_BATCH) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, max_events set to:[" + _classPrivateFieldGet2(_SCSizeEventBatch, _this) + "] events to send in one batch"); } if (_classPrivateFieldGet2(_sessionCookieTimeout, _this) !== configurationDefaultValues.SESSION_COOKIE_TIMEOUT) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "initialize, session_cookie_timeout set to:[" + _classPrivateFieldGet2(_sessionCookieTimeout, _this) + "] minutes to expire a cookies session"); @@ -1426,23 +1571,7 @@ } _this.userData.save(); } - _classPrivateFieldGet2(_notifyLoaders, _this).call(_this); - setTimeout(function () { - if (!Countly.noHeartBeat) { - _classPrivateFieldGet2(_heartBeat, _this).call(_this); - } else { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "initialize, Heartbeat disabled. This is for testing purposes only!"); - } - if (_this.remote_config) { - _this.fetch_remote_config(_this.remote_config); - } - }, 1); - if (isBrowser) { - document.documentElement.setAttribute("data-countly-useragent", currentUserAgentString()); - } - // send instant health check request - _classPrivateFieldGet2(_HealthCheck, _this).sendInstantHCRequest(); - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "initialize, Countly initialized"); + _classPrivateFieldGet2(_getAndSetServerConfig, _this).call(_this); }); _classPrivateFieldInitSpec(this, _updateConsent, function () { if (_classPrivateFieldGet2(_consentTimer, _this)) { @@ -1482,7 +1611,7 @@ _classPrivateFieldSet2(_apiPath, _this, "/i"); _classPrivateFieldSet2(_readPath, _this, "/o/sdk"); _classPrivateFieldSet2(_beatInterval, _this, 500); - _classPrivateFieldSet2(_queueSize, _this, 1000); + _classPrivateFieldSet2(_SCSizeReqQueue, _this, 1000); _classPrivateFieldSet2(_requestQueue, _this, []); _classPrivateFieldSet2(_eventQueue, _this, []); _classPrivateFieldSet2(_remoteConfigs, _this, {}); @@ -1499,9 +1628,8 @@ _classPrivateFieldSet2(_failTimeoutAmount, _this, 60); _classPrivateFieldSet2(_inactivityTime, _this, 20); _classPrivateFieldSet2(_inactivityCounter, _this, 0); - _classPrivateFieldSet2(_sessionUpdate, _this, 60); - _classPrivateFieldSet2(_maxEventBatch, _this, 100); - _classPrivateFieldSet2(_maxCrashLogs, _this, null); + _classPrivateFieldSet2(_SCIntervalSessionUpdate, _this, 60); + _classPrivateFieldSet2(_SCSizeEventBatch, _this, 100); _classPrivateFieldSet2(_useSessionCookie, _this, true); _classPrivateFieldSet2(_sessionCookieTimeout, _this, 30); _classPrivateFieldSet2(_readyToProcess, _this, true); @@ -1572,17 +1700,17 @@ _this.useExplicitRcApi = undefined; _this.remote_config = undefined; _this.ignore_visitor = undefined; - _this.require_consent = undefined; + _classPrivateFieldSet2(_SCEnableConsentRequired, _this, undefined); _this.track_domains = undefined; _this.storage = undefined; _this.enableOrientationTracking = undefined; _this.salt = undefined; - _this.maxKeyLength = undefined; - _this.maxValueSize = undefined; - _this.maxSegmentationValues = undefined; - _this.maxBreadcrumbCount = undefined; - _this.maxStackTraceLinesPerThread = undefined; - _this.maxStackTraceLineLength = undefined; + _classPrivateFieldSet2(_SCLimitKeyLength, _this, undefined); + _classPrivateFieldSet2(_SCLimitValueSize, _this, undefined); + _classPrivateFieldSet2(_SCLimitSegmentationValues, _this, undefined); + _classPrivateFieldSet2(_SCLimitBreadcrumbCount, _this, undefined); + _classPrivateFieldSet2(_SCLimitStackTraceLinesPerThread, _this, undefined); + _classPrivateFieldSet2(_SCLimitStackTraceLineLength, _this, undefined); }); /** * Modify feature groups for consent management. Allows you to group multiple features under one feature group @@ -1630,7 +1758,7 @@ */ _defineProperty(this, "check_consent", function (feature) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "check_consent, Checking if consent is given for specific feature:[" + feature + "]"); - if (!_this.require_consent) { + if (!_classPrivateFieldGet2(_SCEnableConsentRequired, _this)) { // we don't need to have specific consents _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "check_consent, require_consent is off, no consent is necessary"); return true; @@ -1679,7 +1807,7 @@ */ _defineProperty(this, "check_any_consent", function () { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "check_any_consent, Checking if any consent is given"); - if (!_this.require_consent) { + if (!_classPrivateFieldGet2(_SCEnableConsentRequired, _this)) { // we don't need to have consents _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "check_any_consent, require_consent is off, no consent is necessary"); return true; @@ -1772,6 +1900,7 @@ // clear consents _this.remove_consent_internal(Countly.features, false); _classPrivateFieldSet2(_offlineMode, _this, true); + _classPrivateFieldGet2(_exitContentZoneInternal, _this).call(_this); _this.device_id = "[CLY]_temp_id"; _classPrivateFieldSet2(_deviceIdType, _this, DeviceIdTypeInternalEnums.TEMPORARY_ID); }); @@ -1815,6 +1944,11 @@ _classPrivateFieldGet2(_HealthCheck, _this).sendInstantHCRequest(); _classPrivateFieldSet2(_shouldSendHC, _this, false); } + _classPrivateFieldGet2(_getAndSetServerConfig, _this).call(_this); + if (_classPrivateFieldGet2(_SCEnableContent, _this)) { + _classPrivateFieldGet2(_enterContentZoneInternal, _this).call(_this); + _classPrivateFieldSet2(_initContentSent, _this, true); + } }); /** * Start session @@ -1822,6 +1956,10 @@ * @param {bool} force - force begin session request even if session cookie is enabled */ _defineProperty(this, "begin_session", function (noHeartBeat, force) { + if (!_classPrivateFieldGet2(_SCTrackingSession, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "begin_session, Session tracking is disabled by server config"); + return; + } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "begin_session, Starting the session. There was an ongoing session: [" + _classPrivateFieldGet2(_sessionStarted, _this) + "]"); if (noHeartBeat) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "begin_session, Heartbeats are disabled"); @@ -1868,6 +2006,10 @@ * @param {int} sec - amount of seconds to report for current session */ _defineProperty(this, "session_duration", function (sec) { + if (!_classPrivateFieldGet2(_SCTrackingSession, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "session_duration, Session tracking is disabled by server config"); + return; + } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "session_duration, Reporting session duration: [" + sec + "]"); if (!_this.check_consent(featureEnums.SESSIONS)) { return; @@ -1888,6 +2030,10 @@ * @param {bool} force - force end session request even if session cookie is enabled */ _defineProperty(this, "end_session", function (sec, force) { + if (!_classPrivateFieldGet2(_SCTrackingSession, _this) && !force) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "end_session, Session tracking is disabled by server config"); + return; + } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "end_session, Ending the current session. There was an on going session:[" + _classPrivateFieldGet2(_sessionStarted, _this) + "]"); if (_this.check_consent(featureEnums.SESSIONS)) { if (_classPrivateFieldGet2(_sessionStarted, _this)) { @@ -2014,7 +2160,7 @@ respectiveConsent = _this.check_consent(featureEnums.CLICKS) || _this.check_consent(featureEnums.SCROLLS); break; default: - respectiveConsent = _this.check_consent(featureEnums.EVENTS); + respectiveConsent = _classPrivateFieldGet2(_SCTrackingEvents, _this) ? _this.check_consent(featureEnums.EVENTS) : false; } // if consent is given adds event to the queue if (respectiveConsent) { @@ -2029,8 +2175,8 @@ */ _classPrivateFieldInitSpec(this, _add_cly_events, function (event, eventIdOverride) { // ignore bots - if (_this.ignore_visitor) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.ERROR, "Adding event failed. Possible bot or user opt out"); + if (_this.ignore_visitor || !_classPrivateFieldGet2(_SCTrackingAll, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "Not adding the event. Tracking is disabled by the server config:[" + !_classPrivateFieldGet2(_SCTrackingAll, _this) + "] or ignore_visitor is:[" + _this.ignore_visitor + "]"); return; } if (!event.key) { @@ -2043,9 +2189,9 @@ // we omit the internal event keys from truncation. TODO: This is not perfect as it would omit a key that includes an internal event key and more too. But that possibility seems negligible. if (!internalEventKeyEnumsArray.includes(event.key)) { // truncate event name and segmentation to internal limits - event.key = truncateSingleValue(event.key, _this.maxKeyLength, "add_cly_event", _classPrivateFieldGet2(_log, _this)); + event.key = truncateSingleValue(event.key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "add_cly_event", _classPrivateFieldGet2(_log, _this)); } - event.segmentation = truncateObject(event.segmentation, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "add_cly_event", _classPrivateFieldGet2(_log, _this)); + event.segmentation = truncateObject(event.segmentation, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "add_cly_event", _classPrivateFieldGet2(_log, _this)); var props = ["key", "count", "sum", "dur", "segmentation"]; var e = createNewObjectFromProperties(event, props); e.timestamp = getMsTimestamp(); @@ -2074,7 +2220,7 @@ } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "start_event, Starting timed event with key: [" + key + "]"); // truncate event name to internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "start_event", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "start_event", _classPrivateFieldGet2(_log, _this)); if (_classPrivateFieldGet2(_timedEvents, _this)[key]) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "start_event, Timed event with key: [" + key + "] already started"); return; @@ -2093,7 +2239,7 @@ } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "cancel_event, Canceling timed event with key: [" + key + "]"); // truncate event name to internal limits. This is done incase start_event key was truncated. - key = truncateSingleValue(key, _this.maxKeyLength, "cancel_event", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "cancel_event", _classPrivateFieldGet2(_log, _this)); if (_classPrivateFieldGet2(_timedEvents, _this)[key]) { delete _classPrivateFieldGet2(_timedEvents, _this)[key]; _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "cancel_event, Timed event with key: [" + key + "] is canceled"); @@ -2114,7 +2260,7 @@ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "end_event, Ending timed event"); if (typeof event === "string") { // truncate event name to internal limits. This is done incase start_event key was truncated. - event = truncateSingleValue(event, _this.maxKeyLength, "end_event", _classPrivateFieldGet2(_log, _this)); + event = truncateSingleValue(event, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "end_event", _classPrivateFieldGet2(_log, _this)); event = { key: event }; @@ -2201,15 +2347,15 @@ _classPrivateFieldGet2(_sendEventsForced, _this).call(_this); _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "user_details, flushed the event queue"); // truncating user values and custom object key value pairs - user.name = truncateSingleValue(user.name, _this.maxValueSize, "user_details", _classPrivateFieldGet2(_log, _this)); - user.username = truncateSingleValue(user.username, _this.maxValueSize, "user_details", _classPrivateFieldGet2(_log, _this)); - user.email = truncateSingleValue(user.email, _this.maxValueSize, "user_details", _classPrivateFieldGet2(_log, _this)); - user.organization = truncateSingleValue(user.organization, _this.maxValueSize, "user_details", _classPrivateFieldGet2(_log, _this)); - user.phone = truncateSingleValue(user.phone, _this.maxValueSize, "user_details", _classPrivateFieldGet2(_log, _this)); + user.name = truncateSingleValue(user.name, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this)); + user.username = truncateSingleValue(user.username, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this)); + user.email = truncateSingleValue(user.email, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this)); + user.organization = truncateSingleValue(user.organization, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this)); + user.phone = truncateSingleValue(user.phone, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this)); user.picture = truncateSingleValue(user.picture, 4096, "user_details", _classPrivateFieldGet2(_log, _this)); - user.gender = truncateSingleValue(user.gender, _this.maxValueSize, "user_details", _classPrivateFieldGet2(_log, _this)); - user.byear = truncateSingleValue(user.byear, _this.maxValueSize, "user_details", _classPrivateFieldGet2(_log, _this)); - user.custom = truncateObject(user.custom, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "user_details", _classPrivateFieldGet2(_log, _this)); + user.gender = truncateSingleValue(user.gender, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this)); + user.byear = truncateSingleValue(user.byear, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this)); + user.custom = truncateObject(user.custom, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "user_details", _classPrivateFieldGet2(_log, _this)); var props = ["name", "username", "email", "organization", "phone", "picture", "gender", "byear", "custom"]; _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, { user_details: JSON.stringify(createNewObjectFromProperties(user, props)) @@ -2268,8 +2414,8 @@ set: function set(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] set, Setting user's custom property value: [" + value + "] under the key: [" + key + "]"); // truncate user's custom property value to internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData set", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData set", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData set", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData set", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_customData, _this)[key] = value; }, /** @@ -2290,8 +2436,8 @@ set_once: function set_once(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] set_once, Setting user's unique custom property value: [" + value + "] under the key: [" + key + "] "); // truncate user's custom property value to internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData set_once", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData set_once", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData set_once", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData set_once", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, value, "$setOnce"); }, /** @@ -2302,7 +2448,7 @@ increment: function increment(key) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] increment, Increasing user's custom property value under the key: [" + key + "] by one"); // truncate property name wrt internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData increment", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData increment", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, 1, "$inc"); }, /** @@ -2314,8 +2460,8 @@ increment_by: function increment_by(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] increment_by, Increasing user's custom property value under the key: [" + key + "] by: [" + value + "]"); // truncate property name and value wrt internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData increment_by", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData increment_by", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData increment_by", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData increment_by", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, value, "$inc"); }, /** @@ -2327,8 +2473,8 @@ multiply: function multiply(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] multiply, Multiplying user's custom property value under the key: [" + key + "] by: [" + value + "]"); // truncate key value pair wrt internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData multiply", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData multiply", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData multiply", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData multiply", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, value, "$mul"); }, /** @@ -2340,8 +2486,8 @@ max: function max(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] max, Saving user's maximum custom property value compared to the value: [" + value + "] under the key: [" + key + "]"); // truncate key value pair wrt internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData max", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData max", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData max", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData max", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, value, "$max"); }, /** @@ -2353,8 +2499,8 @@ min: function min(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] min, Saving user's minimum custom property value compared to the value: [" + value + "] under the key: [" + key + "]"); // truncate key value pair wrt internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData min", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData min", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData min", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData min", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, value, "$min"); }, /** @@ -2366,8 +2512,8 @@ push: function push(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] push, Pushing a value: [" + value + "] under the key: [" + key + "] to user's custom property array"); // truncate key value pair wrt internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData push", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData push", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData push", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData push", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, value, "$push"); }, /** @@ -2379,8 +2525,8 @@ push_unique: function push_unique(key, value) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] push_unique, Pushing a unique value: [" + value + "] under the key: [" + key + "] to user's custom property array"); // truncate key value pair wrt internal limits - key = truncateSingleValue(key, _this.maxKeyLength, "userData push_unique", _classPrivateFieldGet2(_log, _this)); - value = truncateSingleValue(value, _this.maxValueSize, "userData push_unique", _classPrivateFieldGet2(_log, _this)); + key = truncateSingleValue(key, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "userData push_unique", _classPrivateFieldGet2(_log, _this)); + value = truncateSingleValue(value, _classPrivateFieldGet2(_SCLimitValueSize, _this), "userData push_unique", _classPrivateFieldGet2(_log, _this)); _classPrivateFieldGet2(_change_custom_property, _this).call(_this, key, value, "$addToSet"); }, /** @@ -2435,8 +2581,8 @@ } } // truncate trace name and metrics wrt internal limits - trace.name = truncateSingleValue(trace.name, _this.maxKeyLength, "report_trace", _classPrivateFieldGet2(_log, _this)); - trace.app_metrics = truncateObject(trace.app_metrics, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "report_trace", _classPrivateFieldGet2(_log, _this)); + trace.name = truncateSingleValue(trace.name, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "report_trace", _classPrivateFieldGet2(_log, _this)); + trace.app_metrics = truncateObject(trace.app_metrics, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "report_trace", _classPrivateFieldGet2(_log, _this)); var e = createNewObjectFromProperties(trace, props); e.timestamp = trace.stz; var date = new Date(); @@ -2457,6 +2603,10 @@ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "track_errors, window object is not available. Not tracking errors."); return; } + if (!_classPrivateFieldGet2(_SCTrackingCrashes, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "track_errors, Crash tracking is disabled by the server config. Not tracking errors."); + return; + } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "track_errors, Started tracking errors"); // Indicated that for this instance of the countly error tracking is enabled Countly.i[_this.app_key].tracking_crashes = true; @@ -2464,38 +2614,23 @@ window.cly_crashes = true; _classPrivateFieldSet2(_crashSegments, _this, segments); // override global 'uncaught error' handler - window.onerror = function errorBundler(msg, url, line, col, err) { - // old browsers like IE 10 and Safari 9 won't give this value 'err' to us, but if it is provided we can trigger error recording immediately - if (err !== undefined && err !== null) { - // false indicates fatal error (as in non_fatal:false) - dispatchErrors(err, false); - } - // fallback if no error object is present for older browsers, we create it instead - else { - col = col || window.event && window.event.errorCharacter; - var error = ""; - if (typeof msg !== "undefined") { - error += msg + "\n"; - } - if (typeof url !== "undefined") { - error += "at " + url; - } - if (typeof line !== "undefined") { - error += ":" + line; - } - if (typeof col !== "undefined") { - error += ":" + col; - } + window.addEventListener("error", function (event) { + if (event.error) { + dispatchErrors(event.error, false); // false indicates fatal error + } else { + // For older browsers that don't provide error object, construct an error message + var errorMsg = event.message || "Unknown error"; + var url = event.filename || ""; + var line = event.lineno || 0; + var col = event.colno || 0; + var error = errorMsg + "\n"; + if (url) error += "at " + url; + if (line) error += ":" + line; + if (col) error += ":" + col; error += "\n"; try { var stack = []; - // deprecated, must be changed - // eslint-disable-next-line no-caller - var f = errorBundler.caller; - while (f) { - stack.push(f.name); - f = f.caller; - } + // We don't have caller info in this case, so we skip that part error += stack.join("\n"); } catch (ex) { // silent error @@ -2503,7 +2638,7 @@ // false indicates fatal error (as in non_fatal:false) dispatchErrors(error, false); } - }; + }); // error handling for 'uncaught rejections' window.addEventListener("unhandledrejection", function (event) { @@ -2530,8 +2665,8 @@ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "add_log, Adding a new log of breadcrumbs: [ " + record + " ]"); if (_this.check_consent(featureEnums.CRASHES)) { // truncate description wrt internal limits - record = truncateSingleValue(record, _this.maxValueSize, "add_log", _classPrivateFieldGet2(_log, _this)); - while (_classPrivateFieldGet2(_crashLogs, _this).length >= _this.maxBreadcrumbCount) { + record = truncateSingleValue(record, _classPrivateFieldGet2(_SCLimitValueSize, _this), "add_log", _classPrivateFieldGet2(_log, _this)); + while (_classPrivateFieldGet2(_crashLogs, _this).length >= _classPrivateFieldGet2(_SCLimitBreadcrumbCount, _this)) { _classPrivateFieldGet2(_crashLogs, _this).shift(); _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "add_log, Reached maximum crashLogs size. Will erase the oldest one."); } @@ -2823,7 +2958,11 @@ * */ _defineProperty(this, "track_pageview", function (page, ignoreList, viewSegments) { if (!isBrowser && !page) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "track_pageview, window object is not available. Not tracking page views is page is not provided."); + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "track_pageview, window object is not available. Not tracking page views as page name is not provided."); + return; + } + if (!_classPrivateFieldGet2(_SCTrackingViews, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "track_pageview, View tracking is disabled by the server config. Not tracking page views."); return; } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "track_pageview, Tracking page views"); @@ -2838,7 +2977,7 @@ _classPrivateFieldSet2(_previousViewId, _this, _classPrivateFieldGet2(_currentViewId, _this)); _classPrivateFieldSet2(_currentViewId, _this, secureRandom()); // truncate page name and segmentation wrt internal limits - page = truncateSingleValue(page, _this.maxKeyLength, "track_pageview", _classPrivateFieldGet2(_log, _this)); + page = truncateSingleValue(page, _classPrivateFieldGet2(_SCLimitKeyLength, _this), "track_pageview", _classPrivateFieldGet2(_log, _this)); // if the first parameter we got is an array we got the ignoreList first, assign it here if (page && Array.isArray(page)) { ignoreList = page; @@ -2875,7 +3014,7 @@ view: _this.getViewUrl() }; // truncate new segment - segments = truncateObject(segments, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "track_pageview", _classPrivateFieldGet2(_log, _this)); + segments = truncateObject(segments, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "track_pageview", _classPrivateFieldGet2(_log, _this)); if (_this.track_domains) { segments.domain = window.location.hostname; } @@ -2922,7 +3061,7 @@ segments.referrer = document.referrer; // add referrer } if (viewSegments) { - viewSegments = truncateObject(viewSegments, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "track_pageview", _classPrivateFieldGet2(_log, _this)); + viewSegments = truncateObject(viewSegments, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "track_pageview", _classPrivateFieldGet2(_log, _this)); for (var key in viewSegments) { if (typeof segments[key] === "undefined") { segments[key] = viewSegments[key]; @@ -2993,7 +3132,7 @@ view: _this.getViewUrl() }; // truncate new segment - segments = truncateObject(segments, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "processClick", _classPrivateFieldGet2(_log, _this)); + segments = truncateObject(segments, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "processClick", _classPrivateFieldGet2(_log, _this)); if (_this.track_domains) { segments.domain = window.location.hostname; } @@ -4008,7 +4147,8 @@ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "present_feedback_widget, Removed a wrapper."); } wrapper = document.createElement("div"); - wrapper.className = "countly-" + feedbackWidgetFamily + "-wrapper"; + var wrapperClass = "countly-" + feedbackWidgetFamily + "-wrapper"; + wrapper.className = wrapperClass + " " + wrapperClass + "--" + presentableFeedback.type; wrapper.id = "countly-" + feedbackWidgetFamily + "-wrapper-" + presentableFeedback._id; if (presentableFeedback.type === "survey") { // Set popup position @@ -4218,6 +4358,10 @@ * @param {Object} segments - custom crash segments */ _defineProperty(this, "recordError", function (err, nonfatal, segments) { + if (!_classPrivateFieldGet2(_SCTrackingCrashes, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "recordError, Crash tracking is disabled by the server config. Not tracking errors."); + return; + } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "recordError, Recording error"); if (_this.check_consent(featureEnums.CRASHES) && err) { // crashSegments, if not null, was set while enabling error tracking @@ -4247,18 +4391,18 @@ error = err + ""; } // character limit check - if (error.length > _this.maxStackTraceLineLength * _this.maxStackTraceLinesPerThread) { + if (error.length > _classPrivateFieldGet2(_SCLimitStackTraceLineLength, _this) * _classPrivateFieldGet2(_SCLimitStackTraceLinesPerThread, _this)) { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "record_error, Error stack is too long will be truncated"); // convert error into an array split from each newline var splittedError = error.split("\n"); // trim the array if it is too long - if (splittedError.length > _this.maxStackTraceLinesPerThread) { - splittedError = splittedError.splice(0, _this.maxStackTraceLinesPerThread); + if (splittedError.length > _classPrivateFieldGet2(_SCLimitStackTraceLinesPerThread, _this)) { + splittedError = splittedError.splice(0, _classPrivateFieldGet2(_SCLimitStackTraceLinesPerThread, _this)); } // trim each line to a given limit for (var i = 0, len = splittedError.length; i < len; i++) { - if (splittedError[i].length > _this.maxStackTraceLineLength) { - splittedError[i] = splittedError[i].substring(0, _this.maxStackTraceLineLength); + if (splittedError[i].length > _classPrivateFieldGet2(_SCLimitStackTraceLineLength, _this)) { + splittedError[i] = splittedError[i].substring(0, _classPrivateFieldGet2(_SCLimitStackTraceLineLength, _this)); } } // turn modified array back into error string @@ -4292,7 +4436,7 @@ obj._view = _this.getViewName(); if (typeof segments !== "undefined") { // truncate custom crash segment's key value pairs - segments = truncateObject(segments, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "record_error", _classPrivateFieldGet2(_log, _this)); + segments = truncateObject(segments, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "record_error", _classPrivateFieldGet2(_log, _this)); obj._custom = segments; } try { @@ -4341,17 +4485,11 @@ enterContentZone: function enterContentZone() { _classPrivateFieldGet2(_enterContentZoneInternal, _this).call(_this); }, + refreshContentZone: function refreshContentZone() { + _classPrivateFieldGet2(_refreshContentZoneInternal, _this).call(_this); + }, exitContentZone: function exitContentZone() { - if (!_classPrivateFieldGet2(_inContentZone, _this)) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "content.exitContentZone, Not in content zone"); - return; - } - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "content.exitContentZone, Exiting content zone"); - _classPrivateFieldSet2(_inContentZone, _this, false); - if (_classPrivateFieldGet2(_contentZoneTimer, _this)) { - clearInterval(_classPrivateFieldGet2(_contentZoneTimer, _this)); - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "content.exitContentZone, content zone exited"); - } + _classPrivateFieldGet2(_exitContentZoneInternal, _this).call(_this); } }); _classPrivateFieldInitSpec(this, _enterContentZoneInternal, function (forced) { @@ -4363,6 +4501,14 @@ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "content.enterContentZone, Already in content zone"); return; } + if (!_classPrivateFieldGet2(_initTimestamp, _this) || getMsTimestamp() - _classPrivateFieldGet2(_initTimestamp, _this) < 4000) { + // settimeout + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "content.enterContentZone, Not enough time passed since initialization"); + setTimeout(function () { + _classPrivateFieldGet2(_enterContentZoneInternal, _this).call(_this); + }, 4001); + return; + } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "content.enterContentZone, Entering content zone"); _classPrivateFieldSet2(_inContentZone, _this, true); if (!forced) { @@ -4370,7 +4516,32 @@ } _classPrivateFieldSet2(_contentZoneTimer, _this, setInterval(function () { _classPrivateFieldGet2(_sendContentRequest, _this).call(_this); - }, _classPrivateFieldGet2(_contentTimeInterval, _this))); + }, _classPrivateFieldGet2(_SCIntervalContent, _this))); + }); + _classPrivateFieldInitSpec(this, _refreshContentZoneInternal, function () { + if (!_classPrivateFieldGet2(_SCEnableRefreshContentZone, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "content.refreshContentZone, Refresh content zone is disabled"); + return; + } + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "content.refreshContentZone, Refreshing content zone"); + _classPrivateFieldGet2(_exitContentZoneInternal, _this).call(_this); + _classPrivateFieldGet2(_processAsyncQueue, _this).call(_this); + _classPrivateFieldGet2(_sendEventsForced, _this).call(_this); + setTimeout(function () { + _classPrivateFieldGet2(_enterContentZoneInternal, _this).call(_this); + }, 1000); + }); + _classPrivateFieldInitSpec(this, _exitContentZoneInternal, function () { + if (!_classPrivateFieldGet2(_inContentZone, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "content.exitContentZone, Not in content zone"); + return; + } + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "content.exitContentZone, Exiting content zone"); + _classPrivateFieldSet2(_inContentZone, _this, false); + if (_classPrivateFieldGet2(_contentZoneTimer, _this)) { + clearInterval(_classPrivateFieldGet2(_contentZoneTimer, _this)); + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "content.exitContentZone, content zone exited"); + } }); _classPrivateFieldInitSpec(this, _prepareContentRequest, function () { _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "prepareContentRequest, forming content request"); @@ -4392,7 +4563,8 @@ la: language, resolution: JSON.stringify(resToSend), cly_ws: 1, - cly_origin: window.location.origin + cly_origin: window.location.origin, + dt: userAgentDeviceDetection() }; _classPrivateFieldGet2(_prepareRequest, _this).call(_this, params); return params; @@ -4469,7 +4641,7 @@ } }); _classPrivateFieldInitSpec(this, _interpretContentMessage, function (messageEvent) { - if (messageEvent.origin !== _this.url) { + if (_this.contentWhitelist.indexOf(messageEvent.origin) === -1) { // this.#log(logLevelEnums.ERROR, "interpretContentMessage, Received message from invalid origin"); // silent ignore return; @@ -4662,6 +4834,10 @@ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "reportViewDuration, No last view, will not report view duration"); return; } + if (!_classPrivateFieldGet2(_SCTrackingViews, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "reportViewDuration, View tracking is disabled by the server config. Not tracking view duration"); + return; + } _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "reportViewDuration, Reporting view duration for: [" + _classPrivateFieldGet2(_lastView, _this) + "]"); var segments = { name: _classPrivateFieldGet2(_lastView, _this) @@ -4730,7 +4906,7 @@ request.metrics = JSON.stringify(currentMetrics); } } - if (_this.check_consent(featureEnums.LOCATION)) { + if (_this.check_consent(featureEnums.LOCATION) && _classPrivateFieldGet2(_SCTrackingLocation, _this)) { if (_this.country_code) { request.country_code = _this.country_code; } @@ -4755,7 +4931,11 @@ */ _classPrivateFieldInitSpec(this, _toRequestQueue, function (request) { if (_this.ignore_visitor) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "User is opt_out will ignore the request: " + request); + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "User is opt_out will ignore the request: " + request); + return; + } + if (!_classPrivateFieldGet2(_SCTrackingAll, _this)) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "Tracking is disabled by server config, will not track the request: " + JSON.stringify(request)); return; } if (!_this.app_key || !_this.device_id) { @@ -4763,7 +4943,7 @@ return; } _classPrivateFieldGet2(_prepareRequest, _this).call(_this, request); - if (_classPrivateFieldGet2(_requestQueue, _this).length > _classPrivateFieldGet2(_queueSize, _this)) { + if (_classPrivateFieldGet2(_requestQueue, _this).length > _classPrivateFieldGet2(_SCSizeReqQueue, _this)) { _classPrivateFieldGet2(_requestQueue, _this).shift(); } _classPrivateFieldGet2(_requestQueue, _this).push(request); @@ -4780,7 +4960,7 @@ // ignore bots if (_this.ignore_visitor) { _classPrivateFieldSet2(_hasPulse, _this, false); - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "User opt_out, no heartbeat"); + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "User opt_out:[" + _this.ignore_visitor + "], no heartbeat"); return; } _classPrivateFieldSet2(_hasPulse, _this, true); @@ -4792,7 +4972,7 @@ // extend session if needed if (_classPrivateFieldGet2(_sessionStarted, _this) && _classPrivateFieldGet2(_autoExtend, _this) && _classPrivateFieldGet2(_trackTime, _this)) { var last = getTimestamp(); - if (last - _classPrivateFieldGet2(_lastBeat, _this) > _classPrivateFieldGet2(_sessionUpdate, _this)) { + if (last - _classPrivateFieldGet2(_lastBeat, _this) > _classPrivateFieldGet2(_SCIntervalSessionUpdate, _this)) { _this.session_duration(last - _classPrivateFieldGet2(_lastBeat, _this)); _classPrivateFieldSet2(_lastBeat, _this, last); // save health check logging counters if there are any @@ -4807,13 +4987,13 @@ // process event queue if (_classPrivateFieldGet2(_eventQueue, _this).length > 0 && !_this.test_mode_eq) { - if (_classPrivateFieldGet2(_eventQueue, _this).length <= _classPrivateFieldGet2(_maxEventBatch, _this)) { + if (_classPrivateFieldGet2(_eventQueue, _this).length <= _classPrivateFieldGet2(_SCSizeEventBatch, _this)) { _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, { events: JSON.stringify(_classPrivateFieldGet2(_eventQueue, _this)) }); _classPrivateFieldSet2(_eventQueue, _this, []); } else { - var events = _classPrivateFieldGet2(_eventQueue, _this).splice(0, _classPrivateFieldGet2(_maxEventBatch, _this)); + var events = _classPrivateFieldGet2(_eventQueue, _this).splice(0, _classPrivateFieldGet2(_SCSizeEventBatch, _this)); _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, { events: JSON.stringify(events) }); @@ -4938,7 +5118,10 @@ * @returns {string} returns userAgent string */ _classPrivateFieldInitSpec(this, _getUA, function () { - return _this.metrics._ua || currentUserAgentString(); + if (_this.metrics && _this.metrics._ua) { + return _this.metrics._ua; + } + return currentUserAgentString(); }); /** * Get metrics of the browser or config object @@ -5009,16 +5192,9 @@ width = Math.round(width * window.devicePixelRatio); height = Math.round(height * window.devicePixelRatio); } - if (Math.abs(screen.orientation.angle) === 90) { - _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.VERBOSE, "Screen is in landscape mode, adjusting resolution"); - var temp = width; - width = height; - height = temp; - } return { width: width, - height: height, - orientation: screen.orientation.angle + height: height }; }); /** @@ -5125,8 +5301,13 @@ * @param {Object} params - key value object with URL params * @param {Function} callback - callback when request finished or failed * @param {Boolean} useBroadResponseValidator - if true that means the expected response is either a JSON object or a JSON array, if false only JSON + * @param {Boolean} forced - if true that means the request is forced and should be made regardless of the networking config */ - _classPrivateFieldInitSpec(this, _makeNetworkRequest, function (functionName, url, params, callback, useBroadResponseValidator) { + _classPrivateFieldInitSpec(this, _makeNetworkRequest, function (functionName, url, params, callback, useBroadResponseValidator, forced) { + if (!_classPrivateFieldGet2(_SCNetwork, _this) && !forced) { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "Network request is disabled by the SCNetwork"); + return; + } _classPrivateFieldGet2(_generatedRequests, _this).push({ functionName: functionName, url: url, @@ -5386,7 +5567,7 @@ view: _this.getViewUrl() }; // truncate new segment - segments = truncateObject(segments, _this.maxKeyLength, _this.maxValueSize, _this.maxSegmentationValues, "processScrollView", _classPrivateFieldGet2(_log, _this)); + segments = truncateObject(segments, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "processScrollView", _classPrivateFieldGet2(_log, _this)); if (_this.track_domains) { segments.domain = window.location.hostname; } @@ -5500,7 +5681,7 @@ } var data; // use dev provided storage if available - if (_typeof(_this.storage) === "object" && typeof _this.storage.getItem === "function") { + if (_this.storage && _typeof(_this.storage) === "object" && typeof _this.storage.getItem === "function") { data = _this.storage.getItem(key); return key.endsWith("cly_id") ? data : _this.deserialize(data); } @@ -5678,6 +5859,10 @@ case "cly_ignore": _this.ignore_visitor = _this.deserialize(newValue); break; + case "cly_config": + _classPrivateFieldSet2(_serverConfigCache, _this, _this.deserialize(newValue || "{}")); + _classPrivateFieldGet2(_populateServerConfig, _this).call(_this, _classPrivateFieldGet2(_serverConfigCache, _this)); + break; case "cly_id": _this.device_id = newValue; break; @@ -5851,14 +6036,11 @@ _classPrivateFieldSet2(_sessionStarted, this, false); _classPrivateFieldSet2(_apiPath, this, "/i"); _classPrivateFieldSet2(_readPath, this, "/o/sdk"); - _classPrivateFieldSet2(_beatInterval, this, getConfig("interval", _ob, configurationDefaultValues.BEAT_INTERVAL)); - _classPrivateFieldSet2(_queueSize, this, getConfig("queue_size", _ob, configurationDefaultValues.QUEUE_SIZE)); _classPrivateFieldSet2(_requestQueue, this, []); _classPrivateFieldSet2(_eventQueue, this, []); _classPrivateFieldSet2(_remoteConfigs, this, {}); _classPrivateFieldSet2(_crashLogs, this, []); _classPrivateFieldSet2(_timedEvents, this, {}); - _classPrivateFieldSet2(_ignoreReferrers, this, getConfig("ignore_referrers", _ob, [])); _classPrivateFieldSet2(_crashSegments, this, null); _classPrivateFieldSet2(_autoExtend, this, true); _classPrivateFieldGet2(_lastBeat, this); @@ -5867,17 +6049,9 @@ _classPrivateFieldSet2(_lastViewTime, this, 0); _classPrivateFieldSet2(_lastViewStoredDuration, this, 0); _classPrivateFieldSet2(_failTimeout, this, 0); - _classPrivateFieldSet2(_failTimeoutAmount, this, getConfig("fail_timeout", _ob, configurationDefaultValues.FAIL_TIMEOUT_AMOUNT)); - _classPrivateFieldSet2(_inactivityTime, this, getConfig("inactivity_time", _ob, configurationDefaultValues.INACTIVITY_TIME)); _classPrivateFieldSet2(_inactivityCounter, this, 0); - _classPrivateFieldSet2(_sessionUpdate, this, getConfig("session_update", _ob, configurationDefaultValues.SESSION_UPDATE)); - _classPrivateFieldSet2(_maxEventBatch, this, getConfig("max_events", _ob, configurationDefaultValues.MAX_EVENT_BATCH)); - _classPrivateFieldSet2(_maxCrashLogs, this, getConfig("max_logs", _ob, null)); - _classPrivateFieldSet2(_useSessionCookie, this, getConfig("use_session_cookie", _ob, true)); - _classPrivateFieldSet2(_sessionCookieTimeout, this, getConfig("session_cookie_timeout", _ob, configurationDefaultValues.SESSION_COOKIE_TIMEOUT)); _classPrivateFieldSet2(_readyToProcess, this, true); _classPrivateFieldSet2(_hasPulse, this, false); - _classPrivateFieldSet2(_offlineMode, this, getConfig("offline_mode", _ob, false)); _classPrivateFieldSet2(_lastParams, this, {}); _classPrivateFieldSet2(_trackTime, this, true); _classPrivateFieldSet2(_startTime, this, getTimestamp()); @@ -5890,16 +6064,38 @@ _classPrivateFieldSet2(_currentViewId, this, null); // this is the global variable for tracking the current view's ID. Used in view tracking. Becomes previous view ID at the end. _classPrivateFieldSet2(_previousViewId, this, null); // this is the global variable for tracking the previous view's ID. Used in view tracking. First view has no previous view ID. _classPrivateFieldSet2(_freshUTMTags, this, null); - _classPrivateFieldSet2(_sdkName, this, getConfig("sdk_name", _ob, SDK_NAME)); - _classPrivateFieldSet2(_sdkVersion, this, getConfig("sdk_version", _ob, SDK_VERSION)); _classPrivateFieldSet2(_shouldSendHC, this, false); _classPrivateFieldSet2(_generatedRequests, this, []); - _classPrivateFieldSet2(_contentTimeInterval, this, 30000); _classPrivateFieldSet2(_contentEndPoint, this, "/o/sdk/content"); _classPrivateFieldSet2(_inContentZone, this, false); _classPrivateFieldSet2(_contentZoneTimer, this, null); _classPrivateFieldSet2(_contentIframeID, this, "cly-content-iframe"); _classPrivateFieldSet2(_crashFilterCallback, this, null); + _classPrivateFieldSet2(_SCNetwork, this, true); + _classPrivateFieldSet2(_SCSizeReqQueue, this, getConfig("queue_size", _ob, configurationDefaultValues.QUEUE_SIZE)); + _classPrivateFieldSet2(_SCSizeEventBatch, this, getConfig("max_events", _ob, configurationDefaultValues.MAX_EVENT_BATCH)); + _classPrivateFieldSet2(_SCIntervalSessionUpdate, this, getConfig("session_update", _ob, configurationDefaultValues.SESSION_UPDATE)); + _classPrivateFieldSet2(_SCIntervalContent, this, Math.max(getConfig("content_zone_timer_interval", _ob, 30), 15) * 1000); // min 15 seconds + _classPrivateFieldSet2(_SCInterval, this, 4); // 4 hours + _classPrivateFieldSet2(_SCTrackingAll, this, true); + _classPrivateFieldSet2(_SCTrackingSession, this, true); + _classPrivateFieldSet2(_SCTrackingCrashes, this, true); + _classPrivateFieldSet2(_SCTrackingViews, this, true); + _classPrivateFieldSet2(_SCTrackingEvents, this, true); + _classPrivateFieldSet2(_SCTrackingLocation, this, true); + _classPrivateFieldSet2(_SCEnableContent, this, false); + _classPrivateFieldSet2(_SCEnableRefreshContentZone, this, true); + _classPrivateFieldSet2(_SCEnableConsentRequired, this, getConfig("require_consent", _ob, false)); + _classPrivateFieldSet2(_SCLimitKeyLength, this, getConfig("max_key_length", _ob, configurationDefaultValues.MAX_KEY_LENGTH)); + _classPrivateFieldSet2(_SCLimitValueSize, this, getConfig("max_value_size", _ob, configurationDefaultValues.MAX_VALUE_SIZE)); + _classPrivateFieldSet2(_SCLimitSegmentationValues, this, getConfig("max_segmentation_values", _ob, configurationDefaultValues.MAX_SEGMENTATION_VALUES)); + _classPrivateFieldSet2(_SCLimitBreadcrumbCount, this, getConfig("max_breadcrumb_count", _ob, configurationDefaultValues.MAX_BREADCRUMB_COUNT)); + _classPrivateFieldSet2(_SCLimitStackTraceLinesPerThread, this, getConfig("max_stack_trace_lines_per_thread", _ob, configurationDefaultValues.MAX_STACKTRACE_LINES_PER_THREAD)); + _classPrivateFieldSet2(_SCLimitStackTraceLineLength, this, getConfig("max_stack_trace_line_length", _ob, configurationDefaultValues.MAX_STACKTRACE_LINE_LENGTH)); + this.app_key = getConfig("app_key", _ob, null); + this.url = stripTrailingSlash(getConfig("url", _ob, "")); + this.serialize = getConfig("serialize", _ob, Countly.serialize); + this.deserialize = getConfig("deserialize", _ob, Countly.deserialize); try { localStorage.setItem("cly_testLocal", true); // clean up test @@ -5908,6 +6104,12 @@ _classPrivateFieldGet2(_log, this).call(this, logLevelEnums.ERROR, "Local storage test failed, Halting local storage support: " + e); _classPrivateFieldSet2(_lsSupport, this, false); } + _classPrivateFieldSet2(_serverConfigCache, this, _classPrivateFieldGet2(_getValueFromStorage, this).call(this, "cly_config")); + if (!_classPrivateFieldGet2(_serverConfigCache, this)) { + _classPrivateFieldSet2(_serverConfigCache, this, getConfig("behavior_settings", _ob, {})); + _classPrivateFieldGet2(_setValueInStorage, this).call(this, "cly_config", JSON.stringify(_classPrivateFieldGet2(_serverConfigCache, this))); + } + _classPrivateFieldGet2(_populateServerConfig, this).call(this, _classPrivateFieldGet2(_serverConfigCache, this)); // create object to store consents _classPrivateFieldSet2(_consents, this, {}); @@ -5915,6 +6117,30 @@ _classPrivateFieldGet2(_consents, this)[Countly.features[it]] = {}; } _classPrivateFieldGet2(_initialize, this).call(this, _ob); + + // start SDK + _classPrivateFieldGet2(_notifyLoaders, this).call(this); + setTimeout(function () { + if (!Countly.noHeartBeat) { + _classPrivateFieldGet2(_heartBeat, _this).call(_this); + } else { + _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "initialize, Heartbeat disabled. This is for testing purposes only!"); + } + if (_this.remote_config) { + _this.fetch_remote_config(_this.remote_config); + } + }, 1); + if (isBrowser) { + document.documentElement.setAttribute("data-countly-useragent", currentUserAgentString()); + } + _classPrivateFieldSet2(_initTimestamp, this, getMsTimestamp()); + // send instant health check request + _classPrivateFieldGet2(_HealthCheck, this).sendInstantHCRequest(); + if (_classPrivateFieldGet2(_SCEnableContent, this)) { + _classPrivateFieldGet2(_enterContentZoneInternal, this).call(this); + _classPrivateFieldSet2(_initContentSent, this, true); + } + _classPrivateFieldGet2(_log, this).call(this, logLevelEnums.INFO, "initialize, Countly initialized"); }); var apmLibrariesNotLoaded = true; // used to prevent loading apm scripts multiple times. diff --git a/lib/countly.min.js b/lib/countly.min.js index 91d21b65..581fe5b9 100644 --- a/lib/countly.min.js +++ b/lib/countly.min.js @@ -1,200 +1,207 @@ -(function(va,Ja){"object"===typeof exports&&"undefined"!==typeof module?Ja(exports):"function"===typeof define&&define.amd?define(["exports"],Ja):(va="undefined"!==typeof globalThis?globalThis:va||self,Ja(va.Countly=va.Countly||{}))})(this,function(va){function Ja(m,p,v){if("function"==typeof m?m===p:m.has(p))return 3>arguments.length?p:v;throw new TypeError("Private element is not present on this object");}function b(m,p){return m.get(Ja(m,p))}function q(m,p,v){if(p.has(m))throw new TypeError("Cannot initialize the same private elements twice on an object"); -p.set(m,v)}function l(m,p,v){return m.set(Ja(m,p),v),v}function w(m,p,v){a:{var a=p;if("object"==typeof a&&a){var F=a[Symbol.toPrimitive];if(void 0!==F){a=F.call(a,"string");if("object"!=typeof a)break a;throw new TypeError("@@toPrimitive must return a primitive value.");}a=String(a)}}return(p="symbol"==typeof a?a:a+"")in m?Object.defineProperty(m,p,{value:v,enumerable:!0,configurable:!0,writable:!0}):m[p]=v,m}function R(m){"@babel/helpers - typeof";return R="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator? -function(p){return typeof p}:function(p){return p&&"function"==typeof Symbol&&p.constructor===Symbol&&p!==Symbol.prototype?"symbol":typeof p},R(m)}function bc(m){var p=[];if("undefined"!==typeof m.options)for(var v=0;v=m?lb++:lb=m;return lb}function y(m,p,v){if(p&&Object.keys(p).length){if("undefined"!==typeof p[m])return p[m]}else if("undefined"!==typeof t[m])return t[m];return v}function Gb(m,p,v){for(var a in t.i)t.i[a].tracking_crashes&&t.i[a].recordError(m,p,v)}function Hb(m,p){var v=[],a;for(a in m)v.push(a+ -"="+encodeURIComponent(m[a]));var F=v.join("&");return p?dc(F,p).then(function(c){return F+="&checksum256="+c}):Promise.resolve(F)}function Ka(m){return"string"===typeof m&&"/"===m.substring(m.length-1)?m.substring(0,m.length-1):m}function $a(m,p){for(var v={},a,F=0,c=p.length;Fa){var g={},h=0,n;for(n in m)hp&&(F=m.substring(0,p),a(f.DEBUG,v+", Key: [ "+m+" ] is longer than accepted length. It will be truncated."));return F}function dc(m,p){m=(new TextEncoder).encode(m+p);return crypto.subtle.digest("SHA-256",m).then(function(v){return Array.from(new Uint8Array(v)).map(function(a){return a.toString(16).padStart(2,"0")}).join("")})}function D(m,p,v){A&&(null===m||"undefined"===typeof m?mb()&& -console.warn("[WARNING] [Countly] add_event_listener, Can't bind ["+p+"] event to nonexisting element"):"undefined"!==typeof m.addEventListener?m.addEventListener(p,v,!1):m.attachEvent("on"+p,v))}function nb(m){return m?"undefined"!==typeof m.target?m.target:m.srcElement:window.event.srcElement}function La(m){if(m)return m;(m=navigator.userAgent)||(m=Ib());return m}function Ib(m){if(m)return m;m="";navigator.userAgentData&&(m=navigator.userAgentData.brands.map(function(p){return p.brand+":"+p.version}).join(), -m+=navigator.userAgentData.mobile?" mobi ":" ",m+=navigator.userAgentData.platform);return m}function ec(m){if(!m){if(navigator.userAgentData&&navigator.userAgentData.mobile)return"phone";m=La()}m=m.toLowerCase();var p="desktop",v=/(mobi|ipod|phone|blackberry|opera mini|fennec|minimo|symbian|psp|nintendo ds|archos|skyfire|puffin|blazer|bolt|gobrowser|iris|maemo|semc|teashark|uzard)/;/(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test(m)? -p="tablet":v.test(m)&&(p="phone");return p}function fc(m){var p=/(CountlySiteBot|nuhk|Googlebot|GoogleSecurityScanner|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver|bingbot|Google Web Preview|Mediapartners-Google|AdsBot-Google|Baiduspider|Ezooms|YahooSeeker|AltaVista|AVSearch|Mercator|Scooter|InfoSeek|Ultraseek|Lycos|Wget|YandexBot|Yandex|YaDirectFetcher|SiteBot|Exabot|AhrefsBot|MJ12bot|TurnitinBot|magpie-crawler|Nutch Crawler|CMS Crawler|rogerbot|Domnutch|ssearch_bot|XoviBot|netseer|digincore|fr-crawler|wesee|AliasIO|contxbot|PingdomBot|BingPreview|HeadlessChrome|Lighthouse)/; -if(m)return p.test(m);m=p.test(La());p=p.test(Ib());return m||p}function Jb(m){"undefined"===typeof m.pageY&&"number"===typeof m.clientX&&document.documentElement&&(m.pageX=m.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,m.pageY=m.clientY+document.body.scrollTop+document.documentElement.scrollTop);return m}function ob(){var m=document;return Math.max(Math.max(m.body.scrollHeight,m.documentElement.scrollHeight),Math.max(m.body.offsetHeight,m.documentElement.offsetHeight),Math.max(m.body.clientHeight, -m.documentElement.clientHeight))}function Kb(){var m=document;return Math.max(Math.max(m.body.scrollWidth,m.documentElement.scrollWidth),Math.max(m.body.offsetWidth,m.documentElement.offsetWidth),Math.max(m.body.clientWidth,m.documentElement.clientWidth))}function gc(){var m=document;return Math.min(Math.min(m.body.clientHeight,m.documentElement.clientHeight),Math.min(m.body.offsetHeight,m.documentElement.offsetHeight),window.innerHeight)}function hc(m,p,v,a,F,c){m=document.createElement(m);var d; -m.setAttribute(p,v);m.setAttribute(a,F);p=function(){d||c();d=!0};c&&(m.onreadystatechange=p,m.onload=p);document.getElementsByTagName("head")[0].appendChild(m)}function ic(m,p){hc("script","type","text/javascript","src",m,p)}function pb(m,p){hc("link","rel","stylesheet","href",m,p)}function jc(){if(A){var m=document.getElementById("cly-loader");if(!m){var p=document.head||document.getElementsByTagName("head")[0],v=document.createElement("style");v.type="text/css";v.styleSheet?v.styleSheet.cssText= +(function(Ea,Va){"object"===typeof exports&&"undefined"!==typeof module?Va(exports):"function"===typeof define&&define.amd?define(["exports"],Va):(Ea="undefined"!==typeof globalThis?globalThis:Ea||self,Va(Ea.Countly=Ea.Countly||{}))})(this,function(Ea){function Va(m,q,v){if("function"==typeof m?m===q:m.has(q))return 3>arguments.length?q:v;throw new TypeError("Private element is not present on this object");}function b(m,q){return m.get(Va(m,q))}function p(m,q,v){if(q.has(m))throw new TypeError("Cannot initialize the same private elements twice on an object"); +q.set(m,v)}function k(m,q,v){return m.set(Va(m,q),v),v}function w(m,q,v){a:{var a=q;if("object"==typeof a&&a){var G=a[Symbol.toPrimitive];if(void 0!==G){a=G.call(a,"string");if("object"!=typeof a)break a;throw new TypeError("@@toPrimitive must return a primitive value.");}a=String(a)}}return(q="symbol"==typeof a?a:a+"")in m?Object.defineProperty(m,q,{value:v,enumerable:!0,configurable:!0,writable:!0}):m[q]=v,m}function R(m){"@babel/helpers - typeof";return R="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator? +function(q){return typeof q}:function(q){return q&&"function"==typeof Symbol&&q.constructor===Symbol&&q!==Symbol.prototype?"symbol":typeof q},R(m)}function xc(m){var q=[];if("undefined"!==typeof m.options)for(var v=0;v=m?zb++:zb=m;return zb}function x(m,q,v){if(q&&Object.keys(q).length){if("undefined"!==typeof q[m])return q[m]}else if("undefined"!==typeof t[m])return t[m];return v}function bc(m,q,v){for(var a in t.i)t.i[a].tracking_crashes&&t.i[a].recordError(m,q,v)}function cc(m,q){var v=[],a;for(a in m)v.push(a+ +"="+encodeURIComponent(m[a]));var G=v.join("&");return q?zc(G,q).then(function(c){return G+="&checksum256="+c}):Promise.resolve(G)}function Fa(m){return"string"===typeof m&&"/"===m.substring(m.length-1)?m.substring(0,m.length-1):m}function lb(m,q){for(var v={},a,G=0,c=q.length;Ga){var g={},h=0,n;for(n in m)hq&&(G=m.substring(0,q),a(f.DEBUG,v+", Key: [ "+m+" ] is longer than accepted length. It will be truncated."));return G}function zc(m,q){m=(new TextEncoder).encode(m+q);return crypto.subtle.digest("SHA-256",m).then(function(v){return Array.from(new Uint8Array(v)).map(function(a){return a.toString(16).padStart(2,"0")}).join("")})}function D(m,q,v){A&&(null===m||"undefined"===typeof m?Ab()&& +console.warn("[WARNING] [Countly] add_event_listener, Can't bind ["+q+"] event to nonexisting element"):"undefined"!==typeof m.addEventListener?m.addEventListener(q,v,!1):m.attachEvent("on"+q,v))}function Bb(m){return m?"undefined"!==typeof m.target?m.target:m.srcElement:window.event.srcElement}function Xa(m){if(m)return m;(m=navigator.userAgent)||(m=dc());return m}function dc(m){if(m)return m;m="";navigator.userAgentData&&(m=navigator.userAgentData.brands.map(function(q){return q.brand+":"+q.version}).join(), +m+=navigator.userAgentData.mobile?" mobi ":" ",m+=navigator.userAgentData.platform);return m}function ec(m){if(!m){if(navigator.userAgentData&&navigator.userAgentData.mobile)return"phone";m=Xa()}m=m.toLowerCase();var q="desktop",v=/(mobi|ipod|phone|blackberry|opera mini|fennec|minimo|symbian|psp|nintendo ds|archos|skyfire|puffin|blazer|bolt|gobrowser|iris|maemo|semc|teashark|uzard)/;/(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test(m)? +q="tablet":v.test(m)&&(q="phone");return q}function Ac(m){var q=/(CountlySiteBot|nuhk|Googlebot|GoogleSecurityScanner|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver|bingbot|Google Web Preview|Mediapartners-Google|AdsBot-Google|Baiduspider|Ezooms|YahooSeeker|AltaVista|AVSearch|Mercator|Scooter|InfoSeek|Ultraseek|Lycos|Wget|YandexBot|Yandex|YaDirectFetcher|SiteBot|Exabot|AhrefsBot|MJ12bot|TurnitinBot|magpie-crawler|Nutch Crawler|CMS Crawler|rogerbot|Domnutch|ssearch_bot|XoviBot|netseer|digincore|fr-crawler|wesee|AliasIO|contxbot|PingdomBot|BingPreview|HeadlessChrome|Lighthouse)/; +if(m)return q.test(m);m=q.test(Xa());q=q.test(dc());return m||q}function fc(m){"undefined"===typeof m.pageY&&"number"===typeof m.clientX&&document.documentElement&&(m.pageX=m.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,m.pageY=m.clientY+document.body.scrollTop+document.documentElement.scrollTop);return m}function Cb(){var m=document;return Math.max(Math.max(m.body.scrollHeight,m.documentElement.scrollHeight),Math.max(m.body.offsetHeight,m.documentElement.offsetHeight),Math.max(m.body.clientHeight, +m.documentElement.clientHeight))}function gc(){var m=document;return Math.max(Math.max(m.body.scrollWidth,m.documentElement.scrollWidth),Math.max(m.body.offsetWidth,m.documentElement.offsetWidth),Math.max(m.body.clientWidth,m.documentElement.clientWidth))}function Bc(){var m=document;return Math.min(Math.min(m.body.clientHeight,m.documentElement.clientHeight),Math.min(m.body.offsetHeight,m.documentElement.offsetHeight),window.innerHeight)}function Cc(m,q,v,a,G,c){m=document.createElement(m);var d; +m.setAttribute(q,v);m.setAttribute(a,G);q=function(){d||c();d=!0};c&&(m.onreadystatechange=q,m.onload=q);document.getElementsByTagName("head")[0].appendChild(m)}function Dc(m,q){Cc("script","type","text/javascript","src",m,q)}function Db(m,q){Cc("link","rel","stylesheet","href",m,q)}function Ec(){if(A){var m=document.getElementById("cly-loader");if(!m){var q=document.head||document.getElementsByTagName("head")[0],v=document.createElement("style");v.type="text/css";v.styleSheet?v.styleSheet.cssText= "#cly-loader {height: 4px; width: 100%; position: absolute; z-index: 99999; overflow: hidden; background-color: #fff; top:0px; left:0px;}#cly-loader:before{display: block; position: absolute; content: ''; left: -200px; width: 200px; height: 4px; background-color: #2EB52B; animation: cly-loading 2s linear infinite;}@keyframes cly-loading { from {left: -200px; width: 30%;} 50% {width: 30%;} 70% {width: 70%;} 80% { left: 50%;} 95% {left: 120%;} to {left: 100%;}}":v.appendChild(document.createTextNode("#cly-loader {height: 4px; width: 100%; position: absolute; z-index: 99999; overflow: hidden; background-color: #fff; top:0px; left:0px;}#cly-loader:before{display: block; position: absolute; content: ''; left: -200px; width: 200px; height: 4px; background-color: #2EB52B; animation: cly-loading 2s linear infinite;}@keyframes cly-loading { from {left: -200px; width: 30%;} 50% {width: 30%;} 70% {width: 70%;} 80% { left: 50%;} 95% {left: 120%;} to {left: 100%;}}")); -p.appendChild(v);m=document.createElement("div");m.setAttribute("id","cly-loader");window.addEventListener("load",function(){if(t.showLoaderProtection)mb()&&console.warn("[WARNING] [Countly] showLoader, Loader is already on");else try{document.body.appendChild(m)}catch(a){mb()&&console.error("[ERROR] [Countly] showLoader, Body is not loaded for loader to append: "+a)}})}m.style.display="block"}}function mb(){return t&&t.debug&&"undefined"!==typeof console?!0:!1}function kc(){if(A){t.showLoaderProtection= -!0;var m=document.getElementById("cly-loader");m&&(m.style.display="none")}}function Hc(m){var p=document.createElement("script"),v=document.createElement("script");p.async=!0;v.async=!0;p.src=t.customSourceBoomerang||lc.BOOMERANG_SRC;v.src=t.customSourceCountlyBoomerang||lc.CLY_BOOMERANG_SRC;document.getElementsByTagName("head")[0].appendChild(p);document.getElementsByTagName("head")[0].appendChild(v);var a=!1,F=!1;p.onload=function(){a=!0};v.onload=function(){F=!0};var c=0,d=setInterval(function(){c+= -50;if(a&&F||1500<=c){if(t.debug){var g="BoomerangJS loaded:["+a+"], countly_boomerang loaded:["+F+"].";a&&F?console.log("[DEBUG] "+g):console.warn("[WARNING] "+g+" Initializing without APM.")}t.init(m);clearInterval(d)}},50)}var O={NPS:"[CLY]_nps",SURVEY:"[CLY]_survey",STAR_RATING:"[CLY]_star_rating",VIEW:"[CLY]_view",ORIENTATION:"[CLY]_orientation",ACTION:"[CLY]_action"},Ic=Object.values(O),f={ERROR:"[ERROR] ",WARNING:"[WARNING] ",INFO:"[INFO] ",DEBUG:"[DEBUG] ",VERBOSE:"[VERBOSE] "},lc={BOOMERANG_SRC:"https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/plugin/boomerang/boomerang.min.js", -CLY_BOOMERANG_SRC:"https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/plugin/boomerang/countly_boomerang.js"},Z=Object.freeze({errorCount:"cly_hc_error_count",warningCount:"cly_hc_warning_count",statusCode:"cly_hc_status_code",errorMessage:"cly_hc_error_message"}),mc=/^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?::([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?::([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,A="undefined"!==typeof window,t=globalThis.Countly||{}, -lb=0,ab=new WeakMap,nc=new WeakMap,Ma=new WeakMap,X=new WeakMap,bb=new WeakMap,Na=new WeakMap,Oa=new WeakMap,Pa=new WeakMap,K=new WeakMap,N=new WeakMap,P=new WeakMap,la=new WeakMap,aa=new WeakMap,ba=new WeakMap,cb=new WeakMap,wa=new WeakMap,fa=new WeakMap,db=new WeakMap,S=new WeakMap,xa=new WeakMap,ya=new WeakMap,eb=new WeakMap,Qa=new WeakMap,za=new WeakMap,ra=new WeakMap,Ra=new WeakMap,Aa=new WeakMap,sa=new WeakMap,ha=new WeakMap,Ba=new WeakMap,Sa=new WeakMap,Ta=new WeakMap,L=new WeakMap,ca=new WeakMap, -ma=new WeakMap,qb=new WeakMap,na=new WeakMap,ta=new WeakMap,H=new WeakMap,Ca=new WeakMap,Da=new WeakMap,fb=new WeakMap,oa=new WeakMap,Ua=new WeakMap,ia=new WeakMap,ua=new WeakMap,pa=new WeakMap,gb=new WeakMap,I=new WeakMap,hb=new WeakMap,rb=new WeakMap,Lb=new WeakMap,Ea=new WeakMap,Va=new WeakMap,Wa=new WeakMap,Xa=new WeakMap,Ya=new WeakMap,oc=new WeakMap,Mb=new WeakMap,Y=new WeakMap,Nb=new WeakMap,da=new WeakMap,ja=new WeakMap,Ob=new WeakMap,Pb=new WeakMap,sb=new WeakMap,tb=new WeakMap,Qb=new WeakMap, -Rb=new WeakMap,pc=new WeakMap,Sb=new WeakMap,qc=new WeakMap,rc=new WeakMap,ub=new WeakMap,Fa=new WeakMap,vb=new WeakMap,Tb=new WeakMap,wb=new WeakMap,sc=new WeakMap,Ub=new WeakMap,Ga=new WeakMap,Q=new WeakMap,ib=new WeakMap,tc=new WeakMap,Ha=new WeakMap,xb=new WeakMap,uc=new WeakMap,Vb=new WeakMap,jb=new WeakMap,kb=new WeakMap,yb=new WeakMap,e=new WeakMap,ea=new WeakMap,Wb=new WeakMap,Xb=new WeakMap,zb=new WeakMap,Ab=new WeakMap,Yb=new WeakMap,Bb=new WeakMap,vc=new WeakMap,Zb=new WeakMap,wc=new WeakMap, -xc=new WeakMap,yc=new WeakMap,zc=new WeakMap,$b=new WeakMap,B=new WeakMap,z=new WeakMap,T=new WeakMap,Ac=new WeakMap,Bc=new WeakMap,Cc=new WeakMap,Dc=new WeakMap,qa=new WeakMap,Fc=function(m,p,v){return Object.defineProperty(m,"prototype",{writable:!1}),m}(function v(p){var a=this;if(!(this instanceof v))throw new TypeError("Cannot call a class as a function");q(this,ab,void 0);q(this,nc,void 0);q(this,Ma,void 0);q(this,X,void 0);q(this,bb,void 0);q(this,Na,void 0);q(this,Oa,void 0);q(this,Pa,void 0); -q(this,K,void 0);q(this,N,void 0);q(this,P,void 0);q(this,la,void 0);q(this,aa,void 0);q(this,ba,void 0);q(this,cb,void 0);q(this,wa,void 0);q(this,fa,void 0);q(this,db,void 0);q(this,S,void 0);q(this,xa,void 0);q(this,ya,void 0);q(this,eb,void 0);q(this,Qa,void 0);q(this,za,void 0);q(this,ra,void 0);q(this,Ra,void 0);q(this,Aa,void 0);q(this,sa,void 0);q(this,ha,void 0);q(this,Ba,void 0);q(this,Sa,void 0);q(this,Ta,void 0);q(this,L,void 0);q(this,ca,void 0);q(this,ma,void 0);q(this,qb,void 0);q(this, -na,void 0);q(this,ta,void 0);q(this,H,void 0);q(this,Ca,void 0);q(this,Da,void 0);q(this,fb,void 0);q(this,oa,void 0);q(this,Ua,void 0);q(this,ia,void 0);q(this,ua,void 0);q(this,pa,void 0);q(this,gb,void 0);q(this,I,void 0);q(this,hb,void 0);q(this,rb,void 0);q(this,Lb,void 0);q(this,Ea,void 0);q(this,Va,void 0);q(this,Wa,void 0);q(this,Xa,void 0);q(this,Ya,void 0);q(this,oc,function(c){a.serialize=y("serialize",c,t.serialize);a.deserialize=y("deserialize",c,t.deserialize);a.getViewName=y("getViewName", -c,t.getViewName);a.getViewUrl=y("getViewUrl",c,t.getViewUrl);a.getSearchQuery=y("getSearchQuery",c,t.getSearchQuery);a.DeviceIdType=t.DeviceIdType;a.namespace=y("namespace",c,"");a.clearStoredId=y("clear_stored_id",c,!1);a.app_key=y("app_key",c,null);a.onload=y("onload",c,[]);a.utm=y("utm",c,{source:!0,medium:!0,campaign:!0,term:!0,content:!0});a.ignore_prefetch=y("ignore_prefetch",c,!0);a.rcAutoOptinAb=y("rc_automatic_optin_for_ab",c,!0);a.useExplicitRcApi=y("use_explicit_rc_api",c,!1);a.debug=y("debug", -c,!1);a.test_mode=y("test_mode",c,!1);a.test_mode_eq=y("test_mode_eq",c,!1);a.metrics=y("metrics",c,{});a.headers=y("headers",c,{});a.url=Ka(y("url",c,""));a.app_version=y("app_version",c,"0.0");a.country_code=y("country_code",c,null);a.city=y("city",c,null);a.ip_address=y("ip_address",c,null);a.ignore_bots=y("ignore_bots",c,!0);a.force_post=y("force_post",c,!1);a.remote_config=y("remote_config",c,!1);a.ignore_visitor=y("ignore_visitor",c,!1);a.require_consent=y("require_consent",c,!1);a.track_domains= -A?y("track_domains",c,!0):void 0;a.storage=y("storage",c,"default");a.enableOrientationTracking=A?y("enable_orientation_tracking",c,!0):void 0;a.maxKeyLength=y("max_key_length",c,128);a.maxValueSize=y("max_value_size",c,256);a.maxSegmentationValues=y("max_segmentation_values",c,100);a.maxBreadcrumbCount=y("max_breadcrumb_count",c,null);a.maxStackTraceLinesPerThread=y("max_stack_trace_lines_per_thread",c,30);a.maxStackTraceLineLength=y("max_stack_trace_line_length",c,200);a.heatmapWhitelist=y("heatmap_whitelist", -c,[]);a.salt=y("salt",c,null);a.hcErrorCount=b(B,a).call(a,Z.errorCount)||0;a.hcWarningCount=b(B,a).call(a,Z.warningCount)||0;a.hcStatusCode=b(B,a).call(a,Z.statusCode)||-1;a.hcErrorMessage=b(B,a).call(a,Z.errorMessage)||"";l(Wa,a,y("content_zone_timer_interval",c,null));l(Ya,a,y("crash_filter_callback",c,null));b(Wa,a)&&l(rb,a,1E3*Math.max(b(Wa,a),15));b(sa,a)&&!a.maxBreadcrumbCount?(a.maxBreadcrumbCount=b(sa,a),b(e,a).call(a,f.WARNING,"initialize, 'maxCrashLogs' is deprecated. Use 'maxBreadcrumbCount' instead!")): -b(sa,a)||a.maxBreadcrumbCount||(a.maxBreadcrumbCount=100);"cookie"===a.storage&&l(na,a,!1);a.rcAutoOptinAb||a.useExplicitRcApi||(b(e,a).call(a,f.WARNING,"initialize, Auto opting is disabled, switching to explicit RC API"),a.useExplicitRcApi=!0);Array.isArray(b(ba,a))||l(ba,a,[]);""===a.url&&(b(e,a).call(a,f.ERROR,"initialize, Please provide server URL"),a.ignore_visitor=!0);b(B,a).call(a,"cly_ignore")&&(a.ignore_visitor=!0);b(Qb,a).call(a);if(A)if(window.name&&0===window.name.indexOf("cly:"))try{a.passed_data= -JSON.parse(window.name.replace("cly:",""))}catch(G){b(e,a).call(a,f.ERROR,"initialize, Could not parse name: "+window.name+", error: "+G)}else if(location.hash&&0===location.hash.indexOf("this.#cly:"))try{a.passed_data=JSON.parse(location.hash.replace("this.#cly:",""))}catch(G){b(e,a).call(a,f.ERROR,"initialize, Could not parse hash: "+location.hash+", error: "+G)}if((a.passed_data&&a.passed_data.app_key&&a.passed_data.app_key===a.app_key||a.passed_data&&!a.passed_data.app_key&&b(Ma,a))&&a.passed_data.token&& -a.passed_data.purpose){a.passed_data.token!==b(B,a).call(a,"cly_old_token")&&(b(Zb,a).call(a,a.passed_data.token),b(z,a).call(a,"cly_old_token",a.passed_data.token));var d=[];Array.isArray(a.heatmapWhitelist)?(a.heatmapWhitelist.push(a.url),d=a.heatmapWhitelist.map(function(G){return Ka(G)})):d=[a.url];d.includes(a.passed_data.url)&&"heatmap"===a.passed_data.purpose&&(a.ignore_visitor=!0,jc(),ic(a.passed_data.url+"/views/heatmap.js",kc))}if(a.ignore_visitor)b(e,a).call(a,f.WARNING,"initialize, ignore_visitor:["+ -a.ignore_visitor+"], this user will not be tracked");else{b(Ac,a).call(a);l(K,a,b(B,a).call(a,"cly_queue")||[]);l(N,a,b(B,a).call(a,"cly_event")||[]);l(P,a,b(B,a).call(a,"cly_remote_configs")||{});d="[CLY]_temp_id"===b(B,a).call(a,"cly_id");a.clearStoredId&&(b(B,a).call(a,"cly_id")&&!d&&(a.device_id=b(B,a).call(a,"cly_id"),b(e,a).call(a,f.DEBUG,"initialize, temporarily using the previous device ID to flush existing events"),l(H,a,b(B,a).call(a,"cly_id_type")),b(H,a)||(b(e,a).call(a,f.DEBUG,"initialize, No device ID type info from the previous session, falling back to DEVELOPER_SUPPLIED, for event flushing"), -l(H,a,0)),b(Fa,a).call(a),a.device_id=void 0,l(H,a,1)),b(e,a).call(a,f.INFO,"initialize, Clearing the device ID storage"),b(T,a).call(a,"cly_id"),b(T,a).call(a,"cly_id_type"),b(T,a).call(a,"cly_session"),d=!1);"javascript_native_web"===b(ua,a)&&"25.1.0"===b(pa,a)?b(e,a).call(a,f.DEBUG,"initialize, SDK name:["+b(ua,a)+"], version:["+b(pa,a)+"]"):b(e,a).call(a,f.DEBUG,"initialize, SDK name:["+b(ua,a)+"], version:["+b(pa,a)+"], default name:[javascript_native_web] and default version:[25.1.0]");b(e, -a).call(a,f.DEBUG,"initialize, app_key:["+a.app_key+"], url:["+a.url+"]");b(e,a).call(a,f.DEBUG,"initialize, device_id:["+y("device_id",c,void 0)+"]");b(e,a).call(a,f.DEBUG,"initialize, require_consent is enabled:["+a.require_consent+"]");try{b(e,a).call(a,f.DEBUG,"initialize, metric override:["+JSON.stringify(a.metrics)+"]"),b(e,a).call(a,f.DEBUG,"initialize, header override:["+JSON.stringify(a.headers)+"]"),b(e,a).call(a,f.DEBUG,"initialize, number of onload callbacks provided:["+a.onload.length+ -"]"),b(e,a).call(a,f.DEBUG,"initialize, utm tags:["+JSON.stringify(a.utm)+"]"),b(ba,a)&&b(e,a).call(a,f.DEBUG,"initialize, referrers to ignore :["+JSON.stringify(b(ba,a))+"]"),b(e,a).call(a,f.DEBUG,"initialize, salt given:["+!!a.salt+"]")}catch(G){b(e,a).call(a,f.ERROR,"initialize, Could not stringify some config object values")}b(e,a).call(a,f.DEBUG,"initialize, app_version:["+a.app_version+"]");b(e,a).call(a,f.DEBUG,"initialize, provided location info; country_code:["+a.country_code+"], city:["+ -a.city+"], ip_address:["+a.ip_address+"]");""!==a.namespace&&b(e,a).call(a,f.DEBUG,"initialize, namespace given:["+a.namespace+"]");a.clearStoredId&&b(e,a).call(a,f.DEBUG,"initialize, clearStoredId flag set to:["+a.clearStoredId+"]");a.ignore_prefetch&&b(e,a).call(a,f.DEBUG,"initialize, ignoring pre-fetching and pre-rendering from counting as real website visits :["+a.ignore_prefetch+"]");a.test_mode&&b(e,a).call(a,f.WARNING,"initialize, test_mode:["+a.test_mode+"], request queue won't be processed"); -a.test_mode_eq&&b(e,a).call(a,f.WARNING,"initialize, test_mode_eq:["+a.test_mode_eq+"], event queue won't be processed");a.heatmapWhitelist&&b(e,a).call(a,f.DEBUG,"initialize, heatmap whitelist:["+JSON.stringify(a.heatmapWhitelist)+"], these domains will be whitelisted");"default"!==a.storage&&b(e,a).call(a,f.DEBUG,"initialize, storage is set to:["+a.storage+"]");a.ignore_bots&&b(e,a).call(a,f.DEBUG,"initialize, ignore traffic from bots :["+a.ignore_bots+"]");a.force_post&&b(e,a).call(a,f.DEBUG,"initialize, forced post method for all requests:["+ -a.force_post+"]");a.remote_config&&b(e,a).call(a,f.DEBUG,"initialize, remote_config callback provided:["+!!a.remote_config+"]");"boolean"===typeof a.rcAutoOptinAb&&b(e,a).call(a,f.DEBUG,"initialize, automatic RC optin is enabled:["+a.rcAutoOptinAb+"]");a.useExplicitRcApi||b(e,a).call(a,f.WARNING,"initialize, will use legacy RC API. Consider enabling new API during init with use_explicit_rc_api flag");a.track_domains&&b(e,a).call(a,f.DEBUG,"initialize, tracking domain info:["+a.track_domains+"]"); -a.enableOrientationTracking&&b(e,a).call(a,f.DEBUG,"initialize, enableOrientationTracking:["+a.enableOrientationTracking+"]");b(ha,a)||b(e,a).call(a,f.WARNING,"initialize, use_session_cookie is enabled:["+b(ha,a)+"]");b(L,a)&&b(e,a).call(a,f.DEBUG,"initialize, offline_mode:["+b(L,a)+"], user info won't be send to the servers");b(P,a)&&b(e,a).call(a,f.DEBUG,"initialize, stored remote configs:["+JSON.stringify(b(P,a))+"]");b(Wa,a)&&b(e,a).call(a,f.DEBUG,"initialize, content_zone_timer_interval:["+b(Wa, -a)+"]");b(e,a).call(a,f.DEBUG,"initialize, 'getViewName' callback override provided:["+(a.getViewName!==t.getViewName)+"]");b(e,a).call(a,f.DEBUG,"initialize, 'getSearchQuery' callback override provided:["+(a.getSearchQuery!==t.getSearchQuery)+"]");128!==a.maxKeyLength&&b(e,a).call(a,f.DEBUG,"initialize, maxKeyLength set to:["+a.maxKeyLength+"] characters");256!==a.maxValueSize&&b(e,a).call(a,f.DEBUG,"initialize, maxValueSize set to:["+a.maxValueSize+"] characters");100!==a.maxSegmentationValues&& -b(e,a).call(a,f.DEBUG,"initialize, maxSegmentationValues set to:["+a.maxSegmentationValues+"] key/value pairs");100!==a.maxBreadcrumbCount&&b(e,a).call(a,f.DEBUG,"initialize, maxBreadcrumbCount for custom logs set to:["+a.maxBreadcrumbCount+"] entries");30!==a.maxStackTraceLinesPerThread&&b(e,a).call(a,f.DEBUG,"initialize, maxStackTraceLinesPerThread set to:["+a.maxStackTraceLinesPerThread+"] lines");200!==a.maxStackTraceLineLength&&b(e,a).call(a,f.DEBUG,"initialize, maxStackTraceLineLength set to:["+ -a.maxStackTraceLineLength+"] characters");500!==b(Oa,a)&&b(e,a).call(a,f.DEBUG,"initialize, interval for heartbeats set to:["+b(Oa,a)+"] milliseconds");1E3!==b(Pa,a)&&b(e,a).call(a,f.DEBUG,"initialize, queue_size set to:["+b(Pa,a)+"] items max");60!==b(Qa,a)&&b(e,a).call(a,f.DEBUG,"initialize, fail_timeout set to:["+b(Qa,a)+"] seconds of wait time after a failed connection to server");20!==b(za,a)&&b(e,a).call(a,f.DEBUG,"initialize, inactivity_time set to:["+b(za,a)+"] minutes to consider a user as inactive after no observable action"); -60!==b(Ra,a)&&b(e,a).call(a,f.DEBUG,"initialize, session_update set to:["+b(Ra,a)+"] seconds to check if extending a session is needed while the user is active");100!==b(Aa,a)&&b(e,a).call(a,f.DEBUG,"initialize, max_events set to:["+b(Aa,a)+"] events to send in one batch");b(sa,a)&&b(e,a).call(a,f.WARNING,"initialize, max_logs set to:["+b(sa,a)+"] breadcrumbs to store for crash logs max, deprecated ");30!==b(Ba,a)&&b(e,a).call(a,f.DEBUG,"initialize, session_cookie_timeout set to:["+b(Ba,a)+"] minutes to expire a cookies session"); -var g=null,h=a.getSearchQuery(),n=!1,k={};if(h){0===h.indexOf("?")&&(h=h.substring(1));h=h.split("&");for(var r=0;rwindow.innerHeight?"landscape":"portrait")}})});w(this,"report_conversion",function(c,d){b(e,a).call(a,f.WARNING,"report_conversion, Deprecated function call! Use 'recordDirectAttribution' in place of this call. Call will be redirected now!"); -a.recordDirectAttribution(c,d)});w(this,"recordDirectAttribution",function(c,d){b(e,a).call(a,f.INFO,"recordDirectAttribution, Recording the attribution for campaign ID: ["+c+"] and the user ID: ["+d+"]");a.check_consent("attribution")&&(c=c||b(B,a).call(a,"cly_cmp_id")||"cly_organic",(d=d||b(B,a).call(a,"cly_cmp_uid"))?b(Q,a).call(a,{campaign_id:c,campaign_user:d}):b(Q,a).call(a,{campaign_id:c}))});w(this,"user_details",function(c){b(e,a).call(a,f.INFO,"user_details, Trying to add user details: ", -c);a.check_consent("users")&&(b(Ha,a).call(a),b(Fa,a).call(a),b(e,a).call(a,f.INFO,"user_details, flushed the event queue"),c.name=C(c.name,a.maxValueSize,"user_details",b(e,a)),c.username=C(c.username,a.maxValueSize,"user_details",b(e,a)),c.email=C(c.email,a.maxValueSize,"user_details",b(e,a)),c.organization=C(c.organization,a.maxValueSize,"user_details",b(e,a)),c.phone=C(c.phone,a.maxValueSize,"user_details",b(e,a)),c.picture=C(c.picture,4096,"user_details",b(e,a)),c.gender=C(c.gender,a.maxValueSize, -"user_details",b(e,a)),c.byear=C(c.byear,a.maxValueSize,"user_details",b(e,a)),c.custom=ka(c.custom,a.maxKeyLength,a.maxValueSize,a.maxSegmentationValues,"user_details",b(e,a)),b(Q,a).call(a,{user_details:JSON.stringify($a(c,"name username email organization phone picture gender byear custom".split(" ")))}))});q(this,da,{});q(this,ja,function(c,d,g){a.check_consent("users")&&(b(da,a)[c]||(b(da,a)[c]={}),"$push"===g||"$pull"===g||"$addToSet"===g?(b(da,a)[c][g]||(b(da,a)[c][g]=[]),b(da,a)[c][g].push(d)): -b(da,a)[c][g]=d)});w(this,"userData",{set:function(c,d){b(e,a).call(a,f.INFO,"[userData] set, Setting user's custom property value: ["+d+"] under the key: ["+c+"]");c=C(c,a.maxKeyLength,"userData set",b(e,a));d=C(d,a.maxValueSize,"userData set",b(e,a));b(da,a)[c]=d},unset:function(c){b(e,a).call(a,f.INFO,"[userData] unset, Resetting user's custom property with key: ["+c+"] ");b(da,a)[c]=""},set_once:function(c,d){b(e,a).call(a,f.INFO,"[userData] set_once, Setting user's unique custom property value: ["+ -d+"] under the key: ["+c+"] ");c=C(c,a.maxKeyLength,"userData set_once",b(e,a));d=C(d,a.maxValueSize,"userData set_once",b(e,a));b(ja,a).call(a,c,d,"$setOnce")},increment:function(c){b(e,a).call(a,f.INFO,"[userData] increment, Increasing user's custom property value under the key: ["+c+"] by one");c=C(c,a.maxKeyLength,"userData increment",b(e,a));b(ja,a).call(a,c,1,"$inc")},increment_by:function(c,d){b(e,a).call(a,f.INFO,"[userData] increment_by, Increasing user's custom property value under the key: ["+ -c+"] by: ["+d+"]");c=C(c,a.maxKeyLength,"userData increment_by",b(e,a));d=C(d,a.maxValueSize,"userData increment_by",b(e,a));b(ja,a).call(a,c,d,"$inc")},multiply:function(c,d){b(e,a).call(a,f.INFO,"[userData] multiply, Multiplying user's custom property value under the key: ["+c+"] by: ["+d+"]");c=C(c,a.maxKeyLength,"userData multiply",b(e,a));d=C(d,a.maxValueSize,"userData multiply",b(e,a));b(ja,a).call(a,c,d,"$mul")},max:function(c,d){b(e,a).call(a,f.INFO,"[userData] max, Saving user's maximum custom property value compared to the value: ["+ -d+"] under the key: ["+c+"]");c=C(c,a.maxKeyLength,"userData max",b(e,a));d=C(d,a.maxValueSize,"userData max",b(e,a));b(ja,a).call(a,c,d,"$max")},min:function(c,d){b(e,a).call(a,f.INFO,"[userData] min, Saving user's minimum custom property value compared to the value: ["+d+"] under the key: ["+c+"]");c=C(c,a.maxKeyLength,"userData min",b(e,a));d=C(d,a.maxValueSize,"userData min",b(e,a));b(ja,a).call(a,c,d,"$min")},push:function(c,d){b(e,a).call(a,f.INFO,"[userData] push, Pushing a value: ["+d+"] under the key: ["+ -c+"] to user's custom property array");c=C(c,a.maxKeyLength,"userData push",b(e,a));d=C(d,a.maxValueSize,"userData push",b(e,a));b(ja,a).call(a,c,d,"$push")},push_unique:function(c,d){b(e,a).call(a,f.INFO,"[userData] push_unique, Pushing a unique value: ["+d+"] under the key: ["+c+"] to user's custom property array");c=C(c,a.maxKeyLength,"userData push_unique",b(e,a));d=C(d,a.maxValueSize,"userData push_unique",b(e,a));b(ja,a).call(a,c,d,"$addToSet")},pull:function(c,d){b(e,a).call(a,f.INFO,"[userData] pull, Removing the value: ["+ -d+"] under the key: ["+c+"] from user's custom property array");b(ja,a).call(a,c,d,"$pull")},save:function(){b(e,a).call(a,f.INFO,"[userData] save, Saving changes to user's custom property");a.check_consent("users")&&(b(Ha,a).call(a),b(Fa,a).call(a),b(e,a).call(a,f.INFO,"user_details, flushed the event queue"),b(Q,a).call(a,{user_details:JSON.stringify({custom:b(da,a)})}));l(da,a,{})}});w(this,"report_trace",function(c){b(e,a).call(a,f.INFO,"report_trace, Reporting performance trace");if(a.check_consent("apm")){for(var d= -"type name stz etz apm_metrics apm_attr".split(" "),g=0;g=a.maxBreadcrumbCount;)b(la,a).shift(),b(e,a).call(a,f.WARNING,"add_log, Reached maximum crashLogs size. Will erase the oldest one.");b(la,a).push(c)}});w(this,"fetch_remote_config",function(c,d,g){var h=null,n=null,k=null;c&&(g||"function"!==typeof c?Array.isArray(c)&&(h=c):k=c);d&&(g||"function"!==typeof d?Array.isArray(d)&&(n=d):k=d);k|| -"function"!==typeof g||(k=g);a.useExplicitRcApi?(b(e,a).call(a,f.INFO,"fetch_remote_config, Fetching remote config"),c=a.rcAutoOptinAb?1:0,b(Ob,a).call(a,h,n,c,null,k)):(b(e,a).call(a,f.WARNING,"fetch_remote_config, Fetching remote config, with legacy API"),b(Ob,a).call(a,h,n,null,"legacy",k))});q(this,Ob,function(c,d,g,h,n){b(e,a).call(a,f.INFO,"fetch_remote_config_explicit, Fetching sequence initiated");var k={method:"rc",av:a.app_version};c&&(k.keys=JSON.stringify(c));d&&(k.omit_keys=JSON.stringify(d)); -var r;"legacy"===h&&(k.method="fetch_remote_config");0===g&&(k.oi=0);1===g&&(k.oi=1);"function"===typeof n&&(r=n);a.check_consent("sessions")&&(k.metrics=JSON.stringify(b(jb,a).call(a)));a.check_consent("remote-config")?(b(Ga,a).call(a,k),b(ea,a).call(a,"fetch_remote_config_explicit",a.url+b(Na,a),k,function(u,x,G){if(!u){try{var U=JSON.parse(G);if(k.keys||k.omit_keys)for(var J in U)b(P,a)[J]=U[J];else l(P,a,U);b(z,a).call(a,"cly_remote_configs",b(P,a))}catch(Za){b(e,a).call(a,f.ERROR,"fetch_remote_config_explicit, Had an issue while parsing the response: "+ -Za)}r&&(b(e,a).call(a,f.INFO,"fetch_remote_config_explicit, Callback function is provided"),r(u,b(P,a)))}},!0)):(b(e,a).call(a,f.ERROR,"fetch_remote_config_explicit, Remote config requires explicit consent"),r&&r(Error("Remote config requires explicit consent"),b(P,a)))});w(this,"enrollUserToAb",function(c){b(e,a).call(a,f.INFO,"enrollUserToAb, Providing AB test keys to opt in for");c&&Array.isArray(c)&&0!==c.length?(c={method:"ab",keys:JSON.stringify(c),av:a.app_version},b(Ga,a).call(a,c),b(ea,a).call(a, -"enrollUserToAb",a.url+b(Na,a),c,function(d,g,h){if(!d)try{var n=JSON.parse(h);b(e,a).call(a,f.DEBUG,"enrollUserToAb, Parsed the response's result: ["+n.result+"]")}catch(k){b(e,a).call(a,f.ERROR,"enrollUserToAb, Had an issue while parsing the response: "+k)}},!0)):b(e,a).call(a,f.ERROR,"enrollUserToAb, No keys provided")});w(this,"get_remote_config",function(c){b(e,a).call(a,f.INFO,"get_remote_config, Getting remote config from storage");return"undefined"!==typeof c?b(P,a)[c]:b(P,a)});q(this,Pb, -function(){b(e,a).call(a,f.INFO,"stop_time, Stopping tracking duration");b(ma,a)&&(l(ma,a,!1),l(db,a,M()-b(fa,a)),l(ya,a,M()-b(xa,a)))});q(this,sb,function(){b(e,a).call(a,f.INFO,"start_time, Starting tracking duration");b(ma,a)||(l(ma,a,!0),l(fa,a,M()-b(db,a)),l(xa,a,M()-b(ya,a)),l(ya,a,0),b(Ub,a).call(a))});w(this,"track_sessions",function(){if(A){b(e,a).call(a,f.INFO,"track_session, Starting tracking user session");a.begin_session();b(sb,a).call(a);D(window,"beforeunload",function(){b(Ha,a).call(a); -b(Fa,a).call(a);a.end_session()});var c="hidden",d=function(){document[c]||!document.hasFocus()?b(Pb,a).call(a):b(sb,a).call(a)};D(window,"focus",d);D(window,"blur",d);D(window,"pageshow",d);D(window,"pagehide",d);"onfocusin"in document&&(D(window,"focusin",d),D(window,"focusout",d));c in document?document.addEventListener("visibilitychange",d):"mozHidden"in document?(c="mozHidden",document.addEventListener("mozvisibilitychange",d)):"webkitHidden"in document?(c="webkitHidden",document.addEventListener("webkitvisibilitychange", -d)):"msHidden"in document&&(c="msHidden",document.addEventListener("msvisibilitychange",d));d=function(){b(ra,a)>=b(za,a)&&b(sb,a).call(a);l(ra,a,0)};D(window,"mousemove",d);D(window,"click",d);D(window,"keydown",d);D(window,"scroll",d);setInterval(function(){var g;l(ra,a,(g=b(ra,a),g++,g));b(ra,a)>=b(za,a)&&b(Pb,a).call(a)},6E4)}else b(e,a).call(a,f.WARNING,"track_sessions, window object is not available. Not tracking sessions.")});w(this,"track_pageview",function(c,d,g){if(A||c)if(b(e,a).call(a, -f.INFO,"track_pageview, Tracking page views"),b(e,a).call(a,f.VERBOSE,"track_pageview, last view is:["+b(S,a)+"], current view ID is:["+b(oa,a)+"], previous view ID is:["+b(Ua,a)+"]"),b(S,a)&&b(fb,a)&&(b(e,a).call(a,f.DEBUG,"track_pageview, Scroll registry triggered"),b(Bb,a).call(a),l(Ca,a,!0),l(Da,a,0)),b(wb,a).call(a),l(Ua,a,b(oa,a)),l(oa,a,Db()),(c=C(c,a.maxKeyLength,"track_pageview",b(e,a)))&&Array.isArray(c)&&(d=c,c=null),c||(c=a.getViewName()),void 0===c||""===c)b(e,a).call(a,f.ERROR,"track_pageview, No page name to track (it is either undefined or empty string). No page view can be tracked."); -else if(null===c)b(e,a).call(a,f.ERROR,"track_pageview, View name returned as null. Page view will be ignored.");else{if(d&&d.length)for(var h=0;h