analytics-react-native
Version:
A React Native client for [Segment](https://segment.com) — The hassle-free way to integrate analytics into any application.
320 lines (244 loc) • 8.96 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _base = require('base-64');
var _base2 = _interopRequireDefault(_base);
var _assert = require('./helpers/assert');
var _assert2 = _interopRequireDefault(_assert);
var _validate = require('./helpers/validate');
var _validate2 = _interopRequireDefault(_validate);
var _fetchRetry = require('./helpers/fetch-retry');
var _fetchRetry2 = _interopRequireDefault(_fetchRetry);
var _uid = require('./helpers/uid');
var _uid2 = _interopRequireDefault(_uid);
var _parseResponse = require('./helpers/parse-response');
var _parseResponse2 = _interopRequireDefault(_parseResponse);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// TODO move this to /test
var _ref = process.env.NODE_ENV === 'test' ? { Platform: { OS: 'react-native' } } : require('react-native'),
Platform = _ref.Platform;
var VERSION = '1.2.0';
var noop = function noop() {};
/**
* Expose an `Analytics` client.
*/
var Analytics = function () {
/**
* Initialize a new `Analytics` with your Segment project's `writeKey` and an
* optional dictionary of `options`.
*
* @param {String} writeKey
* @param {Object} options (optional)
* @property {Number} flushAt (default: 20)
* @property {Number} flushAfter (default: 10000)
* @property {String} host (default: 'https://api.segment.io')
*/
function Analytics(writeKey) {
var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref2$host = _ref2.host,
host = _ref2$host === undefined ? Analytics.DEFAULT_HOST : _ref2$host,
_ref2$flushAt = _ref2.flushAt,
flushAt = _ref2$flushAt === undefined ? Analytics.DEFAULT_FLUSH_AT : _ref2$flushAt,
_ref2$flushAfter = _ref2.flushAfter,
flushAfter = _ref2$flushAfter === undefined ? Analytics.DEFAULT_FLUSH_AFTER : _ref2$flushAfter;
_classCallCheck(this, Analytics);
(0, _assert2.default)(writeKey, 'You must pass your Segment project\'s write key.');
this.queue = [];
this.writeKey = writeKey;
this.host = host;
this.flushAt = Math.max(flushAt, 1);
this.flushAfter = flushAfter;
}
/**
* Send an identify `message`.
*
* @param {Object} message
* @param {Function} fn (optional)
* @return {Analytics}
*/
_createClass(Analytics, [{
key: 'identify',
value: function identify(message, fn) {
(0, _validate2.default)(message);
(0, _assert2.default)(message.anonymousId || message.userId, 'You must pass either an `anonymousId` or a `userId`.');
this.enqueue('identify', message, fn);
return this;
}
/**
* Send a group `message`.
*
* @param {Object} message
* @param {Function} fn (optional)
* @return {Analytics}
*/
}, {
key: 'group',
value: function group(message, fn) {
(0, _validate2.default)(message);
(0, _assert2.default)(message.anonymousId || message.userId, 'You must pass either an `anonymousId` or a `userId`.');
(0, _assert2.default)(message.groupId, 'You must pass a `groupId`.');
this.enqueue('group', message, fn);
return this;
}
/**
* Send a track `message`.
*
* @param {Object} message
* @param {Function} fn (optional)
* @return {Analytics}
*/
}, {
key: 'track',
value: function track(message, fn) {
(0, _validate2.default)(message);
(0, _assert2.default)(message.anonymousId || message.userId, 'You must pass either an `anonymousId` or a `userId`.');
(0, _assert2.default)(message.event, 'You must pass an `event`.');
this.enqueue('track', message, fn);
return this;
}
/**
* Send a page `message`.
*
* @param {Object} message
* @param {Function} fn (optional)
* @return {Analytics}
*/
}, {
key: 'page',
value: function page(message, fn) {
(0, _validate2.default)(message);
(0, _assert2.default)(message.anonymousId || message.userId, 'You must pass either an `anonymousId` or a `userId`.');
this.enqueue('page', message, fn);
return this;
}
/**
* Send a screen `message`.
*
* @param {Object} message
* @param {Function} fn (optional)
* @return {Analytics}
*/
}, {
key: 'screen',
value: function screen(message, fn) {
(0, _validate2.default)(message);
(0, _assert2.default)(message.anonymousId || message.userId, 'You must pass either an `anonymousId` or a `userId`.');
this.enqueue('screen', message, fn);
return this;
}
/**
* Send an alias `message`.
*
* @param {Object} message
* @param {Function} fn (optional)
* @return {Analytics}
*/
}, {
key: 'alias',
value: function alias(message, fn) {
(0, _validate2.default)(message);
(0, _assert2.default)(message.userId, 'You must pass a `userId`.');
(0, _assert2.default)(message.previousId, 'You must pass a `previousId`.');
this.enqueue('alias', message, fn);
return this;
}
/**
* Flush the current queue and callback `fn(err, batch)`.
*
* @param {Function} fn (optional)
* @return {Analytics}
*/
}, {
key: 'flush',
value: function flush() {
var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : noop;
if (!this.queue.length) {
return setImmediate(callback);
}
var items = this.queue.splice(0, this.flushAt);
var fns = items.map(function (item) {
return item.callback;
});
fns.push(callback);
var batch = items.map(function (item) {
return item.message;
});
var data = {
batch: batch,
timestamp: new Date(),
sentAt: new Date()
};
(0, _fetchRetry2.default)(this.host + '/v1/batch', {
body: JSON.stringify(data),
method: 'post',
headers: {
Authorization: 'Basic ' + _base2.default.encode(this.writeKey),
'Content-Type': 'application/json; charset=utf-8',
'X-Requested-With': 'XMLHttpRequest'
},
retries: 5
}).then(_parseResponse2.default).then(function () {
fns.forEach(function (fn) {
fn(undefined, data);
});
}).catch(function (error) {
fns.forEach(function (fn) {
fn(error);
});
});
return true;
}
/**
* Add a `message` of type `type` to the queue and check whether it should be
* flushed.
*
* @param {String} messageType
* @param {Object} message
* @param {Functino} fn (optional)
* @api private
*/
}, {
key: 'enqueue',
value: function enqueue(messageType, msg) {
var _this = this;
var fn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : noop;
var message = _extends({}, msg);
message.type = messageType;
message.context = message.context ? _extends({}, message.context) : {};
message.context.library = {
name: 'analytics-' + Platform.OS,
version: VERSION
};
if (!message.timestamp) {
message.timestamp = new Date();
}
if (!message.messageId) {
message.messageId = Platform.OS + '-' + (0, _uid2.default)(32);
}
this.queue.push({
message: message,
callback: fn
});
if (this.queue.length >= this.flushAt) {
this.flush();
}
if (this.timer) {
clearTimeout(this.timer);
}
if (this.flushAfter) {
this.timer = setTimeout(function () {
return _this.flush();
}, this.flushAfter);
}
}
}]);
return Analytics;
}();
Analytics.DEFAULT_HOST = 'https://api.segment.io';
Analytics.DEFAULT_FLUSH_AT = 20;
Analytics.DEFAULT_FLUSH_AFTER = 10000;
exports.default = Analytics;