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.

316 lines 15.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.remoteLoader = exports.ActionDestination = void 0; var tslib_1 = require("tslib"); var load_script_1 = require("../../lib/load-script"); var parse_cdn_1 = require("../../lib/parse-cdn"); var middleware_1 = require("../middleware"); var context_1 = require("../../core/context"); var metric_helpers_1 = require("../../core/stats/metric-helpers"); var analytics_generic_utils_1 = require("@segment/analytics-generic-utils"); var ActionDestination = /** @class */ (function () { function ActionDestination(name, action) { this.version = '1.0.0'; this.alternativeNames = []; this.loadPromise = (0, analytics_generic_utils_1.createDeferred)(); this.middleware = []; this.alias = this._createMethod('alias'); this.group = this._createMethod('group'); this.identify = this._createMethod('identify'); this.page = this._createMethod('page'); this.screen = this._createMethod('screen'); this.track = this._createMethod('track'); this.action = action; this.name = name; this.type = action.type; this.alternativeNames.push(action.name); } ActionDestination.prototype.addMiddleware = function () { var _a; var fn = []; for (var _i = 0; _i < arguments.length; _i++) { fn[_i] = arguments[_i]; } /** Make sure we only apply destination filters to actions of the "destination" type to avoid causing issues for hybrid destinations */ if (this.type === 'destination') { (_a = this.middleware).push.apply(_a, fn); } }; ActionDestination.prototype.transform = function (ctx) { return tslib_1.__awaiter(this, void 0, void 0, function () { var modifiedEvent; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, middleware_1.applyDestinationMiddleware)(this.name, ctx.event, this.middleware)]; case 1: modifiedEvent = _a.sent(); if (modifiedEvent === null) { ctx.cancel(new context_1.ContextCancelation({ retry: false, reason: 'dropped by destination middleware', })); } return [2 /*return*/, new context_1.Context(modifiedEvent)]; } }); }); }; ActionDestination.prototype._createMethod = function (methodName) { var _this = this; return function (ctx) { return tslib_1.__awaiter(_this, void 0, void 0, function () { var transformedContext, error_1; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!this.action[methodName]) return [2 /*return*/, ctx]; transformedContext = ctx; if (!(this.type === 'destination')) return [3 /*break*/, 2]; return [4 /*yield*/, this.transform(ctx)]; case 1: transformedContext = _a.sent(); _a.label = 2; case 2: _a.trys.push([2, 5, , 6]); return [4 /*yield*/, this.ready()]; case 3: if (!(_a.sent())) { throw new Error('Something prevented the destination from getting ready'); } (0, metric_helpers_1.recordIntegrationMetric)(ctx, { integrationName: this.action.name, methodName: methodName, type: 'action', }); return [4 /*yield*/, this.action[methodName](transformedContext)]; case 4: _a.sent(); return [3 /*break*/, 6]; case 5: error_1 = _a.sent(); (0, metric_helpers_1.recordIntegrationMetric)(ctx, { integrationName: this.action.name, methodName: methodName, type: 'action', didError: true, }); throw error_1; case 6: return [2 /*return*/, ctx]; } }); }); }; }; /* --- PASSTHROUGH METHODS --- */ ActionDestination.prototype.isLoaded = function () { return this.action.isLoaded(); }; ActionDestination.prototype.ready = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: _b.trys.push([0, 2, , 3]); return [4 /*yield*/, this.loadPromise.promise]; case 1: _b.sent(); return [2 /*return*/, true]; case 2: _a = _b.sent(); return [2 /*return*/, false]; case 3: return [2 /*return*/]; } }); }); }; ActionDestination.prototype.load = function (ctx, analytics) { return tslib_1.__awaiter(this, void 0, void 0, function () { var loadP, _a, _b, error_2; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: if (this.loadPromise.isSettled()) { return [2 /*return*/, this.loadPromise.promise]; } _c.label = 1; case 1: _c.trys.push([1, 3, , 4]); (0, metric_helpers_1.recordIntegrationMetric)(ctx, { integrationName: this.action.name, methodName: 'load', type: 'action', }); loadP = this.action.load(ctx, analytics); _b = (_a = this.loadPromise).resolve; return [4 /*yield*/, loadP]; case 2: _b.apply(_a, [_c.sent()]); return [2 /*return*/, loadP]; case 3: error_2 = _c.sent(); (0, metric_helpers_1.recordIntegrationMetric)(ctx, { integrationName: this.action.name, methodName: 'load', type: 'action', didError: true, }); this.loadPromise.reject(error_2); throw error_2; case 4: return [2 /*return*/]; } }); }); }; ActionDestination.prototype.unload = function (ctx, analytics) { var _a, _b; return (_b = (_a = this.action).unload) === null || _b === void 0 ? void 0 : _b.call(_a, ctx, analytics); }; return ActionDestination; }()); exports.ActionDestination = ActionDestination; function validate(pluginLike) { if (!Array.isArray(pluginLike)) { throw new Error('Not a valid list of plugins'); } var required = ['load', 'isLoaded', 'name', 'version', 'type']; pluginLike.forEach(function (plugin) { required.forEach(function (method) { var _a; if (plugin[method] === undefined) { throw new Error("Plugin: ".concat((_a = plugin.name) !== null && _a !== void 0 ? _a : 'unknown', " missing required function ").concat(method)); } }); }); return true; } function isPluginDisabled(userIntegrations, remotePlugin) { var creationNameEnabled = userIntegrations[remotePlugin.creationName]; var currentNameEnabled = userIntegrations[remotePlugin.name]; // Check that the plugin isn't explicitly enabled when All: false if (userIntegrations.All === false && !creationNameEnabled && !currentNameEnabled) { return true; } // Check that the plugin isn't explicitly disabled if (creationNameEnabled === false || currentNameEnabled === false) { return true; } return false; } function loadPluginFactory(remotePlugin, obfuscate) { return tslib_1.__awaiter(this, void 0, void 0, function () { var defaultCdn, cdn, urlSplit, name_1, obfuscatedURL, error_3, err_1; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 9, , 10]); defaultCdn = new RegExp('https://cdn.segment.(com|build)'); cdn = (0, parse_cdn_1.getCDN)(); if (!obfuscate) return [3 /*break*/, 6]; urlSplit = remotePlugin.url.split('/'); name_1 = urlSplit[urlSplit.length - 2]; obfuscatedURL = remotePlugin.url.replace(name_1, btoa(name_1).replace(/=/g, '')); _a.label = 1; case 1: _a.trys.push([1, 3, , 5]); return [4 /*yield*/, (0, load_script_1.loadScript)(obfuscatedURL.replace(defaultCdn, cdn))]; case 2: _a.sent(); return [3 /*break*/, 5]; case 3: error_3 = _a.sent(); // Due to syncing concerns it is possible that the obfuscated action destination (or requested version) might not exist. // We should use the unobfuscated version as a fallback. return [4 /*yield*/, (0, load_script_1.loadScript)(remotePlugin.url.replace(defaultCdn, cdn))]; case 4: // Due to syncing concerns it is possible that the obfuscated action destination (or requested version) might not exist. // We should use the unobfuscated version as a fallback. _a.sent(); return [3 /*break*/, 5]; case 5: return [3 /*break*/, 8]; case 6: return [4 /*yield*/, (0, load_script_1.loadScript)(remotePlugin.url.replace(defaultCdn, cdn))]; case 7: _a.sent(); _a.label = 8; case 8: // @ts-expect-error if (typeof window[remotePlugin.libraryName] === 'function') { // @ts-expect-error return [2 /*return*/, window[remotePlugin.libraryName]]; } return [3 /*break*/, 10]; case 9: err_1 = _a.sent(); console.error('Failed to create PluginFactory', remotePlugin); throw err_1; case 10: return [2 /*return*/]; } }); }); } function remoteLoader(settings, userIntegrations, mergedIntegrations, options, routingMiddleware, pluginSources) { var _a, _b, _c; return tslib_1.__awaiter(this, void 0, void 0, function () { var allPlugins, routingRules, pluginPromises; var _this = this; return tslib_1.__generator(this, function (_d) { switch (_d.label) { case 0: allPlugins = []; routingRules = (_b = (_a = settings.middlewareSettings) === null || _a === void 0 ? void 0 : _a.routingRules) !== null && _b !== void 0 ? _b : []; pluginPromises = ((_c = settings.remotePlugins) !== null && _c !== void 0 ? _c : []).map(function (remotePlugin) { return tslib_1.__awaiter(_this, void 0, void 0, function () { var pluginFactory, _a, plugin, plugins, routing_1, error_4; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: if (isPluginDisabled(userIntegrations, remotePlugin)) return [2 /*return*/]; _b.label = 1; case 1: _b.trys.push([1, 6, , 7]); _a = (pluginSources === null || pluginSources === void 0 ? void 0 : pluginSources.find(function (_a) { var pluginName = _a.pluginName; return pluginName === remotePlugin.name; })); if (_a) return [3 /*break*/, 3]; return [4 /*yield*/, loadPluginFactory(remotePlugin, options === null || options === void 0 ? void 0 : options.obfuscate)]; case 2: _a = (_b.sent()); _b.label = 3; case 3: pluginFactory = _a; if (!pluginFactory) return [3 /*break*/, 5]; return [4 /*yield*/, pluginFactory(tslib_1.__assign(tslib_1.__assign({}, remotePlugin.settings), mergedIntegrations[remotePlugin.name]))]; case 4: plugin = _b.sent(); plugins = Array.isArray(plugin) ? plugin : [plugin]; validate(plugins); routing_1 = routingRules.filter(function (rule) { return rule.destinationName === remotePlugin.creationName; }); plugins.forEach(function (plugin) { var wrapper = new ActionDestination(remotePlugin.creationName, plugin); if (routing_1.length && routingMiddleware) { wrapper.addMiddleware(routingMiddleware); } allPlugins.push(wrapper); }); _b.label = 5; case 5: return [3 /*break*/, 7]; case 6: error_4 = _b.sent(); console.warn('Failed to load Remote Plugin', error_4); return [3 /*break*/, 7]; case 7: return [2 /*return*/]; } }); }); }); return [4 /*yield*/, Promise.all(pluginPromises)]; case 1: _d.sent(); return [2 /*return*/, allPlugins.filter(Boolean)]; } }); }); } exports.remoteLoader = remoteLoader; //# sourceMappingURL=index.js.map