@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
JavaScript
"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