'use strict';
var __newtonUtils = {
random: {
chars: (function() {
var c = 'qwertyuiopasdfghjklzxcvbnm';
return {
LOWER: c,
UPPER: c.toUpperCase(),
NUMBER: '1234567890',
SYMBOL: '\\|!£$%&/()=?^\'<>#@-_+*'
};
})(),
string: function(l, alphabet) {
l = parseInt(l, 10);
if (!isFinite(l)) {
return null;
}
var chars = __newtonUtils.random.chars;
alphabet = alphabet || (chars.LOWER + chars.UPPER + chars.NUMBER + chars.SYMBOL);
var m = new MersenneTwister();
var r = '';
for(var i=0; i < l; i++) {
var index = Math.floor(m.random() * alphabet.length);
r += alphabet.charAt(index);
}
return r;
}
},
http: {
getQueryString: function(obj) {
var str = [];
for(var i in obj) {
str.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
}
return str.join('&');
},
getAuthHeader: function getAuthHeader(clientIdentifier, secret, method, url, body, query) {
var timestamp = __newtonUtils.date.getCurrentUTCTimestamp();
body = body || '';
if (typeof body === 'object') {
body = JSON.stringify(body);
}
query = query || '';
if (typeof query === 'object') {
query = __newtonUtils.http.getQueryString(query);
}
var msg = [url, method, body, query, timestamp].join('|');
var hash = CryptoJS.HmacSHA1(msg, secret);
return ['iPawn identifier="',
clientIdentifier,
'", signature="',
hash,
'", version="2.0", timestamp="',
timestamp,
'"'
].join('');
},
doRequest: function doRequest(clientIdentifier, secret, method, url, body, query, callback) {
var request = new XMLHttpRequest();
if (!('withCredentials' in request)) {
return __newtonUtils.http.doRequestuestUsingImage(clientIdentifier, secret, url, body, callback);
}
request.onreadystatechange = function() {
if ((request.readyState == 4) || request.isMockedFromNewton) {
callback(request);
}
};
var urlToSign = __newtonUtils.http.getUrlForSignature(url);
request.open(method.toUpperCase(), url, true);
request.timeout = CONSTANT.http.CONNECTION_TIMEOUT;
request.setRequestHeader('Authorization', __newtonUtils.http.getAuthHeader(clientIdentifier, secret, method, urlToSign, body, query));
request.setRequestHeader('Content-type', 'application/json; charset=UTF-8');
body = (body && (body.constructor !== String)) ? JSON.stringify(body) : body;
_log('Sending', body, 'body to', url);
request.send(body);
},
getUrlForSignature: function(url) {
return url.replace(/^https?:\/\//,'');
},
doRequestuestUsingImage: function doRequestuestUsingImage(clientIdentifier, secret, url, query, callback) {
var timestamp = __newtonUtils.date.getCurrentUTCTimestamp();
query = (query && (query.constructor !== String)) ? JSON.stringify(query) : query;
query = {
events: query
};
var queryToSign = __newtonUtils.http.getQueryString(query);
var urlToSign = __newtonUtils.http.getUrlForSignature(url);
var msg = [urlToSign, 'GET', '', queryToSign, timestamp].join('|');
var hash = CryptoJS.HmacSHA1(msg, secret) + '';
query.identifier = clientIdentifier;
query.signature = hash;
query.timestamp = timestamp;
query.version = '2.0';
var alreadyCalled = false;
function cb() {
if (alreadyCalled) { return; }
alreadyCalled = true;
callback.call(img, {status: 204});
}
var img = document.createElement('img');
img.onload = cb;
img.onerror = cb;
img.src = url + '?' + __newtonUtils.http.getQueryString(query);
// document.body.appendChild(img);
}
},
cookie: {
setItem: function(key, value, end, path, domain) {
if (!key || /^(?:expires|max\-age|path|domain|secure)$/i.test(key)) { return false; }
var sExpires = "";
if (end) {
switch (end.constructor) {
case Date:
sExpires = "; expires=" + end.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(key) + "=" + encodeURIComponent(value) + sExpires + (domain ? "; domain=" + domain : "") + (path ? "; path=" + path : "");
return true;
},
removeItem: function (sKey, sPath, sDomain) {
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;";
return true;
},
getItem: function (key) {
if (!key) { return null; }
return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
}
},
date: {
getCurrentUTCTimestamp: function() {
return Math.ceil(__newtonUtils.date.getCurrentUTCDate().getTime() / 1000);
},
getCurrentUTCDate: function() {
var now = new Date();
return new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds(), now.getUTCMilliseconds());
},
diffDate: function(date1, date2) {
return Math.ceil((date1.getTime() - date2.getTime()) / 1000);
}
},
other: {
mergeSimpleObject: function(so1, so2) {
var so = SimpleObject.fromJSONObject(so1.toJSONObject());
var hash = so2.toJSONObject();
for (var k in hash) {
so._set(k, hash[k]);
}
return so;
},
mergeObjects: function(o1, o2) {
var ret = {};
for (var k in o1) {
ret[k] = o1[k];
}
for (k in o2) {
ret[k] = o2[k];
}
return ret;
}
}
};
var CONSTANT = {
localStorage: {
QUEUED_EVENTS_KEY: 'newton-queued-events',
SESSION_KEY: 'newton-session',
FLOW_KEY: 'newton-flow',
DEVICE_ID: 'newton-device-id'
},
cookie: {
SESSION_KEY: 'newton-session'
},
urls: {
TRACK_BULK_URL: '/events/track_bulk',
DEBUG_TRACK_BULK_URL: '/debug/events/track_bulk'
},
session: {
EXPIRE_DELTA_IN_MINUTES: 24 * 60, // 1 day
ID_LENGTH: 12
},
events: {
FLOW_ID_LENGTH: 12,
DEVICE_ID_LENGHT: 20,
MIN_FLUSHING_PERIOD: 2 // 2 seconds
},
http: {
CONNECTION_TIMEOUT: 10000
}
};
function UserManager() {
this.userId = undefined;
this.deviceId = undefined;
}
UserManager.prototype.start = function() {
// TODO: load from localstorage / cookie
// now start with anonymous user id
this.getAnonymousUserId();
this.getUserId();
};
UserManager.prototype.logout = function() {
this.userId = undefined;
};
UserManager.prototype.isLogged = function() {
return this.getUserId() !== undefined;
};
UserManager.prototype.getUserId = function() {
// force to return a copy and a string
return this.userId === undefined ? undefined : (this.userId + '');
};
UserManager.prototype.setUserId = function(userId) {
// force to store a string
this.userId = userId + '';
};
UserManager.prototype.getDeviceId = function() {
if (this.deviceId) {
return this.deviceId;
}
this.deviceId = localStorage.getItem(CONSTANT.localStorage.DEVICE_ID);
if (!this.deviceId) {
this.deviceId = __newtonUtils.random.string(CONSTANT.events.DEVICE_ID_LENGHT);
localStorage.setItem(CONSTANT.localStorage.DEVICE_ID, this.deviceId);
}
return this.deviceId;
};
UserManager.prototype.getAnonymousUserId = function () {
return 'A_' + this.getDeviceId();
};
UserManager.prototype.getCurrentUserId = function () {
return this.isLogged() ? this.getUserId() : this.getAnonymousUserId();
};
function SessionManager() {
this.sessionId = undefined;
this.eventQueueManager = undefined;
}
SessionManager.prototype.setEventQueueManager = function(eventQueueManager) {
this.eventQueueManager = eventQueueManager;
};
SessionManager.prototype.start = function() {
if (this.isValid()) {
this.sessionId = __newtonUtils.cookie.getItem(CONSTANT.cookie.SESSION_KEY);
return;
}
this.sessionId = __newtonUtils.random.string(CONSTANT.session.ID_LENGTH);
localStorage.setItem(CONSTANT.localStorage.SESSION_KEY, this.sessionId);
var date = __newtonUtils.date.getCurrentUTCDate();
date.setMinutes(date.getMinutes() + CONSTANT.session.EXPIRE_DELTA_IN_MINUTES);
__newtonUtils.cookie.setItem(CONSTANT.cookie.SESSION_KEY, this.sessionId, date, '/');
// emit start event
if (this.eventQueueManager) {
this.eventQueueManager.startSessionEvent(this.sessionId);
}
};
SessionManager.prototype.isValid = function() {
// start session
return !!__newtonUtils.cookie.getItem(CONSTANT.cookie.SESSION_KEY);
};
SessionManager.prototype.stop = function() {
this.sessionId = undefined;
localStorage.removeItem(CONSTANT.localStorage.SESSION_KEY);
__newtonUtils.cookie.removeItem(CONSTANT.cookie.SESSION_KEY);
};
SessionManager.prototype.getSessionId = function() {
// refresh internal sessionId if needed
this.start();
return this.sessionId;
};
function EventQueueManager() {
this.userManager = undefined;
this.sessionManager = undefined;
this.lastFlushTimestamp = 0;
this.queuedEvents = [];
this.intervalId = undefined;
}
EventQueueManager.prototype.setUserManager = function(userManager) {
this.userManager = userManager;
};
EventQueueManager.prototype.setSessionManager = function(sessionManager) {
this.sessionManager = sessionManager;
};
EventQueueManager.prototype.setOnFlushEvents = function(onFlushEvents) {
this.onFlushEvents = onFlushEvents;
};
EventQueueManager.prototype.inflatingEvent = function(event) {
event.session_id = this.sessionManager.getSessionId();
event.creation_date = __newtonUtils.date.getCurrentUTCDate().toISOString();
event.user_id = this.userManager.getCurrentUserId();
return event;
};
EventQueueManager.prototype.addEvent = function(event) {
this.inflatingEvent(event);
var events = localStorage.getItem(CONSTANT.localStorage.QUEUED_EVENTS_KEY);
events = events ? events : '';
events += ',' + JSON.stringify(event);
localStorage.setItem(CONSTANT.localStorage.QUEUED_EVENTS_KEY, events);
var now = __newtonUtils.date.getCurrentUTCTimestamp();
if (now < this.lastFlushTimestamp + CONSTANT.events.MIN_FLUSHING_PERIOD) {
// queued and not flushed
if (!this.timeoutId) {
var self = this;
this.timeoutId = setTimeout(function() {
self.timeoutId = undefined;
var events = localStorage.getItem(CONSTANT.localStorage.QUEUED_EVENTS_KEY);
if (!events) return;
localStorage.removeItem(CONSTANT.localStorage.QUEUED_EVENTS_KEY);
self.onFlushEvents('[' + events.substring(1) + ']');
}, CONSTANT.events.MIN_FLUSHING_PERIOD * 1000);
}
return;
}
// throw ???
if (!this.onFlushEvents) { return; }
this.lastFlushTimestamp = now;
localStorage.removeItem(CONSTANT.localStorage.QUEUED_EVENTS_KEY);
this.onFlushEvents('[' + events.substring(1) + ']');
};
EventQueueManager.prototype.startSessionEvent = function(sessionId) {
var event = getDeviceField();
event.event_type = 'start session';
event.device_id = this.userManager.getDeviceId();
event.sdk_version = 'JS ' + publicInterface.getVersionString();
event.user_agent = window.navigator.userAgent;
this.addEvent(event);
};
function ServerClientManager(credentials, url) {
this.credentials = credentials;
this.url = url;
}
ServerClientManager.prototype.flushEvents = function(events, callback) {
callback = callback || function() {};
__newtonUtils.http.doRequest(
this.credentials.identifier,
this.credentials.secret,
'POST',
this.url,
events,
'',
callback
);
};
function TimerManager() {
this.timers = {};
this.eventQueueManager = undefined;
}
TimerManager.prototype.setEventQueueManager = function(eventQueueManager) {
this.eventQueueManager = eventQueueManager;
};
TimerManager.prototype.startTimer = function(name, cd) {
this.timers[name] = {
name: name,
startDate: __newtonUtils.date.getCurrentUTCTimestamp()
};
if (cd) {
this.timers[name].custom_data = cd;
}
};
TimerManager.prototype.stopTimer = function(name, cd) {
var timedEvent = this.timers[name];
if (!timedEvent) {
throw new Error('Cannot stop a non started timedEvent');
}
timedEvent.end = __newtonUtils.date.getCurrentUTCDate().toISOString();
timedEvent.delta = Math.abs(__newtonUtils.date.getCurrentUTCTimestamp() - timedEvent.startDate);
if (cd) {
timedEvent.custom_data = __newtonUtils.other.mergeObjects(timedEvent.custom_data, cd);
}
timedEvent.event_type = 'timer stop';
this.timers[name + ''] = undefined;
if (this.eventQueueManager) {
this.eventQueueManager.addEvent(timedEvent);
} // TODO: else ???
};
function FlowManager() {
this.eventQueueManager = undefined;
}
FlowManager.prototype.setEventQueueManager = function(eventQueueManager) {
this.eventQueueManager = eventQueueManager;
};
FlowManager.prototype.flowBegin = function(name, cd) {
var flowId = localStorage.getItem(CONSTANT.localStorage.FLOW_KEY);
if (flowId) {
this.flowFail('flow-start', {'started-flow-id': flowId});
}
flowId = __newtonUtils.random.string(CONSTANT.events.FLOW_ID_LENGTH);
localStorage.setItem(CONSTANT.localStorage.FLOW_KEY, flowId);
var ev = {
event_type: 'flow start',
name: name + '',
flow_id: flowId
};
if (cd) {
ev.custom_data = cd;
}
this.eventQueueManager.addEvent(ev);
};
FlowManager.prototype.flowStep = function(name, cd) {
var flowId = localStorage.getItem(CONSTANT.localStorage.FLOW_KEY);
if (!flowId) {
throw new Error('No flow found');
}
var ev = {
event_type: 'flow step',
flow_id: flowId,
name: name
};
if (cd) {
ev.custom_data = cd;
}
this.eventQueueManager.addEvent(ev);
};
FlowManager.prototype.flowSucceed = function(reason, cd) {
var flowId = localStorage.getItem(CONSTANT.localStorage.FLOW_KEY);
if (!flowId) {
throw new Error('No flow found');
}
var ev = {
event_type: 'flow succeeded',
flow_id: flowId,
name: reason ? reason + '' : 'ok'
};
if (cd) {
ev.custom_data = cd;
}
this.eventQueueManager.addEvent(ev);
};
FlowManager.prototype.flowFail = function(reason, cd) {
var flowId = localStorage.getItem(CONSTANT.localStorage.FLOW_KEY);
if (!flowId) {
throw new Error('No flow found');
}
localStorage.removeItem(CONSTANT.localStorage.FLOW_KEY);
var ev = {
event_type: 'flow failed',
flow_id: flowId,
name: reason
};
if (cd) {
ev.custom_data = cd;
}
this.eventQueueManager.addEvent(ev);
};
FlowManager.prototype.flowCancel = function(reason, cd) {
var flowId = localStorage.getItem(CONSTANT.localStorage.FLOW_KEY);
if (!flowId) {
throw new Error('No flow found');
}
localStorage.removeItem(CONSTANT.localStorage.FLOW_KEY);
var ev = {
event_type: 'flow canceled',
flow_id: flowId,
name: reason
};
if (cd) {
ev.custom_data = cd;
}
this.eventQueueManager.addEvent(ev);
};
/*
* UseSetTransaction
*/
function createUserSetTransaction() {
return {
setUserProperty: function(key, value) {
},
setOnceUserProperty: function(key, value) {
},
incrementUserProperty: function(key) {
},
decrementUserProperty: function(key) {
},
commit: function() {
}
};
}
/**
* @class
*/
function SimpleObject() {
this.prop = {};
}
/**
* Never use directly. Use the alias instead
* @method
* @memberOf SimpleObject
*
* @param {String} key - The key
* @param {String|null|Number|Boolean} value - The value
*/
SimpleObject.prototype._set = function (key, value) {
// TODO: do this better. instance only when is needed
var e = new Error('cannot set ' + value + ' as ' + key);
e.key = key;
e.value = value;
if (value === undefined) {
throw e;
}
if (value !== null) {
var valueConstructor = value.constructor;
if (valueConstructor !== Number && valueConstructor !== String && valueConstructor !== Boolean) {
throw e;
}
}
this.prop[key] = value;
};
/**
* @method setString
* @memberOf SimpleObject
* @instance
* @alias SimpleObject#_set
*/
SimpleObject.prototype.setString = SimpleObject.prototype._set;
/**
* @method setInt
* @memberOf SimpleObject
* @instance
* @alias SimpleObject#_set
*/
SimpleObject.prototype.setInt = SimpleObject.prototype._set;
/**
* @method setBool
* @memberOf SimpleObject
* @instance
* @alias SimpleObject#_set
*/
SimpleObject.prototype.setBool = SimpleObject.prototype._set;
/**
* @method setFloat
* @memberOf SimpleObject
* @instance
* @alias SimpleObject#_set
*/
SimpleObject.prototype.setFloat = SimpleObject.prototype._set;
/**
* @method setNull
* @memberOf SimpleObject
* @instance
*
* @param {String} key - The key
*/
SimpleObject.prototype.setNull = function(key) {
this._set(key, null);
};
/**
* @method toJSONObject
* @memberOf SimpleObject
* @instance
*
* @return {Object} - The object stored in this SimpleObject
*/
SimpleObject.prototype.toJSONObject = function() {
var a = {};
for (var k in this.prop) {
a[k] = this.prop[k];
}
return a;
};
/**
* @method fromJSONObject
* @memberOf SimpleObject
* @static
*
* @param {Object} obj - The object you would convert
* @return {SimpleObject}
*/
SimpleObject.fromJSONObject = function(obj) {
if (!obj || obj.constructor !== Object) {
var e = new Error('obj is not a simple object compatible');
e.obj = obj;
throw e;
}
var so = new SimpleObject();
for (var key in obj) {
so._set(key, obj[key]);
}
return so;
};
function assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData) {
if (customData && customData.constructor !== SimpleObject) {
throw new Error('Custom data should be an instance of SimpleObject');
}
}
function getHashFromSimpleObjectOrUndefined(customData) {
return customData ? customData.toJSONObject() : undefined;
}
function assertIsALabel(name) {
/* jshint -W044 */
name = name + '';
if (!(name && name.match(/^[\w-]{1,20}$/))) {
throw new Error('label should be match /^[\w-]{1,20}$/');
}
}
function getIdentifier() {
return window.location.hostname + '|JS';
}
function getEndpoint(hostname, secret) {
return hostname.match(/^static2\.newton\.pm$/) ?
'https://client-api2.newton.pm' + CONSTANT.urls.TRACK_BULK_URL :
(secret.match('_') ?
'https://client-api-sandbox.newton.pm' + CONSTANT.urls.DEBUG_TRACK_BULK_URL :
'https://client-api.newton.pm' + CONSTANT.urls.TRACK_BULK_URL);
}
var _log;
/**
* NewtonSDK
*
* @class NewtonSDK
* @name NewtonSDK
* @constructor
* @private
*/
function createNewtonInstance(secret) {
var debug = false;
_log = function() {
if (debug) { console.log(arguments); }
};
var ravenUrl;
secret = secret || {};
if (secret.constructor === Object ) {
ravenUrl = secret.ravenUrl;
secret = secret.secret;
}
if (!secret) {
throw new Error('secret should be given');
}
var identifier = getIdentifier();
var endpoint = getEndpoint(window.location.hostname, secret);
var userManager = new UserManager();
var sessionManager = new SessionManager();
var eventQueueManager = new EventQueueManager();
var serverClientManager = new ServerClientManager(
{identifier: identifier, secret: secret},
endpoint
);
var timerManager = new TimerManager();
var flowManager = new FlowManager();
sessionManager.setEventQueueManager(eventQueueManager);
eventQueueManager.setSessionManager(sessionManager);
eventQueueManager.setUserManager(userManager);
eventQueueManager.setOnFlushEvents(function(events) {
serverClientManager.flushEvents(events);
});
timerManager.setEventQueueManager(eventQueueManager);
flowManager.setEventQueueManager(eventQueueManager);
var isRavenConfigured = false;
function setRavenUrl(ravenUrl) {
if (!Raven) {
throw new Error('Raven should be included');
}
isRavenConfigured = true;
Raven.config(ravenUrl).install();
}
if (ravenUrl) {
setRavenUrl(ravenUrl);
}
sessionManager.start();
userManager.start();
return {
logInfo: function(line) { },
logNotice: function(line) { },
logWarning: function(line) { },
logError: function(line) { },
makeABTestDecision: function(name, defaultDecision, params, callback) { },
ABTestGoalAchived: function(abTestId) { },
IAPValidateTransaction: function(params, receip, callback) { },
logDebug: function(line) { },
startSet: function() {
return createUserSetTransaction();
},
userLogout: function() {
if (userManager.isLogged()) {
eventQueueManager.addEvent({
event_type: 'logout'
});
}
userManager.logout();
},
isLoginFlowRunning: function() {
return false;
},
/**
* Login utilities
* @class LoginBuilder
* @name LoginBuilder
* @private
*/
/**
* Custom Login
* @class CustomLoginFlow
* @name CustomLoginFlow
* @private
*/
/**
* Return a login builder
* @method
* @instance
* @memberOf NewtonSDK
*
* @return LoginBuilder
*/
getLoginBuilder: function() {
var props = {};
function setWrapper(c) {
return function(k) {
props[c] = k;
return this;
};
}
return {
/**
* Set callback
* @method
* @instance
* @memberOf LoginBuilder
* @param callback
*
* @return {LoginBuilder} the same instance
*/
setCallback: setWrapper('callback'),
/**
* Set login data. Useful to track campaign parameters
* @method
* @instance
* @memberOf LoginBuilder
* @param {SimpleObject} loginData - the custom data for the login event
*
* @return {LoginBuilder} the same instance
*/
setLoginData: setWrapper('custom_data'),
/**
* Set custom id. Used in custom flow.
* @method
* @instance
* @memberOf LoginBuilder
* @param {string} customID - custom user id
*
* @return {LoginBuilder} the same instance
*/
setCustomID: setWrapper('customId'),
/**
* Create a custom login flow.
* @method
* @instance
* @memberOf LoginBuilder
*
* @return {CustomLoginFlow}
*/
getCustomFlow: function() {
if (!props.callback || !props.customId) {
throw new Error('callback and customId must be provided');
}
assertCustomDataIsNullOrIsInstanceOfSimpleObject(props.custom_data);
return {
/**
* Return a string representation
* @method
* @instance
* @memberOf CustomLoginFlow
*
* @return {string}
*/
toString : function() {
return 'CustomLoginFlow(' + JSON.stringify(props) + ')';
},
/**
* Start the custom login flow
* @method
* @instance
* @memberOf CustomLoginFlow
*
*/
startLoginFlow: function() {
if (userManager.isLogged()) {
throw new Error('User already logged in');
}
userManager.setUserId(props.customId);
var ev = {
event_type: 'identify',
login_type: 'CUSTOM'
};
if (props.custom_data) {
ev.custom_data = props.custom_data.toJSONObject();
}
eventQueueManager.addEvent(ev);
setTimeout(props.callback, 0);
}
};
}
};
},
/**
* Login through userId. No check is made.
* @method
* @instance
* @deprecated This method will throw an exception when the real implementation is done
* @memberOf NewtonSDK
*
* @param {String} userId - The user id or null to logout
*/
__temporaryCustomLogin: function(_userId) {
if (userManager.isLogged()) {
throw new Error('User already logged in');
}
userManager.setUserId(_userId);
eventQueueManager.addEvent({
event_type: 'identify',
login_type: 'CUSTOM'
});
},
/**
* Return true if Newton has a set userId
* @method
* @instance
* @memberOf NewtonSDK
*
* @return {Boolean} - true if the userId is set
*/
isUserLogged: function() {
return userManager.isLogged();
},
/**
* This callback is used on NewtonSDK#flushEvents
* @callback NewtonSDK~flushEventsCallback
* @param {Error} [err] - If something was wrong
*/
/**
* Flush event queue
* @method
* @instance
* @memberOf NewtonSDK
* @deprecated
*
* @param {NewtonSDK~flushEventsCallback} callback - The callback called when the request is done
*/
flushEvents: function(callback) {
callback = callback || (function() {});
callback();
},
/**
* Log exception to Sentry if is configured
* @method
* @instance
* @memberOf NewtonSDK
* @throws Throw if there's not a begun flow
*
* @param {Error} error - The error
*/
logException: function(error) {
if (isRavenConfigured) {
Raven.captureException(error);
} else {
console.log('Raven is not configured yet.', error);
}
},
/**
* End a flow with a cancellation
* @method
* @instance
* @memberOf NewtonSDK
* @throws Throw if there's not a begun flow
*
* @param {String} name - The reason of the cancellation
* @param {SimpleObject} [customData] - Some data
*/
flowCancel: function(reason, customData) {
_log('flow cancel', arguments);
assertIsALabel(reason);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
flowManager.flowCancel(reason + '', getHashFromSimpleObjectOrUndefined(customData));
},
/**
* End a flow with a failure
* @method
* @instance
* @memberOf NewtonSDK
* @throws Throw if there's not a begun flow
*
* @param {String} name - The reason of the failure
* @param {SimpleObject} [customData] - Some data
*/
flowFail: function(reason, customData) {
_log('flow fails', arguments);
assertIsALabel(reason);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
flowManager.flowFail(reason +'', getHashFromSimpleObjectOrUndefined(customData));
},
/**
* End a flow with a success
* @method
* @instance
* @memberOf NewtonSDK
* @throws Throw if there's not a begun flow
*
* @param {String} [name="ok"] - A name that identify the end
* @param {SimpleObject} [customData] - Some data
*/
flowSucceed: function(reason, customData) {
_log('flow succeeds', arguments);
if (!reason || reason.constructor === SimpleObject) {
customData = reason;
reason = 'ok';
}
assertIsALabel(reason);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
var cd = getHashFromSimpleObjectOrUndefined(customData);
flowManager.flowSucceed(reason + '', cd);
},
/**
* Make a step for a flow
* @method
* @instance
* @memberOf NewtonSDK
* @throws Throw if there's not a begun flow
*
* @param {String} name - The name of the step
* @param {SimpleObject} [customData] - Some data
*/
flowStep: function(stepName, customData) {
_log('flow step', arguments);
assertIsALabel(stepName);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
flowManager.flowStep(stepName + '', getHashFromSimpleObjectOrUndefined(customData));
},
/**
* Begin a flow. Close a previous flow with a fail if need.
* @method
* @instance
* @memberOf NewtonSDK
*
* @param {String} name - The name of the flow
* @param {SimpleObject} [customData] - Some data
*/
flowBegin: function(name, customData) {
_log('flow begin', arguments);
assertIsALabel(name);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
flowManager.flowBegin(name + '', getHashFromSimpleObjectOrUndefined(customData));
},
/**
* Stop a timed event.
* The event has a merge of this customData and the customData passed on timedEventStart method
* @method
* @instance
* @memberOf NewtonSDK
* @throws Throw if there's no started event the given name
*
* @param {String} name - The name of this event
* @param {SimpleObject} [customData] - Some data
*/
timedEventStop: function(name, customData) {
_log('stop timed event', arguments);
assertIsALabel(name);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
timerManager.stopTimer(name + '', getHashFromSimpleObjectOrUndefined(customData));
},
/**
* Start a timed event
* @method
* @instance
* @memberOf NewtonSDK
*
* @param {String} name - The name of the timed event
* @param {SimpleObject} [customData] - Some data
*/
timedEventStart: function(name, customData) {
_log('start timed event', arguments);
assertIsALabel(name);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
timerManager.startTimer(name + '', getHashFromSimpleObjectOrUndefined(customData));
},
/**
* Queue an event
* @method
* @instance
* @memberOf NewtonSDK
*
* @param {String} name - The name of this event
* @param {SimpleObject} [customData] - Some data attached to this event
*/
sendEvent: function(name, customData) {
_log('add event', arguments);
assertIsALabel(name);
assertCustomDataIsNullOrIsInstanceOfSimpleObject(customData);
var ev = {
event_type: 'custom event',
name: name + ''
};
var cd = getHashFromSimpleObjectOrUndefined(customData);
if (cd) {
ev.custom_data = cd;
}
eventQueueManager.addEvent(ev);
},
setDebug: function(_debug) {
debug = !!_debug;
}
};
}
var newtonInstance;
/**
* The Newton SDK public Interface
* @namespace Newton
*/
var publicInterface = {
/**
* Get the shared instance
* @throws {Error} - Throw if getSharedInstanceWithConfig hasn't been called
* @memberOf Newton
* @return {NewtonSDK}
*/
getSharedInstance: function() {
if (!newtonInstance) {
throw new Error('Call getSharedInstanceWithConfig before');
}
return newtonInstance;
},
/**
* Get the shared instance. Create one if no sharedInstance found
* @memberOf Newton
* @return {NewtonSDK}
*/
getSharedInstanceWithConfig: function(conf_or_secret) {
if (!newtonInstance) {
newtonInstance = createNewtonInstance(conf_or_secret);
}
return newtonInstance;
},
/**
* SimpleObject
* @memberOf Newton
* @alias SimpleObject
*/
SimpleObject: SimpleObject,
/**
* Get current Newton version
* @memberOf Newton
* @return {String}
*/
getVersionString: function getVersionString() {
return [
autorevision.VCS_TAG,
autorevision.VCS_SHORT_HASH,
autorevision.VCS_DATE
].join(' ');
}
};