import { initAnalyticsProxy } from "./analyticsProxy.js";
import { initClearbitReveal } from "./clearbitReveal.js";
import { initLogRocket } from "./logrocket.js";
import { initMntn } from "./mntn.js";
import { initRedditPixel } from "./reddit.js";
import { initSegment } from "./segment.js";
import { initSixSense } from "./sixSense.js";
import { sendSegmentEvents } from "./sixSenseCallbacks.js";
import { initUtmMediumHash } from "./utmMediumHash.js";
import { initVwo } from "./vwo.js";
export { track } from "./track.js";
export { identify } from "./identify.js";
export { personalizePage } from "./personalizePage.js";
export { fetchOutreachAccountCustomFields } from "./fetchOutreachAccountCustomField.js";
export { INDUSTRY_LOOKUP, EMPLOYEE_SIZE_LOOKUP } from "./sixSenseAttributes.js";
export { mntnConversion } from "./mntn.js";
// Helper function to throw when undefined arguments are given when a paramter is required
function requiredParam(argName) {
throw new Error(`${argName} is required`);
}
// Helper function to evaluate a flag
// A flag can either be a boolean or a function returning a boolean
function evaluateFlag(obj, prop) {
const value = obj[prop];
// If the value is undefined or null, treat it as false
if (value === undefined || value === null) {
return false;
}
// If the value is a boolean, return it.
if (typeof value === "boolean") {
return value;
}
// If it is a function, evaluate it.
if (typeof value === "function") {
try {
return !!value();
} catch (err) {
// Evaluating the flag should not stop other code from executing if it throws, so swallow the error.
// Print it out for debugging purposes.
console.error(
`[lr-analytics] evaluating ${prop} as a function threw an error`,
err,
);
return false;
}
}
throw new Error(`flag ${value} is neither a boolean nor a function`);
}
/**
* Functions to be used with the 6sense company API response
*/
export const sixSenseCallbacks = {
sendSegmentEvents,
};
export const __helper = {
evaluateFlag,
};
/**
* Initializes analytics tools and trackers.
*
* The options object given to this function is a a blueprint for what trackers to enable.
*
*
* @example
* window.lr_analytics.init({
* analyticsProxy : { enabled: true },
* segment: {
* enabled: true,
* writeKey: 'abc',
* load: true,
* },
* sixSense: {
* enabled: true,
* apiKey: 'xyz',
* }
* });
*
* @param {Object} options - Options object specifying what analytics/trackers to set up.
* @param {Object} [options.analyticsProxy] - Options for setting up the analytics proxy.
* @param {(boolean|function)} options.analyticsProxy.enabled - Enable the analytics proxy
* @param {string[]} [options.analyticsProxy.hostnames] - Additional hostnames to proxy
* @param {string[]} [options.analyticsProxy.wordsToMask] - Additional words to mask
* @param {Object} [options.segment] - Options for seting up segment snippet
* @param {(boolean|function)} options.segment.enabled - Enable segment
* @param {string} [options.segment.writeKey] - The segment api key
* @param {boolean} [options.segment.load] - Makes the `window.analytics.load()` after executing the snippet. Defaults to false.
* @param {Object} [options.sixSense] -- Options for setting up 6sense & 6signal snippet
* @param {(boolean|function)} options.sixSense.enabled - Enable 6sense
* @param {string} options.sixSense.apiKey - 6sense api key
* @param {boolean} [options.sixSense.qa] - Send data to the QA/test endpoint instead of production
* @param {Object} [options.sixSense.companyDetails] - Options relating to the 6sense company details API
* @param {(boolean|function)} options.sixSense.companyDetails.enabled - Enable the 6sense company details API
* @param {string} options.sixSense.companyDetails.apiKey - The company details API api key
* @param {SixSenseCompanyApiCallback} options.sixSense.companyDetails.callback - function to run after we receive a response from the 6sense company details API
* @param {Object} [options.vwo] - Options for setting up the vwo snippet
* @param {(boolean|function)} options.vwo.enabled - Enable vwo
* @param {number} options.vwo.accountId - VWO account ID
* @param {Object} [options.redditPixel] - Options for setting up the reddit pixel snippet
* @param {(boolean|function)} options.redditPixel.enabled - Enable the redit pixel
* @param {string} options.redditPixel.accountId - Reddit adds advertiser id prefixed by
* @param {Object} [options.clearbitReveal] - Options for setting up Clearbit reveal
* @param {(boolean|function)} options.clearbitReveal.enabled - Enable clearbit reveal
* @param {string} options.clearbitReveal.apiKey - Public api key for clearbit reveal. starts with pk_
* @param {function} options.clearbitReveal.callback - Function to be called with result of clearbit reveal
* @param {Object} [options.utmMediumHash] - Options for utm_medium URL hash
* @param {(boolean|function)} options.utmMediumHash.enabled - Enable putting the utm_medium query param in the hash
* @param {Object} [options.logrocket] - Options for setting up the logrocket snippet
* @param {(boolean|function)} options.logrocket.enabled - Enable LogRocket
* @param {boolean} options.logrocket.callInit - Makes the `LogRocket.init()` call once the script has been loaded.
* @param {string} options.logrocket.appSlug - LogRocket appslug. Will be passed to `LogRocket.init()` if it is called
* @param {Object} options.logrocket.initOptions - Options to pass as-is to `LogRocket.Init()`
* @param {Object} [options.mntn] - Options for setting up the MNTN snippet
* @param {(boolean|function)} options.mntn.enabled - Enable MNTN
*/
export function init({
analyticsProxy = {},
segment = {},
sixSense = {},
vwo = {},
redditPixel = {},
clearbitReveal = {},
utmMediumHash = {},
logrocket = {},
mntn = {},
}) {
if (evaluateFlag(analyticsProxy, "enabled")) {
const { hostnames = [], wordsToMask = [] } = analyticsProxy;
const defaultHostnames = [
"cdn.segment.com",
"cdn.heapanalytics.com",
"marketo.net",
"api.segment.io",
"heapanalytics.com",
"visualwebsiteoptimizer.com",
"mktoresp.com",
"intercom.io",
"mountain.com",
];
const defaultWordsToMask = [
"visitWebPage",
"clickLink",
"associateLead",
"analytics",
"heap",
".gif",
];
initAnalyticsProxy({
hostnames: [...defaultHostnames, ...hostnames],
wordsToMask: [...defaultWordsToMask, ...wordsToMask],
});
}
if (evaluateFlag(segment, "enabled")) {
// It is valid to have an undefined write key. When this happens, the
// segment snippet will be executed, but the segment library won't be
// loaded
const { writeKey, load = false } = segment;
initSegment({ writeKey, load });
}
if (evaluateFlag(sixSense, "enabled")) {
const {
apiKey = requiredParam("sixSense.apiKey"),
companyDetails = {},
qa = false,
} = sixSense;
let options = { apiKey, qa };
if (evaluateFlag(companyDetails, "enabled")) {
const {
apiKey: cdApiKey = requiredParam("sixSense.companyDetails.apiKey"),
callback = requiredParam("sixSense.companyDetails.callback"),
} = companyDetails;
options = { ...options, companyDetails: { apiKey: cdApiKey, callback } };
}
initSixSense(options);
}
if (evaluateFlag(logrocket, "enabled")) {
const { callInit = false, appSlug = "", initOptions = {} } = logrocket;
initLogRocket({ callInit, appSlug, initOptions });
}
if (evaluateFlag(vwo, "enabled")) {
const { accountId = requiredParam("vwo.account_id") } = vwo;
initVwo({ accountId });
}
if (evaluateFlag(redditPixel, "enabled")) {
const { accountId = requiredParam("redditPixel.account_id") } = redditPixel;
initRedditPixel({ accountId });
}
if (evaluateFlag(clearbitReveal, "enabled")) {
const { apiKey, callback } = clearbitReveal;
initClearbitReveal({ apiKey, callback });
}
if (evaluateFlag(utmMediumHash, "enabled")) {
initUtmMediumHash();
}
if (evaluateFlag(mntn, "enabled")) {
initMntn();
}
}
/**
* The expected shape of a function that accepts the result of the 6sense company details API call.
* @callback SixSenseCompanyApiCallback
* @param {string} sixSenseResponse - The result of the 6sense company API call. Can be parsed using `JSON.parse`
*/