@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.
352 lines • 17.8 kB
JavaScript
import { __assign, __awaiter, __generator, __spreadArray } from "tslib";
import { Alias, Group, Identify, Page, Track } from '@segment/facade';
import { isOffline, isOnline } from '../../core/connection';
import { Context, ContextCancelation } from '../../core/context';
import { isServer } from '../../core/environment';
import { attempt } from '@segment/analytics-core';
import { isPlanEventEnabled } from '../../lib/is-plan-event-enabled';
import { mergedOptions } from '../../lib/merged-options';
import { pWhile } from '../../lib/p-while';
import { PriorityQueue } from '../../lib/priority-queue';
import { PersistedPriorityQueue } from '../../lib/priority-queue/persisted';
import { applyDestinationMiddleware, } from '../middleware';
import { buildIntegration, loadIntegration, resolveIntegrationNameFromSource, resolveVersion, unloadIntegration, } from './loader';
import { isPlainObject } from '@segment/analytics-core';
import { isDisabledIntegration as shouldSkipIntegration, isInstallableIntegration, } from './utils';
import { recordIntegrationMetric } from '../../core/stats/metric-helpers';
import { createDeferred } from '@segment/analytics-generic-utils';
function flushQueue(xt, queue) {
return __awaiter(this, void 0, void 0, function () {
var failedQueue;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
failedQueue = [];
if (isOffline()) {
return [2 /*return*/, queue];
}
return [4 /*yield*/, pWhile(function () { return queue.length > 0 && isOnline(); }, function () { return __awaiter(_this, void 0, void 0, function () {
var ctx, result, success;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
ctx = queue.pop();
if (!ctx) {
return [2 /*return*/];
}
return [4 /*yield*/, attempt(ctx, xt)];
case 1:
result = _a.sent();
success = result instanceof Context;
if (!success) {
failedQueue.push(ctx);
}
return [2 /*return*/];
}
});
}); })
// re-add failed tasks
];
case 1:
_a.sent();
// re-add failed tasks
failedQueue.map(function (failed) { return queue.pushWithBackoff(failed); });
return [2 /*return*/, queue];
}
});
});
}
var LegacyDestination = /** @class */ (function () {
function LegacyDestination(name, version, writeKey, settings, options, integrationSource) {
if (settings === void 0) { settings = {}; }
var _this = this;
this.options = {};
this.type = 'destination';
this.middleware = [];
this.initializePromise = createDeferred();
this.flushing = false;
this.name = name;
this.version = version;
this.settings = __assign({}, settings);
this.disableAutoISOConversion = options.disableAutoISOConversion || false;
this.integrationSource = integrationSource;
// AJS-Renderer sets an extraneous `type` setting that clobbers
// existing type defaults. We need to remove it if it's present
if (this.settings['type'] && this.settings['type'] === 'browser') {
delete this.settings['type'];
}
this.initializePromise.promise.then(function (isInitialized) { return (_this._initialized = isInitialized); }, function () { });
this.options = options;
this.buffer = options.disableClientPersistence
? new PriorityQueue(4, [])
: new PersistedPriorityQueue(4, "".concat(writeKey, ":dest-").concat(name));
this.scheduleFlush();
}
LegacyDestination.prototype.isLoaded = function () {
return !!this._ready;
};
LegacyDestination.prototype.ready = function () {
var _this = this;
return this.initializePromise.promise.then(function () { var _a; return (_a = _this.onReady) !== null && _a !== void 0 ? _a : Promise.resolve(); });
};
LegacyDestination.prototype.load = function (ctx, analyticsInstance) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var integrationSource, _b;
var _this = this;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (this._ready || this.onReady !== undefined) {
return [2 /*return*/];
}
if (!((_a = this.integrationSource) !== null && _a !== void 0)) return [3 /*break*/, 1];
_b = _a;
return [3 /*break*/, 3];
case 1: return [4 /*yield*/, loadIntegration(ctx, this.name, this.version, this.options.obfuscate)];
case 2:
_b = (_c.sent());
_c.label = 3;
case 3:
integrationSource = _b;
this.integration = buildIntegration(integrationSource, this.settings, analyticsInstance);
this.onReady = new Promise(function (resolve) {
var onReadyFn = function () {
_this._ready = true;
resolve(true);
};
_this.integration.once('ready', onReadyFn);
});
this.integration.on('initialize', function () {
_this.initializePromise.resolve(true);
});
try {
recordIntegrationMetric(ctx, {
integrationName: this.name,
methodName: 'initialize',
type: 'classic',
});
this.integration.initialize();
}
catch (error) {
recordIntegrationMetric(ctx, {
integrationName: this.name,
methodName: 'initialize',
type: 'classic',
didError: true,
});
this.initializePromise.resolve(false);
throw error;
}
return [2 /*return*/];
}
});
});
};
LegacyDestination.prototype.unload = function (_ctx, _analyticsInstance) {
return unloadIntegration(this.name, this.version, this.options.obfuscate);
};
LegacyDestination.prototype.addMiddleware = function () {
var _a;
var fn = [];
for (var _i = 0; _i < arguments.length; _i++) {
fn[_i] = arguments[_i];
}
this.middleware = (_a = this.middleware).concat.apply(_a, fn);
};
LegacyDestination.prototype.shouldBuffer = function (ctx) {
return (
// page events can't be buffered because of destinations that automatically add page views
ctx.event.type !== 'page' &&
(isOffline() || this._ready !== true || this._initialized !== true));
};
LegacyDestination.prototype.send = function (ctx, clz, eventType) {
var _a, _b;
return __awaiter(this, void 0, void 0, function () {
var plan, ev, planEvent, afterMiddleware, event, err_1;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (this.shouldBuffer(ctx)) {
this.buffer.push(ctx);
this.scheduleFlush();
return [2 /*return*/, ctx];
}
plan = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.plan) === null || _b === void 0 ? void 0 : _b.track;
ev = ctx.event.event;
if (plan && ev && this.name !== 'Segment.io') {
planEvent = plan[ev];
if (!isPlanEventEnabled(plan, planEvent)) {
ctx.updateEvent('integrations', __assign(__assign({}, ctx.event.integrations), { All: false, 'Segment.io': true }));
ctx.cancel(new ContextCancelation({
retry: false,
reason: "Event ".concat(ev, " disabled for integration ").concat(this.name, " in tracking plan"),
type: 'Dropped by plan',
}));
}
else {
ctx.updateEvent('integrations', __assign(__assign({}, ctx.event.integrations), planEvent === null || planEvent === void 0 ? void 0 : planEvent.integrations));
}
if ((planEvent === null || planEvent === void 0 ? void 0 : planEvent.enabled) && (planEvent === null || planEvent === void 0 ? void 0 : planEvent.integrations[this.name]) === false) {
ctx.cancel(new ContextCancelation({
retry: false,
reason: "Event ".concat(ev, " disabled for integration ").concat(this.name, " in tracking plan"),
type: 'Dropped by plan',
}));
}
}
return [4 /*yield*/, applyDestinationMiddleware(this.name, ctx.event, this.middleware)];
case 1:
afterMiddleware = _c.sent();
if (afterMiddleware === null) {
return [2 /*return*/, ctx];
}
event = new clz(afterMiddleware, {
traverse: !this.disableAutoISOConversion,
});
recordIntegrationMetric(ctx, {
integrationName: this.name,
methodName: eventType,
type: 'classic',
});
_c.label = 2;
case 2:
_c.trys.push([2, 5, , 6]);
if (!this.integration) return [3 /*break*/, 4];
return [4 /*yield*/, this.integration.invoke.call(this.integration, eventType, event)];
case 3:
_c.sent();
_c.label = 4;
case 4: return [3 /*break*/, 6];
case 5:
err_1 = _c.sent();
recordIntegrationMetric(ctx, {
integrationName: this.name,
methodName: eventType,
type: 'classic',
didError: true,
});
throw err_1;
case 6: return [2 /*return*/, ctx];
}
});
});
};
LegacyDestination.prototype.track = function (ctx) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.send(ctx, Track, 'track')];
});
});
};
LegacyDestination.prototype.page = function (ctx) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (((_a = this.integration) === null || _a === void 0 ? void 0 : _a._assumesPageview) && !this._initialized) {
this.integration.initialize();
}
return [4 /*yield*/, this.initializePromise.promise];
case 1:
_b.sent();
return [2 /*return*/, this.send(ctx, Page, 'page')];
}
});
});
};
LegacyDestination.prototype.identify = function (ctx) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.send(ctx, Identify, 'identify')];
});
});
};
LegacyDestination.prototype.alias = function (ctx) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.send(ctx, Alias, 'alias')];
});
});
};
LegacyDestination.prototype.group = function (ctx) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.send(ctx, Group, 'group')];
});
});
};
LegacyDestination.prototype.scheduleFlush = function () {
var _this = this;
if (this.flushing) {
return;
}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (isOffline() || this._ready !== true || this._initialized !== true) {
this.scheduleFlush();
return [2 /*return*/];
}
this.flushing = true;
_a = this;
return [4 /*yield*/, flushQueue(this, this.buffer)];
case 1:
_a.buffer = _b.sent();
this.flushing = false;
if (this.buffer.todo > 0) {
this.scheduleFlush();
}
return [2 /*return*/];
}
});
}); }, Math.random() * 5000);
};
return LegacyDestination;
}());
export { LegacyDestination };
export function ajsDestinations(writeKey, settings, globalIntegrations, options, routingMiddleware, legacyIntegrationSources) {
var _a, _b;
if (globalIntegrations === void 0) { globalIntegrations = {}; }
if (options === void 0) { options = {}; }
if (isServer()) {
return [];
}
if (settings.plan) {
options = options !== null && options !== void 0 ? options : {};
options.plan = settings.plan;
}
var routingRules = (_b = (_a = settings.middlewareSettings) === null || _a === void 0 ? void 0 : _a.routingRules) !== null && _b !== void 0 ? _b : [];
var remoteIntegrationsConfig = settings.integrations;
var localIntegrationsConfig = options.integrations;
// merged remote CDN settings with user provided options
var integrationOptions = mergedOptions(settings, options !== null && options !== void 0 ? options : {});
var adhocIntegrationSources = legacyIntegrationSources === null || legacyIntegrationSources === void 0 ? void 0 : legacyIntegrationSources.reduce(function (acc, integrationSource) {
var _a;
return (__assign(__assign({}, acc), (_a = {}, _a[resolveIntegrationNameFromSource(integrationSource)] = integrationSource, _a)));
}, {});
var installableIntegrations = new Set(__spreadArray(__spreadArray([], Object.keys(remoteIntegrationsConfig).filter(function (name) {
return isInstallableIntegration(name, remoteIntegrationsConfig[name]);
}), true), Object.keys(adhocIntegrationSources || {}).filter(function (name) {
return isPlainObject(remoteIntegrationsConfig[name]) ||
isPlainObject(localIntegrationsConfig === null || localIntegrationsConfig === void 0 ? void 0 : localIntegrationsConfig[name]);
}), true));
return Array.from(installableIntegrations)
.filter(function (name) { return !shouldSkipIntegration(name, globalIntegrations); })
.map(function (name) {
var integrationSettings = remoteIntegrationsConfig[name];
var version = resolveVersion(integrationSettings);
var destination = new LegacyDestination(name, version, writeKey, integrationOptions[name], options, adhocIntegrationSources === null || adhocIntegrationSources === void 0 ? void 0 : adhocIntegrationSources[name]);
var routing = routingRules.filter(function (rule) { return rule.destinationName === name; });
if (routing.length > 0 && routingMiddleware) {
destination.addMiddleware(routingMiddleware);
}
return destination;
});
}
//# sourceMappingURL=index.js.map