From 4c4ee69fe2d94570dd15b2c2e2d0bd5d05b0d13e Mon Sep 17 00:00:00 2001 From: turtledreams <62231246+turtledreams@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:15:23 +0900 Subject: [PATCH 1/3] scope refactor --- Countly.js | 2 +- cypress/e2e/remaining_requests.cy.js | 47 +- modules/CountlyClass.js | 3237 +++++++++++++------------- modules/Utils.js | 13 +- 4 files changed, 1667 insertions(+), 1632 deletions(-) diff --git a/Countly.js b/Countly.js index b5fff36..954b8d6 100644 --- a/Countly.js +++ b/Countly.js @@ -174,7 +174,7 @@ if (isBrowser) { var key = parts.pop(); var appKey = parts.pop(); if (Countly.i && Countly.i[appKey]) { - Countly.i[appKey].onStorageChange(key, e.newValue); + Countly.i[appKey]._internals.onStorageChange(key, e.newValue); } }); } diff --git a/cypress/e2e/remaining_requests.cy.js b/cypress/e2e/remaining_requests.cy.js index 9c4af2d..4d69b76 100644 --- a/cypress/e2e/remaining_requests.cy.js +++ b/cypress/e2e/remaining_requests.cy.js @@ -16,41 +16,22 @@ describe("Remaining requests tests ", () => { it("Checks the requests for rr", () => { hp.haltAndClearStorage(() => { initMain(false); + Countly.begin_session(); + Countly.end_session(undefined, true); - // We will expect 4 requests: health check, begin_session, end_session, orientation - hp.interceptAndCheckRequests("POST", undefined, undefined, "?hc=*", "hc", (requestParams) => { - const params = JSON.parse(requestParams.get("hc")); - assert.isTrue(typeof params.el === "number"); - assert.isTrue(typeof params.wl === "number"); - assert.isTrue(typeof params.sc === "number"); - assert.isTrue(typeof params.em === "string"); - expect(requestParams.get("rr")).to.equal(null); - }); cy.wait(1000).then(() => { - // Create a session - Countly.begin_session(); - hp.interceptAndCheckRequests("POST", undefined, undefined, "?begin_session=*", "begin_session", (requestParams) => { - expect(requestParams.get("begin_session")).to.equal("1"); - expect(requestParams.get("rr")).to.equal("3"); - expect(requestParams.get("av")).to.equal(av); - }); - // End the session - Countly.end_session(undefined, true); - hp.interceptAndCheckRequests("POST", undefined, undefined, "?end_session=*", "end", (requestParams) => { - expect(requestParams.get("end_session")).to.equal("1"); - expect(requestParams.get("rr")).to.equal("2"); - expect(requestParams.get("av")).to.equal(av); - }); - hp.interceptAndCheckRequests("POST", undefined, undefined, undefined, "orientation", (requestParams) => { - expect(JSON.parse(requestParams.get("events"))[0].key).to.equal("[CLY]_orientation"); - expect(requestParams.get("rr")).to.equal("1"); - expect(requestParams.get("av")).to.equal(av); - }); - cy.wait(100).then(() => { - cy.fetch_local_request_queue().then((rq) => { - expect(rq.length).to.equal(0); - }); - }); + var queues = Countly._internals.getLocalQueues(); + expect(queues.eventQ.length).to.equal(0); + expect(queues.requestQ.length).to.equal(3); + expect(queues.requestQ[0]["begin_session"]).to.equal(1); + expect(queues.requestQ[1]["end_session"]).to.equal(1); + expect(JSON.parse(queues.requestQ[2]["events"])[0].key).to.equal("[CLY]_orientation"); + + var requests = Countly._internals.testingGetRequests(); + expect(requests.length).to.equal(2); + expect(requests[0].params["rr"]).to.equal(undefined); + expect(requests[1].params["rr"]).to.equal(3); + expect(requests[1].params["av"]).to.equal(av); }); }); }); diff --git a/modules/CountlyClass.js b/modules/CountlyClass.js index f121dde..56239bd 100644 --- a/modules/CountlyClass.js +++ b/modules/CountlyClass.js @@ -37,55 +37,105 @@ import { import { isBrowser, Countly } from "./Platform.js"; class CountlyClass { - #showWidgetInternal; + #consentTimer; + #self; + #global; + #sessionStarted; + #apiPath; + #readPath; + #beatInterval; + #queueSize; + #requestQueue; + #eventQueue; + #remoteConfigs; + #crashLogs; + #timedEvents; + #ignoreReferrers; + #crashSegments; + #autoExtend; + #lastBeat; + #storedDuration; + #lastView; + #lastViewTime; + #lastViewStoredDuration; + #failTimeout; + #failTimeoutAmount; + #inactivityTime; + #inactivityCounter; + #sessionUpdate; + #maxEventBatch; + #maxCrashLogs; + #useSessionCookie; + #sessionCookieTimeout; + #readyToProcess; + #hasPulse; + #offlineMode; + #lastParams; + #trackTime; + #startTime; + #lsSupport; + #firstView; + #deviceIdType; + #isScrollRegistryOpen; + #scrollRegistryTopPosition; + #trackingScrolls; + #currentViewId; + #previousViewId; + #freshUTMTags; + #sdkName; + #sdkVersion; + #shouldSendHC; + #consents; + #generatedRequests; constructor(ob) { - var self = this; - var global = !Countly.i; - var sessionStarted = false; - var apiPath = "/i"; - var readPath = "/o/sdk"; - var beatInterval = getConfig("interval", ob, configurationDefaultValues.BEAT_INTERVAL); - var queueSize = getConfig("queue_size", ob, configurationDefaultValues.QUEUE_SIZE); - var requestQueue = []; - var eventQueue = []; - var remoteConfigs = {}; - var crashLogs = []; - var timedEvents = {}; - var ignoreReferrers = getConfig("ignore_referrers", ob, []); - var crashSegments = null; - var autoExtend = true; - var lastBeat; - var storedDuration = 0; - var lastView = null; - var lastViewTime = 0; - var lastViewStoredDuration = 0; - var failTimeout = 0; - var failTimeoutAmount = getConfig("fail_timeout", ob, configurationDefaultValues.FAIL_TIMEOUT_AMOUNT); - var inactivityTime = getConfig("inactivity_time", ob, configurationDefaultValues.INACTIVITY_TIME); - var inactivityCounter = 0; - var sessionUpdate = getConfig("session_update", ob, configurationDefaultValues.SESSION_UPDATE); - var maxEventBatch = getConfig("max_events", ob, configurationDefaultValues.MAX_EVENT_BATCH); - var maxCrashLogs = getConfig("max_logs", ob, null); - var useSessionCookie = getConfig("use_session_cookie", ob, true); - var sessionCookieTimeout = getConfig("session_cookie_timeout", ob, configurationDefaultValues.SESSION_COOKIE_TIMEOUT); - var readyToProcess = true; - var hasPulse = false; - var offlineMode = getConfig("offline_mode", ob, false); - var lastParams = {}; - var trackTime = true; - var startTime = getTimestamp(); - var lsSupport = true; - var firstView = null; - var deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; - var isScrollRegistryOpen = false; - var scrollRegistryTopPosition = 0; - var trackingScrolls = false; - var currentViewId = null; // this is the global variable for tracking the current view's ID. Used in view tracking. Becomes previous view ID at the end. - var previousViewId = null; // this is the global variable for tracking the previous view's ID. Used in view tracking. First view has no previous view ID. - var freshUTMTags = null; - var sdkName = getConfig("sdk_name", ob, SDK_NAME); - var sdkVersion = getConfig("sdk_version", ob, SDK_VERSION); - var shouldSendHC = false; + this.#self = this; + this.#global = !Countly.i; + this.#sessionStarted = false; + this.#apiPath = "/i"; + this.#readPath = "/o/sdk"; + this.#beatInterval = getConfig("interval", ob, configurationDefaultValues.BEAT_INTERVAL); + this.#queueSize = getConfig("queue_size", ob, configurationDefaultValues.QUEUE_SIZE); + this.#requestQueue = []; + this.#eventQueue = []; + this.#remoteConfigs = {}; + this.#crashLogs = []; + this.#timedEvents = {}; + this.#ignoreReferrers = getConfig("ignore_referrers", ob, []); + this.#crashSegments = null; + this.#autoExtend = true; + this.#lastBeat; + this.#storedDuration = 0; + this.#lastView = null; + this.#lastViewTime = 0; + this.#lastViewStoredDuration = 0; + this.#failTimeout = 0; + this.#failTimeoutAmount = getConfig("fail_timeout", ob, configurationDefaultValues.FAIL_TIMEOUT_AMOUNT); + this.#inactivityTime = getConfig("inactivity_time", ob, configurationDefaultValues.INACTIVITY_TIME); + this.#inactivityCounter = 0; + this.#sessionUpdate = getConfig("session_update", ob, configurationDefaultValues.SESSION_UPDATE); + this.#maxEventBatch = getConfig("max_events", ob, configurationDefaultValues.MAX_EVENT_BATCH); + this.#maxCrashLogs = getConfig("max_logs", ob, null); + this.#useSessionCookie = getConfig("use_session_cookie", ob, true); + this.#sessionCookieTimeout = getConfig("session_cookie_timeout", ob, configurationDefaultValues.SESSION_COOKIE_TIMEOUT); + this.#readyToProcess = true; + this.#hasPulse = false; + this.#offlineMode = getConfig("offline_mode", ob, false); + this.#lastParams = {}; + this.#trackTime = true; + this.#startTime = getTimestamp(); + this.#lsSupport = true; + this.#firstView = null; + this.#deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; + this.#isScrollRegistryOpen = false; + this.#scrollRegistryTopPosition = 0; + this.#trackingScrolls = false; + this.#currentViewId = null; // this is the global variable for tracking the current view's ID. Used in view tracking. Becomes previous view ID at the end. + this.#previousViewId = null; // this is the global variable for tracking the previous view's ID. Used in view tracking. First view has no previous view ID. + this.#freshUTMTags = null; + this.#sdkName = getConfig("sdk_name", ob, SDK_NAME); + this.#sdkVersion = getConfig("sdk_version", ob, SDK_VERSION); + this.#shouldSendHC = false; + this.#generatedRequests = []; try { localStorage.setItem("cly_testLocal", true); @@ -93,449 +143,473 @@ constructor(ob) { localStorage.removeItem("cly_testLocal"); } catch (e) { - log(logLevelEnums.ERROR, "Local storage test failed, Halting local storage support: " + e); - lsSupport = false; + this.#log(logLevelEnums.ERROR, "Local storage test failed, Halting local storage support: " + e); + this.#lsSupport = false; } // create object to store consents - var consents = {}; + this.#consents = {}; for (var it = 0; it < Countly.features.length; it++) { - consents[Countly.features[it]] = {}; + this.#consents[Countly.features[it]] = {}; } - this.initialize = () => { - this.serialize = getConfig("serialize", ob, Countly.serialize); - this.deserialize = getConfig("deserialize", ob, Countly.deserialize); - 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, medium: true, campaign: true, term: true, content: true }); - this.ignore_prefetch = getConfig("ignore_prefetch", ob, true); - this.rcAutoOptinAb = getConfig("rc_automatic_optin_for_ab", ob, true); - this.useExplicitRcApi = getConfig("use_explicit_rc_api", ob, false); - this.debug = getConfig("debug", ob, false); - this.test_mode = getConfig("test_mode", ob, false); - 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); - this.ip_address = getConfig("ip_address", ob, null); - this.ignore_bots = getConfig("ignore_bots", ob, true); - 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.salt = getConfig("salt", ob, null); - this.hcErrorCount = getValueFromStorage(healthCheckCounterEnum.errorCount) || 0; - this.hcWarningCount = getValueFromStorage(healthCheckCounterEnum.warningCount) || 0; - this.hcStatusCode = getValueFromStorage(healthCheckCounterEnum.statusCode) || -1; - this.hcErrorMessage = getValueFromStorage(healthCheckCounterEnum.errorMessage) || ""; - - if (maxCrashLogs && !this.maxBreadcrumbCount) { - this.maxBreadcrumbCount = maxCrashLogs; - log(logLevelEnums.WARNING, "initialize, 'maxCrashLogs' is deprecated. Use 'maxBreadcrumbCount' instead!"); - } - else if (!maxCrashLogs && !this.maxBreadcrumbCount) { - this.maxBreadcrumbCount = 100; - } - - if (this.storage === "cookie") { - lsSupport = false; - } - - if (!this.rcAutoOptinAb && !this.useExplicitRcApi) { - log(logLevelEnums.WARNING, "initialize, Auto opting is disabled, switching to explicit RC API"); - this.useExplicitRcApi = true; - } - - if (!Array.isArray(ignoreReferrers)) { - ignoreReferrers = []; - } - - if (this.url === "") { - log(logLevelEnums.ERROR, "initialize, Please provide server URL"); - this.ignore_visitor = true; - } - if (getValueFromStorage("cly_ignore")) { - // opted out user - this.ignore_visitor = true; - } + this.initialize(ob); + }; - migrate(); + initialize = (ob) => { + this.serialize = getConfig("serialize", ob, Countly.serialize); + this.deserialize = getConfig("deserialize", ob, Countly.deserialize); + 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, medium: true, campaign: true, term: true, content: true }); + this.ignore_prefetch = getConfig("ignore_prefetch", ob, true); + this.rcAutoOptinAb = getConfig("rc_automatic_optin_for_ab", ob, true); + this.useExplicitRcApi = getConfig("use_explicit_rc_api", ob, false); + this.debug = getConfig("debug", ob, false); + this.test_mode = getConfig("test_mode", ob, false); + 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); + this.ip_address = getConfig("ip_address", ob, null); + this.ignore_bots = getConfig("ignore_bots", ob, true); + 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.salt = getConfig("salt", ob, null); + this.hcErrorCount = this.#getValueFromStorage(healthCheckCounterEnum.errorCount) || 0; + this.hcWarningCount = this.#getValueFromStorage(healthCheckCounterEnum.warningCount) || 0; + this.hcStatusCode = this.#getValueFromStorage(healthCheckCounterEnum.statusCode) || -1; + this.hcErrorMessage = this.#getValueFromStorage(healthCheckCounterEnum.errorMessage) || ""; + + if (this.#maxCrashLogs && !this.maxBreadcrumbCount) { + this.maxBreadcrumbCount = this.#maxCrashLogs; + this.#log(logLevelEnums.WARNING, "initialize, 'maxCrashLogs' is deprecated. Use 'maxBreadcrumbCount' instead!"); + } + else if (!this.#maxCrashLogs && !this.maxBreadcrumbCount) { + this.maxBreadcrumbCount = 100; + } - requestQueue = getValueFromStorage("cly_queue") || []; - eventQueue = getValueFromStorage("cly_event") || []; - remoteConfigs = getValueFromStorage("cly_remote_configs") || {}; + if (this.storage === "cookie") { + this.#lsSupport = false; + } - // flag that indicates that the offline mode was enabled at the end of the previous app session - var tempIdModeWasEnabled = (getValueFromStorage("cly_id") === "[CLY]_temp_id"); + if (!this.rcAutoOptinAb && !this.useExplicitRcApi) { + this.#log(logLevelEnums.WARNING, "initialize, Auto opting is disabled, switching to explicit RC API"); + this.useExplicitRcApi = true; + } - if (this.clearStoredId) { - // retrieve stored device ID and type from local storage and use it to flush existing events - if (getValueFromStorage("cly_id") && !tempIdModeWasEnabled) { - this.device_id = getValueFromStorage("cly_id"); - log(logLevelEnums.DEBUG, "initialize, temporarily using the previous device ID to flush existing events"); - deviceIdType = getValueFromStorage("cly_id_type"); - if (!deviceIdType) { - log(logLevelEnums.DEBUG, "initialize, No device ID type info from the previous session, falling back to DEVELOPER_SUPPLIED, for event flushing"); - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; - } - // don't process async queue here, just send the events (most likely async data is for the new user) - sendEventsForced(); - // set them back to their initial values - this.device_id = undefined; - deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; - } - // then clear the storage so that a new device ID is set again later - log(logLevelEnums.INFO, "initialize, Clearing the device ID storage"); - removeValueFromStorage("cly_id"); - removeValueFromStorage("cly_id_type"); - removeValueFromStorage("cly_session"); - } + if (!Array.isArray(this.#ignoreReferrers)) { + this.#ignoreReferrers = []; + } + + if (this.url === "") { + this.#log(logLevelEnums.ERROR, "initialize, Please provide server URL"); + this.ignore_visitor = true; + } + if (this.#getValueFromStorage("cly_ignore")) { + // opted out user + this.ignore_visitor = true; + } - checkIgnore(); + this.#migrate(); + + this.#requestQueue = this.#getValueFromStorage("cly_queue") || []; + this.#eventQueue = this.#getValueFromStorage("cly_event") || []; + this.#remoteConfigs = this.#getValueFromStorage("cly_remote_configs") || {}; + + // flag that indicates that the offline mode was enabled at the end of the previous app session + var tempIdModeWasEnabled = (this.#getValueFromStorage("cly_id") === "[CLY]_temp_id"); + + if (this.clearStoredId) { + // retrieve stored device ID and type from local storage and use it to flush existing events + if (this.#getValueFromStorage("cly_id") && !tempIdModeWasEnabled) { + this.device_id = this.#getValueFromStorage("cly_id"); + this.#log(logLevelEnums.DEBUG, "initialize, temporarily using the previous device ID to flush existing events"); + this.#deviceIdType = this.#getValueFromStorage("cly_id_type"); + if (!this.#deviceIdType) { + this.#log(logLevelEnums.DEBUG, "initialize, No device ID type info from the previous session, falling back to DEVELOPER_SUPPLIED, for event flushing"); + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + } + // don't process async queue here, just send the events (most likely async data is for the new user) + this.#sendEventsForced(); + // set them back to their initial values + this.device_id = undefined; + this.#deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; + } + // then clear the storage so that a new device ID is set again later + this.#log(logLevelEnums.INFO, "initialize, Clearing the device ID storage"); + this.#removeValueFromStorage("cly_id"); + this.#removeValueFromStorage("cly_id_type"); + this.#removeValueFromStorage("cly_session"); + } - if (isBrowser) { - if (window.name && window.name.indexOf("cly:") === 0) { - try { - this.passed_data = JSON.parse(window.name.replace("cly:", "")); - } - catch (ex) { - log(logLevelEnums.ERROR, "initialize, Could not parse name: " + window.name + ", error: " + ex); - } + this.#checkIgnore(); + + if (isBrowser) { + if (window.name && window.name.indexOf("cly:") === 0) { + try { + this.passed_data = JSON.parse(window.name.replace("cly:", "")); } - else if (location.hash && location.hash.indexOf("#cly:") === 0) { - try { - this.passed_data = JSON.parse(location.hash.replace("#cly:", "")); - } - catch (ex) { - log(logLevelEnums.ERROR, "initialize, Could not parse hash: " + location.hash + ", error: " + ex); - } + catch (ex) { + this.#log(logLevelEnums.ERROR, "initialize, Could not parse name: " + window.name + ", error: " + ex); + } + } + else if (location.hash && location.hash.indexOf("this.#cly:") === 0) { + try { + this.passed_data = JSON.parse(location.hash.replace("this.#cly:", "")); + } + catch (ex) { + this.#log(logLevelEnums.ERROR, "initialize, Could not parse hash: " + location.hash + ", error: " + ex); } } + } - 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 && global)) { - if (this.passed_data.token && this.passed_data.purpose) { - if (this.passed_data.token !== getValueFromStorage("cly_old_token")) { - setToken(this.passed_data.token); - setValueInStorage("cly_old_token", this.passed_data.token); - } - var strippedList = []; - // if whitelist is provided is an array - if (Array.isArray(this.heatmapWhitelist)) { - this.heatmapWhitelist.push(this.url); - strippedList = this.heatmapWhitelist.map(function (e) { - // remove trailing slashes from the entries - return stripTrailingSlash(e); - }); - } - else { - strippedList = [this.url]; - } - // if the passed url is in the whitelist proceed - if (strippedList.includes(this.passed_data.url)) { - if (this.passed_data.purpose === "heatmap") { - this.ignore_visitor = true; - showLoader(); - loadJS(this.passed_data.url + "/views/heatmap.js", hideLoader); - } + 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 && this.#global)) { + if (this.passed_data.token && this.passed_data.purpose) { + if (this.passed_data.token !== this.#getValueFromStorage("cly_old_token")) { + this.#setToken(this.passed_data.token); + this.#setValueInStorage("cly_old_token", this.passed_data.token); + } + var strippedList = []; + // if whitelist is provided is an array + if (Array.isArray(this.heatmapWhitelist)) { + this.heatmapWhitelist.push(this.url); + strippedList = this.heatmapWhitelist.map((e) => { + // remove trailing slashes from the entries + return stripTrailingSlash(e); + }); + } + else { + strippedList = [this.url]; + } + // if the passed url is in the whitelist proceed + if (strippedList.includes(this.passed_data.url)) { + if (this.passed_data.purpose === "heatmap") { + this.ignore_visitor = true; + showLoader(); + loadJS(this.passed_data.url + "/views/heatmap.js", hideLoader); } } } + } - if (this.ignore_visitor) { - log(logLevelEnums.WARNING, "initialize, ignore_visitor:[" + this.ignore_visitor + "], this user will not be tracked"); - return; - } + if (this.ignore_visitor) { + this.#log(logLevelEnums.WARNING, "initialize, ignore_visitor:[" + this.ignore_visitor + "], this user will not be tracked"); + return; + } - // init configuration is printed out here: - // key values should be printed out as is - if (sdkName === SDK_NAME && sdkVersion === SDK_VERSION) { - log(logLevelEnums.DEBUG, "initialize, SDK name:[" + sdkName + "], version:[" + sdkVersion + "]"); - } else { - log(logLevelEnums.DEBUG, "initialize, SDK name:[" + sdkName + "], version:[" + sdkVersion + "], default name:[" + SDK_NAME + "] and default version:[" + SDK_VERSION + "]"); - } - log(logLevelEnums.DEBUG, "initialize, app_key:[" + this.app_key + "], url:[" + this.url + "]"); - log(logLevelEnums.DEBUG, "initialize, device_id:[" + getConfig("device_id", ob, undefined) + "]"); - log(logLevelEnums.DEBUG, "initialize, require_consent is enabled:[" + this.require_consent + "]"); - try { - log(logLevelEnums.DEBUG, "initialize, metric override:[" + JSON.stringify(this.metrics) + "]"); - log(logLevelEnums.DEBUG, "initialize, header override:[" + JSON.stringify(this.headers) + "]"); - // empty array is truthy and so would be printed if provided - log(logLevelEnums.DEBUG, "initialize, number of onload callbacks provided:[" + this.onload.length + "]"); - // if the utm object is different to default utm object print it here - log(logLevelEnums.DEBUG, "initialize, utm tags:[" + JSON.stringify(this.utm) + "]"); - // empty array printed if non provided - if (ignoreReferrers) { - log(logLevelEnums.DEBUG, "initialize, referrers to ignore :[" + JSON.stringify(ignoreReferrers) + "]"); - } - log(logLevelEnums.DEBUG, "initialize, salt given:[" + !!this.salt + "]"); - } - catch (e) { - log(logLevelEnums.ERROR, "initialize, Could not stringify some config object values"); - } - log(logLevelEnums.DEBUG, "initialize, app_version:[" + this.app_version + "]"); + // init configuration is printed out here: + // key values should be printed out as is + if (this.#sdkName === SDK_NAME && this.#sdkVersion === SDK_VERSION) { + this.#log(logLevelEnums.DEBUG, "initialize, SDK name:[" + this.#sdkName + "], version:[" + this.#sdkVersion + "]"); + } else { + this.#log(logLevelEnums.DEBUG, "initialize, SDK name:[" + this.#sdkName + "], version:[" + this.#sdkVersion + "], default name:[" + SDK_NAME + "] and default version:[" + SDK_VERSION + "]"); + } + this.#log(logLevelEnums.DEBUG, "initialize, app_key:[" + this.app_key + "], url:[" + this.url + "]"); + this.#log(logLevelEnums.DEBUG, "initialize, device_id:[" + getConfig("device_id", ob, undefined) + "]"); + this.#log(logLevelEnums.DEBUG, "initialize, require_consent is enabled:[" + this.require_consent + "]"); + try { + this.#log(logLevelEnums.DEBUG, "initialize, metric override:[" + JSON.stringify(this.metrics) + "]"); + this.#log(logLevelEnums.DEBUG, "initialize, header override:[" + JSON.stringify(this.headers) + "]"); + // empty array is truthy and so would be printed if provided + this.#log(logLevelEnums.DEBUG, "initialize, number of onload callbacks provided:[" + this.onload.length + "]"); + // if the utm object is different to default utm object print it here + this.#log(logLevelEnums.DEBUG, "initialize, utm tags:[" + JSON.stringify(this.utm) + "]"); + // empty array printed if non provided + if (this.#ignoreReferrers) { + this.#log(logLevelEnums.DEBUG, "initialize, referrers to ignore :[" + JSON.stringify(this.#ignoreReferrers) + "]"); + } + this.#log(logLevelEnums.DEBUG, "initialize, salt given:[" + !!this.salt + "]"); + } + catch (e) { + this.#log(logLevelEnums.ERROR, "initialize, Could not stringify some config object values"); + } + this.#log(logLevelEnums.DEBUG, "initialize, app_version:[" + this.app_version + "]"); - // location info printed here - log(logLevelEnums.DEBUG, "initialize, provided location info; country_code:[" + this.country_code + "], city:[" + this.city + "], ip_address:[" + this.ip_address + "]"); + // location info printed here + this.#log(logLevelEnums.DEBUG, "initialize, provided location info; country_code:[" + this.country_code + "], city:[" + this.city + "], ip_address:[" + this.ip_address + "]"); - // print non vital values only if provided by the developer or differs from the default value - if (this.namespace !== "") { - log(logLevelEnums.DEBUG, "initialize, namespace given:[" + this.namespace + "]"); - } - if (this.clearStoredId) { - log(logLevelEnums.DEBUG, "initialize, clearStoredId flag set to:[" + this.clearStoredId + "]"); - } - if (this.ignore_prefetch) { - log(logLevelEnums.DEBUG, "initialize, ignoring pre-fetching and pre-rendering from counting as real website visits :[" + this.ignore_prefetch + "]"); - } - // if test mode is enabled warn the user - if (this.test_mode) { - log(logLevelEnums.WARNING, "initialize, test_mode:[" + this.test_mode + "], request queue won't be processed"); - } - if (this.test_mode_eq) { - log(logLevelEnums.WARNING, "initialize, test_mode_eq:[" + this.test_mode_eq + "], event queue won't be processed"); - } - // if test mode is enabled warn the user - if (this.heatmapWhitelist) { - log(logLevelEnums.DEBUG, "initialize, heatmap whitelist:[" + JSON.stringify(this.heatmapWhitelist) + "], these domains will be whitelisted"); - } - // if storage is se to something other than local storage - if (this.storage !== "default") { - log(logLevelEnums.DEBUG, "initialize, storage is set to:[" + this.storage + "]"); - } - if (this.ignore_bots) { - log(logLevelEnums.DEBUG, "initialize, ignore traffic from bots :[" + this.ignore_bots + "]"); - } - if (this.force_post) { - log(logLevelEnums.DEBUG, "initialize, forced post method for all requests:[" + this.force_post + "]"); - } - if (this.remote_config) { - log(logLevelEnums.DEBUG, "initialize, remote_config callback provided:[" + !!this.remote_config + "]"); - } - if (typeof this.rcAutoOptinAb === "boolean") { - log(logLevelEnums.DEBUG, "initialize, automatic RC optin is enabled:[" + this.rcAutoOptinAb + "]"); - } - if (!this.useExplicitRcApi) { - log(logLevelEnums.WARNING, "initialize, will use legacy RC API. Consider enabling new API during init with use_explicit_rc_api flag"); - } - if (this.track_domains) { - log(logLevelEnums.DEBUG, "initialize, tracking domain info:[" + this.track_domains + "]"); - } - if (this.enableOrientationTracking) { - log(logLevelEnums.DEBUG, "initialize, enableOrientationTracking:[" + this.enableOrientationTracking + "]"); - } - if (!useSessionCookie) { - log(logLevelEnums.WARNING, "initialize, use_session_cookie is enabled:[" + useSessionCookie + "]"); - } - if (offlineMode) { - log(logLevelEnums.DEBUG, "initialize, offline_mode:[" + offlineMode + "], user info won't be send to the servers"); - } - if (remoteConfigs) { - log(logLevelEnums.DEBUG, "initialize, stored remote configs:[" + JSON.stringify(remoteConfigs) + "]"); - } - // functions, if provided, would be printed as true without revealing their content - log(logLevelEnums.DEBUG, "initialize, 'getViewName' callback override provided:[" + (this.getViewName !== Countly.getViewName) + "]"); - log(logLevelEnums.DEBUG, "initialize, 'getSearchQuery' callback override provided:[" + (this.getSearchQuery !== Countly.getSearchQuery) + "]"); + // print non vital values only if provided by the developer or differs from the default value + if (this.namespace !== "") { + this.#log(logLevelEnums.DEBUG, "initialize, namespace given:[" + this.namespace + "]"); + } + if (this.clearStoredId) { + this.#log(logLevelEnums.DEBUG, "initialize, clearStoredId flag set to:[" + this.clearStoredId + "]"); + } + if (this.ignore_prefetch) { + this.#log(logLevelEnums.DEBUG, "initialize, ignoring pre-fetching and pre-rendering from counting as real website visits :[" + this.ignore_prefetch + "]"); + } + // if test mode is enabled warn the user + if (this.test_mode) { + this.#log(logLevelEnums.WARNING, "initialize, test_mode:[" + this.test_mode + "], request queue won't be processed"); + } + if (this.test_mode_eq) { + this.#log(logLevelEnums.WARNING, "initialize, test_mode_eq:[" + this.test_mode_eq + "], event queue won't be processed"); + } + // if test mode is enabled warn the user + if (this.heatmapWhitelist) { + this.#log(logLevelEnums.DEBUG, "initialize, heatmap whitelist:[" + JSON.stringify(this.heatmapWhitelist) + "], these domains will be whitelisted"); + } + // if storage is se to something other than local storage + if (this.storage !== "default") { + this.#log(logLevelEnums.DEBUG, "initialize, storage is set to:[" + this.storage + "]"); + } + if (this.ignore_bots) { + this.#log(logLevelEnums.DEBUG, "initialize, ignore traffic from bots :[" + this.ignore_bots + "]"); + } + if (this.force_post) { + this.#log(logLevelEnums.DEBUG, "initialize, forced post method for all requests:[" + this.force_post + "]"); + } + if (this.remote_config) { + this.#log(logLevelEnums.DEBUG, "initialize, remote_config callback provided:[" + !!this.remote_config + "]"); + } + if (typeof this.rcAutoOptinAb === "boolean") { + this.#log(logLevelEnums.DEBUG, "initialize, automatic RC optin is enabled:[" + this.rcAutoOptinAb + "]"); + } + if (!this.useExplicitRcApi) { + this.#log(logLevelEnums.WARNING, "initialize, will use legacy RC API. Consider enabling new API during init with use_explicit_rc_api flag"); + } + if (this.track_domains) { + this.#log(logLevelEnums.DEBUG, "initialize, tracking domain info:[" + this.track_domains + "]"); + } + if (this.enableOrientationTracking) { + this.#log(logLevelEnums.DEBUG, "initialize, enableOrientationTracking:[" + this.enableOrientationTracking + "]"); + } + if (!this.#useSessionCookie) { + this.#log(logLevelEnums.WARNING, "initialize, use_session_cookie is enabled:[" + this.#useSessionCookie + "]"); + } + if (this.#offlineMode) { + this.#log(logLevelEnums.DEBUG, "initialize, offline_mode:[" + this.#offlineMode + "], user info won't be send to the servers"); + } + if (this.#remoteConfigs) { + this.#log(logLevelEnums.DEBUG, "initialize, stored remote configs:[" + JSON.stringify(this.#remoteConfigs) + "]"); + } + // functions, if provided, would be printed as true without revealing their content + this.#log(logLevelEnums.DEBUG, "initialize, 'getViewName' callback override provided:[" + (this.getViewName !== Countly.getViewName) + "]"); + this.#log(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) { - log(logLevelEnums.DEBUG, "initialize, maxKeyLength set to:[" + this.maxKeyLength + "] characters"); - } - if (this.maxValueSize !== configurationDefaultValues.MAX_VALUE_SIZE) { - log(logLevelEnums.DEBUG, "initialize, maxValueSize set to:[" + this.maxValueSize + "] characters"); - } - if (this.maxSegmentationValues !== configurationDefaultValues.MAX_SEGMENTATION_VALUES) { - log(logLevelEnums.DEBUG, "initialize, maxSegmentationValues set to:[" + this.maxSegmentationValues + "] key/value pairs"); - } - if (this.maxBreadcrumbCount !== configurationDefaultValues.MAX_BREADCRUMB_COUNT) { - log(logLevelEnums.DEBUG, "initialize, maxBreadcrumbCount for custom logs set to:[" + this.maxBreadcrumbCount + "] entries"); - } - if (this.maxStackTraceLinesPerThread !== configurationDefaultValues.MAX_STACKTRACE_LINES_PER_THREAD) { - log(logLevelEnums.DEBUG, "initialize, maxStackTraceLinesPerThread set to:[" + this.maxStackTraceLinesPerThread + "] lines"); - } - if (this.maxStackTraceLineLength !== configurationDefaultValues.MAX_STACKTRACE_LINE_LENGTH) { - log(logLevelEnums.DEBUG, "initialize, maxStackTraceLineLength set to:[" + this.maxStackTraceLineLength + "] characters"); - } - if (beatInterval !== configurationDefaultValues.BEAT_INTERVAL) { - log(logLevelEnums.DEBUG, "initialize, interval for heartbeats set to:[" + beatInterval + "] milliseconds"); - } - if (queueSize !== configurationDefaultValues.QUEUE_SIZE) { - log(logLevelEnums.DEBUG, "initialize, queue_size set to:[" + queueSize + "] items max"); - } - if (failTimeoutAmount !== configurationDefaultValues.FAIL_TIMEOUT_AMOUNT) { - log(logLevelEnums.DEBUG, "initialize, fail_timeout set to:[" + failTimeoutAmount + "] seconds of wait time after a failed connection to server"); - } - if (inactivityTime !== configurationDefaultValues.INACTIVITY_TIME) { - log(logLevelEnums.DEBUG, "initialize, inactivity_time set to:[" + inactivityTime + "] minutes to consider a user as inactive after no observable action"); - } - if (sessionUpdate !== configurationDefaultValues.SESSION_UPDATE) { - log(logLevelEnums.DEBUG, "initialize, session_update set to:[" + sessionUpdate + "] seconds to check if extending a session is needed while the user is active"); - } - if (maxEventBatch !== configurationDefaultValues.MAX_EVENT_BATCH) { - log(logLevelEnums.DEBUG, "initialize, max_events set to:[" + maxEventBatch + "] events to send in one batch"); - } - if (maxCrashLogs) { - log(logLevelEnums.WARNING, "initialize, max_logs set to:[" + maxCrashLogs + "] breadcrumbs to store for crash logs max, deprecated "); - } - if (sessionCookieTimeout !== configurationDefaultValues.SESSION_COOKIE_TIMEOUT) { - log(logLevelEnums.DEBUG, "initialize, session_cookie_timeout set to:[" + sessionCookieTimeout + "] minutes to expire a cookies session"); - } + // limits are printed here if they were modified + if (this.maxKeyLength !== configurationDefaultValues.MAX_KEY_LENGTH) { + this.#log(logLevelEnums.DEBUG, "initialize, maxKeyLength set to:[" + this.maxKeyLength + "] characters"); + } + if (this.maxValueSize !== configurationDefaultValues.MAX_VALUE_SIZE) { + this.#log(logLevelEnums.DEBUG, "initialize, maxValueSize set to:[" + this.maxValueSize + "] characters"); + } + if (this.maxSegmentationValues !== configurationDefaultValues.MAX_SEGMENTATION_VALUES) { + this.#log(logLevelEnums.DEBUG, "initialize, maxSegmentationValues set to:[" + this.maxSegmentationValues + "] key/value pairs"); + } + if (this.maxBreadcrumbCount !== configurationDefaultValues.MAX_BREADCRUMB_COUNT) { + this.#log(logLevelEnums.DEBUG, "initialize, maxBreadcrumbCount for custom logs set to:[" + this.maxBreadcrumbCount + "] entries"); + } + if (this.maxStackTraceLinesPerThread !== configurationDefaultValues.MAX_STACKTRACE_LINES_PER_THREAD) { + this.#log(logLevelEnums.DEBUG, "initialize, maxStackTraceLinesPerThread set to:[" + this.maxStackTraceLinesPerThread + "] lines"); + } + if (this.maxStackTraceLineLength !== configurationDefaultValues.MAX_STACKTRACE_LINE_LENGTH) { + this.#log(logLevelEnums.DEBUG, "initialize, maxStackTraceLineLength set to:[" + this.maxStackTraceLineLength + "] characters"); + } + if (this.#beatInterval !== configurationDefaultValues.BEAT_INTERVAL) { + this.#log(logLevelEnums.DEBUG, "initialize, interval for heartbeats set to:[" + this.#beatInterval + "] milliseconds"); + } + if (this.#queueSize !== configurationDefaultValues.QUEUE_SIZE) { + this.#log(logLevelEnums.DEBUG, "initialize, queue_size set to:[" + this.#queueSize + "] items max"); + } + if (this.#failTimeoutAmount !== configurationDefaultValues.FAIL_TIMEOUT_AMOUNT) { + this.#log(logLevelEnums.DEBUG, "initialize, fail_timeout set to:[" + this.#failTimeoutAmount + "] seconds of wait time after a failed connection to server"); + } + if (this.#inactivityTime !== configurationDefaultValues.INACTIVITY_TIME) { + this.#log(logLevelEnums.DEBUG, "initialize, inactivity_time set to:[" + this.#inactivityTime + "] minutes to consider a user as inactive after no observable action"); + } + if (this.#sessionUpdate !== configurationDefaultValues.SESSION_UPDATE) { + this.#log(logLevelEnums.DEBUG, "initialize, session_update set to:[" + this.#sessionUpdate + "] seconds to check if extending a session is needed while the user is active"); + } + if (this.#maxEventBatch !== configurationDefaultValues.MAX_EVENT_BATCH) { + this.#log(logLevelEnums.DEBUG, "initialize, max_events set to:[" + this.#maxEventBatch + "] events to send in one batch"); + } + if (this.#maxCrashLogs) { + this.#log(logLevelEnums.WARNING, "initialize, max_logs set to:[" + this.#maxCrashLogs + "] breadcrumbs to store for crash logs max, deprecated "); + } + if (this.#sessionCookieTimeout !== configurationDefaultValues.SESSION_COOKIE_TIMEOUT) { + this.#log(logLevelEnums.DEBUG, "initialize, session_cookie_timeout set to:[" + this.#sessionCookieTimeout + "] minutes to expire a cookies session"); + } - var deviceIdParamValue = null; - var searchQuery = this.getSearchQuery(); - var hasUTM = false; - var utms = {}; - if (searchQuery) { - // remove the '?' character from the beginning if it exists - if (searchQuery.indexOf('?') === 0) { - searchQuery = searchQuery.substring(1); - }; - var parts = searchQuery.split("&"); - for (var i = 0; i < parts.length; i++) { - var nv = parts[i].split("="); - if (nv[0] === "cly_id") { - setValueInStorage("cly_cmp_id", nv[1]); - } - else if (nv[0] === "cly_uid") { - setValueInStorage("cly_cmp_uid", nv[1]); - } - else if (nv[0] === "cly_device_id") { - deviceIdParamValue = nv[1]; - } - else if ((nv[0] + "").indexOf("utm_") === 0 && this.utm[nv[0].replace("utm_", "")]) { - utms[nv[0].replace("utm_", "")] = nv[1]; - hasUTM = true; - } + var deviceIdParamValue = null; + var searchQuery = this.getSearchQuery(); + var hasUTM = false; + var utms = {}; + if (searchQuery) { + // remove the '?' character from the beginning if it exists + if (searchQuery.indexOf('?') === 0) { + searchQuery = searchQuery.substring(1); + }; + var parts = searchQuery.split("&"); + for (var i = 0; i < parts.length; i++) { + var nv = parts[i].split("="); + if (nv[0] === "cly_id") { + this.#setValueInStorage("cly_cmp_id", nv[1]); + } + else if (nv[0] === "cly_uid") { + this.#setValueInStorage("cly_cmp_uid", nv[1]); + } + else if (nv[0] === "cly_device_id") { + deviceIdParamValue = nv[1]; + } + else if ((nv[0] + "").indexOf("utm_") === 0 && this.utm[nv[0].replace("utm_", "")]) { + utms[nv[0].replace("utm_", "")] = nv[1]; + hasUTM = true; } } + } - var developerSetDeviceId = getConfig("device_id", ob, undefined); - if (typeof developerSetDeviceId === "number") { // device ID should always be string - developerSetDeviceId = developerSetDeviceId.toString(); - } + var developerSetDeviceId = getConfig("device_id", ob, undefined); + if (typeof developerSetDeviceId === "number") { // device ID should always be string + developerSetDeviceId = developerSetDeviceId.toString(); + } - // check if there wqs stored ID - if (getValueFromStorage("cly_id") && !tempIdModeWasEnabled) { - this.device_id = getValueFromStorage("cly_id"); - log(logLevelEnums.INFO, "initialize, Set the stored device ID"); - deviceIdType = getValueFromStorage("cly_id_type"); - if (!deviceIdType) { - log(logLevelEnums.INFO, "initialize, No device ID type info from the previous session, falling back to DEVELOPER_SUPPLIED"); - // there is a device ID saved but there is no device ID information saved - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + // check if there wqs stored ID + if (this.#getValueFromStorage("cly_id") && !tempIdModeWasEnabled) { + this.device_id = this.#getValueFromStorage("cly_id"); + this.#log(logLevelEnums.INFO, "initialize, Set the stored device ID"); + this.#deviceIdType = this.#getValueFromStorage("cly_id_type"); + if (!this.#deviceIdType) { + this.#log(logLevelEnums.INFO, "initialize, No device ID type info from the previous session, falling back to DEVELOPER_SUPPLIED"); + // there is a device ID saved but there is no device ID information saved + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + } + this.#offlineMode = false; + } + // if not check if device ID was provided with URL + else if (deviceIdParamValue !== null) { + this.#log(logLevelEnums.INFO, "initialize, Device ID set by URL"); + this.device_id = deviceIdParamValue; + this.#deviceIdType = DeviceIdTypeInternalEnums.URL_PROVIDED; + this.#offlineMode = false; + } + // if not check if developer provided any ID + else if (developerSetDeviceId) { + this.#log(logLevelEnums.INFO, "initialize, Device ID set by developer"); + this.device_id = developerSetDeviceId; + if (ob && Object.keys(ob).length) { + if (ob.device_id !== undefined) { + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; } - offlineMode = false; } - // if not check if device ID was provided with URL - else if (deviceIdParamValue !== null) { - log(logLevelEnums.INFO, "initialize, Device ID set by URL"); - this.device_id = deviceIdParamValue; - deviceIdType = DeviceIdTypeInternalEnums.URL_PROVIDED; - offlineMode = false; + else if (Countly.device_id !== undefined) { + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; } - // if not check if developer provided any ID - else if (developerSetDeviceId) { - log(logLevelEnums.INFO, "initialize, Device ID set by developer"); - this.device_id = developerSetDeviceId; - if (ob && Object.keys(ob).length) { - if (ob.device_id !== undefined) { - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; - } - } - else if (Countly.device_id !== undefined) { - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; - } - offlineMode = false; + this.#offlineMode = false; + } + // if not check if offline mode is on + else if (this.#offlineMode || tempIdModeWasEnabled) { + this.device_id = "[CLY]_temp_id"; + this.#deviceIdType = DeviceIdTypeInternalEnums.TEMPORARY_ID; + if (this.#offlineMode && tempIdModeWasEnabled) { + this.#log(logLevelEnums.INFO, "initialize, Temp ID set, continuing offline mode from previous app session"); } - // if not check if offline mode is on - else if (offlineMode || tempIdModeWasEnabled) { - this.device_id = "[CLY]_temp_id"; - deviceIdType = DeviceIdTypeInternalEnums.TEMPORARY_ID; - if (offlineMode && tempIdModeWasEnabled) { - log(logLevelEnums.INFO, "initialize, Temp ID set, continuing offline mode from previous app session"); - } - else if (offlineMode && !tempIdModeWasEnabled) { - // this if we get here then it means either first init we enter offline mode or we cleared the device ID during the init and still user entered the offline mode - log(logLevelEnums.INFO, "initialize, Temp ID set, entering offline mode"); - } - else { - // no device ID was provided, no offline mode flag was provided, in the previous app session we entered offline mode and now we carry on - offlineMode = true; - log(logLevelEnums.INFO, "initialize, Temp ID set, enabling offline mode"); - } + else if (this.#offlineMode && !tempIdModeWasEnabled) { + // this if we get here then it means either first init we enter offline mode or we cleared the device ID during the init and still user entered the offline mode + this.#log(logLevelEnums.INFO, "initialize, Temp ID set, entering offline mode"); } - // if all fails generate an ID else { - log(logLevelEnums.INFO, "initialize, Generating the device ID"); - this.device_id = getConfig("device_id", ob, getStoredIdOrGenerateId()); - if (ob && Object.keys(ob).length) { - if (ob.device_id !== undefined) { - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; - } - } - else if (Countly.device_id !== undefined) { - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + // no device ID was provided, no offline mode flag was provided, in the previous app session we entered offline mode and now we carry on + this.#offlineMode = true; + this.#log(logLevelEnums.INFO, "initialize, Temp ID set, enabling offline mode"); + } + } + // if all fails generate an ID + else { + this.#log(logLevelEnums.INFO, "initialize, Generating the device ID"); + this.device_id = getConfig("device_id", ob, this.#getStoredIdOrGenerateId()); + if (ob && Object.keys(ob).length) { + if (ob.device_id !== undefined) { + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; } } + else if (Countly.device_id !== undefined) { + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + } + } - // Store the device ID and device ID type - setValueInStorage("cly_id", this.device_id); - setValueInStorage("cly_id_type", deviceIdType); + // Store the device ID and device ID type + this.#setValueInStorage("cly_id", this.device_id); + this.#setValueInStorage("cly_id_type", this.#deviceIdType); - // as we have assigned the device ID now we can save the tags - if (hasUTM) { - freshUTMTags = {}; - for (var tag in this.utm) { // this.utm is a filter for allowed tags - if (utms[tag]) { // utms is the tags that were passed in the URL - this.userData.set("utm_" + tag, utms[tag]); - freshUTMTags[tag] = utms[tag]; - } - else { - this.userData.unset("utm_" + tag); - } + // as we have assigned the device ID now we can save the tags + if (hasUTM) { + this.#freshUTMTags = {}; + for (var tag in this.utm) { // this.utm is a filter for allowed tags + if (utms[tag]) { // utms is the tags that were passed in the URL + this.userData.set("utm_" + tag, utms[tag]); + this.#freshUTMTags[tag] = utms[tag]; + } + else { + this.userData.unset("utm_" + tag); } - this.userData.save(); } + this.userData.save(); + } - notifyLoaders(); + this.#notifyLoaders(); - setTimeout(() => { - if (!Countly.noHeartBeat) { - heartBeat(); - } else { - log(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 - HealthCheck.sendInstantHCRequest(); - log(logLevelEnums.INFO, "initialize, Countly initialized"); - }; + setTimeout(() => { + if (!Countly.noHeartBeat) { + this.#heartBeat(); + } else { + this.#log(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 + this.#HealthCheck.sendInstantHCRequest(); + this.#log(logLevelEnums.INFO, "initialize, Countly initialized"); + }; + + #updateConsent = () => { + if (this.#consentTimer) { + // delay syncing consents + clearTimeout(this.#consentTimer); + this.#consentTimer = null; + } + this.#consentTimer = setTimeout(() => { + var consentMessage = {}; + for (var i = 0; i < Countly.features.length; i++) { + if (this.#consents[Countly.features[i]].optin === true) { + consentMessage[Countly.features[i]] = true; + } + else { + consentMessage[Countly.features[i]] = false; + } + } + this.#toRequestQueue({ consent: JSON.stringify(consentMessage) }); + this.#log(logLevelEnums.DEBUG, "Consent update request has been sent to the queue."); + }, 1000); + }; /** * WARNING!!! @@ -544,53 +618,54 @@ constructor(ob) { * Resets Countly to its initial state (used mainly to wipe the queues in memory). * Calling this will result in a loss of data */ - this.halt = function () { - log(logLevelEnums.WARNING, "halt, Resetting Countly"); + halt = () => { + this.#log(logLevelEnums.WARNING, "halt, Resetting Countly"); Countly.i = undefined; Countly.q = []; Countly.noHeartBeat = undefined; - global = !Countly.i; - sessionStarted = false; - apiPath = "/i"; - readPath = "/o/sdk"; - beatInterval = 500; - queueSize = 1000; - requestQueue = []; - eventQueue = []; - remoteConfigs = {}; - crashLogs = []; - timedEvents = {}; - ignoreReferrers = []; - crashSegments = null; - autoExtend = true; - storedDuration = 0; - lastView = null; - lastViewTime = 0; - lastViewStoredDuration = 0; - failTimeout = 0; - failTimeoutAmount = 60; - inactivityTime = 20; - inactivityCounter = 0; - sessionUpdate = 60; - maxEventBatch = 100; - maxCrashLogs = null; - useSessionCookie = true; - sessionCookieTimeout = 30; - readyToProcess = true; - hasPulse = false; - offlineMode = false; - lastParams = {}; - trackTime = true; - startTime = getTimestamp(); - lsSupport = true; - firstView = null; - deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; - isScrollRegistryOpen = false; - scrollRegistryTopPosition = 0; - trackingScrolls = false; - currentViewId = null; - previousViewId = null; - freshUTMTags = null; + this.#global = !Countly.i; + this.#sessionStarted = false; + this.#apiPath = "/i"; + this.#readPath = "/o/sdk"; + this.#beatInterval = 500; + this.#queueSize = 1000; + this.#requestQueue = []; + this.#eventQueue = []; + this.#remoteConfigs = {}; + this.#crashLogs = []; + this.#timedEvents = {}; + this.#ignoreReferrers = []; + this.#crashSegments = null; + this.#autoExtend = true; + this.#storedDuration = 0; + this.#lastView = null; + this.#lastViewTime = 0; + this.#lastViewStoredDuration = 0; + this.#failTimeout = 0; + this.#failTimeoutAmount = 60; + this.#inactivityTime = 20; + this.#inactivityCounter = 0; + this.#sessionUpdate = 60; + this.#maxEventBatch = 100; + this.#maxCrashLogs = null; + this.#useSessionCookie = true; + this.#sessionCookieTimeout = 30; + this.#readyToProcess = true; + this.#hasPulse = false; + this.#offlineMode = false; + this.#lastParams = {}; + this.#trackTime = true; + this.#startTime = getTimestamp(); + this.#lsSupport = true; + this.#firstView = null; + this.#deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; + this.#isScrollRegistryOpen = false; + this.#scrollRegistryTopPosition = 0; + this.#trackingScrolls = false; + this.#currentViewId = null; + this.#previousViewId = null; + this.#freshUTMTags = null; + this.#generatedRequests = []; try { localStorage.setItem("cly_testLocal", true); @@ -598,50 +673,50 @@ constructor(ob) { localStorage.removeItem("cly_testLocal"); } catch (e) { - log(logLevelEnums.ERROR, "halt, Local storage test failed, will fallback to cookies"); - lsSupport = false; + this.#log(logLevelEnums.ERROR, "halt, Local storage test failed, will fallback to cookies"); + this.#lsSupport = false; } Countly.features = [featureEnums.SESSIONS, featureEnums.EVENTS, featureEnums.VIEWS, featureEnums.SCROLLS, featureEnums.CLICKS, featureEnums.FORMS, featureEnums.CRASHES, featureEnums.ATTRIBUTION, featureEnums.USERS, featureEnums.STAR_RATING, featureEnums.LOCATION, featureEnums.APM, featureEnums.FEEDBACK, featureEnums.REMOTE_CONFIG]; // CONSENTS - consents = {}; + this.#consents = {}; for (var a = 0; a < Countly.features.length; a++) { - consents[Countly.features[a]] = {}; - } - - self.app_key = undefined; - self.device_id = undefined; - self.onload = undefined; - self.utm = undefined; - self.ignore_prefetch = undefined; - self.debug = undefined; - self.test_mode = undefined; - self.test_mode_eq = undefined; - self.metrics = undefined; - self.headers = undefined; - self.url = undefined; - self.app_version = undefined; - self.country_code = undefined; - self.city = undefined; - self.ip_address = undefined; - self.ignore_bots = undefined; - self.force_post = undefined; - self.rcAutoOptinAb = undefined; - self.useExplicitRcApi = undefined; - self.remote_config = undefined; - self.ignore_visitor = undefined; - self.require_consent = undefined; - self.track_domains = undefined; - self.storage = undefined; - self.enableOrientationTracking = undefined; - self.salt = undefined; - self.maxKeyLength = undefined; - self.maxValueSize = undefined; - self.maxSegmentationValues = undefined; - self.maxBreadcrumbCount = undefined; - self.maxStackTraceLinesPerThread = undefined; - self.maxStackTraceLineLength = undefined; + this.#consents[Countly.features[a]] = {}; + } + + this.app_key = undefined; + this.device_id = undefined; + this.onload = undefined; + this.utm = undefined; + this.ignore_prefetch = undefined; + this.debug = undefined; + this.test_mode = undefined; + this.test_mode_eq = undefined; + this.metrics = undefined; + this.headers = undefined; + this.url = undefined; + this.app_version = undefined; + this.country_code = undefined; + this.city = undefined; + this.ip_address = undefined; + this.ignore_bots = undefined; + this.force_post = undefined; + this.rcAutoOptinAb = undefined; + this.useExplicitRcApi = undefined; + this.remote_config = undefined; + this.ignore_visitor = undefined; + this.require_consent = 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; }; /** @@ -659,28 +734,28 @@ constructor(ob) { * //or call Countly.add_consent("interaction") to allow "scrolls","clicks","forms" * //or call Countly.add_consent("crashes") to allow some separate feature */ - this.group_features = function (features) { - log(logLevelEnums.INFO, "group_features, Grouping features"); + group_features = (features) => { + this.#log(logLevelEnums.INFO, "group_features, Grouping features"); if (features) { for (var i in features) { - if (!consents[i]) { + if (!this.#consents[i]) { if (typeof features[i] === "string") { - consents[i] = { features: [features[i]] }; + this.#consents[i] = { features: [features[i]] }; } else if (features[i] && Array.isArray(features[i]) && features[i].length) { - consents[i] = { features: features[i] }; + this.#consents[i] = { features: features[i] }; } else { - log(logLevelEnums.ERROR, "group_features, Incorrect feature list for [" + i + "] value: [" + features[i] + "]"); + this.#log(logLevelEnums.ERROR, "group_features, Incorrect feature list for [" + i + "] value: [" + features[i] + "]"); } } else { - log(logLevelEnums.WARNING, "group_features, Feature name [" + i + "] is already reserved"); + this.#log(logLevelEnums.WARNING, "group_features, Feature name [" + i + "] is already reserved"); } } } else { - log(logLevelEnums.ERROR, "group_features, Incorrect features:[" + features + "]"); + this.#log(logLevelEnums.ERROR, "group_features, Incorrect features:[" + features + "]"); } }; @@ -689,17 +764,17 @@ constructor(ob) { * @param {string} feature - name of the feature, possible values, "sessions","events","views","scrolls","clicks","forms","crashes","attribution","users" or custom provided through {@link Countly.group_features} * @returns {Boolean} true if consent was given for the feature or false if it was not */ - this.check_consent = function (feature) { - log(logLevelEnums.INFO, "check_consent, Checking if consent is given for specific feature:[" + feature + "]"); + check_consent = (feature) => { + this.#log(logLevelEnums.INFO, "check_consent, Checking if consent is given for specific feature:[" + feature + "]"); if (!this.require_consent) { // we don't need to have specific consents - log(logLevelEnums.INFO, "check_consent, require_consent is off, no consent is necessary"); + this.#log(logLevelEnums.INFO, "check_consent, require_consent is off, no consent is necessary"); return true; } - if (consents[feature]) { - return !!(consents[feature] && consents[feature].optin); + if (this.#consents[feature]) { + return !!(this.#consents[feature] && this.#consents[feature].optin); } - log(logLevelEnums.ERROR, "check_consent, No feature available for [" + feature + "]"); + this.#log(logLevelEnums.ERROR, "check_consent, No feature available for [" + feature + "]"); return false; }; @@ -707,19 +782,19 @@ constructor(ob) { * Check and return the current device id type * @returns {number} a number that indicates the device id type */ - this.get_device_id_type = function () { - log(logLevelEnums.INFO, "check_device_id_type, Retrieving the current device id type.[" + deviceIdType + "]"); + get_device_id_type = () => { + this.#log(logLevelEnums.INFO, "check_device_id_type, Retrieving the current device id type.[" + this.#deviceIdType + "]"); var type; - switch (deviceIdType) { + switch (this.#deviceIdType) { case DeviceIdTypeInternalEnums.SDK_GENERATED: - type = self.DeviceIdType.SDK_GENERATED; + type = this.DeviceIdType.SDK_GENERATED; break; case DeviceIdTypeInternalEnums.URL_PROVIDED: case DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED: - type = self.DeviceIdType.DEVELOPER_SUPPLIED; + type = this.DeviceIdType.DEVELOPER_SUPPLIED; break; case DeviceIdTypeInternalEnums.TEMPORARY_ID: - type = self.DeviceIdType.TEMPORARY_ID; + type = this.DeviceIdType.TEMPORARY_ID; break; default: type = -1; @@ -732,28 +807,28 @@ constructor(ob) { * Gets the current device id (of the CountlyClass instance) * @returns {string} device id */ - this.get_device_id = function () { - log(logLevelEnums.INFO, "get_device_id, Retrieving the device id: [" + self.device_id + "]"); - return self.device_id; + get_device_id = () => { + this.#log(logLevelEnums.INFO, "get_device_id, Retrieving the device id: [" + this.device_id + "]"); + return this.device_id; }; /** * Check if any consent is given, for some cases, when crucial parts are like device_id are needed for any request * @returns {Boolean} true is has any consent given, false if no consents given */ - this.check_any_consent = function () { - log(logLevelEnums.INFO, "check_any_consent, Checking if any consent is given"); + check_any_consent = () => { + this.#log(logLevelEnums.INFO, "check_any_consent, Checking if any consent is given"); if (!this.require_consent) { // we don't need to have consents - log(logLevelEnums.INFO, "check_any_consent, require_consent is off, no consent is necessary"); + this.#log(logLevelEnums.INFO, "check_any_consent, require_consent is off, no consent is necessary"); return true; } - for (var i in consents) { - if (consents[i] && consents[i].optin) { + for (var i in this.#consents) { + if (this.#consents[i] && this.#consents[i].optin) { return true; } } - log(logLevelEnums.INFO, "check_any_consent, No consents given"); + this.#log(logLevelEnums.INFO, "check_any_consent, No consents given"); return false; }; @@ -761,40 +836,40 @@ constructor(ob) { * Add consent for specific feature, meaning, user allowed to track that data (either core feature of from custom feature group) * @param {string|array} feature - name of the feature, possible values, "sessions","events","views","scrolls","clicks","forms","crashes","attribution","users", etc or custom provided through {@link Countly.group_features} */ - this.add_consent = function (feature) { - log(logLevelEnums.INFO, "add_consent, Adding consent for [" + feature + "]"); + add_consent = (feature) => { + this.#log(logLevelEnums.INFO, "add_consent, Adding consent for [" + feature + "]"); if (Array.isArray(feature)) { for (var i = 0; i < feature.length; i++) { this.add_consent(feature[i]); } } - else if (consents[feature]) { - if (consents[feature].features) { - consents[feature].optin = true; + else if (this.#consents[feature]) { + if (this.#consents[feature].features) { + this.#consents[feature].optin = true; // this is added group, let's iterate through sub features - this.add_consent(consents[feature].features); + this.add_consent(this.#consents[feature].features); } else { // this is core feature - if (consents[feature].optin !== true) { - consents[feature].optin = true; - updateConsent(); - setTimeout(function () { - if (feature === featureEnums.SESSIONS && lastParams.begin_session) { - self.begin_session.apply(self, lastParams.begin_session); - lastParams.begin_session = null; + if (this.#consents[feature].optin !== true) { + this.#consents[feature].optin = true; + this.#updateConsent(); + setTimeout(() => { + if (feature === featureEnums.SESSIONS && this.#lastParams.begin_session) { + this.begin_session.apply(self, this.#lastParams.begin_session); + this.#lastParams.begin_session = null; } - else if (feature === featureEnums.VIEWS && lastParams.track_pageview) { - lastView = null; - self.track_pageview.apply(self, lastParams.track_pageview); - lastParams.track_pageview = null; + else if (feature === featureEnums.VIEWS && this.#lastParams.track_pageview) { + this.#lastView = null; + this.track_pageview.apply(self, this.#lastParams.track_pageview); + this.#lastParams.track_pageview = null; } }, 1); } } } else { - log(logLevelEnums.ERROR, "add_consent, No feature available for [" + feature + "]"); + this.#log(logLevelEnums.ERROR, "add_consent, No feature available for [" + feature + "]"); } }; @@ -802,8 +877,8 @@ constructor(ob) { * Remove consent for specific feature, meaning, user opted out to track that data (either core feature of from custom feature group) * @param {string|array} feature - name of the feature, possible values, "sessions","events","views","scrolls","clicks","forms","crashes","attribution","users", etc or custom provided through {@link Countly.group_features} */ - this.remove_consent = function (feature) { - log(logLevelEnums.INFO, "remove_consent, Removing consent for [" + feature + "]"); + remove_consent = (feature) => { + this.#log(logLevelEnums.INFO, "remove_consent, Removing consent for [" + feature + "]"); this.remove_consent_internal(feature, true); }; @@ -812,7 +887,7 @@ constructor(ob) { * @param {string|array} feature - name of the feature, possible values, "sessions","events","views","scrolls","clicks","forms","crashes","attribution","users", etc or custom provided through {@link Countly.group_features} * @param {Boolean} enforceConsentUpdate - regulates if a request will be sent to the server or not. If true, removing consents will send a request to the server and if false, consents will be removed without a request */ - this.remove_consent_internal = function (feature, enforceConsentUpdate) { + remove_consent_internal = (feature, enforceConsentUpdate) => { // if true updateConsent will execute when possible enforceConsentUpdate = enforceConsentUpdate || false; if (Array.isArray(feature)) { @@ -820,97 +895,75 @@ constructor(ob) { this.remove_consent_internal(feature[i], enforceConsentUpdate); } } - else if (consents[feature]) { - if (consents[feature].features) { + else if (this.#consents[feature]) { + if (this.#consents[feature].features) { // this is added group, let's iterate through sub features - this.remove_consent_internal(consents[feature].features, enforceConsentUpdate); + this.remove_consent_internal(this.#consents[feature].features, enforceConsentUpdate); } else { - consents[feature].optin = false; + this.#consents[feature].optin = false; // this is core feature - if (enforceConsentUpdate && consents[feature].optin !== false) { - updateConsent(); + if (enforceConsentUpdate && this.#consents[feature].optin !== false) { + this.#updateConsent(); } } } else { - log(logLevelEnums.WARNING, "remove_consent, No feature available for [" + feature + "]"); + this.#log(logLevelEnums.WARNING, "remove_consent, No feature available for [" + feature + "]"); } }; - var consentTimer; - var updateConsent = function () { - if (consentTimer) { - // delay syncing consents - clearTimeout(consentTimer); - consentTimer = null; - } - consentTimer = setTimeout(function () { - var consentMessage = {}; - for (var i = 0; i < Countly.features.length; i++) { - if (consents[Countly.features[i]].optin === true) { - consentMessage[Countly.features[i]] = true; - } - else { - consentMessage[Countly.features[i]] = false; - } - } - toRequestQueue({ consent: JSON.stringify(consentMessage) }); - log(logLevelEnums.DEBUG, "Consent update request has been sent to the queue."); - }, 1000); - }; - - this.enable_offline_mode = function () { - log(logLevelEnums.INFO, "enable_offline_mode, Enabling offline mode"); + enable_offline_mode = () => { + this.#log(logLevelEnums.INFO, "enable_offline_mode, Enabling offline mode"); // clear consents this.remove_consent_internal(Countly.features, false); - offlineMode = true; + this.#offlineMode = true; this.device_id = "[CLY]_temp_id"; - self.device_id = this.device_id; - deviceIdType = DeviceIdTypeInternalEnums.TEMPORARY_ID; + this.device_id = this.device_id; + this.#deviceIdType = DeviceIdTypeInternalEnums.TEMPORARY_ID; }; - this.disable_offline_mode = function (device_id) { - if (!offlineMode) { - log(logLevelEnums.WARNING, "disable_offline_mode, Countly was not in offline mode."); + disable_offline_mode = (device_id) => { + if (!this.#offlineMode) { + this.#log(logLevelEnums.WARNING, "disable_offline_mode, Countly was not in offline mode."); return; } - log(logLevelEnums.INFO, "disable_offline_mode, Disabling offline mode"); - offlineMode = false; + this.#log(logLevelEnums.INFO, "disable_offline_mode, Disabling offline mode"); + this.#offlineMode = false; if (device_id && this.device_id !== device_id) { this.device_id = device_id; - self.device_id = this.device_id; - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; - setValueInStorage("cly_id", this.device_id); - setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED); - log(logLevelEnums.INFO, "disable_offline_mode, Changing id to: " + this.device_id); + this.device_id = this.device_id; + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + this.#setValueInStorage("cly_id", this.device_id); + this.#setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED); + this.#log(logLevelEnums.INFO, "disable_offline_mode, Changing id to: " + this.device_id); } else { - this.device_id = getStoredIdOrGenerateId(); + this.device_id = this.#getStoredIdOrGenerateId(); if (this.device_id === "[CLY]_temp_id") { this.device_id = generateUUID(); } - self.device_id = this.device_id; - if (this.device_id !== getValueFromStorage("cly_id")) { - setValueInStorage("cly_id", this.device_id); - setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.SDK_GENERATED); + this.device_id = this.device_id; + if (this.device_id !== this.#getValueFromStorage("cly_id")) { + this.#setValueInStorage("cly_id", this.device_id); + this.#setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.SDK_GENERATED); } } var needResync = false; - if (requestQueue.length > 0) { - for (var i = 0; i < requestQueue.length; i++) { - if (requestQueue[i].device_id === "[CLY]_temp_id") { - requestQueue[i].device_id = this.device_id; + if (this.#requestQueue.length > 0) { + for (var i = 0; i < this.#requestQueue.length; i++) { + if (this.#requestQueue[i].device_id === "[CLY]_temp_id") { + this.#requestQueue[i].device_id = this.device_id; needResync = true; } } } if (needResync) { - setValueInStorage("cly_queue", requestQueue, true); + this.#setValueInStorage("cly_queue", this.#requestQueue, true); } - if (shouldSendHC) { - HealthCheck.sendInstantHCRequest(); - shouldSendHC = false; + if (this.#shouldSendHC) { + this.#HealthCheck.sendInstantHCRequest(); + this.#shouldSendHC = false; } }; @@ -919,43 +972,43 @@ constructor(ob) { * @param {boolean} noHeartBeat - true if you don't want to use internal heartbeat to manage session * @param {bool} force - force begin session request even if session cookie is enabled */ - this.begin_session = function (noHeartBeat, force) { - log(logLevelEnums.INFO, "begin_session, Starting the session. There was an ongoing session: [" + sessionStarted + "]"); + begin_session = (noHeartBeat, force) => { + this.#log(logLevelEnums.INFO, "begin_session, Starting the session. There was an ongoing session: [" + this.#sessionStarted + "]"); if (noHeartBeat) { - log(logLevelEnums.INFO, "begin_session, Heartbeats are disabled"); + this.#log(logLevelEnums.INFO, "begin_session, Heartbeats are disabled"); } if (force) { - log(logLevelEnums.INFO, "begin_session, Session starts irrespective of session cookie"); + this.#log(logLevelEnums.INFO, "begin_session, Session starts irrespective of session cookie"); } if (this.check_consent(featureEnums.SESSIONS)) { - if (!sessionStarted) { + if (!this.#sessionStarted) { if (this.enableOrientationTracking) { // report orientation - this.report_orientation(); - add_event_listener(window, "resize", function () { - self.report_orientation(); + this.#report_orientation(); + add_event_listener(window, "resize", () => { + this.#report_orientation(); }); } - lastBeat = getTimestamp(); - sessionStarted = true; - autoExtend = !(noHeartBeat); - var expire = getValueFromStorage("cly_session"); - log(logLevelEnums.VERBOSE, "begin_session, Session state, forced: [" + force + "], useSessionCookie: [" + useSessionCookie + "], seconds to expire: [" + (expire - lastBeat) + "], expired: [" + (parseInt(expire) <= getTimestamp()) + "] "); - if (force || !useSessionCookie || !expire || parseInt(expire) <= getTimestamp()) { - log(logLevelEnums.INFO, "begin_session, Session started"); - if (firstView === null) { - firstView = true; + this.#lastBeat = getTimestamp(); + this.#sessionStarted = true; + this.#autoExtend = !(noHeartBeat); + var expire = this.#getValueFromStorage("cly_session"); + this.#log(logLevelEnums.VERBOSE, "begin_session, Session state, forced: [" + force + "], useSessionCookie: [" + this.#useSessionCookie + "], seconds to expire: [" + (expire - this.#lastBeat) + "], expired: [" + (parseInt(expire) <= getTimestamp()) + "] "); + if (force || !this.#useSessionCookie || !expire || parseInt(expire) <= getTimestamp()) { + this.#log(logLevelEnums.INFO, "begin_session, Session started"); + if (this.#firstView === null) { + this.#firstView = true; } var req = {}; req.begin_session = 1; - req.metrics = JSON.stringify(getMetrics()); - toRequestQueue(req); + req.metrics = JSON.stringify(this.#getMetrics()); + this.#toRequestQueue(req); } - setValueInStorage("cly_session", getTimestamp() + (sessionCookieTimeout * 60)); + this.#setValueInStorage("cly_session", getTimestamp() + (this.#sessionCookieTimeout * 60)); } } else { - lastParams.begin_session = arguments; + this.#lastParams.begin_session = [noHeartBeat, force]; } }; @@ -963,15 +1016,20 @@ constructor(ob) { * Report session duration * @param {int} sec - amount of seconds to report for current session */ - this.session_duration = function (sec) { - log(logLevelEnums.INFO, "session_duration, Reporting session duration"); - if (this.check_consent(featureEnums.SESSIONS)) { - if (sessionStarted) { - log(logLevelEnums.INFO, "session_duration, Session extended: ", sec); - toRequestQueue({ session_duration: sec }); - extendSession(); - } + session_duration = (sec) => { + this.#log(logLevelEnums.INFO, "session_duration, Reporting session duration: [" + sec + "]"); + if (!this.check_consent(featureEnums.SESSIONS)) { + return; + } + + if (!this.#sessionStarted) { + this.#log(logLevelEnums.DEBUG, "session_duration, No session was started"); + return; } + + this.#log(logLevelEnums.INFO, "session_duration, Session extended: [" + sec + "]"); + this.#toRequestQueue({ session_duration: sec }); + this.#extendSession(); }; /** @@ -979,20 +1037,20 @@ constructor(ob) { * @param {int} sec - amount of seconds to report for current session, before ending it * @param {bool} force - force end session request even if session cookie is enabled */ - this.end_session = function (sec, force) { - log(logLevelEnums.INFO, "end_session, Ending the current session. There was an on going session:[" + sessionStarted + "]"); + end_session = (sec, force) => { + this.#log(logLevelEnums.INFO, "end_session, Ending the current session. There was an on going session:[" + this.#sessionStarted + "]"); if (this.check_consent(featureEnums.SESSIONS)) { - if (sessionStarted) { - sec = sec || getTimestamp() - lastBeat; - reportViewDuration(); - if (!useSessionCookie || force) { - log(logLevelEnums.INFO, "end_session, Session ended"); - toRequestQueue({ end_session: 1, session_duration: sec }); + if (this.#sessionStarted) { + sec = sec || getTimestamp() - this.#lastBeat; + this.#reportViewDuration(); + if (!this.#useSessionCookie || force) { + this.#log(logLevelEnums.INFO, "end_session, Session ended"); + this.#toRequestQueue({ end_session: 1, session_duration: sec }); } else { this.session_duration(sec); } - sessionStarted = false; + this.#sessionStarted = false; } } }; @@ -1001,13 +1059,13 @@ constructor(ob) { * Changes the current device ID according to the device ID type (the preffered method) * @param {string} newId - new user/device ID to use. Must be a non-empty string value. Invalid values (like null, empty string or undefined) will be rejected * */ - this.set_id = function (newId) { - log(logLevelEnums.INFO, "set_id, Changing the device ID to:[" + newId + "]"); + set_id = (newId) => { + this.#log(logLevelEnums.INFO, "set_id, Changing the device ID to:[" + newId + "]"); if (newId == null || newId === "") { - log(logLevelEnums.WARNING, "set_id, The provided device is not a valid ID"); + this.#log(logLevelEnums.WARNING, "set_id, The provided device is not a valid ID"); return; } - if (deviceIdType === DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED) { + if (this.#deviceIdType === DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED) { /*change ID without merge as current ID is Dev supplied, so not first login*/ this.change_id(newId, false); } else { @@ -1021,54 +1079,54 @@ constructor(ob) { * @param {string} newId - new user/device ID to use. Must be a non-empty string value. Invalid values (like null, empty string or undefined) will be rejected * @param {boolean} merge - move data from old ID to new ID on server * */ - this.change_id = function (newId, merge) { - log(logLevelEnums.INFO, "change_id, Changing the device ID to: [" + newId + "] with merge:[" + merge + "]"); + change_id = (newId, merge) => { + this.#log(logLevelEnums.INFO, "change_id, Changing the device ID to: [" + newId + "] with merge:[" + merge + "]"); if (!newId || typeof newId !== "string" || newId.length === 0) { - log(logLevelEnums.WARNING, "change_id, The provided device ID is not a valid ID"); + this.#log(logLevelEnums.WARNING, "change_id, The provided device ID is not a valid ID"); return; } - if (offlineMode) { - log(logLevelEnums.WARNING, "change_id, Offline mode was on, initiating disabling sequence instead."); + if (this.#offlineMode) { + this.#log(logLevelEnums.WARNING, "change_id, Offline mode was on, initiating disabling sequence instead."); this.disable_offline_mode(newId); return; } // eqeq is used here since we want to catch number to string checks too. type conversion might happen at a new init // eslint-disable-next-line eqeqeq if (this.device_id == newId) { - log(logLevelEnums.DEBUG, "change_id, Provided device ID is equal to the current device ID. Aborting."); + this.#log(logLevelEnums.DEBUG, "change_id, Provided device ID is equal to the current device ID. Aborting."); return; } if (!merge) { // process async queue before sending events - processAsyncQueue(); + this.#processAsyncQueue(); // empty event queue - sendEventsForced(); + this.#sendEventsForced(); // end current session this.end_session(null, true); // clear timed events - timedEvents = {}; + this.#timedEvents = {}; // clear all consents this.remove_consent_internal(Countly.features, false); } var oldId = this.device_id; this.device_id = newId; - self.device_id = this.device_id; - deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; - setValueInStorage("cly_id", this.device_id); - setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED); - log(logLevelEnums.INFO, "change_id, Changing ID from:[" + oldId + "] to [" + newId + "]"); + this.device_id = this.device_id; + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + this.#setValueInStorage("cly_id", this.device_id); + this.#setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED); + this.#log(logLevelEnums.INFO, "change_id, Changing ID from:[" + oldId + "] to [" + newId + "]"); if (merge) { // no consent check here since 21.11.0 - toRequestQueue({ old_device_id: oldId }); + this.#toRequestQueue({ old_device_id: oldId }); } else { // start new session for new ID TODO: check this when no session tracking is enabled - this.begin_session(!autoExtend, true); + this.begin_session(!this.#autoExtend, true); } // if init time remote config was enabled with a callback function, remove currently stored remote configs and fetch remote config again if (this.remote_config) { - remoteConfigs = {}; - setValueInStorage("cly_remote_configs", remoteConfigs); + this.#remoteConfigs = {}; + this.#setValueInStorage("cly_remote_configs", this.#remoteConfigs); this.fetch_remote_config(this.remote_config); } }; @@ -1082,8 +1140,8 @@ constructor(ob) { * @param {number=} event.dur - duration to report with event (if any) * @param {Object=} event.segmentation - object with segments key /values * */ - this.add_event = function (event) { - log(logLevelEnums.INFO, "add_event, Adding event: ", event); + add_event = (event) => { + this.#log(logLevelEnums.INFO, "add_event, Adding event: ", event); // initially no consent is given var respectiveConsent = false; switch (event.key) { @@ -1110,7 +1168,7 @@ constructor(ob) { } // if consent is given adds event to the queue if (respectiveConsent) { - add_cly_events(event); + this.#add_cly_events(event); } }; @@ -1120,15 +1178,15 @@ constructor(ob) { * @param {Event} event - countly event * @param {String} eventIdOverride - countly event ID */ - function add_cly_events(event, eventIdOverride) { + #add_cly_events = (event, eventIdOverride) => { // ignore bots - if (self.ignore_visitor) { - log(logLevelEnums.ERROR, "Adding event failed. Possible bot or user opt out"); + if (this.ignore_visitor) { + this.#log(logLevelEnums.ERROR, "Adding event failed. Possible bot or user opt out"); return; } if (!event.key) { - log(logLevelEnums.ERROR, "Adding event failed. Event must have a key property"); + this.#log(logLevelEnums.ERROR, "Adding event failed. Event must have a key property"); return; } @@ -1138,9 +1196,9 @@ constructor(ob) { // 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, self.maxKeyLength, "add_cly_event", log); + event.key = truncateSingleValue(event.key, this.maxKeyLength, "add_cly_event", this.#log); } - event.segmentation = truncateObject(event.segmentation, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "add_cly_event", log); + event.segmentation = truncateObject(event.segmentation, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "add_cly_event", this.#log); var props = ["key", "count", "sum", "dur", "segmentation"]; var e = createNewObjectFromProperties(event, props); e.timestamp = getMsTimestamp(); @@ -1149,14 +1207,14 @@ constructor(ob) { e.dow = date.getDay(); e.id = eventIdOverride || secureRandom(); if (e.key === internalEventKeyEnums.VIEW) { - e.pvid = previousViewId || ""; + e.pvid = this.#previousViewId || ""; } else { - e.cvid = currentViewId || ""; + e.cvid = this.#currentViewId || ""; } - eventQueue.push(e); - setValueInStorage("cly_event", eventQueue); - log(logLevelEnums.INFO, "With event ID: [" + e.id + "], successfully adding the last event:", e); + this.#eventQueue.push(e); + this.#setValueInStorage("cly_event", this.#eventQueue); + this.#log(logLevelEnums.INFO, "With event ID: [" + e.id + "], successfully adding the last event:", e); } /** @@ -1164,19 +1222,19 @@ constructor(ob) { * This works basically as a timer and does not create an event till end_event is called * @param {string} key - event name that will be used as key property * */ - this.start_event = function (key) { + start_event = (key) => { if (!key || typeof key !== "string") { - log(logLevelEnums.WARNING, "start_event, you have to provide a valid string key instead of: [" + key + "]"); + this.#log(logLevelEnums.WARNING, "start_event, you have to provide a valid string key instead of: [" + key + "]"); return; } - log(logLevelEnums.INFO, "start_event, Starting timed event with key: [" + key + "]"); + this.#log(logLevelEnums.INFO, "start_event, Starting timed event with key: [" + key + "]"); // truncate event name to internal limits - key = truncateSingleValue(key, self.maxKeyLength, "start_event", log); - if (timedEvents[key]) { - log(logLevelEnums.WARNING, "start_event, Timed event with key: [" + key + "] already started"); + key = truncateSingleValue(key, this.maxKeyLength, "start_event", this.#log); + if (this.#timedEvents[key]) { + this.#log(logLevelEnums.WARNING, "start_event, Timed event with key: [" + key + "] already started"); return; } - timedEvents[key] = getTimestamp(); + this.#timedEvents[key] = getTimestamp(); }; /** @@ -1184,20 +1242,20 @@ constructor(ob) { * @param {string} key - event name that will canceled * @returns {boolean} - returns true if the event was canceled and false if no event with that key was found * */ - this.cancel_event = function (key) { + cancel_event = (key) => { if (!key || typeof key !== "string") { - log(logLevelEnums.WARNING, "cancel_event, you have to provide a valid string key instead of: [" + key + "]"); + this.#log(logLevelEnums.WARNING, "cancel_event, you have to provide a valid string key instead of: [" + key + "]"); return false; } - log(logLevelEnums.INFO, "cancel_event, Canceling timed event with key: [" + key + "]"); + this.#log(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, self.maxKeyLength, "cancel_event", log); - if (timedEvents[key]) { - delete timedEvents[key]; - log(logLevelEnums.INFO, "cancel_event, Timed event with key: [" + key + "] is canceled"); + key = truncateSingleValue(key, this.maxKeyLength, "cancel_event", this.#log); + if (this.#timedEvents[key]) { + delete this.#timedEvents[key]; + this.#log(logLevelEnums.INFO, "cancel_event, Timed event with key: [" + key + "] is canceled"); return true; } - log(logLevelEnums.WARNING, "cancel_event, Timed event with key: [" + key + "] was not found"); + this.#log(logLevelEnums.WARNING, "cancel_event, Timed event with key: [" + key + "] was not found"); return false; }; @@ -1205,38 +1263,38 @@ constructor(ob) { * End timed event * @param {string|object} event - event key if string or Countly event same as passed to {@link Countly.add_event} * */ - this.end_event = function (event) { + end_event = (event) => { if (!event) { - log(logLevelEnums.WARNING, "end_event, you have to provide a valid string key or event object instead of: [" + event + "]"); + this.#log(logLevelEnums.WARNING, "end_event, you have to provide a valid string key or event object instead of: [" + event + "]"); return; } - log(logLevelEnums.INFO, "end_event, Ending timed event"); + this.#log(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, self.maxKeyLength, "end_event", log); + event = truncateSingleValue(event, this.maxKeyLength, "end_event", this.#log); event = { key: event }; } if (!event.key) { - log(logLevelEnums.ERROR, "end_event, Timed event must have a key property"); + this.#log(logLevelEnums.ERROR, "end_event, Timed event must have a key property"); return; } - if (!timedEvents[event.key]) { - log(logLevelEnums.ERROR, "end_event, Timed event with key: [" + event.key + "] was not started"); + if (!this.#timedEvents[event.key]) { + this.#log(logLevelEnums.ERROR, "end_event, Timed event with key: [" + event.key + "] was not started"); return; } - event.dur = getTimestamp() - timedEvents[event.key]; + event.dur = getTimestamp() - this.#timedEvents[event.key]; this.add_event(event); - delete timedEvents[event.key]; + delete this.#timedEvents[event.key]; }; /** * Report device orientation * @param {string=} orientation - orientation as landscape or portrait * */ - this.report_orientation = function (orientation) { - log(logLevelEnums.INFO, "report_orientation, Reporting orientation"); + #report_orientation = (orientation) => { + this.#log(logLevelEnums.INFO, "report_orientation, Reporting orientation"); if (this.check_consent(featureEnums.USERS)) { - add_cly_events({ + this.#add_cly_events({ key: internalEventKeyEnums.ORIENTATION, segmentation: { mode: orientation || getOrientation(), @@ -1252,8 +1310,8 @@ constructor(ob) { * * @deprecated use 'recordDirectAttribution' in place of this call * */ - this.report_conversion = function (campaign_id, campaign_user_id) { - log(logLevelEnums.WARNING, "report_conversion, Deprecated function call! Use 'recordDirectAttribution' in place of this call. Call will be redirected now!"); + report_conversion = (campaign_id, campaign_user_id) => { + this.#log(logLevelEnums.WARNING, "report_conversion, Deprecated function call! Use 'recordDirectAttribution' in place of this call. Call will be redirected now!"); this.recordDirectAttribution(campaign_id, campaign_user_id); }; /** @@ -1261,17 +1319,17 @@ constructor(ob) { * @param {string=} campaign_id - id of campaign, or will use the one that is stored after campaign link click * @param {string=} campaign_user_id - id of user's click on campaign, or will use the one that is stored after campaign link click * */ - this.recordDirectAttribution = function (campaign_id, campaign_user_id) { - log(logLevelEnums.INFO, "recordDirectAttribution, Recording the attribution for campaign ID: [" + campaign_id + "] and the user ID: [" + campaign_user_id + "]"); + recordDirectAttribution = (campaign_id, campaign_user_id) => { + this.#log(logLevelEnums.INFO, "recordDirectAttribution, Recording the attribution for campaign ID: [" + campaign_id + "] and the user ID: [" + campaign_user_id + "]"); if (this.check_consent(featureEnums.ATTRIBUTION)) { - campaign_id = campaign_id || getValueFromStorage("cly_cmp_id") || "cly_organic"; - campaign_user_id = campaign_user_id || getValueFromStorage("cly_cmp_uid"); + campaign_id = campaign_id || this.#getValueFromStorage("cly_cmp_id") || "cly_organic"; + campaign_user_id = campaign_user_id || this.#getValueFromStorage("cly_cmp_uid"); if (campaign_user_id) { - toRequestQueue({ campaign_id: campaign_id, campaign_user: campaign_user_id }); + this.#toRequestQueue({ campaign_id: campaign_id, campaign_user: campaign_user_id }); } else { - toRequestQueue({ campaign_id: campaign_id }); + this.#toRequestQueue({ campaign_id: campaign_id }); } } }; @@ -1289,26 +1347,26 @@ constructor(ob) { * @param {number=} user.byear - user's birth year used to calculate current age * @param {Object=} user.custom - object with custom key value properties you want to save with user * */ - this.user_details = function (user) { - log(logLevelEnums.INFO, "user_details, Trying to add user details: ", user); + user_details = (user) => { + this.#log(logLevelEnums.INFO, "user_details, Trying to add user details: ", user); if (this.check_consent(featureEnums.USERS)) { // process async queue before sending events - processAsyncQueue(); + this.#processAsyncQueue(); // flush events to event queue to prevent a drill issue - sendEventsForced(); - log(logLevelEnums.INFO, "user_details, flushed the event queue"); + this.#sendEventsForced(); + this.#log(logLevelEnums.INFO, "user_details, flushed the event queue"); // truncating user values and custom object key value pairs - user.name = truncateSingleValue(user.name, self.maxValueSize, "user_details", log); - user.username = truncateSingleValue(user.username, self.maxValueSize, "user_details", log); - user.email = truncateSingleValue(user.email, self.maxValueSize, "user_details", log); - user.organization = truncateSingleValue(user.organization, self.maxValueSize, "user_details", log); - user.phone = truncateSingleValue(user.phone, self.maxValueSize, "user_details", log); - user.picture = truncateSingleValue(user.picture, 4096, "user_details", log); - user.gender = truncateSingleValue(user.gender, self.maxValueSize, "user_details", log); - user.byear = truncateSingleValue(user.byear, self.maxValueSize, "user_details", log); - user.custom = truncateObject(user.custom, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "user_details", log); + user.name = truncateSingleValue(user.name, this.maxValueSize, "user_details", this.#log); + user.username = truncateSingleValue(user.username, this.maxValueSize, "user_details", this.#log); + user.email = truncateSingleValue(user.email, this.maxValueSize, "user_details", this.#log); + user.organization = truncateSingleValue(user.organization, this.maxValueSize, "user_details", this.#log); + user.phone = truncateSingleValue(user.phone, this.maxValueSize, "user_details", this.#log); + user.picture = truncateSingleValue(user.picture, 4096, "user_details", this.#log); + user.gender = truncateSingleValue(user.gender, this.maxValueSize, "user_details", this.#log); + user.byear = truncateSingleValue(user.byear, this.maxValueSize, "user_details", this.#log); + user.custom = truncateObject(user.custom, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "user_details", this.#log); var props = ["name", "username", "email", "organization", "phone", "picture", "gender", "byear", "custom"]; - toRequestQueue({ user_details: JSON.stringify(createNewObjectFromProperties(user, props)) }); + this.#toRequestQueue({ user_details: JSON.stringify(createNewObjectFromProperties(user, props)) }); } }; @@ -1324,20 +1382,20 @@ constructor(ob) { * - pull, to remove value from array property * - addToSet, creates an array property, if property does not exist, and adds unique value to array, only if it does not yet exist in array ************************* */ - var customData = {}; - var change_custom_property = function (key, value, mod) { - if (self.check_consent(featureEnums.USERS)) { - if (!customData[key]) { - customData[key] = {}; + #customData = {}; + #change_custom_property = (key, value, mod) => { + if (this.check_consent(featureEnums.USERS)) { + if (!this.#customData[key]) { + this.#customData[key] = {}; } if (mod === "$push" || mod === "$pull" || mod === "$addToSet") { - if (!customData[key][mod]) { - customData[key][mod] = []; + if (!this.#customData[key][mod]) { + this.#customData[key][mod] = []; } - customData[key][mod].push(value); + this.#customData[key][mod].push(value); } else { - customData[key][mod] = value; + this.#customData[key][mod] = value; } } }; @@ -1356,28 +1414,28 @@ constructor(ob) { * //send all custom property modified data to server * Countly.userData.save(); */ - this.userData = { + userData = { /** * Sets user's custom property value * @memberof Countly.userData * @param {string} key - name of the property to attach to user * @param {string|number} value - value to store under provided property * */ - set: function (key, value) { - log(logLevelEnums.INFO, "[userData] set, Setting user's custom property value: [" + value + "] under the key: [" + key + "]"); + set: (key, value) => { + this.#log(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, self.maxKeyLength, "userData set", log); - value = truncateSingleValue(value, self.maxValueSize, "userData set", log); - customData[key] = value; + key = truncateSingleValue(key, this.maxKeyLength, "userData set", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData set", this.#log); + this.#customData[key] = value; }, /** * Unset/deletes user's custom property * @memberof Countly.userData * @param {string} key - name of the property to delete * */ - unset: function (key) { - log(logLevelEnums.INFO, "[userData] unset, Resetting user's custom property with key: [" + key + "] "); - customData[key] = ""; + unset: (key) => { + this.#log(logLevelEnums.INFO, "[userData] unset, Resetting user's custom property with key: [" + key + "] "); + this.#customData[key] = ""; }, /** * Sets user's custom property value only if it was not set before @@ -1385,23 +1443,23 @@ constructor(ob) { * @param {string} key - name of the property to attach to user * @param {string|number} value - value to store under provided property * */ - set_once: function (key, value) { - log(logLevelEnums.INFO, "[userData] set_once, Setting user's unique custom property value: [" + value + "] under the key: [" + key + "] "); + set_once: (key, value) => { + this.#log(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, self.maxKeyLength, "userData set_once", log); - value = truncateSingleValue(value, self.maxValueSize, "userData set_once", log); - change_custom_property(key, value, "$setOnce"); + key = truncateSingleValue(key, this.maxKeyLength, "userData set_once", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData set_once", this.#log); + this.#change_custom_property(key, value, "$setOnce"); }, /** * Increment value under the key of this user's custom properties by one * @memberof Countly.userData * @param {string} key - name of the property to attach to user * */ - increment: function (key) { - log(logLevelEnums.INFO, "[userData] increment, Increasing user's custom property value under the key: [" + key + "] by one"); + increment: (key) => { + this.#log(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, self.maxKeyLength, "userData increment", log); - change_custom_property(key, 1, "$inc"); + key = truncateSingleValue(key, this.maxKeyLength, "userData increment", this.#log); + this.#change_custom_property(key, 1, "$inc"); }, /** * Increment value under the key of this user's custom properties by provided value @@ -1409,12 +1467,12 @@ constructor(ob) { * @param {string} key - name of the property to attach to user * @param {number} value - value by which to increment server value * */ - increment_by: function (key, value) { - log(logLevelEnums.INFO, "[userData] increment_by, Increasing user's custom property value under the key: [" + key + "] by: [" + value + "]"); + increment_by: (key, value) => { + this.#log(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, self.maxKeyLength, "userData increment_by", log); - value = truncateSingleValue(value, self.maxValueSize, "userData increment_by", log); - change_custom_property(key, value, "$inc"); + key = truncateSingleValue(key, this.maxKeyLength, "userData increment_by", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData increment_by", this.#log); + this.#change_custom_property(key, value, "$inc"); }, /** * Multiply value under the key of this user's custom properties by provided value @@ -1422,12 +1480,12 @@ constructor(ob) { * @param {string} key - name of the property to attach to user * @param {number} value - value by which to multiply server value * */ - multiply: function (key, value) { - log(logLevelEnums.INFO, "[userData] multiply, Multiplying user's custom property value under the key: [" + key + "] by: [" + value + "]"); + multiply: (key, value) => { + this.#log(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, self.maxKeyLength, "userData multiply", log); - value = truncateSingleValue(value, self.maxValueSize, "userData multiply", log); - change_custom_property(key, value, "$mul"); + key = truncateSingleValue(key, this.maxKeyLength, "userData multiply", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData multiply", this.#log); + this.#change_custom_property(key, value, "$mul"); }, /** * Save maximal value under the key of this user's custom properties @@ -1435,12 +1493,12 @@ constructor(ob) { * @param {string} key - name of the property to attach to user * @param {number} value - value which to compare to server's value and store maximal value of both provided * */ - max: function (key, value) { - log(logLevelEnums.INFO, "[userData] max, Saving user's maximum custom property value compared to the value: [" + value + "] under the key: [" + key + "]"); + max: (key, value) => { + this.#log(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, self.maxKeyLength, "userData max", log); - value = truncateSingleValue(value, self.maxValueSize, "userData max", log); - change_custom_property(key, value, "$max"); + key = truncateSingleValue(key, this.maxKeyLength, "userData max", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData max", this.#log); + this.#change_custom_property(key, value, "$max"); }, /** * Save minimal value under the key of this user's custom properties @@ -1448,12 +1506,12 @@ constructor(ob) { * @param {string} key - name of the property to attach to user * @param {number} value - value which to compare to server's value and store minimal value of both provided * */ - min: function (key, value) { - log(logLevelEnums.INFO, "[userData] min, Saving user's minimum custom property value compared to the value: [" + value + "] under the key: [" + key + "]"); + min: (key, value) => { + this.#log(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, self.maxKeyLength, "userData min", log); - value = truncateSingleValue(value, self.maxValueSize, "userData min", log); - change_custom_property(key, value, "$min"); + key = truncateSingleValue(key, this.maxKeyLength, "userData min", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData min", this.#log); + this.#change_custom_property(key, value, "$min"); }, /** * Add value to array under the key of this user's custom properties. If property is not an array, it will be converted to array @@ -1461,12 +1519,12 @@ constructor(ob) { * @param {string} key - name of the property to attach to user * @param {string|number} value - value which to add to array * */ - push: function (key, value) { - log(logLevelEnums.INFO, "[userData] push, Pushing a value: [" + value + "] under the key: [" + key + "] to user's custom property array"); + push: (key, value) => { + this.#log(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, self.maxKeyLength, "userData push", log); - value = truncateSingleValue(value, self.maxValueSize, "userData push", log); - change_custom_property(key, value, "$push"); + key = truncateSingleValue(key, this.maxKeyLength, "userData push", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData push", this.#log); + this.#change_custom_property(key, value, "$push"); }, /** * Add value to array under the key of this user's custom properties, storing only unique values. If property is not an array, it will be converted to array @@ -1474,12 +1532,12 @@ constructor(ob) { * @param {string} key - name of the property to attach to user * @param {string|number} value - value which to add to array * */ - push_unique: function (key, value) { - log(logLevelEnums.INFO, "[userData] push_unique, Pushing a unique value: [" + value + "] under the key: [" + key + "] to user's custom property array"); + push_unique: (key, value) => { + this.#log(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, self.maxKeyLength, "userData push_unique", log); - value = truncateSingleValue(value, self.maxValueSize, "userData push_unique", log); - change_custom_property(key, value, "$addToSet"); + key = truncateSingleValue(key, this.maxKeyLength, "userData push_unique", this.#log); + value = truncateSingleValue(value, this.maxValueSize, "userData push_unique", this.#log); + this.#change_custom_property(key, value, "$addToSet"); }, /** * Remove value from array under the key of this user's custom properties @@ -1487,25 +1545,25 @@ constructor(ob) { * @param {string} key - name of the property * @param {string|number} value - value which to remove from array * */ - pull: function (key, value) { - log(logLevelEnums.INFO, "[userData] pull, Removing the value: [" + value + "] under the key: [" + key + "] from user's custom property array"); - change_custom_property(key, value, "$pull"); + pull: (key, value) => { + this.#log(logLevelEnums.INFO, "[userData] pull, Removing the value: [" + value + "] under the key: [" + key + "] from user's custom property array"); + this.#change_custom_property(key, value, "$pull"); }, /** * Save changes made to user's custom properties object and send them to server * @memberof Countly.userData * */ - save: function () { - log(logLevelEnums.INFO, "[userData] save, Saving changes to user's custom property"); - if (self.check_consent(featureEnums.USERS)) { + save: () => { + this.#log(logLevelEnums.INFO, "[userData] save, Saving changes to user's custom property"); + if (this.check_consent(featureEnums.USERS)) { // process async queue before sending events - processAsyncQueue(); + this.#processAsyncQueue(); // flush events to event queue to prevent a drill issue - sendEventsForced(); - log(logLevelEnums.INFO, "user_details, flushed the event queue"); - toRequestQueue({ user_details: JSON.stringify({ custom: customData }) }); + this.#sendEventsForced(); + this.#log(logLevelEnums.INFO, "user_details, flushed the event queue"); + this.#toRequestQueue({ user_details: JSON.stringify({ custom: this.#customData }) }); } - customData = {}; + this.#customData = {}; } }; @@ -1519,26 +1577,26 @@ constructor(ob) { * @param {Object} trace.app_metrics - key/value metrics like duration, to report with trace where value is number * @param {Object=} trace.apm_attr - object profiling attributes (not yet supported) */ - this.report_trace = function (trace) { - log(logLevelEnums.INFO, "report_trace, Reporting performance trace"); + report_trace = (trace) => { + this.#log(logLevelEnums.INFO, "report_trace, Reporting performance trace"); if (this.check_consent(featureEnums.APM)) { var props = ["type", "name", "stz", "etz", "apm_metrics", "apm_attr"]; for (var i = 0; i < props.length; i++) { if (props[i] !== "apm_attr" && typeof trace[props[i]] === "undefined") { - log(logLevelEnums.WARNING, "report_trace, APM trace don't have the property: " + props[i]); + this.#log(logLevelEnums.WARNING, "report_trace, APM trace don't have the property: " + props[i]); return; } } // truncate trace name and metrics wrt internal limits - trace.name = truncateSingleValue(trace.name, self.maxKeyLength, "report_trace", log); - trace.app_metrics = truncateObject(trace.app_metrics, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "report_trace", log); + trace.name = truncateSingleValue(trace.name, this.maxKeyLength, "report_trace", this.#log); + trace.app_metrics = truncateObject(trace.app_metrics, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "report_trace", this.#log); var e = createNewObjectFromProperties(trace, props); e.timestamp = trace.stz; var date = new Date(); e.hour = date.getHours(); e.dow = date.getDay(); - toRequestQueue({ apm: JSON.stringify(e) }); - log(logLevelEnums.INFO, "report_trace, Successfully adding APM trace: ", e); + this.#toRequestQueue({ apm: JSON.stringify(e) }); + this.#log(logLevelEnums.INFO, "report_trace, Successfully adding APM trace: ", e); } }; @@ -1546,17 +1604,17 @@ constructor(ob) { * Automatically track javascript errors that happen on the website and report them to the server * @param {Object} segments - additional key value pairs you want to provide with error report, like versions of libraries used, etc. * */ - this.track_errors = function (segments) { + track_errors = (segments) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "track_errors, window object is not available. Not tracking errors."); + this.#log(logLevelEnums.WARNING, "track_errors, window object is not available. Not tracking errors."); return; } - log(logLevelEnums.INFO, "track_errors, Started tracking errors"); + this.#log(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; if (!window.cly_crashes) { window.cly_crashes = true; - crashSegments = segments; + this.#crashSegments = 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 @@ -1594,7 +1652,7 @@ constructor(ob) { error += stack.join("\n"); } catch (ex) { - log(logLevelEnums.ERROR, "track_errors, Call stack generation experienced a problem: " + ex); + // silent error } // false indicates fatal error (as in non_fatal:false) dispatchErrors(error, false); @@ -1602,7 +1660,7 @@ constructor(ob) { }; // error handling for 'uncaught rejections' - window.addEventListener("unhandledrejection", function (event) { + window.addEventListener("unhandledrejection", (event) => { // true indicates non fatal error (as in non_fatal: true) dispatchErrors(new Error("Unhandled rejection (reason: " + (event.reason && event.reason.stack ? event.reason.stack : event.reason) + ")."), true); }); @@ -1614,8 +1672,8 @@ constructor(ob) { * @param {Object} err - error exception object provided in catch block * @param {Object} segments - additional key value pairs you want to provide with error report, like versions of libraries used, etc. * */ - this.log_error = function (err, segments) { - log(logLevelEnums.INFO, "log_error, Logging errors"); + log_error = (err, segments) => { + this.#log(logLevelEnums.INFO, "log_error, Logging errors"); // true indicates non fatal error (as in non_fatal:true) this.recordError(err, true, segments); }; @@ -1624,16 +1682,16 @@ constructor(ob) { * Add new line in the log of breadcrumbs of what user did, will be included together with error report * @param {string} record - any text describing what user did * */ - this.add_log = function (record) { - log(logLevelEnums.INFO, "add_log, Adding a new log of breadcrumbs: [ " + record + " ]"); + add_log = (record) => { + this.#log(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, self.maxValueSize, "add_log", log); - while (crashLogs.length >= self.maxBreadcrumbCount) { - crashLogs.shift(); - log(logLevelEnums.WARNING, "add_log, Reached maximum crashLogs size. Will erase the oldest one."); + record = truncateSingleValue(record, this.maxValueSize, "add_log", this.#log); + while (this.#crashLogs.length >= this.maxBreadcrumbCount) { + this.#crashLogs.shift(); + this.#log(logLevelEnums.WARNING, "add_log, Reached maximum crashLogs size. Will erase the oldest one."); } - crashLogs.push(record); + this.#crashLogs.push(record); } }; /** @@ -1642,7 +1700,7 @@ constructor(ob) { * @param {array=} omit_keys - Array of keys to omit, if provided will fetch all keys except provided ones * @param {function=} callback - Callback to notify with first param error and second param remote config object * */ - this.fetch_remote_config = function (keys, omit_keys, callback) { + fetch_remote_config = (keys, omit_keys, callback) => { var keysFiltered = null; var omitKeysFiltered = null; var callbackFiltered = null; @@ -1676,15 +1734,15 @@ constructor(ob) { // use new RC API if (this.useExplicitRcApi) { - log(logLevelEnums.INFO, "fetch_remote_config, Fetching remote config"); + this.#log(logLevelEnums.INFO, "fetch_remote_config, Fetching remote config"); // opt in is true(1) or false(0) var opt = this.rcAutoOptinAb ? 1 : 0; - fetch_remote_config_explicit(keysFiltered, omitKeysFiltered, opt, null, callbackFiltered); + this.#fetch_remote_config_explicit(keysFiltered, omitKeysFiltered, opt, null, callbackFiltered); return; } - log(logLevelEnums.WARNING, "fetch_remote_config, Fetching remote config, with legacy API"); - fetch_remote_config_explicit(keysFiltered, omitKeysFiltered, null, "legacy", callbackFiltered); + this.#log(logLevelEnums.WARNING, "fetch_remote_config, Fetching remote config, with legacy API"); + this.#fetch_remote_config_explicit(keysFiltered, omitKeysFiltered, null, "legacy", callbackFiltered); }; /** @@ -1695,11 +1753,11 @@ constructor(ob) { * @param {string=} api - which API to use, if not provided would use default ("legacy" is for method="fetch_remote_config", default is method="rc") * @param {function=} callback - Callback to notify with first param error and second param remote config object * */ - function fetch_remote_config_explicit(keys, omit_keys, optIn, api, callback) { - log(logLevelEnums.INFO, "fetch_remote_config_explicit, Fetching sequence initiated"); + #fetch_remote_config_explicit = (keys, omit_keys, optIn, api, callback) =>{ + this.#log(logLevelEnums.INFO, "fetch_remote_config_explicit, Fetching sequence initiated"); var request = { method: "rc", - av: self.app_version + av: this.app_version }; // check if keys were provided if (keys) { @@ -1725,12 +1783,12 @@ constructor(ob) { if (typeof callback === "function") { providedCall = callback; } - if (self.check_consent(featureEnums.SESSIONS)) { - request.metrics = JSON.stringify(getMetrics()); + if (this.check_consent(featureEnums.SESSIONS)) { + request.metrics = JSON.stringify(this.#getMetrics()); } - if (self.check_consent(featureEnums.REMOTE_CONFIG)) { - prepareRequest(request); - makeNetworkRequest("fetch_remote_config_explicit", self.url + readPath, request, function (err, params, responseText) { + if (this.check_consent(featureEnums.REMOTE_CONFIG)) { + this.#prepareRequest(request); + this.#makeNetworkRequest("fetch_remote_config_explicit", this.url + this.#readPath, request, (err, params, responseText) => { if (err) { // error has been logged by the request function return; @@ -1740,29 +1798,29 @@ constructor(ob) { if (request.keys || request.omit_keys) { // we merge config for (var i in configs) { - remoteConfigs[i] = configs[i]; + this.#remoteConfigs[i] = configs[i]; } } else { // we replace config - remoteConfigs = configs; + this.#remoteConfigs = configs; } - setValueInStorage("cly_remote_configs", remoteConfigs); + this.#setValueInStorage("cly_remote_configs", this.#remoteConfigs); } catch (ex) { - log(logLevelEnums.ERROR, "fetch_remote_config_explicit, Had an issue while parsing the response: " + ex); + this.#log(logLevelEnums.ERROR, "fetch_remote_config_explicit, Had an issue while parsing the response: " + ex); } if (providedCall) { - log(logLevelEnums.INFO, "fetch_remote_config_explicit, Callback function is provided"); - providedCall(err, remoteConfigs); + this.#log(logLevelEnums.INFO, "fetch_remote_config_explicit, Callback function is provided"); + providedCall(err, this.#remoteConfigs); } // JSON array can pass }, true); } else { - log(logLevelEnums.ERROR, "fetch_remote_config_explicit, Remote config requires explicit consent"); + this.#log(logLevelEnums.ERROR, "fetch_remote_config_explicit, Remote config requires explicit consent"); if (providedCall) { - providedCall(new Error("Remote config requires explicit consent"), remoteConfigs); + providedCall(new Error("Remote config requires explicit consent"), this.#remoteConfigs); } } } @@ -1771,29 +1829,29 @@ constructor(ob) { * AB testing key provider, opts the user in for the selected keys * @param {array=} keys - Array of keys opt in FOR * */ - this.enrollUserToAb = function (keys) { - log(logLevelEnums.INFO, "enrollUserToAb, Providing AB test keys to opt in for"); + enrollUserToAb = (keys) => { + this.#log(logLevelEnums.INFO, "enrollUserToAb, Providing AB test keys to opt in for"); if (!keys || !Array.isArray(keys) || keys.length === 0) { - log(logLevelEnums.ERROR, "enrollUserToAb, No keys provided"); + this.#log(logLevelEnums.ERROR, "enrollUserToAb, No keys provided"); return; } var request = { method: "ab", keys: JSON.stringify(keys), - av: self.app_version + av: this.app_version }; - prepareRequest(request); - makeNetworkRequest("enrollUserToAb", this.url + readPath, request, function (err, params, responseText) { + this.#prepareRequest(request); + this.#makeNetworkRequest("enrollUserToAb", this.url + this.#readPath, request, (err, params, responseText) => { if (err) { // error has been logged by the request function return; } try { var resp = JSON.parse(responseText); - log(logLevelEnums.DEBUG, "enrollUserToAb, Parsed the response's result: [" + resp.result + "]"); + this.#log(logLevelEnums.DEBUG, "enrollUserToAb, Parsed the response's result: [" + resp.result + "]"); } catch (ex) { - log(logLevelEnums.ERROR, "enrollUserToAb, Had an issue while parsing the response: " + ex); + this.#log(logLevelEnums.ERROR, "enrollUserToAb, Had an issue while parsing the response: " + ex); } // JSON array can pass }, true); @@ -1804,59 +1862,59 @@ constructor(ob) { * @param {string=} key - if provided, will return value for key, or return whole object * @returns {object} remote configs * */ - this.get_remote_config = function (key) { - log(logLevelEnums.INFO, "get_remote_config, Getting remote config from storage"); + get_remote_config = (key) => { + this.#log(logLevelEnums.INFO, "get_remote_config, Getting remote config from storage"); if (typeof key !== "undefined") { - return remoteConfigs[key]; + return this.#remoteConfigs[key]; } - return remoteConfigs; + return this.#remoteConfigs; }; /** * Stop tracking duration time for this user * */ - this.stop_time = function () { - log(logLevelEnums.INFO, "stop_time, Stopping tracking duration"); - if (trackTime) { - trackTime = false; - storedDuration = getTimestamp() - lastBeat; - lastViewStoredDuration = getTimestamp() - lastViewTime; + #stop_time = () => { + this.#log(logLevelEnums.INFO, "stop_time, Stopping tracking duration"); + if (this.#trackTime) { + this.#trackTime = false; + this.#storedDuration = getTimestamp() - this.#lastBeat; + this.#lastViewStoredDuration = getTimestamp() - this.#lastViewTime; } }; /** * Start tracking duration time for this user, by default it is automatically tracked if you are using internal session handling * */ - this.start_time = function () { - log(logLevelEnums.INFO, "start_time, Starting tracking duration"); - if (!trackTime) { - trackTime = true; - lastBeat = getTimestamp() - storedDuration; - lastViewTime = getTimestamp() - lastViewStoredDuration; - lastViewStoredDuration = 0; - extendSession(); + #start_time = () => { + this.#log(logLevelEnums.INFO, "start_time, Starting tracking duration"); + if (!this.#trackTime) { + this.#trackTime = true; + this.#lastBeat = getTimestamp() - this.#storedDuration; + this.#lastViewTime = getTimestamp() - this.#lastViewStoredDuration; + this.#lastViewStoredDuration = 0; + this.#extendSession(); } }; /** * Track user sessions automatically, including time user spent on your website * */ - this.track_sessions = function () { + track_sessions = () => { if (!isBrowser) { - log(logLevelEnums.WARNING, "track_sessions, window object is not available. Not tracking sessions."); + this.#log(logLevelEnums.WARNING, "track_sessions, window object is not available. Not tracking sessions."); return; } - log(logLevelEnums.INFO, "track_session, Starting tracking user session"); + this.#log(logLevelEnums.INFO, "track_session, Starting tracking user session"); // start session this.begin_session(); - this.start_time(); + this.#start_time(); // end session on unload - add_event_listener(window, "beforeunload", function () { + add_event_listener(window, "beforeunload", () => { // process async queue before sending events - processAsyncQueue(); + this.#processAsyncQueue(); // empty the event queue - sendEventsForced(); - self.end_session(); + this.#sendEventsForced(); + this.end_session(); }); // manage sessions on window visibility events @@ -1865,12 +1923,12 @@ constructor(ob) { /** * Handle visibility change events */ - function onchange() { + var onchange = () => { if (document[hidden] || !document.hasFocus()) { - self.stop_time(); + this.#stop_time(); } else { - self.start_time(); + this.#start_time(); } } @@ -1908,11 +1966,11 @@ constructor(ob) { /** * Reset inactivity counter and time */ - function resetInactivity() { - if (inactivityCounter >= inactivityTime) { - self.start_time(); + var resetInactivity = () => { + if (this.#inactivityCounter >= this.#inactivityTime) { + this.#start_time(); } - inactivityCounter = 0; + this.#inactivityCounter = 0; } add_event_listener(window, "mousemove", resetInactivity); @@ -1921,10 +1979,10 @@ constructor(ob) { add_event_listener(window, "scroll", resetInactivity); // track user inactivity - setInterval(function () { - inactivityCounter++; - if (inactivityCounter >= inactivityTime) { - self.stop_time(); + setInterval(() => { + this.#inactivityCounter++; + if (this.#inactivityCounter >= this.#inactivityTime) { + this.#stop_time(); } }, 60000); }; @@ -1935,24 +1993,24 @@ constructor(ob) { * @param {array=} ignoreList - optional array of strings or regexps to test for the url/view name to ignore and not report * @param {object=} viewSegments - optional key value object with segments to report with the view * */ - this.track_pageview = function (page, ignoreList, viewSegments) { + track_pageview = (page, ignoreList, viewSegments) => { if (!isBrowser && !page) { - log(logLevelEnums.WARNING, "track_pageview, window object is not available. Not tracking page views is page is not provided."); + this.#log(logLevelEnums.WARNING, "track_pageview, window object is not available. Not tracking page views is page is not provided."); return; } - log(logLevelEnums.INFO, "track_pageview, Tracking page views"); - log(logLevelEnums.VERBOSE, "track_pageview, last view is:[" + lastView + "], current view ID is:[" + currentViewId + "], previous view ID is:[" + previousViewId + "]"); - if (lastView && trackingScrolls) { - log(logLevelEnums.DEBUG, "track_pageview, Scroll registry triggered"); - processScrollView(); // for single page site's view change - isScrollRegistryOpen = true; - scrollRegistryTopPosition = 0; - } - reportViewDuration(); - previousViewId = currentViewId; - currentViewId = secureRandom(); + this.#log(logLevelEnums.INFO, "track_pageview, Tracking page views"); + this.#log(logLevelEnums.VERBOSE, "track_pageview, last view is:[" + this.#lastView + "], current view ID is:[" + this.#currentViewId + "], previous view ID is:[" + this.#previousViewId + "]"); + if (this.#lastView && this.#trackingScrolls) { + this.#log(logLevelEnums.DEBUG, "track_pageview, Scroll registry triggered"); + this.#processScrollView(); // for single page site's view change + this.#isScrollRegistryOpen = true; + this.#scrollRegistryTopPosition = 0; + } + this.#reportViewDuration(); + this.#previousViewId = this.#currentViewId; + this.#currentViewId = secureRandom(); // truncate page name and segmentation wrt internal limits - page = truncateSingleValue(page, self.maxKeyLength, "track_pageview", log); + page = truncateSingleValue(page, this.maxKeyLength, "track_pageview", this.#log); // if the first parameter we got is an array we got the ignoreList first, assign it here if (page && Array.isArray(page)) { ignoreList = page; @@ -1963,11 +2021,11 @@ constructor(ob) { page = this.getViewName(); } if (page === undefined || page === "") { - log(logLevelEnums.ERROR, "track_pageview, No page name to track (it is either undefined or empty string). No page view can be tracked."); + this.#log(logLevelEnums.ERROR, "track_pageview, No page name to track (it is either undefined or empty string). No page view can be tracked."); return; } if (page === null) { - log(logLevelEnums.ERROR, "track_pageview, View name returned as null. Page view will be ignored."); + this.#log(logLevelEnums.ERROR, "track_pageview, View name returned as null. Page view will be ignored."); return; } @@ -1976,38 +2034,38 @@ constructor(ob) { try { var reg = new RegExp(ignoreList[i]); if (reg.test(page)) { - log(logLevelEnums.INFO, "track_pageview, Ignoring the page: " + page); + this.#log(logLevelEnums.INFO, "track_pageview, Ignoring the page: " + page); return; } } catch (ex) { - log(logLevelEnums.ERROR, "track_pageview, Problem with finding ignore list item: " + ignoreList[i] + ", error: " + ex); + this.#log(logLevelEnums.ERROR, "track_pageview, Problem with finding ignore list item: " + ignoreList[i] + ", error: " + ex); } } } var segments = { name: page, visit: 1, - view: self.getViewUrl() + view: this.getViewUrl() }; // truncate new segment - segments = truncateObject(segments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "track_pageview", log); + segments = truncateObject(segments, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "track_pageview", this.#log); if (this.track_domains) { segments.domain = window.location.hostname; } - if (useSessionCookie) { - if (!sessionStarted) { + if (this.#useSessionCookie) { + if (!this.#sessionStarted) { // tracking view was called before tracking session, so we check expiration ourselves - var expire = getValueFromStorage("cly_session"); + var expire = this.#getValueFromStorage("cly_session"); if (!expire || parseInt(expire) <= getTimestamp()) { - firstView = false; + this.#firstView = false; segments.start = 1; } } // tracking views called after tracking session, so we can rely on tracking session decision - else if (firstView) { - firstView = false; + else if (this.#firstView) { + this.#firstView = false; segments.start = 1; } } @@ -2022,11 +2080,11 @@ constructor(ob) { } // add utm tags - if (freshUTMTags && Object.keys(freshUTMTags).length) { - log(logLevelEnums.INFO, "track_pageview, Adding fresh utm tags to segmentation:[" + JSON.stringify(freshUTMTags) + "]"); - for (var utm in freshUTMTags) { + if (this.#freshUTMTags && Object.keys(this.#freshUTMTags).length) { + this.#log(logLevelEnums.INFO, "track_pageview, Adding fresh utm tags to segmentation:[" + JSON.stringify(this.#freshUTMTags) + "]"); + for (var utm in this.#freshUTMTags) { if (typeof segments["utm_" + utm] === "undefined") { - segments["utm_" + utm] = freshUTMTags[utm]; + segments["utm_" + utm] = this.#freshUTMTags[utm]; } } // TODO: Current logic adds utm tags to each view if the user landed with utm tags for that session(in non literal sense) @@ -2034,13 +2092,13 @@ constructor(ob) { } // add referrer if it is usable - if (isBrowser && isReferrerUsable()) { - log(logLevelEnums.INFO, "track_pageview, Adding referrer to segmentation:[" + document.referrer + "]"); + if (isBrowser && this.#isReferrerUsable()) { + this.#log(logLevelEnums.INFO, "track_pageview, Adding referrer to segmentation:[" + document.referrer + "]"); segments.referrer = document.referrer; // add referrer } if (viewSegments) { - viewSegments = truncateObject(viewSegments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "track_pageview", log); + viewSegments = truncateObject(viewSegments, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "track_pageview", this.#log); for (var key in viewSegments) { if (typeof segments[key] === "undefined") { @@ -2051,16 +2109,16 @@ constructor(ob) { // track pageview if (this.check_consent(featureEnums.VIEWS)) { - add_cly_events({ + this.#add_cly_events({ key: internalEventKeyEnums.VIEW, segmentation: segments - }, currentViewId); - lastView = page; - lastViewTime = getTimestamp(); - log(logLevelEnums.VERBOSE, "track_pageview, last view is assigned:[" + lastView + "]"); + }, this.#currentViewId); + this.#lastView = page; + this.#lastViewTime = getTimestamp(); + this.#log(logLevelEnums.VERBOSE, "track_pageview, last view is assigned:[" + this.#lastView + "]"); } else { - lastParams.track_pageview = arguments; + this.#lastParams.track_pageview = [page, ignoreList, viewSegments]; } }; @@ -2070,8 +2128,8 @@ constructor(ob) { * @param {array=} ignoreList - optional array of strings or regexps to test for the url/view name to ignore and not report * @param {object=} segments - optional view segments to track with the view * */ - this.track_view = function (page, ignoreList, segments) { - log(logLevelEnums.INFO, "track_view, Initiating tracking page views"); + track_view = (page, ignoreList, segments) => { + this.#log(logLevelEnums.INFO, "track_view, Initiating tracking page views"); this.track_pageview(page, ignoreList, segments); }; @@ -2079,14 +2137,14 @@ constructor(ob) { * Track all clicks on this page * @param {Object=} parent - DOM object which children to track, by default it is document body * */ - this.track_clicks = function (parent) { + track_clicks = (parent) =>{ if (!isBrowser) { - log(logLevelEnums.WARNING, "track_clicks, window object is not available. Not tracking clicks."); + this.#log(logLevelEnums.WARNING, "track_clicks, window object is not available. Not tracking clicks."); return; } - log(logLevelEnums.INFO, "track_clicks, Starting to track clicks"); + this.#log(logLevelEnums.INFO, "track_clicks, Starting to track clicks"); if (parent) { - log(logLevelEnums.INFO, "track_clicks, Tracking the specified children:[" + parent + "]"); + this.#log(logLevelEnums.INFO, "track_clicks, Tracking the specified children:[" + parent + "]"); } parent = parent || document; var shouldProcess = true; @@ -2094,7 +2152,7 @@ constructor(ob) { * Process click information * @param {Event} event - click event */ - function processClick(event) { + var processClick = (event) => { if (shouldProcess) { shouldProcess = false; @@ -2105,27 +2163,27 @@ constructor(ob) { var width = getDocWidth(); // record click event - if (self.check_consent(featureEnums.CLICKS)) { + if (this.check_consent(featureEnums.CLICKS)) { var segments = { type: "click", x: event.pageX, y: event.pageY, width: width, height: height, - view: self.getViewUrl() + view: this.getViewUrl() }; // truncate new segment - segments = truncateObject(segments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "processClick", log); - if (self.track_domains) { + segments = truncateObject(segments, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "processClick", this.#log); + if (this.track_domains) { segments.domain = window.location.hostname; } - add_cly_events({ + this.#add_cly_events({ key: internalEventKeyEnums.ACTION, segmentation: segments }); } } - setTimeout(function () { + setTimeout(() => { shouldProcess = true; }, 1000); } @@ -2138,42 +2196,42 @@ constructor(ob) { * Track all scrolls on this page * @param {Object=} parent - DOM object which children to track, by default it is document body * */ - this.track_scrolls = function (parent) { + track_scrolls = (parent) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "track_scrolls, window object is not available. Not tracking scrolls."); + this.#log(logLevelEnums.WARNING, "track_scrolls, window object is not available. Not tracking scrolls."); return; } - log(logLevelEnums.INFO, "track_scrolls, Starting to track scrolls"); + this.#log(logLevelEnums.INFO, "track_scrolls, Starting to track scrolls"); if (parent) { - log(logLevelEnums.INFO, "track_scrolls, Tracking the specified children"); + this.#log(logLevelEnums.INFO, "track_scrolls, Tracking the specified children"); } parent = parent || window; - isScrollRegistryOpen = true; - trackingScrolls = true; + this.#isScrollRegistryOpen = true; + this.#trackingScrolls = true; - add_event_listener(parent, "scroll", processScroll); - add_event_listener(parent, "beforeunload", processScrollView); + add_event_listener(parent, "scroll", this.#processScroll); + add_event_listener(parent, "beforeunload", this.#processScrollView); }; /** * Generate custom event for all links that were clicked on this page * @param {Object=} parent - DOM object which children to track, by default it is document body * */ - this.track_links = function (parent) { + track_links = (parent) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "track_links, window object is not available. Not tracking links."); + this.#log(logLevelEnums.WARNING, "track_links, window object is not available. Not tracking links."); return; } - log(logLevelEnums.INFO, "track_links, Starting to track clicks to links"); + this.#log(logLevelEnums.INFO, "track_links, Starting to track clicks to links"); if (parent) { - log(logLevelEnums.INFO, "track_links, Tracking the specified children"); + this.#log(logLevelEnums.INFO, "track_links, Tracking the specified children"); } parent = parent || document; /** * Process click information * @param {Event} event - click event */ - function processClick(event) { + var processClick = (event) => { // get element which was clicked var elem = get_closest_element(get_event_target(event), "a"); @@ -2182,14 +2240,14 @@ constructor(ob) { get_page_coord(event); // record click event - if (self.check_consent(featureEnums.CLICKS)) { - add_cly_events({ + if (this.check_consent(featureEnums.CLICKS)) { + this.#add_cly_events({ key: "linkClick", segmentation: { href: elem.href, text: elem.innerText, id: elem.id, - view: self.getViewUrl() + view: this.getViewUrl() } }); } @@ -2205,33 +2263,33 @@ constructor(ob) { * @param {Object=} parent - DOM object which children to track, by default it is document body * @param {boolean=} trackHidden - provide true to also track hidden inputs, default false * */ - this.track_forms = function (parent, trackHidden) { + track_forms = (parent, trackHidden) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "track_forms, window object is not available. Not tracking forms."); + this.#log(logLevelEnums.WARNING, "track_forms, window object is not available. Not tracking forms."); return; } - log(logLevelEnums.INFO, "track_forms, Starting to track form submissions. DOM object provided:[" + (!!parent) + "] Tracking hidden inputs :[" + (!!trackHidden) + "]"); + this.#log(logLevelEnums.INFO, "track_forms, Starting to track form submissions. DOM object provided:[" + (!!parent) + "] Tracking hidden inputs :[" + (!!trackHidden) + "]"); parent = parent || document; /** * Get name of the input * @param {HTMLElement} input - HTML input from which to get name * @returns {String} name of the input */ - function getInputName(input) { + var getInputName = (input) => { return input.name || input.id || input.type || input.nodeName; } /** * Process form data * @param {Event} event - form submission event */ - function processForm(event) { + var processForm = (event) => { var form = get_event_target(event); var segmentation = { id: form.attributes.id && form.attributes.id.nodeValue, name: form.attributes.name && form.attributes.name.nodeValue, action: form.attributes.action && form.attributes.action.nodeValue, method: form.attributes.method && form.attributes.method.nodeValue, - view: self.getViewUrl() + view: this.getViewUrl() }; // get input values @@ -2282,8 +2340,8 @@ constructor(ob) { } // record submit event - if (self.check_consent(featureEnums.FORMS)) { - add_cly_events({ + if (this.check_consent(featureEnums.FORMS)) { + this.#add_cly_events({ key: "formSubmit", segmentation: segmentation }); @@ -2299,18 +2357,18 @@ constructor(ob) { * @param {Object=} parent - DOM object which children to track, by default it is document body * @param {boolean} [useCustom=false] - submit collected data as custom user properties, by default collects as main user properties * */ - this.collect_from_forms = function (parent, useCustom) { + collect_from_forms = (parent, useCustom) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "collect_from_forms, window object is not available. Not collecting from forms."); + this.#log(logLevelEnums.WARNING, "collect_from_forms, window object is not available. Not collecting from forms."); return; } - log(logLevelEnums.INFO, "collect_from_forms, Starting to collect possible user data. DOM object provided:[" + (!!parent) + "] Submitting custom user property:[" + (!!useCustom) + "]"); + this.#log(logLevelEnums.INFO, "collect_from_forms, Starting to collect possible user data. DOM object provided:[" + (!!parent) + "] Submitting custom user property:[" + (!!useCustom) + "]"); parent = parent || document; /** * Process form data * @param {Event} event - form submission event */ - function processForm(event) { + var processForm = (event) => { var form = get_event_target(event); var userdata = {}; var hasUserInfo = false; @@ -2426,12 +2484,12 @@ constructor(ob) { // record user info, if any if (hasUserInfo) { - log(logLevelEnums.INFO, "collect_from_forms, Gathered user data", userdata); + this.#log(logLevelEnums.INFO, "collect_from_forms, Gathered user data", userdata); if (useCustom) { - self.user_details({ custom: userdata }); + this.user_details({ custom: userdata }); } else { - self.user_details(userdata); + this.user_details(userdata); } } } @@ -2444,18 +2502,18 @@ constructor(ob) { * Collect information about user from Facebook, if your website integrates Facebook SDK. Call this method after Facebook SDK is loaded and user is authenticated. * @param {Object=} custom - Custom keys to collected from Facebook, key will be used to store as key in custom user properties and value as key in Facebook graph object. For example, {"tz":"timezone"} will collect Facebook's timezone property, if it is available and store it in custom user's property under "tz" key. If you want to get value from some sub object properties, then use dot as delimiter, for example, {"location":"location.name"} will collect data from Facebook's {"location":{"name":"MyLocation"}} object and store it in user's custom property "location" key * */ - this.collect_from_facebook = function (custom) { + collect_from_facebook = (custom) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "collect_from_facebook, window object is not available. Not collecting from Facebook."); + this.#log(logLevelEnums.WARNING, "collect_from_facebook, window object is not available. Not collecting from Facebook."); return; } if (typeof FB === "undefined" || !FB || !FB.api) { - log(logLevelEnums.ERROR, "collect_from_facebook, Facebook SDK is not available"); + this.#log(logLevelEnums.ERROR, "collect_from_facebook, Facebook SDK is not available"); return; } - log(logLevelEnums.INFO, "collect_from_facebook, Starting to collect possible user data"); + this.#log(logLevelEnums.INFO, "collect_from_facebook, Starting to collect possible user data"); /* globals FB */ - FB.api("/me", function (resp) { + FB.api("/me", (resp) => { var data = {}; if (resp.name) { data.name = resp.name; @@ -2495,30 +2553,31 @@ constructor(ob) { } } } - self.user_details(data); + this.user_details(data); }); }; /** * Opts out user of any metric tracking * */ - this.opt_out = function () { - log(logLevelEnums.INFO, "opt_out, Opting out the user"); + opt_out = () => { + this.#log(logLevelEnums.WARNING, "opt_out, Opting out the user. Deprecated function call! Use 'consent' in place of this call."); this.ignore_visitor = true; - setValueInStorage("cly_ignore", true); + this.#setValueInStorage("cly_ignore", true); }; /** * Opts in user for tracking, if complies with other user ignore rules like bot useragent and prefetch settings * */ - this.opt_in = function () { - log(logLevelEnums.INFO, "opt_in, Opting in the user"); - setValueInStorage("cly_ignore", false); + opt_in = () => { + this.#log(logLevelEnums.WARNING, "opt_in, Opting in the user. Deprecated function call! Use 'consent' in place of this call."); + this.#setValueInStorage("cly_ignore", false); this.ignore_visitor = false; - checkIgnore(); - if (!this.ignore_visitor && !hasPulse) { - heartBeat(); + this.#checkIgnore(); + if (!this.ignore_visitor && !this.#hasPulse) { + this.#heartBeat(); } }; + /** * Provide information about user * @param {Object} ratingWidget - object with rating widget properties @@ -2532,8 +2591,8 @@ constructor(ob) { * * @deprecated use 'recordRatingWidgetWithID' in place of this call * */ - this.report_feedback = function (ratingWidget) { - log(logLevelEnums.WARNING, "report_feedback, Deprecated function call! Use 'recordRatingWidgetWithID' or 'reportFeedbackWidgetManually' in place of this call. Call will be redirected to 'recordRatingWidgetWithID' now!"); + report_feedback = (ratingWidget) => { + this.#log(logLevelEnums.WARNING, "report_feedback, Deprecated function call! Use 'recordRatingWidgetWithID' or 'reportFeedbackWidgetManually' in place of this call. Call will be redirected to 'recordRatingWidgetWithID' now!"); this.recordRatingWidgetWithID(ratingWidget); }; /** @@ -2547,17 +2606,17 @@ constructor(ob) { * @param {string=} ratingWidget.email - user's email * @param {string=} ratingWidget.comment - user's comment * */ - this.recordRatingWidgetWithID = function (ratingWidget) { - log(logLevelEnums.INFO, "recordRatingWidgetWithID, Providing information about user with ID: [ " + ratingWidget.widget_id + " ]"); + recordRatingWidgetWithID = (ratingWidget) => { + this.#log(logLevelEnums.INFO, "recordRatingWidgetWithID, Providing information about user with ID: [ " + ratingWidget.widget_id + " ]"); if (!this.check_consent(featureEnums.STAR_RATING)) { return; } if (!ratingWidget.widget_id) { - log(logLevelEnums.ERROR, "recordRatingWidgetWithID, Rating Widget must contain widget_id property"); + this.#log(logLevelEnums.ERROR, "recordRatingWidgetWithID, Rating Widget must contain widget_id property"); return; } if (!ratingWidget.rating) { - log(logLevelEnums.ERROR, "recordRatingWidgetWithID, Rating Widget must contain rating property"); + this.#log(logLevelEnums.ERROR, "recordRatingWidgetWithID, Rating Widget must contain rating property"); return; } var props = ["widget_id", "contactMe", "platform", "app_version", "rating", "email", "comment"]; @@ -2571,15 +2630,15 @@ constructor(ob) { event.segmentation.app_version = this.metrics._app_version || this.app_version; } if (event.segmentation.rating > 5) { - log(logLevelEnums.WARNING, "recordRatingWidgetWithID, You have entered a rating higher than 5. Changing it back to 5 now."); + this.#log(logLevelEnums.WARNING, "recordRatingWidgetWithID, You have entered a rating higher than 5. Changing it back to 5 now."); event.segmentation.rating = 5; } else if (event.segmentation.rating < 1) { - log(logLevelEnums.WARNING, "recordRatingWidgetWithID, You have entered a rating lower than 1. Changing it back to 1 now."); + this.#log(logLevelEnums.WARNING, "recordRatingWidgetWithID, You have entered a rating lower than 1. Changing it back to 1 now."); event.segmentation.rating = 1; } - log(logLevelEnums.INFO, "recordRatingWidgetWithID, Reporting Rating Widget: ", event); - add_cly_events(event); + this.#log(logLevelEnums.INFO, "recordRatingWidgetWithID, Reporting Rating Widget: ", event); + this.#add_cly_events(event); }; /** * Report information about survey, nps or rating widget answers/results @@ -2608,24 +2667,24 @@ constructor(ob) { * comment: "comment" * } * */ - this.reportFeedbackWidgetManually = function (CountlyFeedbackWidget, CountlyWidgetData, widgetResult) { + reportFeedbackWidgetManually = (CountlyFeedbackWidget, CountlyWidgetData, widgetResult) => { if (!this.check_consent(featureEnums.FEEDBACK)) { return; } if (!(CountlyFeedbackWidget && CountlyWidgetData)) { - log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget data and/or Widget object not provided. Aborting."); + this.#log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget data and/or Widget object not provided. Aborting."); return; } if (!CountlyFeedbackWidget._id) { - log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Feedback Widgets must contain _id property"); + this.#log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Feedback Widgets must contain _id property"); return; } - if (offlineMode) { - log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Feedback Widgets can not be reported in offline mode"); + if (this.#offlineMode) { + this.#log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Feedback Widgets can not be reported in offline mode"); return; } - log(logLevelEnums.INFO, "reportFeedbackWidgetManually, Providing information about user with, provided result of the widget with ID: [ " + CountlyFeedbackWidget._id + " ] and type: [" + CountlyFeedbackWidget.type + "]"); + this.#log(logLevelEnums.INFO, "reportFeedbackWidgetManually, Providing information about user with, provided result of the widget with ID: [ " + CountlyFeedbackWidget._id + " ] and type: [" + CountlyFeedbackWidget.type + "]"); // type specific checks to see if everything was provided var props = []; @@ -2634,16 +2693,16 @@ constructor(ob) { if (type === "nps") { if (widgetResult) { if (!widgetResult.rating) { - log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget must contain rating property"); + this.#log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget must contain rating property"); return; } widgetResult.rating = Math.round(widgetResult.rating); if (widgetResult.rating > 10) { - log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating higher than 10. Changing it back to 10 now."); + this.#log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating higher than 10. Changing it back to 10 now."); widgetResult.rating = 10; } else if (widgetResult.rating < 0) { - log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating lower than 0. Changing it back to 0 now."); + this.#log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating lower than 0. Changing it back to 0 now."); widgetResult.rating = 0; } props = ["rating", "comment"]; @@ -2653,7 +2712,7 @@ constructor(ob) { else if (type === "survey") { if (widgetResult) { if (Object.keys(widgetResult).length < 1) { - log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget should have answers to be reported"); + this.#log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget should have answers to be reported"); return; } props = Object.keys(widgetResult); @@ -2663,16 +2722,16 @@ constructor(ob) { else if (type === "rating") { if (widgetResult) { if (!widgetResult.rating) { - log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget must contain rating property"); + this.#log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget must contain rating property"); return; } widgetResult.rating = Math.round(widgetResult.rating); if (widgetResult.rating > 5) { - log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating higher than 5. Changing it back to 5 now."); + this.#log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating higher than 5. Changing it back to 5 now."); widgetResult.rating = 5; } else if (widgetResult.rating < 1) { - log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating lower than 1. Changing it back to 1 now."); + this.#log(logLevelEnums.WARNING, "reportFeedbackWidgetManually, You have entered a rating lower than 1. Changing it back to 1 now."); widgetResult.rating = 1; } props = ["rating", "comment", "email", "contactMe"]; @@ -2680,7 +2739,7 @@ constructor(ob) { eventKey = internalEventKeyEnums.STAR_RATING; } else { - log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget has an unacceptable type"); + this.#log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Widget has an unacceptable type"); return; } @@ -2704,41 +2763,42 @@ constructor(ob) { } // add event - log(logLevelEnums.INFO, "reportFeedbackWidgetManually, Reporting " + type + ": ", event); - add_cly_events(event); + this.#log(logLevelEnums.INFO, "reportFeedbackWidgetManually, Reporting " + type + ": ", event); + this.#add_cly_events(event); }; /** * Show specific widget popup by the widget id * @param {string} id - id value of related rating widget, you can get this value by click "Copy ID" button in row menu at "Feedback widgets" screen * - * @deprecated use 'presentRatingWidgetWithID' in place of this call + * @deprecated use 'feedback.showRating' in place of this call */ - this.show_feedback_popup = function (id) { + show_feedback_popup = (id) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "show_feedback_popup, window object is not available. Not showing feedback popup."); + this.#log(logLevelEnums.WARNING, "show_feedback_popup, window object is not available. Not showing feedback popup."); return; } - log(logLevelEnums.WARNING, "show_feedback_popup, Deprecated function call! Use 'presentRatingWidgetWithID' in place of this call. Call will be redirected now!"); - this.presentRatingWidgetWithID(id); + this.#log(logLevelEnums.WARNING, "show_feedback_popup, Deprecated function call! Use 'presentRatingWidgetWithID' in place of this call. Call will be redirected now!"); + presentRatingWidgetWithID(id); }; /** * Show specific widget popup by the widget id * @param {string} id - id value of related rating widget, you can get this value by click "Copy ID" button in row menu at "Feedback widgets" screen + * @deprecated use 'feedback.showRating' in place of this call */ - this.presentRatingWidgetWithID = function (id) { + presentRatingWidgetWithID = (id) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "presentRatingWidgetWithID, window object is not available. Not showing rating widget popup."); + this.#log(logLevelEnums.WARNING, "presentRatingWidgetWithID, window object is not available. Not showing rating widget popup."); return; } - log(logLevelEnums.INFO, "presentRatingWidgetWithID, Showing rating widget popup for the widget with ID: [ " + id + " ]"); + this.#log(logLevelEnums.INFO, "presentRatingWidgetWithID, Showing rating widget popup for the widget with ID: [ " + id + " ]"); if (!this.check_consent(featureEnums.STAR_RATING)) { return; } - if (offlineMode) { - log(logLevelEnums.ERROR, "presentRatingWidgetWithID, Cannot show ratingWidget popup in offline mode"); + if (this.#offlineMode) { + this.#log(logLevelEnums.ERROR, "presentRatingWidgetWithID, Cannot show ratingWidget popup in offline mode"); } else { - makeNetworkRequest("presentRatingWidgetWithID,", this.url + "/o/feedback/widget", { widget_id: id, av: self.app_version }, function (err, params, responseText) { + this.#makeNetworkRequest("presentRatingWidgetWithID,", this.url + "/o/feedback/widget", { widget_id: id, av: this.app_version }, (err, params, responseText) => { if (err) { // error has been logged by the request function return; @@ -2746,10 +2806,10 @@ constructor(ob) { try { // widget object var currentWidget = JSON.parse(responseText); - processWidget(currentWidget, false); + this.#processWidget(currentWidget, false); } catch (JSONParseError) { - log(logLevelEnums.ERROR, "presentRatingWidgetWithID, JSON parse failed: " + JSONParseError); + this.#log(logLevelEnums.ERROR, "presentRatingWidgetWithID, JSON parse failed: " + JSONParseError); } // JSON array can pass }, true); @@ -2760,31 +2820,32 @@ constructor(ob) { * Prepare rating widgets according to the current options * @param {array=} enableWidgets - widget ids array * - * @deprecated use 'initializeRatingWidgets' in place of this call + * @deprecated use 'feedback.showRating' in place of this call */ - this.initialize_feedback_popups = function (enableWidgets) { + initialize_feedback_popups = (enableWidgets) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "initialize_feedback_popups, window object is not available. Not initializing feedback popups."); + this.#log(logLevelEnums.WARNING, "initialize_feedback_popups, window object is not available. Not initializing feedback popups."); return; } - log(logLevelEnums.WARNING, "initialize_feedback_popups, Deprecated function call! Use 'initializeRatingWidgets' in place of this call. Call will be redirected now!"); + this.#log(logLevelEnums.WARNING, "initialize_feedback_popups, Deprecated function call! Use 'initializeRatingWidgets' in place of this call. Call will be redirected now!"); this.initializeRatingWidgets(enableWidgets); }; /** * Prepare rating widgets according to the current options * @param {array=} enableWidgets - widget ids array + * @deprecated use 'feedback.showRating' in place of this call */ - this.initializeRatingWidgets = function (enableWidgets) { + initializeRatingWidgets = (enableWidgets) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "initializeRatingWidgets, window object is not available. Not initializing rating widgets."); + this.#log(logLevelEnums.WARNING, "initializeRatingWidgets, window object is not available. Not initializing rating widgets."); return; } - log(logLevelEnums.INFO, "initializeRatingWidgets, Initializing rating widget with provided widget IDs:[ " + enableWidgets + "]"); + this.#log(logLevelEnums.INFO, "initializeRatingWidgets, Initializing rating widget with provided widget IDs:[ " + enableWidgets + "]"); if (!this.check_consent(featureEnums.STAR_RATING)) { return; } if (!enableWidgets) { - enableWidgets = getValueFromStorage("cly_fb_widgets"); + enableWidgets = this.#getValueFromStorage("cly_fb_widgets"); } // remove all old stickers before add new one @@ -2793,7 +2854,7 @@ constructor(ob) { stickers[0].remove(); } - makeNetworkRequest("initializeRatingWidgets,", this.url + "/o/feedback/multiple-widgets-by-id", { widgets: JSON.stringify(enableWidgets), av: self.app_version }, function (err, params, responseText) { + this.#makeNetworkRequest("initializeRatingWidgets,", this.url + "/o/feedback/multiple-widgets-by-id", { widgets: JSON.stringify(enableWidgets), av: this.app_version }, (err, params, responseText) => { if (err) { // error has been logged by the request function return; @@ -2813,7 +2874,7 @@ constructor(ob) { } // is target_page option provided as "All"? if (widgets[i].target_page === "all" && !widgets[i].hide_sticker) { - processWidget(widgets[i], true); + this.#processWidget(widgets[i], true); } // is target_page option provided as "selected"? else { @@ -2823,7 +2884,7 @@ constructor(ob) { var isFullPathMatched = pages[k] === window.location.pathname; var isContainAsterisk = pages[k].includes("*"); if (((isContainAsterisk && isWildcardMatched) || isFullPathMatched) && !widgets[i].hide_sticker) { - processWidget(widgets[i], true); + this.#processWidget(widgets[i], true); } } } @@ -2832,7 +2893,7 @@ constructor(ob) { } } catch (JSONParseError) { - log(logLevelEnums.ERROR, "initializeRatingWidgets, JSON parse error: " + JSONParseError); + this.#log(logLevelEnums.ERROR, "initializeRatingWidgets, JSON parse error: " + JSONParseError); } // JSON array can pass }, true); @@ -2843,35 +2904,36 @@ constructor(ob) { * @param {object=} params - required - includes "popups" property as string array of widgets ("widgets" for old versions) * example params: {"popups":["5b21581b967c4850a7818617"]} * - * @deprecated use 'enableRatingWidgets' in place of this call + * @deprecated use 'feedback.showRating' in place of this call * */ - this.enable_feedback = function (params) { + enable_feedback = (params) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "enable_feedback, window object is not available. Not enabling feedback."); + this.#log(logLevelEnums.WARNING, "enable_feedback, window object is not available. Not enabling feedback."); return; } - log(logLevelEnums.WARNING, "enable_feedback, Deprecated function call! Use 'enableRatingWidgets' in place of this call. Call will be redirected now!"); + this.#log(logLevelEnums.WARNING, "enable_feedback, Deprecated function call! Use 'enableRatingWidgets' in place of this call. Call will be redirected now!"); this.enableRatingWidgets(params); }; /** * Show rating widget popup by passed widget ids array * @param {object=} params - required - includes "popups" property as string array of widgets ("widgets" for old versions) * example params: {"popups":["5b21581b967c4850a7818617"]} + * @deprecated use 'feedback.showRating' in place of this call * */ - this.enableRatingWidgets = function (params) { + enableRatingWidgets = (params) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "enableRatingWidgets, window object is not available. Not enabling rating widgets."); + this.#log(logLevelEnums.WARNING, "enableRatingWidgets, window object is not available. Not enabling rating widgets."); return; } - log(logLevelEnums.INFO, "enableRatingWidgets, Enabling rating widget with params:", params); + this.#log(logLevelEnums.INFO, "enableRatingWidgets, Enabling rating widget with params:", params); if (!this.check_consent(featureEnums.STAR_RATING)) { return; } - if (offlineMode) { - log(logLevelEnums.ERROR, "enableRatingWidgets, Cannot enable rating widgets in offline mode"); + if (this.#offlineMode) { + this.#log(logLevelEnums.ERROR, "enableRatingWidgets, Cannot enable rating widgets in offline mode"); } else { - setValueInStorage("cly_fb_widgets", params.popups || params.widgets); + this.#setValueInStorage("cly_fb_widgets", params.popups || params.widgets); // inject feedback styles loadCSS(this.url + "/star-rating/stylesheets/countly-feedback-web.css"); // get enable widgets by app_key @@ -2883,7 +2945,7 @@ constructor(ob) { this.initializeRatingWidgets(enableWidgets); } else { - log(logLevelEnums.ERROR, "enableRatingWidgets, You should provide at least one widget id as param. Read documentation for more detail. https://resources.count.ly/plugins/feedback"); + this.#log(logLevelEnums.ERROR, "enableRatingWidgets, You should provide at least one widget id as param. Read documentation for more detail. https://resources.count.ly/plugins/feedback"); } } }; @@ -2893,11 +2955,11 @@ constructor(ob) { * @param {String} widgetType - The type of widget ("nps", "survey", "rating"). * @param {String} [nameIDorTag] - The name, id, or tag of the widget to display. */ - this.#showWidgetInternal = (widgetType, nameIDorTag) => { - log(logLevelEnums.INFO, `showWidget, Showing ${widgetType} widget, nameIDorTag:[${nameIDorTag}]`); + #showWidgetInternal = (widgetType, nameIDorTag) => { + this.#log(logLevelEnums.INFO, `showWidget, Showing ${widgetType} widget, nameIDorTag:[${nameIDorTag}]`); this.get_available_feedback_widgets((feedbackWidgetArray, error) => { if (error) { - log(logLevelEnums.ERROR, `showWidget, Error while getting feedback widgets list: ${error}`); + this.#log(logLevelEnums.ERROR, `showWidget, Error while getting feedback widgets list: ${error}`); return; } @@ -2910,24 +2972,24 @@ constructor(ob) { ); if (matchedWidget) { widget = matchedWidget; - log(logLevelEnums.VERBOSE, `showWidget, Found ${widgetType} widget by name, id, or tag: [${JSON.stringify(matchedWidget)}]`); + this.#log(logLevelEnums.VERBOSE, `showWidget, Found ${widgetType} widget by name, id, or tag: [${JSON.stringify(matchedWidget)}]`); } } if (!widget) { - log(logLevelEnums.ERROR, `showWidget, No ${widgetType} widget found.`); + this.#log(logLevelEnums.ERROR, `showWidget, No ${widgetType} widget found.`); return; } - this.present_feedback_widget(widget, null, null, null); + present_feedback_widget(widget, null, null, null); }); - }, + }; /** * Feedback interface with convenience methods for feedback widgets: * - showNPS([String nameIDorTag]) - shows an NPS widget by name, id or tag, or a random one if not provided * - showSurvey([String nameIDorTag]) - shows a Survey widget by name, id or tag, or a random one if not provided * - showRating([String nameIDorTag]) - shows a Rating widget by name, id or tag, or a random one if not provided */ - this.feedback = { + feedback = { /** * Displays the first available NPS widget or the one with the provided name, id, or tag. * @param {String} [nameIDorTag] - Name, id, or tag of the NPS widget to display. @@ -2952,8 +3014,8 @@ constructor(ob) { * This function retrieves all associated widget information (IDs, type, name etc in an array/list of objects) of your app * @param {Function} callback - Callback function with two parameters, 1st for returned list, 2nd for error * */ - this.get_available_feedback_widgets = function (callback) { - log(logLevelEnums.INFO, "get_available_feedback_widgets, Getting the feedback list, callback function is provided:[" + (!!callback) + "]"); + get_available_feedback_widgets = (callback) => { + this.#log(logLevelEnums.INFO, "get_available_feedback_widgets, Getting the feedback list, callback function is provided:[" + (!!callback) + "]"); if (!this.check_consent(featureEnums.FEEDBACK)) { if (callback) { callback(null, new Error("Consent for feedback not provided.")); @@ -2961,20 +3023,20 @@ constructor(ob) { return; } - if (offlineMode) { - log(logLevelEnums.ERROR, "get_available_feedback_widgets, Cannot enable feedback widgets in offline mode."); + if (this.#offlineMode) { + this.#log(logLevelEnums.ERROR, "get_available_feedback_widgets, Cannot enable feedback widgets in offline mode."); return; } - var url = this.url + readPath; + var url = this.url + this.#readPath; var data = { method: featureEnums.FEEDBACK, device_id: this.device_id, app_key: this.app_key, - av: self.app_version + av: this.app_version }; - makeNetworkRequest("get_available_feedback_widgets,", url, data, function (err, params, responseText) { + this.#makeNetworkRequest("get_available_feedback_widgets,", url, data, (err, params, responseText) => { if (err) { // error has been logged by the request function if (callback) { @@ -2991,7 +3053,7 @@ constructor(ob) { } } catch (error) { - log(logLevelEnums.ERROR, "get_available_feedback_widgets, Error while parsing feedback widgets list: " + error); + this.#log(logLevelEnums.ERROR, "get_available_feedback_widgets, Error while parsing feedback widgets list: " + error); if (callback) { callback(null, error); } @@ -3005,12 +3067,12 @@ constructor(ob) { * @param {Object} CountlyFeedbackWidget - Widget object, retrieved from 'get_available_feedback_widgets' * @param {Function} callback - Callback function with two parameters, 1st for returned widget data, 2nd for error * */ - this.getFeedbackWidgetData = function (CountlyFeedbackWidget, callback) { + getFeedbackWidgetData = (CountlyFeedbackWidget, callback) => { if (!CountlyFeedbackWidget.type) { - log(logLevelEnums.ERROR, "getFeedbackWidgetData, Expected the provided widget object to have a type but got: [" + JSON.stringify(CountlyFeedbackWidget) + "], aborting."); + this.#log(logLevelEnums.ERROR, "getFeedbackWidgetData, Expected the provided widget object to have a type but got: [" + JSON.stringify(CountlyFeedbackWidget) + "], aborting."); return; } - log(logLevelEnums.INFO, "getFeedbackWidgetData, Retrieving data for: [" + JSON.stringify(CountlyFeedbackWidget) + "], callback function is provided:[" + (!!callback) + "]"); + this.#log(logLevelEnums.INFO, "getFeedbackWidgetData, Retrieving data for: [" + JSON.stringify(CountlyFeedbackWidget) + "], callback function is provided:[" + (!!callback) + "]"); if (!this.check_consent(featureEnums.FEEDBACK)) { if (callback) { callback(null, new Error("Consent for feedback not provided.")); @@ -3018,8 +3080,8 @@ constructor(ob) { return; } - if (offlineMode) { - log(logLevelEnums.ERROR, "getFeedbackWidgetData, Cannot enable feedback widgets in offline mode."); + if (this.#offlineMode) { + this.#log(logLevelEnums.ERROR, "getFeedbackWidgetData, Cannot enable feedback widgets in offline mode."); return; } @@ -3027,8 +3089,8 @@ constructor(ob) { var data = { widget_id: CountlyFeedbackWidget._id, shown: 1, - sdk_version: sdkVersion, - sdk_name: sdkName, + sdk_version: this.#sdkVersion, + sdk_name: this.#sdkName, platform: this.platform, app_version: this.app_version }; @@ -3043,11 +3105,11 @@ constructor(ob) { url += "/o/surveys/rating/widget"; } else { - log(logLevelEnums.ERROR, "getFeedbackWidgetData, Unknown type info: [" + CountlyFeedbackWidget.type + "]"); + this.#log(logLevelEnums.ERROR, "getFeedbackWidgetData, Unknown type info: [" + CountlyFeedbackWidget.type + "]"); return; } - makeNetworkRequest("getFeedbackWidgetData,", url, data, responseCallback, true); + this.#makeNetworkRequest("getFeedbackWidgetData,", url, data, responseCallback, true); /** * Server response would be evaluated here @@ -3055,7 +3117,7 @@ constructor(ob) { * @param {*} params - parameters * @param {*} responseText - server reponse text */ - function responseCallback(err, params, responseText) { + var responseCallback = (err, params, responseText) => { if (err) { // error has been logged by the request function if (callback) { @@ -3072,7 +3134,7 @@ constructor(ob) { } } catch (error) { - log(logLevelEnums.ERROR, "getFeedbackWidgetData, Error while parsing feedback widgets list: " + error); + this.#log(logLevelEnums.ERROR, "getFeedbackWidgetData, Error while parsing feedback widgets list: " + error); if (callback) { callback(null, error); } @@ -3087,13 +3149,13 @@ constructor(ob) { * @param {String} [className] - Class name to append the feedback widget (optional, in case not used pass undefined) * @param {Object} [feedbackWidgetSegmentation] - Segmentation object to be passed to the feedback widget (optional) * */ - this.present_feedback_widget = function (presentableFeedback, id, className, feedbackWidgetSegmentation) { + present_feedback_widget = (presentableFeedback, id, className, feedbackWidgetSegmentation) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "present_feedback_widget, window object is not available. Not presenting feedback widget."); + this.#log(logLevelEnums.WARNING, "present_feedback_widget, window object is not available. Not presenting feedback widget."); return; } // TODO: feedbackWidgetSegmentation implementation only assumes we want to send segmentation data. Change it if we add more data to the custom object. - log(logLevelEnums.INFO, "present_feedback_widget, Presenting the feedback widget by appending to the element with ID: [ " + id + " ] and className: [ " + className + " ]"); + this.#log(logLevelEnums.INFO, "present_feedback_widget, Presenting the feedback widget by appending to the element with ID: [ " + id + " ] and className: [ " + className + " ]"); if (!this.check_consent(featureEnums.FEEDBACK)) { return; @@ -3103,13 +3165,13 @@ constructor(ob) { || (typeof presentableFeedback !== "object") || Array.isArray(presentableFeedback) ) { - log(logLevelEnums.ERROR, "present_feedback_widget, Please provide at least one feedback widget object."); + this.#log(logLevelEnums.ERROR, "present_feedback_widget, Please provide at least one feedback widget object."); return; } - log(logLevelEnums.INFO, "present_feedback_widget, Adding segmentation to feedback widgets:[" + JSON.stringify(feedbackWidgetSegmentation) + "]"); + this.#log(logLevelEnums.INFO, "present_feedback_widget, Adding segmentation to feedback widgets:[" + JSON.stringify(feedbackWidgetSegmentation) + "]"); if (!feedbackWidgetSegmentation || typeof feedbackWidgetSegmentation !== "object" || Object.keys(feedbackWidgetSegmentation).length === 0) { - log(logLevelEnums.DEBUG, "present_feedback_widget, Segmentation is not an object or empty"); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Segmentation is not an object or empty"); feedbackWidgetSegmentation = null; } @@ -3117,19 +3179,19 @@ constructor(ob) { var url = this.url; if (presentableFeedback.type === "nps") { - log(logLevelEnums.DEBUG, "present_feedback_widget, Widget type: nps."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Widget type: nps."); url += "/feedback/nps"; } else if (presentableFeedback.type === "survey") { - log(logLevelEnums.DEBUG, "present_feedback_widget, Widget type: survey."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Widget type: survey."); url += "/feedback/survey"; } else if (presentableFeedback.type === "rating") { - log(logLevelEnums.DEBUG, "present_feedback_widget, Widget type: rating."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Widget type: rating."); url += "/feedback/rating"; } else { - log(logLevelEnums.ERROR, "present_feedback_widget, Feedback widget only accepts nps, rating and survey types."); + this.#log(logLevelEnums.ERROR, "present_feedback_widget, Feedback widget only accepts nps, rating and survey types."); return; } @@ -3138,14 +3200,14 @@ constructor(ob) { // set feedback widget family as ratings and load related style file when type is ratings if (presentableFeedback.type === "rating") { - log(logLevelEnums.DEBUG, "present_feedback_widget, Loading css for rating widget."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Loading css for rating widget."); feedbackWidgetFamily = "ratings"; loadCSS(this.url + "/star-rating/stylesheets/countly-feedback-web.css"); } // if it's not ratings, it means we need to name it as surveys and load related style file // (at least until we add new type in future) else { - log(logLevelEnums.DEBUG, "present_feedback_widget, Loading css for survey or nps."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Loading css for survey or nps."); loadCSS(this.url + "/surveys/stylesheets/countly-surveys.css"); feedbackWidgetFamily = "surveys"; } @@ -3153,10 +3215,10 @@ constructor(ob) { url += "?widget_id=" + presentableFeedback._id; url += "&app_key=" + this.app_key; url += "&device_id=" + this.device_id; - url += "&sdk_name=" + sdkName; + url += "&sdk_name=" + this.#sdkName; url += "&platform=" + this.platform; url += "&app_version=" + this.app_version; - url += "&sdk_version=" + sdkVersion; + url += "&sdk_version=" + this.#sdkVersion; var customObjectToSendWithTheWidget = {}; customObjectToSendWithTheWidget.tc = 1; // indicates SDK supports opening links from the widget in a new tab if (feedbackWidgetSegmentation) { @@ -3174,7 +3236,7 @@ constructor(ob) { iframe.id = "countly-" + feedbackWidgetFamily + "-iframe"; var initiated = false; - iframe.onload = function () { + iframe.onload = () => { // This is used as a fallback for browsers where postMessage API doesn't work. if (initiated) { @@ -3189,7 +3251,7 @@ constructor(ob) { // Any subsequent onload means that the survey is being refreshed or reset. // This time hide it as being done in the above check. initiated = true; - log(logLevelEnums.DEBUG, "present_feedback_widget, Loaded iframe."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Loaded iframe."); }; var overlay = document.getElementById("csbg"); @@ -3197,14 +3259,14 @@ constructor(ob) { // Remove any existing overlays overlay.remove(); overlay = document.getElementById("csbg"); - log(logLevelEnums.DEBUG, "present_feedback_widget, Removing past overlay."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Removing past overlay."); } var wrapper = document.getElementsByClassName("countly-" + feedbackWidgetFamily + "-wrapper"); for (var i = 0; i < wrapper.length; i++) { // Remove any existing feedback wrappers wrapper[i].remove(); - log(logLevelEnums.DEBUG, "present_feedback_widget, Removed a wrapper."); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Removed a wrapper."); } wrapper = document.createElement("div"); @@ -3225,7 +3287,7 @@ constructor(ob) { found = true; } else { - log(logLevelEnums.ERROR, "present_feedback_widget, Provided ID not found."); + this.#log(logLevelEnums.ERROR, "present_feedback_widget, Provided ID not found."); } } @@ -3236,7 +3298,7 @@ constructor(ob) { element = document.getElementsByClassName(className)[0]; } else { - log(logLevelEnums.ERROR, "present_feedback_widget, Provided class not found."); + this.#log(logLevelEnums.ERROR, "present_feedback_widget, Provided class not found."); } } } @@ -3249,30 +3311,30 @@ constructor(ob) { ratingsOverlay.className = "countly-ratings-overlay"; ratingsOverlay.id = "countly-ratings-overlay-" + presentableFeedback._id; wrapper.appendChild(ratingsOverlay); - log(logLevelEnums.DEBUG, "present_feedback_widget, appended the rating overlay to wrapper"); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, appended the rating overlay to wrapper"); // add an event listener for the overlay // so if someone clicked on the overlay, we can close popup - add_event_listener(document.getElementById("countly-ratings-overlay-" + presentableFeedback._id), "click", function () { + add_event_listener(document.getElementById("countly-ratings-overlay-" + presentableFeedback._id), "click", () => { document.getElementById("countly-ratings-wrapper-" + presentableFeedback._id).style.display = "none"; }); } wrapper.appendChild(iframe); - log(logLevelEnums.DEBUG, "present_feedback_widget, Appended the iframe"); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Appended the iframe"); - add_event_listener(window, "message", function (e) { + add_event_listener(window, "message", (e) => { var data = {}; try { data = JSON.parse(e.data); - log(logLevelEnums.DEBUG, "present_feedback_widget, Parsed response message " + data); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Parsed response message " + data); } catch (ex) { - log(logLevelEnums.ERROR, "present_feedback_widget, Error while parsing message body " + ex); + this.#log(logLevelEnums.ERROR, "present_feedback_widget, Error while parsing message body " + ex); } if (!data.close) { - log(logLevelEnums.DEBUG, "present_feedback_widget, Closing signal not sent yet"); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Closing signal not sent yet"); return; } @@ -3293,7 +3355,7 @@ constructor(ob) { } } else { - add_event_listener(document, "readystatechange", function (e) { + add_event_listener(document, "readystatechange", (e) => { if (e.target.readyState === "complete") { if (!surveyShown) { surveyShown = true; @@ -3306,7 +3368,7 @@ constructor(ob) { break; case "afterConstantDelay": - setTimeout(function () { + setTimeout(() => { if (!surveyShown) { surveyShown = true; showSurvey(presentableFeedback); @@ -3317,7 +3379,7 @@ constructor(ob) { case "onAbandon": if (document.readyState === "complete") { - add_event_listener(document, "mouseleave", function () { + add_event_listener(document, "mouseleave", () => { if (!surveyShown) { surveyShown = true; showSurvey(presentableFeedback); @@ -3325,9 +3387,9 @@ constructor(ob) { }); } else { - add_event_listener(document, "readystatechange", function (e) { + add_event_listener(document, "readystatechange", (e) => { if (e.target.readyState === "complete") { - add_event_listener(document, "mouseleave", function () { + add_event_listener(document, "mouseleave", () => { if (!surveyShown) { surveyShown = true; showSurvey(presentableFeedback); @@ -3340,7 +3402,7 @@ constructor(ob) { break; case "onScrollHalfwayDown": - add_event_listener(window, "scroll", function () { + add_event_listener(window, "scroll", () => { if (!surveyShown) { var scrollY = Math.max(window.scrollY, document.body.scrollTop, document.documentElement.scrollTop); var documentHeight = getDocHeight(); @@ -3374,7 +3436,7 @@ constructor(ob) { } } else { - add_event_listener(document, "readystatechange", function (e) { + add_event_listener(document, "readystatechange", (e) => { if (e.target.readyState === "complete") { if (!ratingShown) { ratingShown = true; @@ -3386,14 +3448,14 @@ constructor(ob) { } } catch (e) { - log(logLevelEnums.ERROR, "present_feedback_widget, Something went wrong while presenting the widget: " + e); + this.#log(logLevelEnums.ERROR, "present_feedback_widget, Something went wrong while presenting the widget: " + e); } /** * Function to show survey popup * @param {Object} feedback - feedback object */ - function showSurvey(feedback) { + var showSurvey = (feedback) => { document.getElementById("countly-surveys-wrapper-" + feedback._id).style.display = "block"; document.getElementById("csbg").style.display = "block"; } @@ -3402,17 +3464,17 @@ constructor(ob) { * Function to prepare rating sticker and feedback widget * @param {Object} feedback - feedback object */ - function showRatingForFeedbackWidget(feedback) { + var showRatingForFeedbackWidget = (feedback) => { // remove old stickers if exists var stickers = document.getElementsByClassName("countly-feedback-sticker"); while (stickers.length > 0) { - log(logLevelEnums.VERBOSE, "present_feedback_widget, Removing old stickers"); + this.#log(logLevelEnums.VERBOSE, "present_feedback_widget, Removing old stickers"); stickers[0].remove(); } // render sticker if hide sticker property isn't set if (!feedback.appearance.hideS) { - log(logLevelEnums.DEBUG, "present_feedback_widget, handling the sticker as it was not set to hidden"); + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, handling the sticker as it was not set to hidden"); // create sticker wrapper element var sticker = document.createElement("div"); sticker.innerText = feedback.appearance.text; @@ -3423,7 +3485,7 @@ constructor(ob) { document.body.appendChild(sticker); // sticker event handler - add_event_listener(document.getElementById("countly-feedback-sticker-" + feedback._id), "click", function () { + add_event_listener(document.getElementById("countly-feedback-sticker-" + feedback._id), "click", () => { document.getElementById("countly-ratings-wrapper-" + feedback._id).style.display = "flex"; document.getElementById("csbg").style.display = "block"; }); @@ -3431,7 +3493,7 @@ constructor(ob) { // feedback widget close event handler // TODO: Check if this is still valid - add_event_listener(document.getElementById("countly-feedback-close-icon-" + feedback._id), "click", function () { + add_event_listener(document.getElementById("countly-feedback-close-icon-" + feedback._id), "click", () => { document.getElementById("countly-ratings-wrapper-" + feedback._id).style.display = "none"; document.getElementById("csbg").style.display = "none"; }); @@ -3444,11 +3506,11 @@ constructor(ob) { * @param {Boolean} nonfatal - nonfatal if true and false if fatal * @param {Object} segments - custom crash segments */ - this.recordError = function (err, nonfatal, segments) { - log(logLevelEnums.INFO, "recordError, Recording error"); + recordError = (err, nonfatal, segments) => { + this.#log(logLevelEnums.INFO, "recordError, Recording error"); if (this.check_consent(featureEnums.CRASHES) && err) { // crashSegments, if not null, was set while enabling error tracking - segments = segments || crashSegments; + segments = segments || this.#crashSegments; var error = ""; if (typeof err === "object") { if (typeof err.stack !== "undefined") { @@ -3476,18 +3538,18 @@ constructor(ob) { error = err + ""; } // character limit check - if (error.length > (self.maxStackTraceLineLength * self.maxStackTraceLinesPerThread)) { - log(logLevelEnums.DEBUG, "record_error, Error stack is too long will be truncated"); + if (error.length > (this.maxStackTraceLineLength * this.maxStackTraceLinesPerThread)) { + this.#log(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 > self.maxStackTraceLinesPerThread) { - splittedError = splittedError.splice(0, self.maxStackTraceLinesPerThread); + if (splittedError.length > this.maxStackTraceLinesPerThread) { + splittedError = splittedError.splice(0, this.maxStackTraceLinesPerThread); } // trim each line to a given limit for (var i = 0, len = splittedError.length; i < len; i++) { - if (splittedError[i].length > self.maxStackTraceLineLength) { - splittedError[i] = splittedError[i].substring(0, self.maxStackTraceLineLength); + if (splittedError[i].length > this.maxStackTraceLineLength) { + splittedError[i] = splittedError[i].substring(0, this.maxStackTraceLineLength); } } // turn modified array back into error string @@ -3495,8 +3557,8 @@ constructor(ob) { } nonfatal = !!(nonfatal); - var metrics = getMetrics(); - var obj = { _resolution: metrics._resolution, _error: error, _app_version: metrics._app_version, _run: getTimestamp() - startTime }; + var metrics = this.#getMetrics(); + var obj = { _resolution: metrics._resolution, _error: error, _app_version: metrics._app_version, _run: getTimestamp() - this.#startTime }; obj._not_os_specific = true; obj._javascript = true; @@ -3514,10 +3576,10 @@ constructor(ob) { obj._background = !(document.hasFocus()); } - if (crashLogs.length > 0) { - obj._logs = crashLogs.join("\n"); + if (this.#crashLogs.length > 0) { + obj._logs = this.#crashLogs.join("\n"); } - crashLogs = []; + this.#crashLogs = []; obj._nonfatal = nonfatal; @@ -3525,7 +3587,7 @@ constructor(ob) { if (typeof segments !== "undefined") { // truncate custom crash segment's key value pairs - segments = truncateObject(segments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "record_error", log); + segments = truncateObject(segments, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "record_error", this.#log); obj._custom = segments; } @@ -3535,7 +3597,7 @@ constructor(ob) { obj._opengl = gl.getParameter(gl.VERSION); } catch (ex) { - log(logLevelEnums.ERROR, "Could not get the experimental-webgl context: " + ex); + this.#log(logLevelEnums.ERROR, "Could not get the experimental-webgl context: " + ex); } // send userAgent string with the crash object incase it gets removed by a gateway @@ -3543,34 +3605,34 @@ constructor(ob) { req.crash = JSON.stringify(obj); req.metrics = JSON.stringify({ _ua: metrics._ua }); - toRequestQueue(req); + this.#toRequestQueue(req); } }; /** * Check if user or visit should be ignored */ - function checkIgnore() { - log(logLevelEnums.INFO, "checkIgnore, Checking if user or visit should be ignored"); - if (self.ignore_prefetch && isBrowser && typeof document.visibilityState !== "undefined" && document.visibilityState === "prerender") { - self.ignore_visitor = true; - log(logLevelEnums.DEBUG, "checkIgnore, Ignoring visit due to prerendering"); + #checkIgnore = () => { + this.#log(logLevelEnums.INFO, "checkIgnore, Checking if user or visit should be ignored"); + if (this.ignore_prefetch && isBrowser && typeof document.visibilityState !== "undefined" && document.visibilityState === "prerender") { + this.ignore_visitor = true; + this.#log(logLevelEnums.DEBUG, "checkIgnore, Ignoring visit due to prerendering"); } - if (self.ignore_bots && userAgentSearchBotDetection()) { - self.ignore_visitor = true; - log(logLevelEnums.DEBUG, "checkIgnore, Ignoring visit due to bot"); + if (this.ignore_bots && userAgentSearchBotDetection()) { + this.ignore_visitor = true; + this.#log(logLevelEnums.DEBUG, "checkIgnore, Ignoring visit due to bot"); } } /** * Check and send the events to request queue if there are any, empty the event queue */ - function sendEventsForced() { - if (eventQueue.length > 0) { - log(logLevelEnums.DEBUG, "Flushing events"); - toRequestQueue({ events: JSON.stringify(eventQueue) }); - eventQueue = []; - setValueInStorage("cly_event", eventQueue); + #sendEventsForced = () => { + if (this.#eventQueue.length > 0) { + this.#log(logLevelEnums.DEBUG, "Flushing events"); + this.#toRequestQueue({ events: JSON.stringify(this.#eventQueue) }); + this.#eventQueue = []; + this.#setValueInStorage("cly_event", this.#eventQueue); } } @@ -3579,15 +3641,15 @@ constructor(ob) { * @param {Object} currentWidget - widget object * @param {Boolean} hasSticker - if widget has sticker */ - function processWidget(currentWidget, hasSticker) { + #processWidget = (currentWidget, hasSticker) => { if (!isBrowser) { - log(logLevelEnums.WARNING, "processWidget, window object is not available. Not processing widget."); + this.#log(logLevelEnums.WARNING, "processWidget, window object is not available. Not processing widget."); return; } // prevent widget create process if widget exist with same id var isDuplicate = !!document.getElementById("countly-feedback-sticker-" + currentWidget._id); if (isDuplicate) { - log(logLevelEnums.ERROR, "Widget with same ID exists"); + this.#log(logLevelEnums.ERROR, "Widget with same ID exists"); return; } try { @@ -3605,12 +3667,12 @@ constructor(ob) { var iframe = document.createElement("iframe"); iframe.name = "countly-feedback-iframe"; iframe.id = "countly-feedback-iframe"; - iframe.src = self.url + "/feedback?widget_id=" + currentWidget._id + "&app_key=" + self.app_key + "&device_id=" + self.device_id + "&sdk_version=" + sdkVersion; + iframe.src = this.url + "/feedback?widget_id=" + currentWidget._id + "&app_key=" + this.app_key + "&device_id=" + this.device_id + "&sdk_version=" + this.#sdkVersion; // inject them to dom document.body.appendChild(wrapper); wrapper.appendChild(closeIcon); wrapper.appendChild(iframe); - add_event_listener(document.getElementById("countly-feedback-close-icon-" + currentWidget._id), "click", function () { + add_event_listener(document.getElementById("countly-feedback-close-icon-" + currentWidget._id), "click", () => { document.getElementById("countly-iframe-wrapper-" + currentWidget._id).style.display = "none"; document.getElementById("cfbg").style.display = "none"; }); @@ -3647,7 +3709,7 @@ constructor(ob) { if (smileySvg) { smileySvg.style.fill = ((currentWidget.trigger_font_color.length < 7) ? "#" + currentWidget.trigger_font_color : currentWidget.trigger_font_color); } - add_event_listener(document.getElementById("countly-feedback-sticker-" + currentWidget._id), "click", function () { + add_event_listener(document.getElementById("countly-feedback-sticker-" + currentWidget._id), "click", () => { document.getElementById("countly-iframe-wrapper-" + currentWidget._id).style.display = "block"; document.getElementById("cfbg").style.display = "block"; }); @@ -3658,23 +3720,23 @@ constructor(ob) { } } catch (e) { - log(logLevelEnums.ERROR, "Somethings went wrong while element injecting process: " + e); + this.#log(logLevelEnums.ERROR, "Somethings went wrong while element injecting process: " + e); } } /** * Notify all waiting callbacks that script was loaded and instance created */ - function notifyLoaders() { + #notifyLoaders = () => { // notify load waiters var i; - if (typeof self.onload !== "undefined" && self.onload.length > 0) { - for (i = 0; i < self.onload.length; i++) { - if (typeof self.onload[i] === "function") { - self.onload[i](self); + if (typeof this.onload !== "undefined" && this.onload.length > 0) { + for (i = 0; i < this.onload.length; i++) { + if (typeof this.onload[i] === "function") { + this.onload[i](self); } } - self.onload = []; + this.onload = []; } } @@ -3682,21 +3744,24 @@ constructor(ob) { * Report duration of how long user was on this view * @memberof Countly._internals */ - function reportViewDuration() { - if (lastView) { - var segments = { - name: lastView - }; + #reportViewDuration = () => { + if (!this.#lastView) { + this.#log(logLevelEnums.INFO, "reportViewDuration, No last view, will not report view duration"); + return; + } + this.#log(logLevelEnums.INFO, "reportViewDuration, Reporting view duration for: [" + this.#lastView + "]"); + var segments = { + name: this.#lastView + }; - // track pageview - if (self.check_consent(featureEnums.VIEWS)) { - add_cly_events({ - key: internalEventKeyEnums.VIEW, - dur: (trackTime) ? getTimestamp() - lastViewTime : lastViewStoredDuration, - segmentation: segments - }, currentViewId); - lastView = null; - } + // track pageview + if (this.check_consent(featureEnums.VIEWS)) { + this.#add_cly_events({ + key: internalEventKeyEnums.VIEW, + dur: (this.#trackTime) ? getTimestamp() - this.#lastViewTime : this.#lastViewStoredDuration, + segmentation: segments + }, this.#currentViewId); + this.#lastView = null; } } @@ -3705,38 +3770,43 @@ constructor(ob) { * @memberof Countly._internals * @returns {String} view name */ - function getLastView() { - return lastView; + #getLastView = () => { + this.#log(logLevelEnums.INFO, "getLastView, Getting last view: [" + this.#lastView + "]"); + return this.#lastView; } /** * Extend session's cookie's time */ - function extendSession() { - if (useSessionCookie) { - // if session expired, we should start a new one - var expire = getValueFromStorage("cly_session"); - if (!expire || parseInt(expire) <= getTimestamp()) { - sessionStarted = false; - self.begin_session(!autoExtend); - } - setValueInStorage("cly_session", getTimestamp() + (sessionCookieTimeout * 60)); + #extendSession = () => { + if (!this.#useSessionCookie) { + this.#log(logLevelEnums.DEBUG, "Will not extend the session as session cookie is disabled"); + return; } + this.#log(logLevelEnums.DEBUG, "Extending session"); + + // if session expired, we should start a new one + var expire = this.#getValueFromStorage("cly_session"); + if (!expire || parseInt(expire) <= getTimestamp()) { + this.#sessionStarted = false; + this.begin_session(!this.#autoExtend); + } + this.#setValueInStorage("cly_session", getTimestamp() + (this.#sessionCookieTimeout * 60)); } /** * Prepare request params by adding common properties to it * @param {Object} request - request object */ - function prepareRequest(request) { - request.app_key = self.app_key; - request.device_id = self.device_id; - request.sdk_name = sdkName; - request.sdk_version = sdkVersion; - request.t = deviceIdType; - request.av = self.app_version; - - var ua = getUA(); + #prepareRequest = (request) => { + request.app_key = this.app_key; + request.device_id = this.device_id; + request.sdk_name = this.#sdkName; + request.sdk_version = this.#sdkVersion; + request.t = this.#deviceIdType; + request.av = this.app_version; + + var ua = this.#getUA(); if (!request.metrics) { // if metrics not provided pass useragent with this event request.metrics = JSON.stringify({ _ua: ua }); } @@ -3748,17 +3818,17 @@ constructor(ob) { } } - if (self.check_consent(featureEnums.LOCATION)) { - if (self.country_code) { - request.country_code = self.country_code; + if (this.check_consent(featureEnums.LOCATION)) { + if (this.country_code) { + request.country_code = this.country_code; } - if (self.city) { - request.city = self.city; + if (this.city) { + request.city = this.city; } - if (self.ip_address !== null) { - request.ip_address = self.ip_address; + if (this.ip_address !== null) { + request.ip_address = this.ip_address; } } else { @@ -3777,25 +3847,25 @@ constructor(ob) { * @memberof Countly._internals * @param {Object} request - object with request parameters */ - function toRequestQueue(request) { - if (self.ignore_visitor) { - log(logLevelEnums.WARNING, "User is opt_out will ignore the request: " + request); + #toRequestQueue = (request) => { + if (this.ignore_visitor) { + this.#log(logLevelEnums.WARNING, "User is opt_out will ignore the request: " + request); return; } - if (!self.app_key || !self.device_id) { - log(logLevelEnums.ERROR, "app_key or device_id is missing ", self.app_key, self.device_id); + if (!this.app_key || !this.device_id) { + this.#log(logLevelEnums.ERROR, "app_key or device_id is missing ", this.app_key, this.device_id); return; } - prepareRequest(request); + this.#prepareRequest(request); - if (requestQueue.length > queueSize) { - requestQueue.shift(); + if (this.#requestQueue.length > this.#queueSize) { + this.#requestQueue.shift(); } - requestQueue.push(request); - setValueInStorage("cly_queue", requestQueue, true); + this.#requestQueue.push(request); + this.#setValueInStorage("cly_queue", this.#requestQueue, true); } /** @@ -3803,85 +3873,95 @@ constructor(ob) { * @memberof Countly._internals * @returns {void} void */ - function heartBeat() { - notifyLoaders(); + #heartBeat = () => { + this.#notifyLoaders(); // ignore bots - if (self.ignore_visitor) { - hasPulse = false; - log(logLevelEnums.WARNING, "User opt_out, no heartbeat"); + if (this.ignore_visitor) { + this.#hasPulse = false; + this.#log(logLevelEnums.WARNING, "User opt_out, no heartbeat"); return; } - hasPulse = true; + this.#hasPulse = true; // process queue - if (global && typeof Countly.q !== "undefined" && Countly.q.length > 0) { - processAsyncQueue(); + if (this.#global && typeof Countly.q !== "undefined" && Countly.q.length > 0) { + this.#processAsyncQueue(); } // extend session if needed - if (sessionStarted && autoExtend && trackTime) { + if (this.#sessionStarted && this.#autoExtend && this.#trackTime) { var last = getTimestamp(); - if (last - lastBeat > sessionUpdate) { - self.session_duration(last - lastBeat); - lastBeat = last; + if (last - this.#lastBeat > this.#sessionUpdate) { + this.session_duration(last - this.#lastBeat); + this.#lastBeat = last; // save health check logging counters if there are any - if (self.hcErrorCount > 0) { - setValueInStorage(healthCheckCounterEnum.errorCount, self.hcErrorCount); + if (this.hcErrorCount > 0) { + this.#setValueInStorage(healthCheckCounterEnum.errorCount, this.hcErrorCount); } - if (self.hcWarningCount > 0) { - setValueInStorage(healthCheckCounterEnum.warningCount, self.hcWarningCount); + if (this.hcWarningCount > 0) { + this.#setValueInStorage(healthCheckCounterEnum.warningCount, this.hcWarningCount); } } } // process event queue - if (eventQueue.length > 0 && !self.test_mode_eq) { - if (eventQueue.length <= maxEventBatch) { - toRequestQueue({ events: JSON.stringify(eventQueue) }); - eventQueue = []; + if (this.#eventQueue.length > 0 && !this.test_mode_eq) { + if (this.#eventQueue.length <= this.#maxEventBatch) { + this.#toRequestQueue({ events: JSON.stringify(this.#eventQueue) }); + this.#eventQueue = []; } else { - var events = eventQueue.splice(0, maxEventBatch); - toRequestQueue({ events: JSON.stringify(events) }); + var events = this.#eventQueue.splice(0, this.#maxEventBatch); + this.#toRequestQueue({ events: JSON.stringify(events) }); } - setValueInStorage("cly_event", eventQueue); + this.#setValueInStorage("cly_event", this.#eventQueue); } // process request queue with event queue - if (!offlineMode && requestQueue.length > 0 && readyToProcess && getTimestamp() > failTimeout) { - readyToProcess = false; - var params = requestQueue[0]; - params.rr = requestQueue.length; // added at 23.2.3. It would give the current length of the queue. That includes the current request. - log(logLevelEnums.DEBUG, "Processing request", params); - setValueInStorage("cly_queue", requestQueue, true); - if (!self.test_mode) { - makeNetworkRequest("send_request_queue", self.url + apiPath, params, function (err, parameters) { + if (!this.#offlineMode && this.#requestQueue.length > 0 && this.#readyToProcess && getTimestamp() > this.#failTimeout) { + this.#readyToProcess = false; + var params = this.#requestQueue[0]; + params.rr = this.#requestQueue.length; // added at 23.2.3. It would give the current length of the queue. That includes the current request. + this.#log(logLevelEnums.DEBUG, "Processing request", params); + this.#setValueInStorage("cly_queue", this.#requestQueue, true); + if (!this.test_mode) { + this.#makeNetworkRequest("send_request_queue", this.url + this.#apiPath, params, (err, parameters) => { if (err) { // error has been logged by the request function - failTimeout = getTimestamp() + failTimeoutAmount; + this.#failTimeout = getTimestamp() + this.#failTimeoutAmount; } else { // remove first item from queue - requestQueue.shift(); + this.#requestQueue.shift(); } - setValueInStorage("cly_queue", requestQueue, true); - readyToProcess = true; + this.#setValueInStorage("cly_queue", this.#requestQueue, true); + this.#readyToProcess = true; // expected response is only JSON object }, false); } } - setTimeout(heartBeat, beatInterval); + setTimeout(() => { + this.#heartBeat(); + }, this.#beatInterval); } + /** + * Returns generated requests for the instance for testing purposes + * @returns {Array} - Returns generated requests + */ + #getGeneratedRequests = () => { + return this.#generatedRequests; + }; + /** * Process queued calls * @memberof Countly._internals */ - function processAsyncQueue() { + #processAsyncQueue = () => { if (typeof Countly === "undefined" || typeof Countly.i === "undefined") { - log(logLevelEnums.DEBUG, "Countly is not finished initialization yet, will process the queue after initialization is done"); + this.#log(logLevelEnums.DEBUG, "Countly is not finished initialization yet, will process the queue after initialization is done"); return; } @@ -3889,7 +3969,7 @@ constructor(ob) { Countly.q = []; for (let i = 0; i < q.length; i++) { let req = q[i]; - log(logLevelEnums.DEBUG, "Processing queued calls:" + req); + this.#log(logLevelEnums.DEBUG, "Processing queued calls:" + req); if (typeof req === "function") { req(); } @@ -3904,7 +3984,7 @@ constructor(ob) { } } catch (error) { // possibly first init and no other instance - log(logLevelEnums.DEBUG, "No instance found for the provided key while processing async queue"); + this.#log(logLevelEnums.DEBUG, "No instance found for the provided key while processing async queue"); Countly.q.push(req); // return it back to queue and continue to the next one continue; } @@ -3929,10 +4009,10 @@ constructor(ob) { * @memberof Countly._internals * @returns {String} device id */ - function getStoredIdOrGenerateId() { - var storedDeviceId = getValueFromStorage("cly_id"); + #getStoredIdOrGenerateId = () => { + var storedDeviceId = this.#getValueFromStorage("cly_id"); if (storedDeviceId) { - deviceIdType = getValueFromStorage("cly_id_type"); + this.#deviceIdType = this.#getValueFromStorage("cly_id_type"); return storedDeviceId; } return generateUUID(); @@ -3944,7 +4024,7 @@ constructor(ob) { * @param {string} providedId - Id to check * @returns {Boolean} true if it is in UUID format */ - function isUUID(providedId) { + #isUUID = (providedId) => { return /[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-4[0-9a-fA-F]{3}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/.test(providedId); } @@ -3953,8 +4033,8 @@ constructor(ob) { * @memberof Countly._internals * @returns {string} returns userAgent string */ - function getUA() { - return self.metrics._ua || currentUserAgentString(); + #getUA = () => { + return this.metrics._ua || currentUserAgentString(); } /** @@ -3962,11 +4042,11 @@ constructor(ob) { * @memberof Countly._internals * @returns {Object} Metrics object */ - function getMetrics() { - var metrics = JSON.parse(JSON.stringify(self.metrics || {})); + #getMetrics = () => { + var metrics = JSON.parse(JSON.stringify(this.metrics || {})); // getting app version - metrics._app_version = metrics._app_version || self.app_version; + metrics._app_version = metrics._app_version || this.app_version; metrics._ua = metrics._ua || currentUserAgentString(); // getting resolution @@ -4004,11 +4084,11 @@ constructor(ob) { metrics._locale = metrics._locale || locale; } - if (isReferrerUsable()) { + if (this.#isReferrerUsable()) { metrics._store = metrics._store || document.referrer; } - log(logLevelEnums.DEBUG, "Got metrics", metrics); + this.#log(logLevelEnums.DEBUG, "Got metrics", metrics); return metrics; } @@ -4021,7 +4101,7 @@ constructor(ob) { * @param {string} customReferrer - custom referrer for testing * @returns {boolean} true if document.referrer is not empty string, undefined, current host or in the ignore list. */ - function isReferrerUsable(customReferrer) { + #isReferrerUsable = (customReferrer) => { if (!isBrowser) { return false; } @@ -4030,33 +4110,33 @@ constructor(ob) { // do not report referrer if it is empty string or undefined if (typeof referrer === "undefined" || referrer.length === 0) { - log(logLevelEnums.DEBUG, "Invalid referrer:[" + referrer + "], ignoring."); + this.#log(logLevelEnums.DEBUG, "Invalid referrer:[" + referrer + "], ignoring."); } else { // dissect the referrer (check urlParseRE's comments for more info on this process) var matches = urlParseRE.exec(referrer); // this can return null if (!matches) { - log(logLevelEnums.DEBUG, "Referrer is corrupt:[" + referrer + "], ignoring."); + this.#log(logLevelEnums.DEBUG, "Referrer is corrupt:[" + referrer + "], ignoring."); } else if (!matches[11]) { - log(logLevelEnums.DEBUG, "No path found in referrer:[" + referrer + "], ignoring."); + this.#log(logLevelEnums.DEBUG, "No path found in referrer:[" + referrer + "], ignoring."); } else if (matches[11] === window.location.hostname) { - log(logLevelEnums.DEBUG, "Referrer is current host:[" + referrer + "], ignoring."); + this.#log(logLevelEnums.DEBUG, "Referrer is current host:[" + referrer + "], ignoring."); } else { - if (ignoreReferrers && ignoreReferrers.length) { + if (this.#ignoreReferrers && this.#ignoreReferrers.length) { isReferrerLegit = true; - for (var k = 0; k < ignoreReferrers.length; k++) { - if (referrer.indexOf(ignoreReferrers[k]) >= 0) { - log(logLevelEnums.DEBUG, "Referrer in ignore list:[" + referrer + "], ignoring."); + for (var k = 0; k < this.#ignoreReferrers.length; k++) { + if (referrer.indexOf(this.#ignoreReferrers[k]) >= 0) { + this.#log(logLevelEnums.DEBUG, "Referrer in ignore list:[" + referrer + "], ignoring."); isReferrerLegit = false; break; } } } else { - log(logLevelEnums.DEBUG, "Valid referrer:[" + referrer + "]"); + this.#log(logLevelEnums.DEBUG, "Valid referrer:[" + referrer + "]"); isReferrerLegit = true; } } @@ -4071,15 +4151,15 @@ constructor(ob) { * @param {string} message - any string message * @memberof Countly._internals */ - function log(level, message) { - if (self.debug && typeof console !== "undefined") { + #log = (level, message, third) => { + if (this.debug && typeof console !== "undefined") { // parse the arguments into a string if it is an object - if (arguments[2] && typeof arguments[2] === "object") { - arguments[2] = JSON.stringify(arguments[2]); + if (third && typeof third === "object") { + third = JSON.stringify(third); } // append app_key to the start of the message if it is not the first instance (for multi instancing) - if (!global) { - message = "[" + self.app_key + "] " + message; + if (!this.#global) { + message = "[" + this.app_key + "] " + message; } // if the provided level is not a proper log level re-assign it as [DEBUG] if (!level) { @@ -4087,8 +4167,8 @@ constructor(ob) { } // append level, message and args var extraArguments = ""; - for (var i = 2; i < arguments.length; i++) { - extraArguments += arguments[i]; + if (third) { + extraArguments = " " + third; } // eslint-disable-next-line no-shadow var log = level + "[Countly] " + message + extraArguments; @@ -4096,12 +4176,12 @@ constructor(ob) { if (level === logLevelEnums.ERROR) { // eslint-disable-next-line no-console console.error(log); - HealthCheck.incrementErrorCount(); + this.#HealthCheck.incrementErrorCount(); } else if (level === logLevelEnums.WARNING) { // eslint-disable-next-line no-console console.warn(log); - HealthCheck.incrementWarningCount(); + this.#HealthCheck.incrementWarningCount(); } else if (level === logLevelEnums.INFO) { // eslint-disable-next-line no-console @@ -4128,12 +4208,13 @@ constructor(ob) { * @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 */ - function makeNetworkRequest(functionName, url, params, callback, useBroadResponseValidator) { + #makeNetworkRequest = (functionName, url, params, callback, useBroadResponseValidator) => { + this.#generatedRequests.push({ functionName: functionName, url: url, params: params}); if (!isBrowser) { - sendFetchRequest(functionName, url, params, callback, useBroadResponseValidator); + this.#sendFetchRequest(functionName, url, params, callback, useBroadResponseValidator); } else { - sendXmlHttpRequest(functionName, url, params, callback, useBroadResponseValidator); + this.#sendXmlHttpRequest(functionName, url, params, callback, useBroadResponseValidator); } } @@ -4146,15 +4227,15 @@ constructor(ob) { * @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 */ - function sendXmlHttpRequest(functionName, url, params, callback, useBroadResponseValidator) { + #sendXmlHttpRequest = (functionName, url, params, callback, useBroadResponseValidator) => { useBroadResponseValidator = useBroadResponseValidator || false; try { - log(logLevelEnums.DEBUG, "Sending XML HTTP request"); + this.#log(logLevelEnums.DEBUG, "Sending XML HTTP request"); var xhr = new XMLHttpRequest(); params = params || {}; - prepareParams(params, self.salt).then(saltedData => { + prepareParams(params, this.salt).then(saltedData => { var method = "POST"; - if (self.force_post || saltedData.length >= 2000) { + if (this.force_post || saltedData.length >= 2000) { method = "POST"; } if (method === "GET") { @@ -4164,35 +4245,35 @@ constructor(ob) { xhr.open("POST", url, true); xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); } - for (var header in self.headers) { - xhr.setRequestHeader(header, self.headers[header]); + for (var header in this.headers) { + xhr.setRequestHeader(header, this.headers[header]); } // fallback on error - xhr.onreadystatechange = function () { - if (this.readyState === 4) { - log(logLevelEnums.DEBUG, functionName + " HTTP request completed with status code: [" + this.status + "] and response: [" + this.responseText + "]"); + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + this.#log(logLevelEnums.DEBUG, functionName + " HTTP request completed with status code: [" + xhr.status + "] and response: [" + xhr.responseText + "]"); // response validation function will be selected to also accept JSON arrays if useBroadResponseValidator is true var isResponseValidated; if (useBroadResponseValidator) { // JSON array/object both can pass - isResponseValidated = isResponseValidBroad(this.status, this.responseText); + isResponseValidated = this.#isResponseValidBroad(xhr.status, xhr.responseText); } else { // only JSON object can pass - isResponseValidated = isResponseValid(this.status, this.responseText); + isResponseValidated = this.#isResponseValid(xhr.status, xhr.responseText); } if (isResponseValidated) { if (typeof callback === "function") { - callback(false, params, this.responseText); + callback(false, params, xhr.responseText); } } else { - log(logLevelEnums.ERROR, functionName + " Invalid response from server"); + this.#log(logLevelEnums.ERROR, functionName + " Invalid response from server"); if (functionName === "send_request_queue") { - HealthCheck.saveRequestCounters(this.status, this.responseText); + this.#HealthCheck.saveRequestCounters(xhr.status, xhr.responseText); } if (typeof callback === "function") { - callback(true, params, this.status, this.responseText); + callback(true, params, xhr.status, xhr.responseText); } } } @@ -4207,7 +4288,7 @@ constructor(ob) { } catch (e) { // fallback - log(logLevelEnums.ERROR, functionName + " Something went wrong while making an XML HTTP request: " + e); + this.#log(logLevelEnums.ERROR, functionName + " Something went wrong while making an XML HTTP request: " + e); if (typeof callback === "function") { callback(true, params); } @@ -4223,12 +4304,12 @@ constructor(ob) { * @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 */ - function sendFetchRequest(functionName, url, params, callback, useBroadResponseValidator) { + #sendFetchRequest = (functionName, url, params, callback, useBroadResponseValidator) => { useBroadResponseValidator = useBroadResponseValidator || false; var response; try { - log(logLevelEnums.DEBUG, "Sending Fetch request"); + this.#log(logLevelEnums.DEBUG, "Sending Fetch request"); // Prepare request options var method = "POST"; @@ -4236,8 +4317,8 @@ constructor(ob) { var body = null; params = params || {}; - prepareParams(params, self.salt).then(saltedData => { - if (self.force_post || saltedData.length >= 2000) { + prepareParams(params, this.salt).then(saltedData => { + if (this.force_post || saltedData.length >= 2000) { method = "POST"; body = saltedData; } @@ -4246,8 +4327,8 @@ constructor(ob) { } // Add custom headers - for (var header in self.headers) { - headers[header] = self.headers[header]; + for (var header in this.headers) { + headers[header] = this.headers[header]; } // Make the fetch request @@ -4255,17 +4336,17 @@ constructor(ob) { method: method, headers: headers, body: body, - }).then(function (res) { + }).then((res) => { response = res; return response.text(); - }).then(function (data) { - log(logLevelEnums.DEBUG, functionName + " Fetch request completed wit status code: [" + response.status + "] and response: [" + data + "]"); + }).then((data) => { + this.#log(logLevelEnums.DEBUG, functionName + " Fetch request completed wit status code: [" + response.status + "] and response: [" + data + "]"); var isResponseValidated; if (useBroadResponseValidator) { - isResponseValidated = isResponseValidBroad(response.status, data); + isResponseValidated = this.#isResponseValidBroad(response.status, data); } else { - isResponseValidated = isResponseValid(response.status, data); + isResponseValidated = this.#isResponseValid(response.status, data); } if (isResponseValidated) { @@ -4274,16 +4355,16 @@ constructor(ob) { } } else { - log(logLevelEnums.ERROR, functionName + " Invalid response from server"); + this.#log(logLevelEnums.ERROR, functionName + " Invalid response from server"); if (functionName === "send_request_queue") { - HealthCheck.saveRequestCounters(response.status, data); + this.#HealthCheck.saveRequestCounters(response.status, data); } if (typeof callback === "function") { callback(true, params, response.status, data); } } - }).catch(function (error) { - log(logLevelEnums.ERROR, functionName + " Failed Fetch request: " + error); + }).catch((error) => { + this.#log(logLevelEnums.ERROR, functionName + " Failed Fetch request: " + error); if (typeof callback === "function") { callback(true, params); } @@ -4292,7 +4373,7 @@ constructor(ob) { } catch (e) { // fallback - log(logLevelEnums.ERROR, functionName + " Something went wrong with the Fetch request attempt: " + e); + this.#log(logLevelEnums.ERROR, functionName + " Something went wrong with the Fetch request attempt: " + e); if (typeof callback === "function") { callback(true, params); } @@ -4308,10 +4389,10 @@ constructor(ob) { * @param {String} str - response from server, ideally must be: {"result":"Success"} or should contain at least result field * @returns {Boolean} - returns true if response passes the tests */ - function isResponseValid(statusCode, str) { + #isResponseValid = (statusCode, str) => { // status code and response format check if (!(statusCode >= 200 && statusCode < 300)) { - log(logLevelEnums.ERROR, "Http response status code:[" + statusCode + "] is not within the expected range"); + this.#log(logLevelEnums.ERROR, "Http response status code:[" + statusCode + "] is not within the expected range"); return false; } @@ -4321,14 +4402,14 @@ constructor(ob) { // check if parsed response is a JSON object, if not the response is not valid if (Object.prototype.toString.call(parsedResponse) !== "[object Object]") { - log(logLevelEnums.ERROR, "Http response is not JSON Object"); + this.#log(logLevelEnums.ERROR, "Http response is not JSON Object"); return false; } return !!(parsedResponse.result); } catch (e) { - log(logLevelEnums.ERROR, "Http response is not JSON: " + e); + this.#log(logLevelEnums.ERROR, "Http response is not JSON: " + e); return false; } } @@ -4342,10 +4423,10 @@ constructor(ob) { * @param {String} str - response from server, ideally must be: {"result":"Success"} or should contain at least result field * @returns {Boolean} - returns true if response passes the tests */ - function isResponseValidBroad(statusCode, str) { + #isResponseValidBroad = (statusCode, str) => { // status code and response format check if (!(statusCode >= 200 && statusCode < 300)) { - log(logLevelEnums.ERROR, "Http response status code:[" + statusCode + "] is not within the expected range"); + this.#log(logLevelEnums.ERROR, "Http response status code:[" + statusCode + "] is not within the expected range"); return false; } @@ -4354,7 +4435,7 @@ constructor(ob) { var parsedResponse = JSON.parse(str); // check if parsed response is a JSON object or JSON array, if not it is not valid if ((Object.prototype.toString.call(parsedResponse) !== "[object Object]") && (!Array.isArray(parsedResponse))) { - log(logLevelEnums.ERROR, "Http response is not JSON Object nor JSON Array"); + this.#log(logLevelEnums.ERROR, "Http response is not JSON Object nor JSON Array"); return false; } @@ -4362,7 +4443,7 @@ constructor(ob) { return true; } catch (e) { - log(logLevelEnums.ERROR, "Http response is not JSON: " + e); + this.#log(logLevelEnums.ERROR, "Http response is not JSON: " + e); return false; } } @@ -4372,44 +4453,44 @@ constructor(ob) { * @memberof Countly._internals * */ - function processScroll() { + #processScroll = () => { if (!isBrowser) { - log(logLevelEnums.WARNING, "processScroll, window object is not available. Not processing scroll."); + this.#log(logLevelEnums.WARNING, "processScroll, window object is not available. Not processing scroll."); return; } - scrollRegistryTopPosition = Math.max(scrollRegistryTopPosition, window.scrollY, document.body.scrollTop, document.documentElement.scrollTop); + this.#scrollRegistryTopPosition = Math.max(this.#scrollRegistryTopPosition, window.scrollY, document.body.scrollTop, document.documentElement.scrollTop); } /** * Process scroll data * @memberof Countly._internals */ - function processScrollView() { + #processScrollView = () => { if (!isBrowser) { - log(logLevelEnums.WARNING, "processScrollView, window object is not available. Not processing scroll view."); + this.#log(logLevelEnums.WARNING, "processScrollView, window object is not available. Not processing scroll view."); return; } - if (isScrollRegistryOpen) { - isScrollRegistryOpen = false; + if (this.#isScrollRegistryOpen) { + this.#isScrollRegistryOpen = false; var height = getDocHeight(); var width = getDocWidth(); var viewportHeight = getViewportHeight(); - if (self.check_consent(featureEnums.SCROLLS)) { + if (this.check_consent(featureEnums.SCROLLS)) { var segments = { type: "scroll", - y: scrollRegistryTopPosition + viewportHeight, + y: this.#scrollRegistryTopPosition + viewportHeight, width: width, height: height, - view: self.getViewUrl() + view: this.getViewUrl() }; // truncate new segment - segments = truncateObject(segments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "processScrollView", log); - if (self.track_domains) { + segments = truncateObject(segments, this.maxKeyLength, this.maxValueSize, this.maxSegmentationValues, "processScrollView", this.#log); + if (this.track_domains) { segments.domain = window.location.hostname; } - add_cly_events({ + this.#add_cly_events({ key: internalEventKeyEnums.ACTION, segmentation: segments }); @@ -4422,8 +4503,8 @@ constructor(ob) { * @memberof Countly._internals * @returns {String} token - auth token */ - function getInternalDeviceIdType() { - return deviceIdType; + #getInternalDeviceIdType = () => { + return this.#deviceIdType; } /** @@ -4431,8 +4512,8 @@ constructor(ob) { * @memberof Countly._internals * @param {String} token - auth token */ - function setToken(token) { - setValueInStorage("cly_token", token); + #setToken = (token) => { + this.#setValueInStorage("cly_token", token); } /** @@ -4440,9 +4521,9 @@ constructor(ob) { * @memberof Countly._internals * @returns {String} auth token */ - function getToken() { - var token = getValueFromStorage("cly_token"); - removeValueFromStorage("cly_token"); + #getToken = () => { + var token = this.#getValueFromStorage("cly_token"); + this.#removeValueFromStorage("cly_token"); return token; } @@ -4451,8 +4532,8 @@ constructor(ob) { * @memberof Countly._internals * @returns {Array} event queue */ - function getEventQueue() { - return eventQueue; + #getEventQueue = () => { + return this.#eventQueue; } /** @@ -4460,8 +4541,8 @@ constructor(ob) { * @memberof Countly._internals * @returns {Array} request queue */ - function getRequestQueue() { - return requestQueue; + #getRequestQueue = () => { + return this.#requestQueue; } /** @@ -4469,7 +4550,7 @@ constructor(ob) { * @param {String} cookieKey - The key, name or identifier for the cookie * @returns {Varies} stored value */ - function readCookie(cookieKey) { + #readCookie = (cookieKey) => { var cookieID = cookieKey + "="; // array of all cookies available var cookieArray = document.cookie.split(";"); @@ -4495,7 +4576,7 @@ constructor(ob) { * @param {String} cookieVal - Contents to store * @param {Number} exp - Expiration in days */ - function createCookie(cookieKey, cookieVal, exp) { + #createCookie = (cookieKey, cookieVal, exp) => { var date = new Date(); date.setTime(date.getTime() + (exp * 24 * 60 * 60 * 1000)); // TODO: If we offer the developer the ability to manipulate the expiration date in the future, this part must be reworked @@ -4511,39 +4592,39 @@ constructor(ob) { * @param {Boolean} useRawKey - if true, raw key will be used without any prefix * @returns {Varies} values stored for key */ - function getValueFromStorage(key, useLocalStorage, useRawKey) { + #getValueFromStorage = (key, useLocalStorage, useRawKey) => { // check if we should use storage at all. If in worker context but no storage is available, return early - if (self.storage === "none" || (typeof self.storage !== "object" && !isBrowser)) { - log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: [" + key + "] won't be retrieved"); + if (this.storage === "none" || (typeof this.storage !== "object" && !isBrowser)) { + this.#log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: [" + key + "] won't be retrieved"); return; } // apply namespace or app_key if (!useRawKey) { - key = self.app_key + "/" + key; - if (self.namespace) { - key = stripTrailingSlash(self.namespace) + "/" + key; + key = this.app_key + "/" + key; + if (this.namespace) { + key = stripTrailingSlash(this.namespace) + "/" + key; } } var data; // use dev provided storage if available - if (typeof self.storage === "object" && typeof self.storage.getItem === "function") { - data = self.storage.getItem(key); - return key.endsWith("cly_id") ? data : self.deserialize(data); + if (typeof this.storage === "object" && typeof this.storage.getItem === "function") { + data = this.storage.getItem(key); + return key.endsWith("cly_id") ? data : this.deserialize(data); } // developer set values takes priority if (useLocalStorage === undefined) { - useLocalStorage = lsSupport; + useLocalStorage = this.#lsSupport; } // Get value if (useLocalStorage) { // Native support data = localStorage.getItem(key); } - else if (self.storage !== "localstorage") { // Use cookie - data = readCookie(key); + else if (this.storage !== "localstorage") { // Use cookie + data = this.#readCookie(key); } // we return early without parsing if we are trying to get the device ID. This way we are keeping it as a string incase it was numerical. @@ -4551,7 +4632,7 @@ constructor(ob) { return data; } - return self.deserialize(data); + return this.deserialize(data); } /** @@ -4562,40 +4643,40 @@ constructor(ob) { * @param {Boolean} useLocalStorage - if false, will fallback to storing as cookies * @param {Boolean} useRawKey - if true, raw key will be used without any prefix */ - function setValueInStorage(key, value, useLocalStorage, useRawKey) { + #setValueInStorage = (key, value, useLocalStorage, useRawKey) => { // check if we should use storage options at all - if (self.storage === "none" || (typeof self.storage !== "object" && !isBrowser)) { - log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: " + key + " won't be stored"); + if (this.storage === "none" || (typeof this.storage !== "object" && !isBrowser)) { + this.#log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: " + key + " won't be stored"); return; } // apply namespace if (!useRawKey) { - key = self.app_key + "/" + key; - if (self.namespace) { - key = stripTrailingSlash(self.namespace) + "/" + key; + key = this.app_key + "/" + key; + if (this.namespace) { + key = stripTrailingSlash(this.namespace) + "/" + key; } } if (typeof value !== "undefined" && value !== null) { // use dev provided storage if available - if (typeof self.storage === "object" && typeof self.storage.setItem === "function") { - self.storage.setItem(key, value); + if (typeof this.storage === "object" && typeof this.storage.setItem === "function") { + this.storage.setItem(key, value); return; } // developer set values takes priority if (useLocalStorage === undefined) { - useLocalStorage = lsSupport; + useLocalStorage = this.#lsSupport; } - value = self.serialize(value); + value = this.serialize(value); // Set the store if (useLocalStorage) { // Native support localStorage.setItem(key, value); } - else if (self.storage !== "localstorage") { // Use Cookie - createCookie(key, value, 30); + else if (this.storage !== "localstorage") { // Use Cookie + this.#createCookie(key, value, 30); } } } @@ -4607,76 +4688,76 @@ constructor(ob) { * @param {Boolean} useLocalStorage - if false, will fallback to removing cookies * @param {Boolean} useRawKey - if true, raw key will be used without any prefix */ - function removeValueFromStorage(key, useLocalStorage, useRawKey) { + #removeValueFromStorage = (key, useLocalStorage, useRawKey) => { // check if we should use storage options at all - if (self.storage === "none" || (typeof self.storage !== "object" && !isBrowser)) { - log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: " + key + " won't be removed"); + if (this.storage === "none" || (typeof this.storage !== "object" && !isBrowser)) { + this.#log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: " + key + " won't be removed"); return; } // apply namespace if (!useRawKey) { - key = self.app_key + "/" + key; - if (self.namespace) { - key = stripTrailingSlash(self.namespace) + "/" + key; + key = this.app_key + "/" + key; + if (this.namespace) { + key = stripTrailingSlash(this.namespace) + "/" + key; } } // use dev provided storage if available - if (typeof self.storage === "object" && typeof self.storage.removeItem === "function") { - self.storage.removeItem(key); + if (typeof this.storage === "object" && typeof this.storage.removeItem === "function") { + this.storage.removeItem(key); return; } // developer set values takes priority if (useLocalStorage === undefined) { - useLocalStorage = lsSupport; + useLocalStorage = this.#lsSupport; } if (useLocalStorage) { // Native support localStorage.removeItem(key); } - else if (self.storage !== "localstorage") { // Use cookie - createCookie(key, "", -1); + else if (this.storage !== "localstorage") { // Use cookie + this.#createCookie(key, "", -1); } } /** * Migrate from old storage to new app_key prefixed storage */ - function migrate() { - if (getValueFromStorage(self.namespace + "cly_id", false, true)) { + #migrate = () => { + if (this.#getValueFromStorage(this.namespace + "cly_id", false, true)) { // old data exists, we should migrate it - setValueInStorage("cly_id", getValueFromStorage(self.namespace + "cly_id", false, true)); - setValueInStorage("cly_id_type", getValueFromStorage(self.namespace + "cly_id_type", false, true)); - setValueInStorage("cly_event", getValueFromStorage(self.namespace + "cly_event", false, true)); - setValueInStorage("cly_session", getValueFromStorage(self.namespace + "cly_session", false, true)); + this.#setValueInStorage("cly_id", this.#getValueFromStorage(this.namespace + "cly_id", false, true)); + this.#setValueInStorage("cly_id_type", this.#getValueFromStorage(this.namespace + "cly_id_type", false, true)); + this.#setValueInStorage("cly_event", this.#getValueFromStorage(this.namespace + "cly_event", false, true)); + this.#setValueInStorage("cly_session", this.#getValueFromStorage(this.namespace + "cly_session", false, true)); // filter out requests with correct app_key - var requests = getValueFromStorage(self.namespace + "cly_queue", false, true); + var requests = this.#getValueFromStorage(this.namespace + "cly_queue", false, true); if (Array.isArray(requests)) { - requests = requests.filter(function (req) { - return req.app_key === self.app_key; + requests = requests.filter((req) => { + return req.app_key === this.app_key; }); - setValueInStorage("cly_queue", requests); + this.#setValueInStorage("cly_queue", requests); } - if (getValueFromStorage(self.namespace + "cly_cmp_id", false, true)) { - setValueInStorage("cly_cmp_id", getValueFromStorage(self.namespace + "cly_cmp_id", false, true)); - setValueInStorage("cly_cmp_uid", getValueFromStorage(self.namespace + "cly_cmp_uid", false, true)); + if (this.#getValueFromStorage(this.namespace + "cly_cmp_id", false, true)) { + this.#setValueInStorage("cly_cmp_id", this.#getValueFromStorage(this.namespace + "cly_cmp_id", false, true)); + this.#setValueInStorage("cly_cmp_uid", this.#getValueFromStorage(this.namespace + "cly_cmp_uid", false, true)); } - if (getValueFromStorage(self.namespace + "cly_ignore", false, true)) { - setValueInStorage("cly_ignore", getValueFromStorage(self.namespace + "cly_ignore", false, true)); + if (this.#getValueFromStorage(this.namespace + "cly_ignore", false, true)) { + this.#setValueInStorage("cly_ignore", this.#getValueFromStorage(this.namespace + "cly_ignore", false, true)); } // now deleting old data, so we won't migrate again - removeValueFromStorage("cly_id", false, true); - removeValueFromStorage("cly_id_type", false, true); - removeValueFromStorage("cly_event", false, true); - removeValueFromStorage("cly_session", false, true); - removeValueFromStorage("cly_queue", false, true); - removeValueFromStorage("cly_cmp_id", false, true); - removeValueFromStorage("cly_cmp_uid", false, true); - removeValueFromStorage("cly_ignore", false, true); + this.#removeValueFromStorage("cly_id", false, true); + this.#removeValueFromStorage("cly_id_type", false, true); + this.#removeValueFromStorage("cly_event", false, true); + this.#removeValueFromStorage("cly_session", false, true); + this.#removeValueFromStorage("cly_queue", false, true); + this.#removeValueFromStorage("cly_cmp_id", false, true); + this.#removeValueFromStorage("cly_cmp_uid", false, true); + this.#removeValueFromStorage("cly_ignore", false, true); } } @@ -4685,43 +4766,64 @@ constructor(ob) { * @param {String} key - key of storage modified * @param {Varies} newValue - new value for storage */ - this.onStorageChange = function (key, newValue) { - log(logLevelEnums.DEBUG, "onStorageChange, Applying storage changes for key:", key); - log(logLevelEnums.DEBUG, "onStorageChange, Applying storage changes for value:", newValue); + #onStorageChange = (key, newValue) => { + this.#log(logLevelEnums.DEBUG, "onStorageChange, Applying storage changes for key:", key); + this.#log(logLevelEnums.DEBUG, "onStorageChange, Applying storage changes for value:", newValue); switch (key) { // queue of requests case "cly_queue": - requestQueue = self.deserialize(newValue || "[]"); + this.#requestQueue = this.deserialize(newValue || "[]"); break; // queue of events case "cly_event": - eventQueue = self.deserialize(newValue || "[]"); + this.#eventQueue = this.deserialize(newValue || "[]"); break; case "cly_remote_configs": - remoteConfigs = self.deserialize(newValue || "{}"); + this.#remoteConfigs = this.deserialize(newValue || "{}"); break; case "cly_ignore": - self.ignore_visitor = self.deserialize(newValue); + this.ignore_visitor = this.deserialize(newValue); break; case "cly_id": - self.device_id = newValue; + this.device_id = newValue; break; case "cly_id_type": - deviceIdType = self.deserialize(newValue); + this.#deviceIdType = this.deserialize(newValue); break; default: // do nothing } }; + /** + * Clear queued data for testing purposes + * @memberof Countly._internals + */ + #clearQueue = () => { + this.#requestQueue = []; + this.#setValueInStorage("cly_queue", []); + this.#eventQueue = []; + this.#setValueInStorage("cly_event", []); + }; + + /** + * For testing purposes only + * @returns {Object} - returns the local queues + */ + #getLocalQueues = () => { + return { + eventQ: this.#eventQueue, + requestQ: this.#requestQueue + }; + }; + /** * Expose internal methods to end user for usability * @namespace Countly._internals * @name Countly._internals */ - this._internals = { - // TODO: looks like we do not use this function. Either use it for something or eliminate. - store: setValueInStorage, + _internals = { + store: this.#setValueInStorage, getDocWidth: getDocWidth, getDocHeight: getDocHeight, getViewportHeight: getViewportHeight, @@ -4733,69 +4835,53 @@ constructor(ob) { truncateSingleValue: truncateSingleValue, stripTrailingSlash: stripTrailingSlash, prepareParams: prepareParams, - sendXmlHttpRequest: sendXmlHttpRequest, - isResponseValid: isResponseValid, - getInternalDeviceIdType: getInternalDeviceIdType, + sendXmlHttpRequest: this.#sendXmlHttpRequest, + isResponseValid: this.#isResponseValid, + getInternalDeviceIdType: this.#getInternalDeviceIdType, getMsTimestamp: getMsTimestamp, getTimestamp: getTimestamp, - isResponseValidBroad: isResponseValidBroad, + isResponseValidBroad: this.#isResponseValidBroad, secureRandom: secureRandom, - log: log, + log: this.#log, checkIfLoggingIsOn: checkIfLoggingIsOn, - getMetrics: getMetrics, - getUA: getUA, - prepareRequest: prepareRequest, + getMetrics: this.#getMetrics, + getUA: this.#getUA, + prepareRequest: this.#prepareRequest, generateUUID: generateUUID, - sendEventsForced: sendEventsForced, - isUUID: isUUID, + sendEventsForced: this.#sendEventsForced, + isUUID: this.#isUUID, calculateChecksum: calculateChecksum, - isReferrerUsable: isReferrerUsable, - getId: getStoredIdOrGenerateId, - heartBeat: heartBeat, - toRequestQueue: toRequestQueue, - reportViewDuration: reportViewDuration, + isReferrerUsable: this.#isReferrerUsable, + getId: this.#getStoredIdOrGenerateId, + heartBeat: this.#heartBeat, + toRequestQueue: this.#toRequestQueue, + reportViewDuration: this.#reportViewDuration, loadJS: loadJS, loadCSS: loadCSS, - getLastView: getLastView, - setToken: setToken, - getToken: getToken, + getLastView: this.#getLastView, + setToken: this.#setToken, + getToken: this.#getToken, showLoader: showLoader, hideLoader: hideLoader, - setValueInStorage: setValueInStorage, - getValueFromStorage: getValueFromStorage, - removeValueFromStorage: removeValueFromStorage, - add_cly_events: add_cly_events, - processScrollView: processScrollView, - processScroll: processScroll, + setValueInStorage: this.#setValueInStorage, + getValueFromStorage: this.#getValueFromStorage, + removeValueFromStorage: this.#removeValueFromStorage, + add_cly_events: this.#add_cly_events, + processScrollView: this.#processScrollView, + processScroll: this.#processScroll, currentUserAgentString: currentUserAgentString, currentUserAgentDataString: currentUserAgentDataString, userAgentDeviceDetection: userAgentDeviceDetection, userAgentSearchBotDetection: userAgentSearchBotDetection, - getRequestQueue: getRequestQueue, - getEventQueue: getEventQueue, - sendFetchRequest: sendFetchRequest, - processAsyncQueue: processAsyncQueue, - makeNetworkRequest: makeNetworkRequest, - /** - * Clear queued data - * @memberof Countly._internals - */ - clearQueue: function () { - requestQueue = []; - setValueInStorage("cly_queue", []); - eventQueue = []; - setValueInStorage("cly_event", []); - }, - /** - * For testing pusposes only - * @returns {Object} - returns the local queues - */ - getLocalQueues: function () { - return { - eventQ: eventQueue, - requestQ: requestQueue - }; - } + getRequestQueue: this.#getRequestQueue, + getEventQueue: this.#getEventQueue, + sendFetchRequest: this.#sendFetchRequest, + processAsyncQueue: this.#processAsyncQueue, + makeNetworkRequest: this.#makeNetworkRequest, + onStorageChange: this.#onStorageChange, + clearQueue: this.#clearQueue, + getLocalQueues: this.#getLocalQueues, + testingGetRequests: this.#getGeneratedRequests, }; /** @@ -4807,96 +4893,67 @@ constructor(ob) { * {resetCounters} Resets health check counters * {saveRequestCounters} Saves health check request counters */ - var HealthCheck = {}; - HealthCheck.sendInstantHCRequest = sendInstantHCRequest; - HealthCheck.resetAndSaveCounters = resetAndSaveCounters; - HealthCheck.incrementErrorCount = incrementErrorCount; - HealthCheck.incrementWarningCount = incrementWarningCount; - HealthCheck.resetCounters = resetCounters; - HealthCheck.saveRequestCounters = saveRequestCounters; - /** - * Increments health check error count - */ - function incrementErrorCount() { - self.hcErrorCount++; - } - /** - * Increments health check warning count - */ - function incrementWarningCount() { - self.hcWarningCount++; - } - /** - * Resets health check counters - */ - function resetCounters() { - self.hcErrorCount = 0; - self.hcWarningCount = 0; - self.hcStatusCode = -1; - self.hcErrorMessage = ""; - } - /** - * Sets and saves the status code and error message counters - * @param {number} status - response status code of the request - * @param {string} responseText - response text of the request - */ - function saveRequestCounters(status, responseText) { - self.hcStatusCode = status; - self.hcErrorMessage = responseText; - setValueInStorage(healthCheckCounterEnum.statusCode, self.hcStatusCode); - setValueInStorage(healthCheckCounterEnum.errorMessage, self.hcErrorMessage); - } - /** - * Resets and saves health check counters - */ - function resetAndSaveCounters() { - HealthCheck.resetCounters(); - setValueInStorage(healthCheckCounterEnum.errorCount, self.hcErrorCount); - setValueInStorage(healthCheckCounterEnum.warningCount, self.hcWarningCount); - setValueInStorage(healthCheckCounterEnum.statusCode, self.hcStatusCode); - setValueInStorage(healthCheckCounterEnum.errorMessage, self.hcErrorMessage); - } - /** - * Countly health check request sender - */ - function sendInstantHCRequest() { - if (offlineMode) { - log(logLevelEnums.DEBUG, "sendInstantHCRequest, Offline mode is active. Not sending health check request."); - shouldSendHC = true; - return; - } - // truncate error message to 1000 characters - var curbedMessage = truncateSingleValue(self.hcErrorMessage, 1000, "healthCheck", log); - // due to some server issues we pass empty string as is - if (curbedMessage !== "") { - curbedMessage = JSON.stringify(curbedMessage); - } - // prepare hc object - var hc = { - el: self.hcErrorCount, - wl: self.hcWarningCount, - sc: self.hcStatusCode, - em: curbedMessage - }; - // prepare request - var request = { - hc: JSON.stringify(hc), - metrics: JSON.stringify({ _app_version: self.app_version }) - }; - // add common request params - prepareRequest(request); - // send request - makeNetworkRequest("[healthCheck]", self.url + apiPath, request, function (err) { - // request maker already logs the error. No need to log it again here - if (!err) { - // reset and save health check counters if request was successful - HealthCheck.resetAndSaveCounters(); + #HealthCheck = { + sendInstantHCRequest: () => { + if (this.#offlineMode) { + this.#log(logLevelEnums.DEBUG, "sendInstantHCRequest, Offline mode is active. Not sending health check request."); + this.#shouldSendHC = true; + return; } - }, true); - } - - // initialize Countly Class - this.initialize(); - }; + // truncate error message to 1000 characters + var curbedMessage = truncateSingleValue(this.hcErrorMessage, 1000, "healthCheck", this.#log); + // due to some server issues we pass empty string as is + if (curbedMessage !== "") { + curbedMessage = JSON.stringify(curbedMessage); + } + // prepare hc object + var hc = { + el: this.hcErrorCount, + wl: this.hcWarningCount, + sc: this.hcStatusCode, + em: curbedMessage + }; + // prepare request + var request = { + hc: JSON.stringify(hc), + metrics: JSON.stringify({ _app_version: this.app_version }) + }; + // add common request params + this.#prepareRequest(request); + // send request + this.#makeNetworkRequest("[healthCheck]", this.url + this.#apiPath, request, (err) => { + // request maker already logs the error. No need to log it again here + if (!err) { + // reset and save health check counters if request was successful + this.#HealthCheck.resetAndSaveCounters(); + } + }, true); + }, + resetAndSaveCounters: () => { + this.#HealthCheck.resetCounters(); + this.#setValueInStorage(healthCheckCounterEnum.errorCount, this.hcErrorCount); + this.#setValueInStorage(healthCheckCounterEnum.warningCount, this.hcWarningCount); + this.#setValueInStorage(healthCheckCounterEnum.statusCode, this.hcStatusCode); + this.#setValueInStorage(healthCheckCounterEnum.errorMessage, this.hcErrorMessage); + }, + incrementErrorCount: () => { + this.hcErrorCount++; + }, + incrementWarningCount: () => { + this.hcWarningCount++; + }, + resetCounters: () => { + this.hcErrorCount = 0; + this.hcWarningCount = 0; + this.hcStatusCode = -1; + this.hcErrorMessage = ""; + }, + saveRequestCounters: (status, responseText) => { + this.hcStatusCode = status; + this.hcErrorMessage = responseText; + this.#setValueInStorage(healthCheckCounterEnum.statusCode, this.hcStatusCode); + this.#setValueInStorage(healthCheckCounterEnum.errorMessage, this.hcErrorMessage); + } + }; } export default CountlyClass; \ No newline at end of file diff --git a/modules/Utils.js b/modules/Utils.js index c9707b9..38ab8e2 100644 --- a/modules/Utils.js +++ b/modules/Utils.js @@ -585,25 +585,22 @@ function showLoader() { head.appendChild(style); loader = document.createElement("div"); loader.setAttribute("id", "cly-loader"); - document.body.onload = function () { - // check if hideLoader is on and if so return + window.addEventListener("load", () => { if (Countly.showLoaderProtection) { if (checkIfLoggingIsOn()) { - // eslint-disable-next-line no-console - console.warn("[WARNING] [Countly] showloader, Loader is already on"); + console.warn("[WARNING] [Countly] showLoader, Loader is already on"); } return; } try { document.body.appendChild(loader); - } - catch (e) { + } catch (e) { if (checkIfLoggingIsOn()) { - // eslint-disable-next-line no-console console.error("[ERROR] [Countly] showLoader, Body is not loaded for loader to append: " + e); } } - }; + }); + } loader.style.display = "block"; } From fab053bece948667c5c41a6c5940d063772971ec Mon Sep 17 00:00:00 2001 From: turtledreams <62231246+turtledreams@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:26:33 +0900 Subject: [PATCH 2/3] Refactor and content --- .gitignore | 4 + CHANGELOG.md | 8 + cypress.config.js | 11 +- cypress/e2e/sessions.cy.js | 23 +- cypress/e2e/web_worker_queues.cy.js | 7 +- cypress/fixtures/session_test_manual_1.html | 32 +- cypress/support/e2e.js | 1 + examples/example_opt_out.html | 84 - examples/example_rating_widgets.html | 62 - examples/examples_feedback_widgets.html | 2 +- modules/CountlyClass.js | 411 +++-- package-lock.json | 1772 ++++++++++++++++++- package.json | 6 +- 13 files changed, 2120 insertions(+), 303 deletions(-) delete mode 100644 examples/example_opt_out.html delete mode 100644 examples/example_rating_widgets.html diff --git a/.gitignore b/.gitignore index f1acec4..31dc032 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,8 @@ node_modules/ dist/ rollup.config.js Countly.d.ts +src/ +instrumented/ +coverage/ +.nyc_output/ ``` \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d348080..926ea10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 24.11.1 + +* Deprecated `initializeRatingWidgets` method, use `feedback.showRating` instead. +* Deprecated `enableRatingWidgets` method, use `feedback.showRating` instead. +* Added an interface `content` for Content feature methods: + * `enterContentZone`, to start Content checks (Experimental!) + * `exitContentZone`, to stop Content checks (Experimental!) + ## 24.11.0 * Mitigated an issue where SDK could try to send old stored offline mode data during init if `clear_stored_id` was true diff --git a/cypress.config.js b/cypress.config.js index 7fb2fb4..13700d1 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,9 +1,18 @@ import { defineConfig } from "cypress"; +import { createRequire } from "module"; + +const require = createRequire(import.meta.url); export default defineConfig({ e2e: { setupNodeEvents(on, config) { - // implement node event listeners here + const codeCoverageTask = require('@cypress/code-coverage/task'); + codeCoverageTask(on, config); + + // Include any other plugin code... + + // IMPORTANT: Return the config object with any changed environment variables + return config; }, }, userAgent: "abcd", diff --git a/cypress/e2e/sessions.cy.js b/cypress/e2e/sessions.cy.js index 1b47548..a3f8f6d 100644 --- a/cypress/e2e/sessions.cy.js +++ b/cypress/e2e/sessions.cy.js @@ -97,9 +97,7 @@ describe("Browser session tests, auto", () => { describe("Browser session tests, manual 1", () => { it("Single sessions test with manual sessions", () => { cy.visit("./cypress/fixtures/session_test_manual_1.html?use_session_cookie=true"); - cy.contains("Start").click().wait(waitTime); - cy.contains("Event").click().wait(300); - cy.contains("End").click().wait(300); + cy.wait(waitTime + 1000); cy.visit("./cypress/fixtures/base.html"); cy.fetch_local_request_queue(app_key).then((rq) => { cy.log(rq); @@ -109,10 +107,10 @@ describe("Browser session tests, manual 1", () => { cy.check_session(rq[0], undefined, undefined, app_key); // third object of the queue should be about session extension, also input the expected duration cy.check_session(rq[2], 5, undefined, app_key); - // fourth object of the queue should be about event sent - cy.check_event(JSON.parse(rq[3].events)[0], eventObj, undefined, false); // fifth object of the queue should be about session extension, also input the expected duration - cy.check_session(rq[4], 1, undefined, app_key); + cy.check_session(rq[3], 1, undefined, app_key); + // fourth object of the queue should be about event sent + cy.check_event(JSON.parse(rq[4].events)[0], eventObj, undefined, false); }); }); }); @@ -160,12 +158,7 @@ describe("Browser session tests, auto, no cookie", () => { describe("Browser session tests, manual 1, no cookie", () => { it("Single bounce test with manual sessions with no cookies", () => { cy.visit("./cypress/fixtures/session_test_manual_1.html"); - cy.contains("Start").click(); - cy.wait(waitTime); - cy.contains("Event").click(); - cy.wait(300); - cy.contains("End").click(); - cy.wait(300); + cy.wait(waitTime + 1000); cy.visit("./cypress/fixtures/base.html"); cy.fetch_local_request_queue(app_key).then((rq) => { cy.log(rq); @@ -175,10 +168,10 @@ describe("Browser session tests, manual 1, no cookie", () => { cy.check_session(rq[0], undefined, undefined, app_key); // third object of the queue should be about session extension, also input the expected duration cy.check_session(rq[2], 5, undefined, app_key); - // fourth object of the queue should be about event sent - cy.check_event(JSON.parse(rq[3].events)[0], eventObj, undefined, false); // fifth object of the queue should be about session extension, also input the expected duration - cy.check_session(rq[4], 1, true, app_key); + cy.check_session(rq[3], 1, true, app_key); + // fourth object of the queue should be about event sent + cy.check_event(JSON.parse(rq[4].events)[0], eventObj, undefined, false); }); }); }); diff --git a/cypress/e2e/web_worker_queues.cy.js b/cypress/e2e/web_worker_queues.cy.js index d612d86..1b6279f 100644 --- a/cypress/e2e/web_worker_queues.cy.js +++ b/cypress/e2e/web_worker_queues.cy.js @@ -18,16 +18,17 @@ describe("Web Worker Local Queue Tests", () => { requestQueue = e.data.requestQ; // Array of requests eventQueue = e.data.eventQ; // Array of events myWorker.terminate(); // terminate worker - + }; + cy.wait(3000).then(() => { // verify event queue expect(eventQueue.length).to.equal(2); cy.check_event(eventQueue[0], { key: "key" }, undefined, false); cy.check_view_event(eventQueue[1], "home_page", undefined, false); - + // verify request queue expect(requestQueue.length).to.equal(2); cy.check_session(requestQueue[0], undefined, false, false, true); cy.check_session(requestQueue[1], 0, false, false, false); - }; + }); }); }); \ No newline at end of file diff --git a/cypress/fixtures/session_test_manual_1.html b/cypress/fixtures/session_test_manual_1.html index 2f7fa41..4d135b0 100644 --- a/cypress/fixtures/session_test_manual_1.html +++ b/cypress/fixtures/session_test_manual_1.html @@ -32,28 +32,20 @@ use_session_cookie: confObj.use_session_cookie || false, debug:true }) + Countly.begin_session(); + setTimeout(() => { + Countly.add_event({ + key: "buttonClick", + "segmentation": { + "id": "id" + } + }); + Countly.end_session(undefined, true); + }, 7000); + + - - - - - diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js index 0e7290a..8b1a673 100644 --- a/cypress/support/e2e.js +++ b/cypress/support/e2e.js @@ -15,6 +15,7 @@ // Import commands.js using ES2015 syntax: import './commands' +import '@cypress/code-coverage/support' // Alternatively you can use CommonJS syntax: // require('./commands') \ No newline at end of file diff --git a/examples/example_opt_out.html b/examples/example_opt_out.html deleted file mode 100644 index c128a20..0000000 --- a/examples/example_opt_out.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - -
- -

-

-
- - - \ No newline at end of file diff --git a/examples/example_rating_widgets.html b/examples/example_rating_widgets.html deleted file mode 100644 index d9448c0..0000000 --- a/examples/example_rating_widgets.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - -
- -

Countly

-

-

-

-
- - - \ No newline at end of file diff --git a/examples/examples_feedback_widgets.html b/examples/examples_feedback_widgets.html index e897079..b901550 100644 --- a/examples/examples_feedback_widgets.html +++ b/examples/examples_feedback_widgets.html @@ -90,7 +90,7 @@ } // Get data with the widget object - Countly.getFeedbackWidgetData(CountlyFeedbackWidget, + Countly.getFeedbackWidgetData(countlyFeedbackWidget, // callback function, 1st param is the feedback widget data function (feedbackData, err) { if (err) { // error handling diff --git a/modules/CountlyClass.js b/modules/CountlyClass.js index 56239bd..b8b8616 100644 --- a/modules/CountlyClass.js +++ b/modules/CountlyClass.js @@ -87,6 +87,11 @@ class CountlyClass { #shouldSendHC; #consents; #generatedRequests; + #contentTimeInterval; + #contentEndPoint; + #inContentZone; + #contentZoneTimer; + #contentIframeID; constructor(ob) { this.#self = this; this.#global = !Countly.i; @@ -136,6 +141,11 @@ constructor(ob) { this.#sdkVersion = getConfig("sdk_version", ob, SDK_VERSION); this.#shouldSendHC = false; this.#generatedRequests = []; + this.#contentTimeInterval = 30000; + this.#contentEndPoint = "/o/sdk/content"; + this.#inContentZone = false; + this.#contentZoneTimer = null; + this.#contentIframeID = "cly-content-iframe"; try { localStorage.setItem("cly_testLocal", true); @@ -153,10 +163,15 @@ constructor(ob) { this.#consents[Countly.features[it]] = {}; } - this.initialize(ob); + this.#initialize(ob); }; - initialize = (ob) => { + /** + * Initialize the Countly + * @param {Object} ob - config object + * @returns + */ + #initialize = (ob) => { this.serialize = getConfig("serialize", ob, Countly.serialize); this.deserialize = getConfig("deserialize", ob, Countly.deserialize); this.getViewName = getConfig("getViewName", ob, Countly.getViewName); @@ -231,39 +246,6 @@ constructor(ob) { // opted out user this.ignore_visitor = true; } - - this.#migrate(); - - this.#requestQueue = this.#getValueFromStorage("cly_queue") || []; - this.#eventQueue = this.#getValueFromStorage("cly_event") || []; - this.#remoteConfigs = this.#getValueFromStorage("cly_remote_configs") || {}; - - // flag that indicates that the offline mode was enabled at the end of the previous app session - var tempIdModeWasEnabled = (this.#getValueFromStorage("cly_id") === "[CLY]_temp_id"); - - if (this.clearStoredId) { - // retrieve stored device ID and type from local storage and use it to flush existing events - if (this.#getValueFromStorage("cly_id") && !tempIdModeWasEnabled) { - this.device_id = this.#getValueFromStorage("cly_id"); - this.#log(logLevelEnums.DEBUG, "initialize, temporarily using the previous device ID to flush existing events"); - this.#deviceIdType = this.#getValueFromStorage("cly_id_type"); - if (!this.#deviceIdType) { - this.#log(logLevelEnums.DEBUG, "initialize, No device ID type info from the previous session, falling back to DEVELOPER_SUPPLIED, for event flushing"); - this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; - } - // don't process async queue here, just send the events (most likely async data is for the new user) - this.#sendEventsForced(); - // set them back to their initial values - this.device_id = undefined; - this.#deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; - } - // then clear the storage so that a new device ID is set again later - this.#log(logLevelEnums.INFO, "initialize, Clearing the device ID storage"); - this.#removeValueFromStorage("cly_id"); - this.#removeValueFromStorage("cly_id_type"); - this.#removeValueFromStorage("cly_session"); - } - this.#checkIgnore(); if (isBrowser) { @@ -319,6 +301,38 @@ constructor(ob) { return; } + this.#migrate(); + + this.#requestQueue = this.#getValueFromStorage("cly_queue") || []; + this.#eventQueue = this.#getValueFromStorage("cly_event") || []; + this.#remoteConfigs = this.#getValueFromStorage("cly_remote_configs") || {}; + + // flag that indicates that the offline mode was enabled at the end of the previous app session + var tempIdModeWasEnabled = (this.#getValueFromStorage("cly_id") === "[CLY]_temp_id"); + + if (this.clearStoredId) { + // retrieve stored device ID and type from local storage and use it to flush existing events + if (this.#getValueFromStorage("cly_id") && !tempIdModeWasEnabled) { + this.device_id = this.#getValueFromStorage("cly_id"); + this.#log(logLevelEnums.DEBUG, "initialize, temporarily using the previous device ID to flush existing events"); + this.#deviceIdType = this.#getValueFromStorage("cly_id_type"); + if (!this.#deviceIdType) { + this.#log(logLevelEnums.DEBUG, "initialize, No device ID type info from the previous session, falling back to DEVELOPER_SUPPLIED, for event flushing"); + this.#deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED; + } + // don't process async queue here, just send the events (most likely async data is for the new user) + this.#sendEventsForced(); + // set them back to their initial values + this.device_id = undefined; + this.#deviceIdType = DeviceIdTypeInternalEnums.SDK_GENERATED; + } + // then clear the storage so that a new device ID is set again later + this.#log(logLevelEnums.INFO, "initialize, Clearing the device ID storage"); + this.#removeValueFromStorage("cly_id"); + this.#removeValueFromStorage("cly_id_type"); + this.#removeValueFromStorage("cly_session"); + } + // init configuration is printed out here: // key values should be printed out as is if (this.#sdkName === SDK_NAME && this.#sdkVersion === SDK_VERSION) { @@ -856,12 +870,12 @@ constructor(ob) { this.#updateConsent(); setTimeout(() => { if (feature === featureEnums.SESSIONS && this.#lastParams.begin_session) { - this.begin_session.apply(self, this.#lastParams.begin_session); + this.begin_session.apply(this, this.#lastParams.begin_session); this.#lastParams.begin_session = null; } else if (feature === featureEnums.VIEWS && this.#lastParams.track_pageview) { this.#lastView = null; - this.track_pageview.apply(self, this.#lastParams.track_pageview); + this.track_pageview.apply(this, this.#lastParams.track_pageview); this.#lastParams.track_pageview = null; } }, 1); @@ -2980,7 +2994,7 @@ constructor(ob) { this.#log(logLevelEnums.ERROR, `showWidget, No ${widgetType} widget found.`); return; } - present_feedback_widget(widget, null, null, null); + this.present_feedback_widget(widget, null, null, null); }); }; /** @@ -3324,23 +3338,71 @@ constructor(ob) { this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Appended the iframe"); add_event_listener(window, "message", (e) => { + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Received message from widget with origin: [" + e.origin + "] and data: [" + e.data + "]"); var data = {}; try { data = JSON.parse(e.data); - this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Parsed response message " + data); } catch (ex) { this.#log(logLevelEnums.ERROR, "present_feedback_widget, Error while parsing message body " + ex); } - if (!data.close) { - this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Closing signal not sent yet"); + if (data.close !== true) { // to not mix with content we check against true value + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, These are not the closing signals you are looking for"); return; } document.getElementById("countly-" + feedbackWidgetFamily + "-wrapper-" + presentableFeedback._id).style.display = "none"; document.getElementById("csbg").style.display = "none"; + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, Closed the widget"); }); + /** + * Function to show survey popup + * @param {Object} feedback - feedback object + */ + var showSurvey = (feedback) => { + document.getElementById("countly-surveys-wrapper-" + feedback._id).style.display = "block"; + document.getElementById("csbg").style.display = "block"; + } + + /** + * Function to prepare rating sticker and feedback widget + * @param {Object} feedback - feedback object + */ + var showRatingForFeedbackWidget = (feedback) => { + // remove old stickers if exists + var stickers = document.getElementsByClassName("countly-feedback-sticker"); + while (stickers.length > 0) { + this.#log(logLevelEnums.VERBOSE, "present_feedback_widget, Removing old stickers"); + stickers[0].remove(); + } + + // render sticker if hide sticker property isn't set + if (!feedback.appearance.hideS) { + this.#log(logLevelEnums.DEBUG, "present_feedback_widget, handling the sticker as it was not set to hidden"); + // create sticker wrapper element + var sticker = document.createElement("div"); + sticker.innerText = feedback.appearance.text; + sticker.style.color = ((feedback.appearance.text_color.length < 7) ? "#" + feedback.appearance.text_color : feedback.appearance.text_color); + sticker.style.backgroundColor = ((feedback.appearance.bg_color.length < 7) ? "#" + feedback.appearance.bg_color : feedback.appearance.bg_color); + sticker.className = "countly-feedback-sticker " + feedback.appearance.position + "-" + feedback.appearance.size; + sticker.id = "countly-feedback-sticker-" + feedback._id; + document.body.appendChild(sticker); + + // sticker event handler + add_event_listener(document.getElementById("countly-feedback-sticker-" + feedback._id), "click", () => { + document.getElementById("countly-ratings-wrapper-" + feedback._id).style.display = "flex"; + document.getElementById("csbg").style.display = "block"; + }); + } + + // feedback widget close event handler + // TODO: Check if this is still valid + add_event_listener(document.getElementById("countly-feedback-close-icon-" + feedback._id), "click", () => { + document.getElementById("countly-ratings-wrapper-" + feedback._id).style.display = "none"; + document.getElementById("csbg").style.display = "none"; + }); + } if (presentableFeedback.type === "survey") { var surveyShown = false; @@ -3451,53 +3513,7 @@ constructor(ob) { this.#log(logLevelEnums.ERROR, "present_feedback_widget, Something went wrong while presenting the widget: " + e); } - /** - * Function to show survey popup - * @param {Object} feedback - feedback object - */ - var showSurvey = (feedback) => { - document.getElementById("countly-surveys-wrapper-" + feedback._id).style.display = "block"; - document.getElementById("csbg").style.display = "block"; - } - - /** - * Function to prepare rating sticker and feedback widget - * @param {Object} feedback - feedback object - */ - var showRatingForFeedbackWidget = (feedback) => { - // remove old stickers if exists - var stickers = document.getElementsByClassName("countly-feedback-sticker"); - while (stickers.length > 0) { - this.#log(logLevelEnums.VERBOSE, "present_feedback_widget, Removing old stickers"); - stickers[0].remove(); - } - // render sticker if hide sticker property isn't set - if (!feedback.appearance.hideS) { - this.#log(logLevelEnums.DEBUG, "present_feedback_widget, handling the sticker as it was not set to hidden"); - // create sticker wrapper element - var sticker = document.createElement("div"); - sticker.innerText = feedback.appearance.text; - sticker.style.color = ((feedback.appearance.text_color.length < 7) ? "#" + feedback.appearance.text_color : feedback.appearance.text_color); - sticker.style.backgroundColor = ((feedback.appearance.bg_color.length < 7) ? "#" + feedback.appearance.bg_color : feedback.appearance.bg_color); - sticker.className = "countly-feedback-sticker " + feedback.appearance.position + "-" + feedback.appearance.size; - sticker.id = "countly-feedback-sticker-" + feedback._id; - document.body.appendChild(sticker); - - // sticker event handler - add_event_listener(document.getElementById("countly-feedback-sticker-" + feedback._id), "click", () => { - document.getElementById("countly-ratings-wrapper-" + feedback._id).style.display = "flex"; - document.getElementById("csbg").style.display = "block"; - }); - } - - // feedback widget close event handler - // TODO: Check if this is still valid - add_event_listener(document.getElementById("countly-feedback-close-icon-" + feedback._id), "click", () => { - document.getElementById("countly-ratings-wrapper-" + feedback._id).style.display = "none"; - document.getElementById("csbg").style.display = "none"; - }); - } }; /** @@ -3624,6 +3640,156 @@ constructor(ob) { } } + content = { + enterContentZone: () => { + this.#enterContentZoneInternal(); + }, + exitContentZone: () => { + if (!this.#inContentZone) { + this.#log(logLevelEnums.DEBUG, "content.exitContentZone, Not in content zone"); + return; + } + this.#log(logLevelEnums.INFO, "content.exitContentZone, Exiting content zone"); + this.#inContentZone = false; + if (this.#contentZoneTimer) { + clearInterval(this.#contentZoneTimer); + this.#log(logLevelEnums.DEBUG, "content.exitContentZone, content zone exited"); + } + }, + }; + + #enterContentZoneInternal = (forced) => { + if (!isBrowser) { + this.#log(logLevelEnums.WARNING, "content.enterContentZone, window object is not available. Not entering content zone."); + return; + }; + if (this.#inContentZone && !forced) { + this.#log(logLevelEnums.DEBUG, "content.enterContentZone, Already in content zone"); + return; + } + this.#log(logLevelEnums.INFO, "content.enterContentZone, Entering content zone"); + this.#inContentZone = true; + if (!forced) { + this.#sendContentRequest(); + } + this.#contentZoneTimer = setInterval(() => { + this.#sendContentRequest(); + }, this.#contentTimeInterval); + }; + + #prepareContentRequest = () => { + this.#log(logLevelEnums.DEBUG, "prepareContentRequest, forming content request"); + const resInfo = this.#getResolution(); + var resToSend = {l : {}, p: {}}; + resToSend.l.w = resInfo.width; + resToSend.l.h = resInfo.height; + resToSend.p.w = resInfo.height; + resToSend.p.h = resInfo.width; + + const local = navigator.language || navigator.browserLanguage || navigator.systemLanguage || navigator.userLanguage; + const language = local.split('-')[0]; + var params = { + method: "queue", + la: language, + resolution: JSON.stringify(resToSend), + cly_ws: 1, + cly_origin: window.location.origin, + }; + + this.#prepareRequest(params); + return params; + }; + + #sendContentRequest = () => { + this.#log(logLevelEnums.DEBUG, "sendContentRequest, sending content request"); + var params = this.#prepareContentRequest(); + this.#makeNetworkRequest("sendContentRequest,", this.url + this.#contentEndPoint, params, (e,param,resp) => { + if (e) { + return; + } + this.#log(logLevelEnums.DEBUG, "sendContentRequest, received content: [" + resp + "]"); + this.#displayContent(resp); + clearInterval(this.#contentZoneTimer); // prevent multiple content requests while one is on + window.addEventListener('message', (event) => { + this.#interpretContentMessage(event); + }); + }, true); + }; + + #displayContent = (content) => { + if (!content) { + this.#log(logLevelEnums.DEBUG, "displayContent, no content to display"); + return; + } + this.#log(logLevelEnums.DEBUG, "displayContent, displaying content"); + var response = JSON.parse(content); + + var iframe = document.createElement("iframe"); + iframe.id = this.#contentIframeID; + iframe.src = response.html; + iframe.style.position = "absolute"; + iframe.style.left = response.geo.l.x + "px"; + iframe.style.top = response.geo.l.y + "px"; + iframe.style.width = response.geo.l.w + "px"; + iframe.style.height = response.geo.l.h + "px"; + iframe.style.border = "none"; + iframe.style.zIndex = "999999"; + document.body.appendChild(iframe); + }; + + #interpretContentMessage = (messageEvent) => { + this.#log(logLevelEnums.DEBUG, "sendContentRequest, Received message from: [" + messageEvent.origin + "] with data: [" + JSON.stringify(messageEvent.data) + "]"); + if (messageEvent.origin !== this.url) { + this.#log(logLevelEnums.ERROR, "sendContentRequest, Received message from invalid origin"); + return; + } + const {close, link, event} = messageEvent.data; + + if (event) { + this.#log(logLevelEnums.DEBUG, "sendContentRequest, Received event: [" + event + "]"); + if (close === 1) { + this.#log(logLevelEnums.DEBUG, "sendContentRequest, Closing content frame for event: [" + event + "]"); + this.#closeContentFrame(); + } + if (!Array.isArray(event)) { + if (typeof event === "object") { + event = [event]; + } else { + this.#log(logLevelEnums.ERROR, "sendContentRequest, Invalid event type: [" + typeof event + "]"); + return; + } + }; + // event is expected to be an array of events + for (var i = 0; i < event.length; i++) { + this.#add_cly_events(event[i]); + } + } + + if (link) { + if (close === 1) { + this.#log(logLevelEnums.DEBUG, "sendContentRequest, Closing content frame for link"); + this.#closeContentFrame(); + } + window.open(link, "_blank"); + this.#log(logLevelEnums.DEBUG, `sendContentRequest, Opened link in new tab: [${link}]`); + } + + if (close === 1) { + this.#closeContentFrame(); + } + }; + + #closeContentFrame = () => { + const iframe = document.getElementById(this.#contentIframeID); + if (iframe) { + iframe.remove(); + this.#log(logLevelEnums.DEBUG, "sendContentRequest, removed iframe"); + if (this.#inContentZone) { // if user did not exit content zone, re-enter + this.#enterContentZoneInternal(true); + } + } + }; + /** * Check and send the events to request queue if there are any, empty the event queue */ @@ -3733,7 +3899,7 @@ constructor(ob) { if (typeof this.onload !== "undefined" && this.onload.length > 0) { for (i = 0; i < this.onload.length; i++) { if (typeof this.onload[i] === "function") { - this.onload[i](self); + this.onload[i](this); } } this.onload = []; @@ -3974,7 +4140,7 @@ constructor(ob) { req(); } else if (Array.isArray(req) && req.length > 0) { - var inst = self; + var inst = this; var arg = 0; // check if it is meant for other tracker try { @@ -4050,27 +4216,10 @@ constructor(ob) { metrics._ua = metrics._ua || currentUserAgentString(); // getting resolution - if (isBrowser && screen.width) { - var width = (screen.width) ? parseInt(screen.width) : 0; - var height = (screen.height) ? parseInt(screen.height) : 0; - if (width !== 0 && height !== 0) { - var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); - if (iOS && window.devicePixelRatio) { - // ios provides dips, need to multiply - width = Math.round(width * window.devicePixelRatio); - height = Math.round(height * window.devicePixelRatio); - } - else { - if (Math.abs(window.orientation) === 90) { - // we have landscape orientation - // switch values for all except ios - var temp = width; - width = height; - height = temp; - } - } - metrics._resolution = metrics._resolution || "" + width + "x" + height; - } + var resolution = this.#getResolution(); + if (resolution) { + var formattedRes = "" + resolution.width + "x" + resolution.height; + metrics._resolution = metrics._resolution || formattedRes; } // getting density ratio @@ -4092,6 +4241,48 @@ constructor(ob) { return metrics; } + /** + * returns the resolution of the device + * @param {bool} getAvailable - get available resolution + * @returns {object} resolution object: {width: 1920, height: 1080, orientation: 0} + */ + #getResolution = (getAvailable) => { + this.#log(logLevelEnums.DEBUG, "Getting the resolution of the device"); + if (!isBrowser || !screen) { + this.#log(logLevelEnums.DEBUG, "No screen available"); + return null; + }; + + var width = (screen.width) ? parseInt(screen.width) : 0; + var height = (screen.height) ? parseInt(screen.height) : 0; + + if (getAvailable) { + width = (screen.availWidth) ? parseInt(screen.availWidth) : width; + height = (screen.availHeight) ? parseInt(screen.availHeight) : height; + } + + if (width === 0 || height === 0) { + this.#log(logLevelEnums.DEBUG, "Screen width or height is non existent"); + return null; + } + var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); + if (iOS && window.devicePixelRatio) { + // ios provides dips, need to multiply + width = Math.round(width * window.devicePixelRatio); + height = Math.round(height * window.devicePixelRatio); + } + else { + if (Math.abs(screen.orientation.angle) === 90) { + // we have landscape orientation + // switch values for all except ios + var temp = width; + width = height; + height = temp; + } + } + return { width: width, height: height , orientation: screen.orientation.angle }; + }; + /** * @memberof Countly._internals * document.referrer returns the full URL of the page the user was on before they came to your site. diff --git a/package-lock.json b/package-lock.json index 275d3fd..41e3932 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,14 +11,17 @@ "devDependencies": { "@babel/core": "^7.22.9", "@babel/preset-env": "^7.22.9", + "@cypress/code-coverage": "^3.13.7", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "babel-loader": "^9.1.3", + "babel-plugin-istanbul": "^7.0.0", "babel-preset-env": "^1.7.0", "cypress": "^13.6.0", "cypress-localstorage-commands": "^2.2.5", + "nyc": "^17.1.0", "rollup": "^4.6.0" } }, @@ -1488,6 +1491,280 @@ "node": ">=0.1.90" } }, + "node_modules/@cypress/code-coverage": { + "version": "3.13.7", + "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.13.7.tgz", + "integrity": "sha512-E8oT0D1cA363cot4q7wonaDATAPybj7/DJ3PAE+BCmEBy41aYWn5DaEYWLRYe8eg+h4IlNPkZG1QMVo33pMcfw==", + "dev": true, + "dependencies": { + "@cypress/webpack-preprocessor": "^6.0.0", + "chalk": "4.1.2", + "dayjs": "1.11.13", + "debug": "4.3.7", + "execa": "4.1.0", + "globby": "11.1.0", + "istanbul-lib-coverage": "^3.0.0", + "js-yaml": "4.1.0", + "nyc": "15.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.1", + "@babel/preset-env": "^7.0.0", + "babel-loader": "^8.3 || ^9", + "cypress": "*", + "webpack": "^4 || ^5" + } + }, + "node_modules/@cypress/code-coverage/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@cypress/code-coverage/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@cypress/code-coverage/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@cypress/code-coverage/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/@cypress/code-coverage/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/@cypress/code-coverage/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/code-coverage/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@cypress/code-coverage/node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/code-coverage/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/code-coverage/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@cypress/code-coverage/node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/@cypress/code-coverage/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@cypress/code-coverage/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/code-coverage/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/code-coverage/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/code-coverage/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/code-coverage/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@cypress/request": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.6.tgz", @@ -1517,6 +1794,29 @@ "node": ">= 6" } }, + "node_modules/@cypress/webpack-preprocessor": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@cypress/webpack-preprocessor/-/webpack-preprocessor-6.0.2.tgz", + "integrity": "sha512-0+1+4iy4W9PE6R5ywBNKAZoFp8Sf//w3UJ+CKTqkcAjA29b+dtsD0iFT70DsYE0BMqUM1PO7HXFGbXllQ+bRAA==", + "dev": true, + "dependencies": { + "bluebird": "3.7.1", + "debug": "^4.3.4", + "lodash": "^4.17.20" + }, + "peerDependencies": { + "@babel/core": "^7.0.1", + "@babel/preset-env": "^7.0.0", + "babel-loader": "^8.3 || ^9", + "webpack": "^4 || ^5" + } + }, + "node_modules/@cypress/webpack-preprocessor/node_modules/bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "dev": true + }, "node_modules/@cypress/xvfb": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", @@ -1536,6 +1836,114 @@ "ms": "^2.1.1" } }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -1594,6 +2002,41 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@rollup/plugin-babel": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", @@ -2305,10 +2748,22 @@ "node": ">=0.10.0" } }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true, "funding": [ { @@ -2325,6 +2780,27 @@ } ] }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -2567,6 +3043,22 @@ "babel-runtime": "^6.22.0" } }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz", + "integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.12", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", @@ -3149,6 +3641,18 @@ "balanced-match": "^1.0.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", @@ -3229,6 +3733,21 @@ "node": ">=6" } }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -3248,6 +3767,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001680", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", @@ -3376,6 +3904,67 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3442,6 +4031,12 @@ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -3664,6 +4259,15 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -3673,6 +4277,21 @@ "node": ">=0.10.0" } }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -3699,6 +4318,18 @@ "node": ">=0.4.0" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -3806,6 +4437,12 @@ "dev": true, "peer": true }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -3838,6 +4475,19 @@ "node": ">=8.0.0" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3978,6 +4628,22 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3991,6 +4657,15 @@ "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", "dev": true }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -4015,6 +4690,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-cache-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", @@ -4047,6 +4734,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -4070,6 +4770,26 @@ "node": ">= 6" } }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -4123,6 +4843,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -4142,6 +4871,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -4195,6 +4933,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -4226,6 +4976,26 @@ "node": ">=4" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -4301,6 +5071,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -4313,6 +5108,12 @@ "node": ">= 0.4" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "node_modules/http-signature": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz", @@ -4356,6 +5157,24 @@ } ] }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -4415,6 +5234,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -4424,6 +5252,18 @@ "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-installed-globally": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", @@ -4446,7 +5286,16 @@ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true }, - "node_modules/is-path-inside": { + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", @@ -4494,6 +5343,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4506,6 +5364,164 @@ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -4543,6 +5559,18 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -4698,6 +5726,12 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -4878,12 +5912,61 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -4948,6 +6031,18 @@ "dev": true, "peer": true }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -4966,6 +6061,226 @@ "node": ">=8" } }, + "node_modules/nyc": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", + "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^3.3.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^6.0.2", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nyc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nyc/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/nyc/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/object-inspect": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", @@ -5053,6 +6368,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/path-exists": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", @@ -5062,6 +6401,15 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5077,6 +6425,15 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -5161,6 +6518,18 @@ "node": ">= 0.6.0" } }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", @@ -5202,6 +6571,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -5279,6 +6668,18 @@ "regjsparser": "bin/parser" } }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -5288,6 +6689,15 @@ "throttleit": "^1.0.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -5297,6 +6707,12 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -5314,6 +6730,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -5327,12 +6752,81 @@ "node": ">=8" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/rollup": { "version": "4.25.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz", @@ -5370,6 +6864,29 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -5442,6 +6959,12 @@ "randombytes": "^2.1.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -5504,6 +7027,15 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", @@ -5558,6 +7090,29 @@ "source-map": "^0.6.0" } }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -5630,6 +7185,15 @@ "node": ">=0.10.0" } }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -5782,6 +7346,63 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/throttleit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", @@ -5833,6 +7454,18 @@ "node": ">=0.10.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tough-cookie": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", @@ -5890,6 +7523,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", @@ -6156,6 +7798,12 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6215,12 +7863,126 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/package.json b/package.json index d2841ff..a708f91 100644 --- a/package.json +++ b/package.json @@ -26,14 +26,16 @@ "devDependencies": { "@babel/core": "^7.22.9", "@babel/preset-env": "^7.22.9", + "@cypress/code-coverage": "^3.13.7", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "babel-loader": "^9.1.3", "babel-preset-env": "^1.7.0", + "cypress": "^13.6.0", "cypress-localstorage-commands": "^2.2.5", - "rollup": "^4.6.0", - "cypress": "^13.6.0" + "nyc": "^17.1.0", + "rollup": "^4.6.0" } } From 25dfc6dcc38b6bfd38bc5a8b0ffa076a00032238 Mon Sep 17 00:00:00 2001 From: turtledreams <62231246+turtledreams@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:37:26 +0900 Subject: [PATCH 3/3] version --- examples/example_async.html | 5 +++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/example_async.html b/examples/example_async.html index bf312bd..7cd1ed6 100644 --- a/examples/example_async.html +++ b/examples/example_async.html @@ -13,6 +13,8 @@ //provide countly initialization parameters Countly.app_key = "YOUR_APP_KEY"; Countly.url = "https://your.server.ly"; //your server goes here + Countly.debug = true; + Countly.loadAPMScriptsAsync = true; if(Countly.app_key === "YOUR_APP_KEY" || Countly.url === "https://your.server.ly"){ console.warn("Please do not use default set of app key and server url") @@ -23,6 +25,9 @@ //track sessions automatically Countly.q.push(['track_sessions']); + //track performance automatically + Countly.q.push(["track_performance"]); + //track sessions automatically Countly.q.push(['track_pageview']); diff --git a/package-lock.json b/package-lock.json index 41e3932..5056a04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "countly-sdk-js", - "version": "24.11.0", + "version": "24.11.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "countly-sdk-js", - "version": "24.11.0", + "version": "24.11.1", "license": "MIT", "devDependencies": { "@babel/core": "^7.22.9", diff --git a/package.json b/package.json index a708f91..1d8c504 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "countly-sdk-js", - "version": "24.11.0", + "version": "24.11.1", "description": "Countly JavaScript SDK", "type": "module", "main": "Countly.js",