UNPKG

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
'use strict'; 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;