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.

346 lines 13.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AnalyticsBuffered = exports.callAnalyticsMethod = exports.PreInitMethodCallBuffer = exports.PreInitMethodCall = exports.hasBufferedPageContextAsLastArg = exports.popPageContext = exports.flushAnalyticsCallsInNewTask = exports.flushSetAnonymousID = exports.flushOn = exports.flushRegister = exports.flushAddSourceMiddleware = void 0; var tslib_1 = require("tslib"); var is_thenable_1 = require("../../lib/is-thenable"); var version_1 = require("../../generated/version"); var global_analytics_helper_1 = require("../../lib/global-analytics-helper"); var page_1 = require("../page"); var version_type_1 = require("../../lib/version-type"); var flushSyncAnalyticsCalls = function (name, analytics, buffer) { buffer.getAndRemove(name).forEach(function (c) { // While the underlying methods are synchronous, the callAnalyticsMethod returns a promise, // which normalizes success and error states between async and non-async methods, with no perf penalty. callAnalyticsMethod(analytics, c).catch(console.error); }); }; var flushAddSourceMiddleware = function (analytics, buffer) { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var _i, _a, c; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: _i = 0, _a = buffer.getAndRemove('addSourceMiddleware'); _b.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 4]; c = _a[_i]; return [4 /*yield*/, callAnalyticsMethod(analytics, c).catch(console.error)]; case 2: _b.sent(); _b.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); }; exports.flushAddSourceMiddleware = flushAddSourceMiddleware; /** * Flush register plugin */ var flushRegister = function (analytics, buffer) { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var _i, _a, c; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: _i = 0, _a = buffer.getAndRemove('register'); _b.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 4]; c = _a[_i]; return [4 /*yield*/, callAnalyticsMethod(analytics, c).catch(console.error)]; case 2: _b.sent(); _b.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); }; exports.flushRegister = flushRegister; exports.flushOn = flushSyncAnalyticsCalls.bind(this, 'on'); exports.flushSetAnonymousID = flushSyncAnalyticsCalls.bind(this, 'setAnonymousId'); var flushAnalyticsCallsInNewTask = function (analytics, buffer) { ; Object.keys(buffer.calls).forEach(function (m) { buffer.getAndRemove(m).forEach(function (c) { // No one remembers why this event loop optimization is/was neccessary. Lost to history. setTimeout(function () { callAnalyticsMethod(analytics, c).catch(console.error); }, 0); }); }); }; exports.flushAnalyticsCallsInNewTask = flushAnalyticsCallsInNewTask; var popPageContext = function (args) { if ((0, exports.hasBufferedPageContextAsLastArg)(args)) { var ctx = args.pop(); return (0, page_1.createPageContext)(ctx); } }; exports.popPageContext = popPageContext; var hasBufferedPageContextAsLastArg = function (args) { var lastArg = args[args.length - 1]; return (0, page_1.isBufferedPageContext)(lastArg); }; exports.hasBufferedPageContextAsLastArg = hasBufferedPageContextAsLastArg; /** * Represents a buffered method call that occurred before initialization. */ var PreInitMethodCall = /** @class */ (function () { function PreInitMethodCall(method, args, resolve, reject) { if (resolve === void 0) { resolve = function () { }; } if (reject === void 0) { reject = console.error; } this.method = method; this.resolve = resolve; this.reject = reject; this.called = false; this.args = args; } return PreInitMethodCall; }()); exports.PreInitMethodCall = PreInitMethodCall; /** * Represents any and all the buffered method calls that occurred before initialization. */ var PreInitMethodCallBuffer = /** @class */ (function () { function PreInitMethodCallBuffer() { var calls = []; for (var _i = 0; _i < arguments.length; _i++) { calls[_i] = arguments[_i]; } this._callMap = {}; this.add.apply(this, calls); } Object.defineProperty(PreInitMethodCallBuffer.prototype, "calls", { /** * Pull any buffered method calls from the window object, and use them to hydrate the instance buffer. */ get: function () { this._pushSnippetWindowBuffer(); return this._callMap; }, set: function (calls) { this._callMap = calls; }, enumerable: false, configurable: true }); PreInitMethodCallBuffer.prototype.get = function (methodName) { var _a; return ((_a = this.calls[methodName]) !== null && _a !== void 0 ? _a : []); }; /** * Get all buffered method calls for a given method name, and clear them from the buffer. */ PreInitMethodCallBuffer.prototype.getAndRemove = function (methodName) { var calls = this.get(methodName); this.calls[methodName] = []; return calls; }; PreInitMethodCallBuffer.prototype.add = function () { var _this = this; var calls = []; for (var _i = 0; _i < arguments.length; _i++) { calls[_i] = arguments[_i]; } calls.forEach(function (call) { var eventsExpectingPageContext = [ 'track', 'screen', 'alias', 'group', 'page', 'identify', ]; if (eventsExpectingPageContext.includes(call.method) && !(0, exports.hasBufferedPageContextAsLastArg)(call.args)) { call.args = tslib_1.__spreadArray(tslib_1.__spreadArray([], call.args, true), [(0, page_1.getDefaultBufferedPageContext)()], false); } if (_this.calls[call.method]) { _this.calls[call.method].push(call); } else { _this.calls[call.method] = [call]; } }); }; PreInitMethodCallBuffer.prototype.clear = function () { // clear calls in the global snippet buffered array. this._pushSnippetWindowBuffer(); // clear calls in this instance this.calls = {}; }; PreInitMethodCallBuffer.prototype.toArray = function () { var _a; return (_a = []).concat.apply(_a, Object.values(this.calls)); }; /** * Fetch the buffered method calls from the window object, * normalize them, and use them to hydrate the buffer. * This removes existing buffered calls from the window object. */ PreInitMethodCallBuffer.prototype._pushSnippetWindowBuffer = function () { // if this is the npm version, we don't want to read from the window object. // This avoids namespace conflicts if there is a seperate analytics library on the page. if ((0, version_type_1.getVersionType)() === 'npm') { return undefined; } var wa = (0, global_analytics_helper_1.getGlobalAnalytics)(); if (!Array.isArray(wa)) return undefined; var buffered = wa.splice(0, wa.length); var calls = buffered.map(function (_a) { var methodName = _a[0], args = _a.slice(1); return new PreInitMethodCall(methodName, args); }); this.add.apply(this, calls); }; return PreInitMethodCallBuffer; }()); exports.PreInitMethodCallBuffer = PreInitMethodCallBuffer; /** * Call method and mark as "called" * This function should never throw an error */ function callAnalyticsMethod(analytics, call) { return tslib_1.__awaiter(this, void 0, void 0, function () { var result, err_1; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 3, , 4]); if (call.called) { return [2 /*return*/, undefined]; } call.called = true; result = analytics[call.method].apply(analytics, call.args); if (!(0, is_thenable_1.isThenable)(result)) return [3 /*break*/, 2]; // do not defer for non-async methods return [4 /*yield*/, result]; case 1: // do not defer for non-async methods _a.sent(); _a.label = 2; case 2: call.resolve(result); return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); call.reject(err_1); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); } exports.callAnalyticsMethod = callAnalyticsMethod; var AnalyticsBuffered = /** @class */ (function () { function AnalyticsBuffered(loader) { var _this = this; this.trackSubmit = this._createMethod('trackSubmit'); this.trackClick = this._createMethod('trackClick'); this.trackLink = this._createMethod('trackLink'); this.pageView = this._createMethod('pageview'); this.identify = this._createMethod('identify'); this.reset = this._createMethod('reset'); this.group = this._createMethod('group'); this.track = this._createMethod('track'); this.ready = this._createMethod('ready'); this.alias = this._createMethod('alias'); this.debug = this._createChainableMethod('debug'); this.page = this._createMethod('page'); this.once = this._createChainableMethod('once'); this.off = this._createChainableMethod('off'); this.on = this._createChainableMethod('on'); this.addSourceMiddleware = this._createMethod('addSourceMiddleware'); this.setAnonymousId = this._createMethod('setAnonymousId'); this.addDestinationMiddleware = this._createMethod('addDestinationMiddleware'); this.screen = this._createMethod('screen'); this.register = this._createMethod('register'); this.deregister = this._createMethod('deregister'); this.user = this._createMethod('user'); this.VERSION = version_1.version; this._preInitBuffer = new PreInitMethodCallBuffer(); this._promise = loader(this._preInitBuffer); this._promise .then(function (_a) { var ajs = _a[0], ctx = _a[1]; _this.instance = ajs; _this.ctx = ctx; }) .catch(function () { // intentionally do nothing... // this result of this promise will be caught by the 'catch' block on this class. }); } AnalyticsBuffered.prototype.then = function () { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return (_a = this._promise).then.apply(_a, args); }; AnalyticsBuffered.prototype.catch = function () { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return (_a = this._promise).catch.apply(_a, args); }; AnalyticsBuffered.prototype.finally = function () { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return (_a = this._promise).finally.apply(_a, args); }; AnalyticsBuffered.prototype._createMethod = function (methodName) { var _this = this; return function () { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (_this.instance) { var result = (_a = _this.instance)[methodName].apply(_a, args); return Promise.resolve(result); } return new Promise(function (resolve, reject) { _this._preInitBuffer.add(new PreInitMethodCall(methodName, args, resolve, reject)); }); }; }; /** * These are for methods that where determining when the method gets "flushed" is not important. * These methods will resolve when analytics is fully initialized, and return type (other than Analytics)will not be available. */ AnalyticsBuffered.prototype._createChainableMethod = function (methodName) { var _this = this; return function () { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (_this.instance) { void (_a = _this.instance)[methodName].apply(_a, args); return _this; } else { _this._preInitBuffer.add(new PreInitMethodCall(methodName, args)); } return _this; }; }; return AnalyticsBuffered; }()); exports.AnalyticsBuffered = AnalyticsBuffered; //# sourceMappingURL=index.js.map