@@ -262,14 +262,6 @@ var version = require('./version');
262262var type = require ( './type' ) ;
263263var DEFAULT_OPTIONS = require ( './options' ) ;
264264
265- var log = function ( s ) {
266- try {
267- console . log ( '[Amplitude] ' + s ) ;
268- } catch ( e ) {
269- // console logging not available
270- }
271- } ;
272-
273265var DEFAULT_INSTANCE = '$default_instance' ;
274266var IDENTIFY_EVENT = '$identify' ;
275267var API_VERSION = 2 ;
@@ -375,8 +367,8 @@ AmplitudeClient.prototype.init = function(apiKey, opt_userId, opt_config, callba
375367 this . _lastEventTime = now ;
376368 _saveCookieData ( this ) ;
377369
378- //log('initialized with apiKey=' + apiKey);
379- //opt_userId !== undefined && opt_userId !== null && log('initialized with userId=' + opt_userId);
370+ //utils. log('initialized with apiKey=' + apiKey);
371+ //opt_userId !== undefined && opt_userId !== null && utils. log('initialized with userId=' + opt_userId);
380372
381373 if ( this . options . saveEvents ) {
382374 this . _unsentEvents = this . _loadSavedUnsentEvents ( this . options . unsentKey ) || this . _unsentEvents ;
@@ -392,7 +384,7 @@ AmplitudeClient.prototype.init = function(apiKey, opt_userId, opt_config, callba
392384 this . _saveReferrer ( this . _getReferrer ( ) ) ;
393385 }
394386 } catch ( e ) {
395- log ( e ) ;
387+ utils . log ( e ) ;
396388 }
397389
398390 if ( callback && type ( callback ) === 'function' ) {
@@ -404,7 +396,7 @@ AmplitudeClient.prototype.Identify = Identify;
404396
405397AmplitudeClient . prototype . _apiKeySet = function ( methodName ) {
406398 if ( ! this . options . apiKey ) {
407- log ( 'apiKey cannot be undefined or null, set apiKey with init() before calling ' + methodName ) ;
399+ utils . log ( 'apiKey cannot be undefined or null, set apiKey with init() before calling ' + methodName ) ;
408400 return false ;
409401 }
410402 return true ;
@@ -426,7 +418,7 @@ AmplitudeClient.prototype._loadSavedUnsentEvents = function(unsentKey) {
426418 try {
427419 return JSON . parse ( savedUnsentEventsString ) ;
428420 } catch ( e ) {
429- //log(e);
421+ //utils. log(e);
430422 }
431423 }
432424 return null ;
@@ -640,7 +632,7 @@ AmplitudeClient.prototype._saveReferrer = function(referrer) {
640632 hasSessionStorage = true ;
641633 }
642634 } catch ( e ) {
643- // log(e); // sessionStorage disabled
635+ // utils. log(e); // sessionStorage disabled
644636 }
645637
646638 if ( ( hasSessionStorage && ! ( this . _getFromStorage ( sessionStorage , LocalStorageKeys . REFERRER ) ) ) || ! hasSessionStorage ) {
@@ -663,7 +655,7 @@ AmplitudeClient.prototype.saveEvents = function() {
663655 this . _setInStorage ( localStorage , this . options . unsentKey , JSON . stringify ( this . _unsentEvents ) ) ;
664656 this . _setInStorage ( localStorage , this . options . unsentIdentifyKey , JSON . stringify ( this . _unsentIdentifys ) ) ;
665657 } catch ( e ) {
666- //log(e);
658+ // utils. log(e);
667659 }
668660} ;
669661
@@ -679,9 +671,9 @@ AmplitudeClient.prototype.setDomain = function(domain) {
679671 this . options . domain = this . cookieStorage . options ( ) . domain ;
680672 _loadCookieData ( this ) ;
681673 _saveCookieData ( this ) ;
682- //log('set domain=' + domain);
674+ // utils. log('set domain=' + domain);
683675 } catch ( e ) {
684- log ( e ) ;
676+ utils . log ( e ) ;
685677 }
686678} ;
687679
@@ -693,9 +685,9 @@ AmplitudeClient.prototype.setUserId = function(userId) {
693685 try {
694686 this . options . userId = ( userId !== undefined && userId !== null && ( '' + userId ) ) || null ;
695687 _saveCookieData ( this ) ;
696- //log('set userId=' + userId);
688+ // utils. log('set userId=' + userId);
697689 } catch ( e ) {
698- log ( e ) ;
690+ utils . log ( e ) ;
699691 }
700692} ;
701693
@@ -707,9 +699,9 @@ AmplitudeClient.prototype.setOptOut = function(enable) {
707699 try {
708700 this . options . optOut = enable ;
709701 _saveCookieData ( this ) ;
710- //log('set optOut=' + enable);
702+ // utils. log('set optOut=' + enable);
711703 } catch ( e ) {
712- log ( e ) ;
704+ utils . log ( e ) ;
713705 }
714706} ;
715707
@@ -724,7 +716,7 @@ AmplitudeClient.prototype.setDeviceId = function(deviceId) {
724716 _saveCookieData ( this ) ;
725717 }
726718 } catch ( e ) {
727- log ( e ) ;
719+ utils . log ( e ) ;
728720 }
729721} ;
730722
@@ -778,9 +770,9 @@ AmplitudeClient.prototype.identify = function(identify) {
778770AmplitudeClient . prototype . setVersionName = function ( versionName ) {
779771 try {
780772 this . options . versionName = versionName ;
781- //log('set versionName=' + versionName);
773+ // utils. log('set versionName=' + versionName);
782774 } catch ( e ) {
783- log ( e ) ;
775+ utils . log ( e ) ;
784776 }
785777} ;
786778
@@ -847,7 +839,7 @@ AmplitudeClient.prototype._logEvent = function(eventType, eventProperties, apiPr
847839 }
848840
849841 apiProperties = apiProperties || { } ;
850- eventProperties = eventProperties || { } ;
842+ eventProperties = utils . validateProperties ( eventProperties ) || { } ;
851843 var event = {
852844 device_id : this . options . deviceId ,
853845 user_id : this . options . userId || this . options . deviceId ,
@@ -891,7 +883,7 @@ AmplitudeClient.prototype._logEvent = function(eventType, eventProperties, apiPr
891883
892884 return eventId ;
893885 } catch ( e ) {
894- log ( e ) ;
886+ utils . log ( e ) ;
895887 }
896888} ;
897889
@@ -918,7 +910,7 @@ var _isNumber = function(n) {
918910AmplitudeClient . prototype . logRevenue = function ( price , quantity , product ) {
919911 // Test that the parameters are of the right type.
920912 if ( ! this . _apiKeySet ( 'logRevenue()' ) || ! _isNumber ( price ) || quantity !== undefined && ! _isNumber ( quantity ) ) {
921- // log('Price and quantity arguments to logRevenue must be numbers');
913+ // utils. log('Price and quantity arguments to logRevenue must be numbers');
922914 return - 1 ;
923915 }
924916
@@ -987,7 +979,7 @@ AmplitudeClient.prototype.sendEvents = function(callback) {
987979 scope . _sending = false ;
988980 try {
989981 if ( status === 200 && response === 'success' ) {
990- //log('sucessful upload');
982+ // utils. log('sucessful upload');
991983 scope . removeEvents ( maxEventId , maxIdentifyId ) ;
992984
993985 // Update the event cache after the removal of sent events.
@@ -1001,7 +993,7 @@ AmplitudeClient.prototype.sendEvents = function(callback) {
1001993 }
1002994
1003995 } else if ( status === 413 ) {
1004- //log('request too large');
996+ // utils. log('request too large');
1005997 // Can't even get this one massive event through. Drop it.
1006998 if ( scope . options . uploadBatchSize === 1 ) {
1007999 // if massive event is identify, still need to drop it
@@ -1017,7 +1009,7 @@ AmplitudeClient.prototype.sendEvents = function(callback) {
10171009 callback ( status , response ) ;
10181010 }
10191011 } catch ( e ) {
1020- //log('failed upload');
1012+ // utils. log('failed upload');
10211013 }
10221014 } ) ;
10231015 } else if ( callback ) {
@@ -2227,6 +2219,7 @@ module.exports = getUtmData;
22272219} , { } ] ,
222822204 : [ function ( require , module , exports ) {
22292221var type = require ( './type' ) ;
2222+ var utils = require ( './utils' ) ;
22302223
22312224/*
22322225 * Wrapper for a user properties JSON object that supports operations.
@@ -2241,14 +2234,6 @@ var AMP_OP_SET = '$set';
22412234var AMP_OP_SET_ONCE = '$setOnce' ;
22422235var AMP_OP_UNSET = '$unset' ;
22432236
2244- var log = function ( s ) {
2245- try {
2246- console . log ( '[Amplitude] ' + s ) ;
2247- } catch ( e ) {
2248- // console logging not available
2249- }
2250- } ;
2251-
22522237var Identify = function ( ) {
22532238 this . userPropertiesOperations = { } ;
22542239 this . properties = [ ] ; // keep track of keys that have been added
@@ -2258,7 +2243,7 @@ Identify.prototype.add = function(property, value) {
22582243 if ( type ( value ) === 'number' || type ( value ) === 'string' ) {
22592244 this . _addOperation ( AMP_OP_ADD , property , value ) ;
22602245 } else {
2261- log ( 'Unsupported type for value: ' + type ( value ) + ', expecting number or string' ) ;
2246+ utils . log ( 'Unsupported type for value: ' + type ( value ) + ', expecting number or string' ) ;
22622247 }
22632248 return this ;
22642249} ;
@@ -2274,7 +2259,7 @@ Identify.prototype.append = function(property, value) {
22742259Identify . prototype . clearAll = function ( ) {
22752260 if ( Object . keys ( this . userPropertiesOperations ) . length > 0 ) {
22762261 if ( ! this . userPropertiesOperations . hasOwnProperty ( AMP_OP_CLEAR_ALL ) ) {
2277- log ( 'Need to send $clearAll on its own Identify object without any other operations, skipping $clearAll' ) ;
2262+ utils . log ( 'Need to send $clearAll on its own Identify object without any other operations, skipping $clearAll' ) ;
22782263 }
22792264 return this ;
22802265 }
@@ -2300,13 +2285,13 @@ Identify.prototype.unset = function(property) {
23002285Identify . prototype . _addOperation = function ( operation , property , value ) {
23012286 // check that the identify doesn't already contain a clearAll
23022287 if ( this . userPropertiesOperations . hasOwnProperty ( AMP_OP_CLEAR_ALL ) ) {
2303- log ( 'This identify already contains a $clearAll operation, skipping operation ' + operation ) ;
2288+ utils . log ( 'This identify already contains a $clearAll operation, skipping operation ' + operation ) ;
23042289 return ;
23052290 }
23062291
23072292 // check that property wasn't already used in this Identify
23082293 if ( this . properties . indexOf ( property ) !== - 1 ) {
2309- log ( 'User property "' + property + '" already used in this identify, skipping operation ' + operation ) ;
2294+ utils . log ( 'User property "' + property + '" already used in this identify, skipping operation ' + operation ) ;
23102295 return ;
23112296 }
23122297
@@ -2319,7 +2304,7 @@ Identify.prototype._addOperation = function(operation, property, value) {
23192304
23202305module . exports = Identify ;
23212306
2322- } , { "./type" :6 } ] ,
2307+ } , { "./type" :6 , "./utils" : 7 } ] ,
232323086 : [ function ( require , module , exports ) {
23242309/* Taken from: https://github.com/component/type */
23252310
@@ -2368,6 +2353,95 @@ module.exports = function(val){
23682353} ;
23692354
23702355} , { } ] ,
2356+ 7 : [ function ( require , module , exports ) {
2357+ var type = require ( './type' ) ;
2358+
2359+ var log = function ( s ) {
2360+ try {
2361+ console . log ( '[Amplitude] ' + s ) ;
2362+ } catch ( e ) {
2363+ // console logging not available
2364+ }
2365+ } ;
2366+
2367+ var isEmptyString = function ( str ) {
2368+ return ( ! str || str . length === 0 ) ;
2369+ } ;
2370+
2371+ var validateProperties = function ( properties ) {
2372+ var propsType = type ( properties ) ;
2373+ if ( propsType !== 'object' ) {
2374+ log ( 'Error: invalid event properties format. Expecting Javascript object, received ' + propsType + ', ignoring' ) ;
2375+ return { } ;
2376+ }
2377+
2378+ var copy = { } ; // create a copy with all of the valid properties
2379+ for ( var property in properties ) {
2380+ if ( ! properties . hasOwnProperty ( property ) ) {
2381+ continue ;
2382+ }
2383+
2384+ // validate key
2385+ var key = property ;
2386+ var keyType = type ( key ) ;
2387+ if ( keyType !== 'string' ) {
2388+ log ( 'WARNING: Non-string property key, received type ' + keyType + ', coercing to string "' + key + '"' ) ;
2389+ key = String ( key ) ;
2390+ }
2391+
2392+ // validate value
2393+ var value = validatePropertyValue ( key , properties [ property ] ) ;
2394+ if ( value === null ) {
2395+ continue ;
2396+ }
2397+
2398+ copy [ key ] = value ;
2399+ }
2400+
2401+ return copy ;
2402+ } ;
2403+
2404+ var invalidValueTypes = [
2405+ 'null' , 'nan' , 'undefined' , 'function' , 'arguments' , 'regexp' , 'element'
2406+ ] ;
2407+
2408+ var validatePropertyValue = function ( key , value ) {
2409+ var valueType = type ( value ) ;
2410+ if ( invalidValueTypes . indexOf ( valueType ) !== - 1 ) {
2411+ log ( 'WARNING: Property key "' + key + '" with value type ' + valueType + ', ignoring' ) ;
2412+ value = null ;
2413+ }
2414+ else if ( valueType === 'error' ) {
2415+ value = String ( value ) ;
2416+ log ( 'WARNING: Property key "' + key + '" with value type error, coercing to ' + value ) ;
2417+ }
2418+ else if ( valueType === 'array' ) {
2419+ // check for nested arrays or objects
2420+ var arrayCopy = [ ] ;
2421+ for ( var i = 0 ; i < value . length ; i ++ ) {
2422+ var element = value [ i ] ;
2423+ var elemType = type ( element ) ;
2424+ if ( elemType === 'array' || elemType === 'object' ) {
2425+ log ( 'WARNING: Cannot have array or object nested in an array property value, skipping' ) ;
2426+ continue ;
2427+ }
2428+ arrayCopy . push ( validatePropertyValue ( key , element ) ) ;
2429+ }
2430+ value = arrayCopy ;
2431+ }
2432+ else if ( valueType === 'object' ) {
2433+ value = validateProperties ( value ) ;
2434+ }
2435+ return value ;
2436+ } ;
2437+
2438+ module . exports = {
2439+ log : log ,
2440+ isEmptyString : isEmptyString ,
2441+ validateProperties : validateProperties
2442+ } ;
2443+
2444+ } , { "./type" :6 } ] ,
2371244514 : [ function ( require , module , exports ) {
23722446/*
23732447 * JavaScript MD5 1.0.1
@@ -3816,16 +3890,6 @@ function isBuffer(obj) {
38163890
38173891} ) ( this ) ;
38183892
3819- } , { } ] ,
3820- 7 : [ function ( require , module , exports ) {
3821- var isEmptyString = function ( str ) {
3822- return ( ! str || str . length === 0 ) ;
3823- } ;
3824-
3825- module . exports = {
3826- isEmptyString : isEmptyString
3827- } ;
3828-
38293893} , { } ] ,
3830389417 : [ function ( require , module , exports ) {
38313895/* jshint bitwise: false, laxbreak: true */
0 commit comments