@auryc/analytics.js-integration-auryc
Version:
Auryc integration for [Analytics.js][].
241 lines (206 loc) • 6.05 kB
JavaScript
var integration = require('@segment/analytics.js-integration')
var is = require('is');
var extend = require('@ndhoule/extend');
var each = require('component-each');
var toISOString = require('@segment/to-iso-string');
var toString = Object.prototype.toString
/**
* Expose `Auryc` integration
*/
var Auryc = (module.exports = integration('Auryc')
.option('siteid', null)
.tag('<script src="https://cdn.auryc.com/{{ siteid }}/container.js"></script>')
)
/**
* Initialize Auryc
*/
Auryc.prototype.initialize = function () {
function safeInvoke(g, fn) {
return function wrapper() {
if (g.auryc && typeof g.auryc[fn] !== 'undefined' && g.auryc[fn] !== wrapper) {
g.auryc[fn].apply(this, Array.prototype.slice.call(arguments, 0));
}
else {
var args = arguments;
g.aurycReadyCb.push(function () {
g.auryc[fn].apply(this, Array.prototype.slice.call(args, 0));
});
}
}
}
(function (g) {
g.aurycReadyCb = g.aurycReadyCb || [];
g.auryc = g.auryc || {};
var fns = ['identify', 'addUserProperties', 'track', 'addSessionProperties', 'pause', 'resume'];
each(fns, function (fn) {
g.auryc[fn] = safeInvoke(g, fn);
});
})(window)
this.load(this.ready);
}
Auryc.prototype.loaded = function () {
return !!window.aurycReadyCb;
};
/**
* Identify a user
*
* https://docs.auryc.com/knowledge-base/client-side-api/#identify-users
*
* @param {Identify} identify
*/
Auryc.prototype.identify = function (identify) {
var id = identify.userId();
if (id) window.auryc.identify(id);
var traits = identify.traits();
if (traits) {
var props = {};
Object.keys(traits).forEach(function(key){if (key !== 'id') props[key] = traits[key]});
window.auryc.addUserProperties(normalize(props));
}
}
/**
* Track.
*
* https://docs.auryc.com/knowledge-base/client-side-api/#custom-events-and-event-properties
*
* @param {Track} track
*/
Auryc.prototype.track = function(track) {
var props = normalize(track.properties()) || {};
props['auryc_integration'] = 'segment';
window.auryc.track(track.event(), props);
};
/**
* Group
*
* @param {Group} properties
*/
Auryc.prototype.group = function(group) {
var props = {};
var id = group.groupId();
if (id) {
props['groupId'] = id;
}
var traits = group.traits();
if (traits) {
Object.keys(traits).forEach(function(key){
if (key !== 'id') props['group_' + key] = traits[key]
});
}
if (Object.keys(props).length > 0) {
window.auryc.addUserProperties(normalize(props));
}
}
/**
* Handle all possible data types for properties
* Data type options include any, array, object, boolean, integer, number, string.
*
* @param {Object} properties
* @return {Object}
*/
function normalize(properties) {
var normalized = {};
Object.keys(properties).forEach(function(key) {
var prop = properties[key];
if (typeof prop === 'undefined' || prop === null) return;
if (is.date(prop)) {
normalized[key] = toISOString(prop);
return;
}
if (is.boolean(prop) || is.number(prop)) {
normalized[key] = prop;
return;
}
// array of objects. need to flatten
if (toString.call(prop) === '[object Array]') {
// Auryc can handle array of int, string, bools, but not objects
var newProps = [];
var primitive = true;
prop.forEach(function (item) {
if (!primitive) return;
if (is.date(item)) {
newProps.push(toISOString(item));
} else if (is.boolean(item) || is.number(item) || is.string(item)) {
newProps.push(item);
} else {
primitive = false;
}
});
if (primitive) {
normalized[key] = newProps;
} else { // has complex types, normalize
normalized = extend(normalized, unnest(key, prop));
}
return;
}
if (toString.call(prop) !== '[object Object]') {
normalized[key] = prop.toString();
return;
}
// anything else
normalized = extend(normalized, unnest(key, prop));
});
return normalized;
}
function unnest(key, value) {
var nestedObj = {};
nestedObj[key] = value;
var flattenedObj = flatten(nestedObj, { safe: true });
for (var k in flattenedObj) {
if (is.array(flattenedObj[k])) flattenedObj[k] = JSON.stringify(flattenedObj[k]);
}
return flattenedObj;
}
/**
* Flatten nested objects
* taken from https://www.npmjs.com/package/flat
* @param {Object} target
* @param {Object} opts
*
* @return {Object} output
*/
function flatten(target, opts) {
opts = opts || {};
var delimiter = opts.delimiter || '.';
var maxDepth = opts.maxDepth;
var currentDepth = 1;
var output = {};
function step(object, prev) {
Object.keys(object).forEach(function(key) {
var value = object[key];
var isarray = opts.safe && Array.isArray(value);
var type = Object.prototype.toString.call(value);
var isobject = type === '[object Object]' || type === '[object Array]';
var newKey = prev
? prev + delimiter + key
: key;
if (!opts.maxDepth) {
maxDepth = currentDepth + 1;
}
if (!isarray && isobject && Object.keys(value).length && currentDepth < maxDepth) {
++currentDepth;
return step(value, newKey);
}
output[newKey] = value;
});
}
step(target);
return output;
}
/**
* Polyfill Object.keys
* // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
* Note: Had to do this because for some reason, the above will not work properly without using Object.keys
*/
if (!Object.keys) {
Object.keys = function(o) {
if (o !== Object(o)) {
throw new TypeError('Object.keys called on a non-object');
}
var k = [];
var p;
for (p in o) if (Object.prototype.hasOwnProperty.call(o, p)) k.push(p);
return k;
};
}