UNPKG

@segment/analytics-next

Version:

Analytics Next (aka Analytics 2.0) is the latest version of Segment’s JavaScript SDK - enabling you to send your data to any tool without having to learn, test, or use a new API every time.

334 lines 17.6 kB
import { __assign, __awaiter, __extends, __generator, __spreadArray } from "tslib"; import { getProcessEnv } from '../lib/get-process-env'; import { getCDN, setGlobalCDNUrl } from '../lib/parse-cdn'; import { fetch } from '../lib/fetch'; import { Analytics, NullAnalytics } from '../core/analytics'; import { Context } from '../core/context'; import { mergedOptions } from '../lib/merged-options'; import { createDeferred } from '@segment/analytics-generic-utils'; import { envEnrichment } from '../plugins/env-enrichment'; import { remoteLoader, } from '../plugins/remote-loader'; import { segmentio } from '../plugins/segmentio'; import { AnalyticsBuffered, flushAnalyticsCallsInNewTask, flushAddSourceMiddleware, flushSetAnonymousID, flushOn, PreInitMethodCall, flushRegister, } from '../core/buffer'; import { attachInspector } from '../core/inspector'; import { Stats } from '../core/stats'; import { setGlobalAnalyticsKey } from '../lib/global-analytics-helper'; export function loadCDNSettings(writeKey, baseUrl) { return fetch("".concat(baseUrl, "/v1/projects/").concat(writeKey, "/settings")) .then(function (res) { if (!res.ok) { return res.text().then(function (errorResponseMessage) { throw new Error(errorResponseMessage); }); } return res.json(); }) .catch(function (err) { console.error(err.message); throw err; }); } function hasLegacyDestinations(settings) { return (getProcessEnv().NODE_ENV !== 'test' && // just one integration means segmentio Object.keys(settings.integrations).length > 1); } function hasTsubMiddleware(settings) { var _a, _b, _c; return (getProcessEnv().NODE_ENV !== 'test' && ((_c = (_b = (_a = settings.middlewareSettings) === null || _a === void 0 ? void 0 : _a.routingRules) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 0); } /** * With AJS classic, we allow users to call setAnonymousId before the library initialization. * This is important because some of the destinations will use the anonymousId during the initialization, * and if we set anonId afterwards, that wouldn’t impact the destination. * * Also Ensures events can be registered before library initialization. * This is important so users can register to 'initialize' and any events that may fire early during setup. */ function flushPreBuffer(analytics, buffer) { flushSetAnonymousID(analytics, buffer); flushOn(analytics, buffer); } /** * Finish flushing buffer and cleanup. */ function flushFinalBuffer(analytics, buffer) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: // Call popSnippetWindowBuffer before each flush task since there may be // analytics calls during async function calls. return [4 /*yield*/, flushAddSourceMiddleware(analytics, buffer)]; case 1: // Call popSnippetWindowBuffer before each flush task since there may be // analytics calls during async function calls. _a.sent(); flushAnalyticsCallsInNewTask(analytics, buffer); return [2 /*return*/]; } }); }); } function registerPlugins(writeKey, cdnSettings, analytics, options, pluginLikes, legacyIntegrationSources, preInitBuffer) { var _a, _b, _c; if (pluginLikes === void 0) { pluginLikes = []; } return __awaiter(this, void 0, void 0, function () { var pluginsFromSettings, pluginSources, tsubMiddleware, _d, legacyDestinations, _e, schemaFilter, _f, mergedSettings, remotePlugins, basePlugins, shouldIgnoreSegmentio, _g, _h, ctx; var _this = this; return __generator(this, function (_j) { switch (_j.label) { case 0: flushPreBuffer(analytics, preInitBuffer); pluginsFromSettings = pluginLikes === null || pluginLikes === void 0 ? void 0 : pluginLikes.filter(function (pluginLike) { return typeof pluginLike === 'object'; }); pluginSources = pluginLikes === null || pluginLikes === void 0 ? void 0 : pluginLikes.filter(function (pluginLike) { return typeof pluginLike === 'function' && typeof pluginLike.pluginName === 'string'; }); if (!hasTsubMiddleware(cdnSettings)) return [3 /*break*/, 2]; return [4 /*yield*/, import( /* webpackChunkName: "tsub-middleware" */ '../plugins/routing-middleware').then(function (mod) { return mod.tsubMiddleware(cdnSettings.middlewareSettings.routingRules); })]; case 1: _d = _j.sent(); return [3 /*break*/, 3]; case 2: _d = undefined; _j.label = 3; case 3: tsubMiddleware = _d; if (!(hasLegacyDestinations(cdnSettings) || legacyIntegrationSources.length > 0)) return [3 /*break*/, 5]; return [4 /*yield*/, import( /* webpackChunkName: "ajs-destination" */ '../plugins/ajs-destination').then(function (mod) { return mod.ajsDestinations(writeKey, cdnSettings, analytics.integrations, options, tsubMiddleware, legacyIntegrationSources); })]; case 4: _e = _j.sent(); return [3 /*break*/, 6]; case 5: _e = []; _j.label = 6; case 6: legacyDestinations = _e; if (!cdnSettings.legacyVideoPluginsEnabled) return [3 /*break*/, 8]; return [4 /*yield*/, import( /* webpackChunkName: "legacyVideos" */ '../plugins/legacy-video-plugins').then(function (mod) { return mod.loadLegacyVideoPlugins(analytics); })]; case 7: _j.sent(); _j.label = 8; case 8: if (!((_a = options.plan) === null || _a === void 0 ? void 0 : _a.track)) return [3 /*break*/, 10]; return [4 /*yield*/, import( /* webpackChunkName: "schemaFilter" */ '../plugins/schema-filter').then(function (mod) { var _a; return mod.schemaFilter((_a = options.plan) === null || _a === void 0 ? void 0 : _a.track, cdnSettings); })]; case 9: _f = _j.sent(); return [3 /*break*/, 11]; case 10: _f = undefined; _j.label = 11; case 11: schemaFilter = _f; mergedSettings = mergedOptions(cdnSettings, options); return [4 /*yield*/, remoteLoader(cdnSettings, analytics.integrations, mergedSettings, options, tsubMiddleware, pluginSources).catch(function () { return []; })]; case 12: remotePlugins = _j.sent(); basePlugins = __spreadArray(__spreadArray([envEnrichment], legacyDestinations, true), remotePlugins, true); if (schemaFilter) { basePlugins.push(schemaFilter); } shouldIgnoreSegmentio = (((_b = options.integrations) === null || _b === void 0 ? void 0 : _b.All) === false && !options.integrations['Segment.io']) || (options.integrations && options.integrations['Segment.io'] === false); if (!!shouldIgnoreSegmentio) return [3 /*break*/, 14]; _h = (_g = basePlugins).push; return [4 /*yield*/, segmentio(analytics, mergedSettings['Segment.io'], cdnSettings.integrations)]; case 13: _h.apply(_g, [_j.sent()]); _j.label = 14; case 14: return [4 /*yield*/, analytics.register.apply(analytics, __spreadArray(__spreadArray([], basePlugins, false), pluginsFromSettings, false))]; case 15: ctx = _j.sent(); // register user-defined plugins registered via analytics.register() return [4 /*yield*/, flushRegister(analytics, preInitBuffer)]; case 16: // register user-defined plugins registered via analytics.register() _j.sent(); if (!Object.entries((_c = cdnSettings.enabledMiddleware) !== null && _c !== void 0 ? _c : {}).some(function (_a) { var enabled = _a[1]; return enabled; })) return [3 /*break*/, 18]; return [4 /*yield*/, import( /* webpackChunkName: "remoteMiddleware" */ '../plugins/remote-middleware').then(function (_a) { var remoteMiddlewares = _a.remoteMiddlewares; return __awaiter(_this, void 0, void 0, function () { var middleware, promises; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, remoteMiddlewares(ctx, cdnSettings, options.obfuscate)]; case 1: middleware = _b.sent(); promises = middleware.map(function (mdw) { return analytics.addSourceMiddleware(mdw); }); return [2 /*return*/, Promise.all(promises)]; } }); }); })]; case 17: _j.sent(); _j.label = 18; case 18: return [2 /*return*/, ctx]; } }); }); } function loadAnalytics(settings, options, preInitBuffer) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; if (options === void 0) { options = {}; } return __awaiter(this, void 0, void 0, function () { var cdnURL, cdnSettings, _m, disabled, retryQueue, analytics, plugins, classicIntegrations, segmentLoadOptions, ctx, search, hash, term; return __generator(this, function (_o) { switch (_o.label) { case 0: // return no-op analytics instance if disabled if (options.disable === true) { return [2 /*return*/, [new NullAnalytics(), Context.system()]]; } if (options.globalAnalyticsKey) setGlobalAnalyticsKey(options.globalAnalyticsKey); // this is an ugly side-effect, but it's for the benefits of the plugins that get their cdn via getCDN() if (settings.cdnURL) setGlobalCDNUrl(settings.cdnURL); if (options.initialPageview) { // capture the page context early, so it's always up-to-date preInitBuffer.add(new PreInitMethodCall('page', [])); } cdnURL = (_a = settings.cdnURL) !== null && _a !== void 0 ? _a : getCDN(); if (!((_b = settings.cdnSettings) !== null && _b !== void 0)) return [3 /*break*/, 1]; _m = _b; return [3 /*break*/, 3]; case 1: return [4 /*yield*/, loadCDNSettings(settings.writeKey, cdnURL)]; case 2: _m = (_o.sent()); _o.label = 3; case 3: cdnSettings = _m; if (options.updateCDNSettings) { cdnSettings = options.updateCDNSettings(cdnSettings); } if (!(typeof options.disable === 'function')) return [3 /*break*/, 5]; return [4 /*yield*/, options.disable(cdnSettings)]; case 4: disabled = _o.sent(); if (disabled) { return [2 /*return*/, [new NullAnalytics(), Context.system()]]; } _o.label = 5; case 5: retryQueue = (_d = (_c = cdnSettings.integrations['Segment.io']) === null || _c === void 0 ? void 0 : _c.retryQueue) !== null && _d !== void 0 ? _d : true; options = __assign({ retryQueue: retryQueue }, options); analytics = new Analytics(__assign(__assign({}, settings), { cdnSettings: cdnSettings, cdnURL: cdnURL }), options); attachInspector(analytics); plugins = (_e = settings.plugins) !== null && _e !== void 0 ? _e : []; classicIntegrations = (_f = settings.classicIntegrations) !== null && _f !== void 0 ? _f : []; segmentLoadOptions = (_g = options.integrations) === null || _g === void 0 ? void 0 : _g['Segment.io']; Stats.initRemoteMetrics(__assign(__assign({}, cdnSettings.metrics), { host: (_h = segmentLoadOptions === null || segmentLoadOptions === void 0 ? void 0 : segmentLoadOptions.apiHost) !== null && _h !== void 0 ? _h : (_j = cdnSettings.metrics) === null || _j === void 0 ? void 0 : _j.host, protocol: segmentLoadOptions === null || segmentLoadOptions === void 0 ? void 0 : segmentLoadOptions.protocol })); return [4 /*yield*/, registerPlugins(settings.writeKey, cdnSettings, analytics, options, plugins, classicIntegrations, preInitBuffer)]; case 6: ctx = _o.sent(); search = (_k = window.location.search) !== null && _k !== void 0 ? _k : ''; hash = (_l = window.location.hash) !== null && _l !== void 0 ? _l : ''; term = search.length ? search : hash.replace(/(?=#).*(?=\?)/, ''); if (!term.includes('ajs_')) return [3 /*break*/, 8]; return [4 /*yield*/, analytics.queryString(term).catch(console.error)]; case 7: _o.sent(); _o.label = 8; case 8: analytics.initialized = true; analytics.emit('initialize', settings, options); return [4 /*yield*/, flushFinalBuffer(analytics, preInitBuffer)]; case 9: _o.sent(); return [2 /*return*/, [analytics, ctx]]; } }); }); } /** * The public browser interface for Segment Analytics * * @example * ```ts * export const analytics = new AnalyticsBrowser() * analytics.load({ writeKey: 'foo' }) * ``` * @link https://github.com/segmentio/analytics-next/#readme */ var AnalyticsBrowser = /** @class */ (function (_super) { __extends(AnalyticsBrowser, _super); function AnalyticsBrowser() { var _this = this; var _a = createDeferred(), loadStart = _a.promise, resolveLoadStart = _a.resolve; _this = _super.call(this, function (buffer) { return loadStart.then(function (_a) { var settings = _a[0], options = _a[1]; return loadAnalytics(settings, options, buffer); }); }) || this; _this._resolveLoadStart = function (settings, options) { return resolveLoadStart([settings, options]); }; return _this; } /** * Fully initialize an analytics instance, including: * * * Fetching settings from the segment CDN (by default). * * Fetching all remote destinations configured by the user (if applicable). * * Flushing buffered analytics events. * * Loading all middleware. * * Note:️ This method should only be called *once* in your application. * * @example * ```ts * export const analytics = new AnalyticsBrowser() * analytics.load({ writeKey: 'foo' }) * ``` */ AnalyticsBrowser.prototype.load = function (settings, options) { if (options === void 0) { options = {}; } this._resolveLoadStart(settings, options); return this; }; /** * Instantiates an object exposing Analytics methods. * * @example * ```ts * const ajs = AnalyticsBrowser.load({ writeKey: '<YOUR_WRITE_KEY>' }) * * ajs.track("foo") * ... * ``` */ AnalyticsBrowser.load = function (settings, options) { if (options === void 0) { options = {}; } return new AnalyticsBrowser().load(settings, options); }; AnalyticsBrowser.standalone = function (writeKey, options) { return AnalyticsBrowser.load({ writeKey: writeKey }, options).then(function (res) { return res[0]; }); }; return AnalyticsBrowser; }(AnalyticsBuffered)); export { AnalyticsBrowser }; //# sourceMappingURL=index.js.map