UNPKG

@ezbot-ai/javascript-sdk

Version:

The easiest way to interact with ezbot via JS (node and browser)

264 lines 20 kB
/* eslint-disable functional/immutable-data */ /* * This package uses source code from Snowplow Analytics Ltd * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import { enableButtonClickTracking } from '@snowplow/browser-plugin-button-click-tracking'; import { enableLinkClickTracking } from '@snowplow/browser-plugin-link-click-tracking'; import { addGlobalContexts, newTracker, } from '@snowplow/browser-tracker'; import { defaultWebConfiguration, ezbotPredictionsContextSchemaPath, ezbotTrackerDomain, plugins, } from './constants'; import { getPredictions } from './predictions'; import { setUserId, setUserIdFromCookie, startActivityTracking, trackLinkClick, trackPageView, trackRewardEvent, } from './tracking'; import { createCrossDomainLinkChecker } from './utils/crossDomainLinker'; import { makeVisualChange, makeVisualChanges, visualChanges, visualUtils, } from './visualChanges'; const ezbotTrackerId = 'ezbot'; async function initEzbot(projectId, userId, _config = defaultWebConfiguration) { const existingTracker = window.ezbot?.tracker; if (existingTracker) { existingTracker.setUserId(userId); return existingTracker; } // Prepare tracker configuration const trackerConfig = { appId: projectId.toString(), plugins: plugins, stateStorageStrategy: 'localStorage', discoverRootDomain: true, }; // Handle cross-domain tracking if enabled if (_config?.crossDomain?.enabled) { if (!_config?.crossDomain.domains.length) { throw new Error('Cross-domain tracking enabled but no domains provided'); } const extendedCrossDomainLinkerOptions = { userId: true, sessionId: true, }; trackerConfig.useExtendedCrossDomainLinker = extendedCrossDomainLinkerOptions; const crossDomainLinkerFunction = createCrossDomainLinkChecker(_config.crossDomain.domains); trackerConfig.crossDomainLinker = crossDomainLinkerFunction; } const tracker = newTracker(ezbotTrackerId, ezbotTrackerDomain(projectId), trackerConfig); if (!tracker) { throw new Error('Failed to initialize tracker'); } if (userId) { tracker.setUserId(userId); } tracker.setUserIdFromReferrer('_sp'); const domainUserInfo = tracker.getDomainUserInfo(); // eslint-disable-next-line functional/no-let let sessionId = domainUserInfo[6]; // TODO: this should happen automatically somehow if (window.location.href.includes('_sp=')) { // get sessionId for cross-domain linking const urlParams = new URLSearchParams(window.location.search); const snowPlowParams = urlParams.get('_sp'); if (snowPlowParams != null) { sessionId = snowPlowParams.split('.')[2]; } } // eslint-disable-next-line functional/no-let let predictions = []; try { predictions = await getPredictions(projectId, sessionId, tracker); } catch (error) { if (error && typeof error === 'object' && 'name' in error && error.name === 'EzbotPaymentError') { const paymentError = error; // Payment or subscription issue - disable the SDK console.error('SDK disabled due to payment/subscription issue:', paymentError.message); window.ezbot = { trackerConfig: trackerConfig, userId: userId, tracker: tracker, predictions: [], sessionId: sessionId, disabled: true, disabledReason: paymentError.message, trackPageView: () => { console.warn('Ezbot SDK is disabled due to payment/subscription issue'); return undefined; }, trackRewardEvent: () => { console.warn('Ezbot SDK is disabled due to payment/subscription issue'); return undefined; }, startActivityTracking: () => { console.warn('Ezbot SDK is disabled due to payment/subscription issue'); return undefined; }, setUserId: () => { console.warn('Ezbot SDK is disabled due to payment/subscription issue'); return undefined; }, setUserIdFromCookie: () => { console.warn('Ezbot SDK is disabled due to payment/subscription issue'); return undefined; }, makeVisualChanges: () => { console.warn('Ezbot SDK is disabled due to payment/subscription issue'); return undefined; }, utils: { visual: visualUtils, }, actions: { visual: visualChanges, }, intervals: [], mode: 'ezbot', }; throw error; // Re-throw to let the caller know the SDK is disabled } console.error('Failed to get predictions', error); } const predictionsContext = { schema: ezbotPredictionsContextSchemaPath, data: { predictions: predictions.map((pred) => ({ variable: pred.key, value: pred.value, })), }, }; addGlobalContexts([predictionsContext], [tracker.id]); window.ezbot = { trackerConfig: trackerConfig, userId: userId, tracker: tracker, predictions: [...predictions], sessionId: sessionId, trackPageView: trackPageView, // only send to ezbot tracker trackRewardEvent: trackRewardEvent, startActivityTracking: startActivityTracking, makeVisualChanges: makeVisualChanges, setUserId: setUserId, setUserIdFromCookie: setUserIdFromCookie, utils: { visual: visualUtils, }, actions: { visual: visualChanges, }, intervals: [], mode: 'ezbot', }; try { enableLinkClickTracking(); enableButtonClickTracking(); } catch (error) { console.error('Failed to enable click tracking', error); } return tracker; } async function initEzbotWithServerSidePredictions(projectId, predictions, userId, _config = defaultWebConfiguration) { const existingTracker = window.ezbot?.tracker; if (existingTracker) { existingTracker.setUserId(userId); return existingTracker; } // Prepare tracker configuration const trackerConfig = { appId: projectId.toString(), plugins: plugins, stateStorageStrategy: 'localStorage', discoverRootDomain: true, }; // Handle cross-domain tracking if enabled if (_config?.crossDomain?.enabled) { if (!_config?.crossDomain.domains.length) { throw new Error('Cross-domain tracking enabled but no domains provided'); } const extendedCrossDomainLinkerOptions = { userId: true, sessionId: true, }; trackerConfig.useExtendedCrossDomainLinker = extendedCrossDomainLinkerOptions; const crossDomainLinkerFunction = createCrossDomainLinkChecker(_config.crossDomain.domains); trackerConfig.crossDomainLinker = crossDomainLinkerFunction; } const tracker = newTracker(ezbotTrackerId, ezbotTrackerDomain(projectId), trackerConfig); if (!tracker) { throw new Error('Failed to initialize tracker'); } if (userId) { tracker.setUserId(userId); } tracker.setUserIdFromReferrer('_sp'); const domainUserInfo = tracker.getDomainUserInfo(); const sessionId = domainUserInfo[6]; // Use provided predictions instead of fetching them const predictionsContext = { schema: ezbotPredictionsContextSchemaPath, data: { predictions: predictions.map((pred) => ({ variable: pred.key, value: pred.value, })), }, }; addGlobalContexts([predictionsContext], [tracker.id]); window.ezbot = { trackerConfig: trackerConfig, userId: userId, tracker: tracker, predictions: [...predictions], sessionId: sessionId, disabled: false, disabledReason: undefined, trackPageView: trackPageView, // only send to ezbot tracker trackRewardEvent: trackRewardEvent, startActivityTracking: startActivityTracking, makeVisualChanges: makeVisualChanges, setUserId: setUserId, setUserIdFromCookie: setUserIdFromCookie, utils: { visual: visualUtils, }, actions: { visual: visualChanges, }, intervals: [], mode: 'ezbot', }; try { enableLinkClickTracking(); enableButtonClickTracking(); } catch (error) { console.error('Failed to enable click tracking', error); } return tracker; } export { trackRewardEvent, initEzbot, initEzbotWithServerSidePredictions, makeVisualChange, makeVisualChanges, startActivityTracking, trackLinkClick, trackPageView, setUserId, setUserIdFromCookie, }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXpib3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2V6Ym90LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDhDQUE4QztBQUU5Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFFSCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxnREFBZ0QsQ0FBQztBQUMzRixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQztBQUN2RixPQUFPLEVBQ0wsaUJBQWlCLEVBR2pCLFVBQVUsR0FFWCxNQUFNLDJCQUEyQixDQUFDO0FBRW5DLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsaUNBQWlDLEVBQ2pDLGtCQUFrQixFQUNsQixPQUFPLEdBQ1IsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvQyxPQUFPLEVBQ0wsU0FBUyxFQUNULG1CQUFtQixFQUNuQixxQkFBcUIsRUFDckIsY0FBYyxFQUNkLGFBQWEsRUFDYixnQkFBZ0IsR0FDakIsTUFBTSxZQUFZLENBQUM7QUFhcEIsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDekUsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixpQkFBaUIsRUFDakIsYUFBYSxFQUNiLFdBQVcsR0FDWixNQUFNLGlCQUFpQixDQUFDO0FBRXpCLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQztBQUUvQixLQUFLLFVBQVUsU0FBUyxDQUN0QixTQUFpQixFQUNqQixNQUFzQixFQUN0QixVQUE4Qix1QkFBNkM7SUFFM0UsTUFBTSxlQUFlLEdBQUcsTUFBTSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUM7SUFDOUMsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNwQixlQUFlLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2xDLE9BQU8sZUFBZSxDQUFDO0lBQ3pCLENBQUM7SUFF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