@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.
338 lines • 18.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnalyticsBrowser = exports.loadCDNSettings = void 0;
var tslib_1 = require("tslib");
var get_process_env_1 = require("../lib/get-process-env");
var parse_cdn_1 = require("../lib/parse-cdn");
var fetch_1 = require("../lib/fetch");
var analytics_1 = require("../core/analytics");
var context_1 = require("../core/context");
var merged_options_1 = require("../lib/merged-options");
var analytics_generic_utils_1 = require("@segment/analytics-generic-utils");
var env_enrichment_1 = require("../plugins/env-enrichment");
var remote_loader_1 = require("../plugins/remote-loader");
var segmentio_1 = require("../plugins/segmentio");
var buffer_1 = require("../core/buffer");
var inspector_1 = require("../core/inspector");
var stats_1 = require("../core/stats");
var global_analytics_helper_1 = require("../lib/global-analytics-helper");
function loadCDNSettings(writeKey, baseUrl) {
return (0, fetch_1.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;
});
}
exports.loadCDNSettings = loadCDNSettings;
function hasLegacyDestinations(settings) {
return ((0, get_process_env_1.getProcessEnv)().NODE_ENV !== 'test' &&
// just one integration means segmentio
Object.keys(settings.integrations).length > 1);
}
function hasTsubMiddleware(settings) {
var _a, _b, _c;
return ((0, get_process_env_1.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) {
(0, buffer_1.flushSetAnonymousID)(analytics, buffer);
(0, buffer_1.flushOn)(analytics, buffer);
}
/**
* Finish flushing buffer and cleanup.
*/
function flushFinalBuffer(analytics, buffer) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__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*/, (0, buffer_1.flushAddSourceMiddleware)(analytics, buffer)];
case 1:
// Call popSnippetWindowBuffer before each flush task since there may be
// analytics calls during async function calls.
_a.sent();
(0, buffer_1.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 tslib_1.__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 tslib_1.__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*/, Promise.resolve().then(function () { return tslib_1.__importStar(require(
/* 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*/, Promise.resolve().then(function () { return tslib_1.__importStar(require(
/* 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*/, Promise.resolve().then(function () { return tslib_1.__importStar(require(
/* 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*/, Promise.resolve().then(function () { return tslib_1.__importStar(require(
/* 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 = (0, merged_options_1.mergedOptions)(cdnSettings, options);
return [4 /*yield*/, (0, remote_loader_1.remoteLoader)(cdnSettings, analytics.integrations, mergedSettings, options, tsubMiddleware, pluginSources).catch(function () { return []; })];
case 12:
remotePlugins = _j.sent();
basePlugins = tslib_1.__spreadArray(tslib_1.__spreadArray([env_enrichment_1.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*/, (0, segmentio_1.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, tslib_1.__spreadArray(tslib_1.__spreadArray([], basePlugins, false), pluginsFromSettings, false))];
case 15:
ctx = _j.sent();
// register user-defined plugins registered via analytics.register()
return [4 /*yield*/, (0, buffer_1.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*/, Promise.resolve().then(function () { return tslib_1.__importStar(require(
/* webpackChunkName: "remoteMiddleware" */ '../plugins/remote-middleware')); }).then(function (_a) {
var remoteMiddlewares = _a.remoteMiddlewares;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var middleware, promises;
return tslib_1.__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 tslib_1.__awaiter(this, void 0, void 0, function () {
var cdnURL, cdnSettings, _m, disabled, retryQueue, analytics, plugins, classicIntegrations, segmentLoadOptions, ctx, search, hash, term;
return tslib_1.__generator(this, function (_o) {
switch (_o.label) {
case 0:
// return no-op analytics instance if disabled
if (options.disable === true) {
return [2 /*return*/, [new analytics_1.NullAnalytics(), context_1.Context.system()]];
}
if (options.globalAnalyticsKey)
(0, global_analytics_helper_1.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)
(0, parse_cdn_1.setGlobalCDNUrl)(settings.cdnURL);
if (options.initialPageview) {
// capture the page context early, so it's always up-to-date
preInitBuffer.add(new buffer_1.PreInitMethodCall('page', []));
}
cdnURL = (_a = settings.cdnURL) !== null && _a !== void 0 ? _a : (0, parse_cdn_1.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 analytics_1.NullAnalytics(), context_1.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 = tslib_1.__assign({ retryQueue: retryQueue }, options);
analytics = new analytics_1.Analytics(tslib_1.__assign(tslib_1.__assign({}, settings), { cdnSettings: cdnSettings, cdnURL: cdnURL }), options);
(0, inspector_1.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_1.Stats.initRemoteMetrics(tslib_1.__assign(tslib_1.__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) {
tslib_1.__extends(AnalyticsBrowser, _super);
function AnalyticsBrowser() {
var _this = this;
var _a = (0, analytics_generic_utils_1.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;
}(buffer_1.AnalyticsBuffered));
exports.AnalyticsBrowser = AnalyticsBrowser;
//# sourceMappingURL=index.js.map