@mparticle/web-sdk 2.18.3 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mparticle.common.js +22 -5
- package/dist/mparticle.esm.js +22 -5
- package/dist/mparticle.js +122 -101
- package/package.json +1 -1
- package/src/batchUploader.ts +146 -109
- package/src/vault.ts +141 -0
package/dist/mparticle.common.js
CHANGED
|
@@ -32,7 +32,7 @@ function _defineProperty(obj, key, value) {
|
|
|
32
32
|
|
|
33
33
|
var _TriggerUploadType,MessageType$1={SessionStart:1,SessionEnd:2,PageView:3,PageEvent:4,CrashReport:5,OptOut:6,AppStateTransition:10,Profile:14,Commerce:16,Media:20,UserAttributeChange:17,UserIdentityChange:18},TriggerUploadType=(_TriggerUploadType={},_defineProperty(_TriggerUploadType,MessageType$1.Commerce,1),_defineProperty(_TriggerUploadType,MessageType$1.UserAttributeChange,1),_defineProperty(_TriggerUploadType,MessageType$1.UserIdentityChange,1),_TriggerUploadType),EventType={Unknown:0,Navigation:1,Location:2,Search:3,Transaction:4,UserContent:5,UserPreference:6,Social:7,Other:8,Media:9,getName:function getName(a){return a===EventType.Unknown?"Unknown":a===EventType.Navigation?"Navigation":a===EventType.Location?"Location":a===EventType.Search?"Search":a===EventType.Transaction?"Transaction":a===EventType.UserContent?"User Content":a===EventType.UserPreference?"User Preference":a===EventType.Social?"Social":a===CommerceEventType.ProductAddToCart?"Product Added to Cart":a===CommerceEventType.ProductAddToWishlist?"Product Added to Wishlist":a===CommerceEventType.ProductCheckout?"Product Checkout":a===CommerceEventType.ProductCheckoutOption?"Product Checkout Options":a===CommerceEventType.ProductClick?"Product Click":a===CommerceEventType.ProductImpression?"Product Impression":a===CommerceEventType.ProductPurchase?"Product Purchased":a===CommerceEventType.ProductRefund?"Product Refunded":a===CommerceEventType.ProductRemoveFromCart?"Product Removed From Cart":a===CommerceEventType.ProductRemoveFromWishlist?"Product Removed from Wishlist":a===CommerceEventType.ProductViewDetail?"Product View Details":a===CommerceEventType.PromotionClick?"Promotion Click":a===CommerceEventType.PromotionView?"Promotion View":"Other"}},CommerceEventType={ProductAddToCart:10,ProductRemoveFromCart:11,ProductCheckout:12,ProductCheckoutOption:13,ProductClick:14,ProductViewDetail:15,ProductPurchase:16,ProductRefund:17,PromotionView:18,PromotionClick:19,ProductAddToWishlist:20,ProductRemoveFromWishlist:21,ProductImpression:22},IdentityType={Other:0,CustomerId:1,Facebook:2,Twitter:3,Google:4,Microsoft:5,Yahoo:6,Email:7,FacebookCustomAudienceId:9,Other2:10,Other3:11,Other4:12,Other5:13,Other6:14,Other7:15,Other8:16,Other9:17,Other10:18,MobileNumber:19,PhoneNumber2:20,PhoneNumber3:21};IdentityType.isValid=function(a){if("number"==typeof a)for(var b in IdentityType)if(IdentityType.hasOwnProperty(b)&&IdentityType[b]===a)return !0;return !1},IdentityType.getName=function(a){return a===window.mParticle.IdentityType.CustomerId?"Customer ID":a===window.mParticle.IdentityType.Facebook?"Facebook ID":a===window.mParticle.IdentityType.Twitter?"Twitter ID":a===window.mParticle.IdentityType.Google?"Google ID":a===window.mParticle.IdentityType.Microsoft?"Microsoft ID":a===window.mParticle.IdentityType.Yahoo?"Yahoo ID":a===window.mParticle.IdentityType.Email?"Email":a===window.mParticle.IdentityType.FacebookCustomAudienceId?"Facebook App User ID":"Other ID"},IdentityType.getIdentityType=function(a){return "other"===a?IdentityType.Other:"customerid"===a?IdentityType.CustomerId:"facebook"===a?IdentityType.Facebook:"twitter"===a?IdentityType.Twitter:"google"===a?IdentityType.Google:"microsoft"===a?IdentityType.Microsoft:"yahoo"===a?IdentityType.Yahoo:"email"===a?IdentityType.Email:"facebookcustomaudienceid"===a?IdentityType.FacebookCustomAudienceId:"other2"===a?IdentityType.Other2:"other3"===a?IdentityType.Other3:"other4"===a?IdentityType.Other4:"other5"===a?IdentityType.Other5:"other6"===a?IdentityType.Other6:"other7"===a?IdentityType.Other7:"other8"===a?IdentityType.Other8:"other9"===a?IdentityType.Other9:"other10"===a?IdentityType.Other10:"mobile_number"===a?IdentityType.MobileNumber:"phone_number_2"===a?IdentityType.PhoneNumber2:!("phone_number_3"!=a)&&IdentityType.PhoneNumber3},IdentityType.getIdentityName=function(a){return a===IdentityType.Other?"other":a===IdentityType.CustomerId?"customerid":a===IdentityType.Facebook?"facebook":a===IdentityType.Twitter?"twitter":a===IdentityType.Google?"google":a===IdentityType.Microsoft?"microsoft":a===IdentityType.Yahoo?"yahoo":a===IdentityType.Email?"email":a===IdentityType.FacebookCustomAudienceId?"facebookcustomaudienceid":a===IdentityType.Other2?"other2":a===IdentityType.Other3?"other3":a===IdentityType.Other4?"other4":a===IdentityType.Other5?"other5":a===IdentityType.Other6?"other6":a===IdentityType.Other7?"other7":a===IdentityType.Other8?"other8":a===IdentityType.Other9?"other9":a===IdentityType.Other10?"other10":a===IdentityType.MobileNumber?"mobile_number":a===IdentityType.PhoneNumber2?"phone_number_2":a===IdentityType.PhoneNumber3?"phone_number_3":void 0};var ProductActionType={Unknown:0,AddToCart:1,RemoveFromCart:2,Checkout:3,CheckoutOption:4,Click:5,ViewDetail:6,Purchase:7,Refund:8,AddToWishlist:9,RemoveFromWishlist:10};ProductActionType.getName=function(a){return a===ProductActionType.AddToCart?"Add to Cart":a===ProductActionType.RemoveFromCart?"Remove from Cart":a===ProductActionType.Checkout?"Checkout":a===ProductActionType.CheckoutOption?"Checkout Option":a===ProductActionType.Click?"Click":a===ProductActionType.ViewDetail?"View Detail":a===ProductActionType.Purchase?"Purchase":a===ProductActionType.Refund?"Refund":a===ProductActionType.AddToWishlist?"Add to Wishlist":a===ProductActionType.RemoveFromWishlist?"Remove from Wishlist":"Unknown"},ProductActionType.getExpansionName=function(a){return a===ProductActionType.AddToCart?"add_to_cart":a===ProductActionType.RemoveFromCart?"remove_from_cart":a===ProductActionType.Checkout?"checkout":a===ProductActionType.CheckoutOption?"checkout_option":a===ProductActionType.Click?"click":a===ProductActionType.ViewDetail?"view_detail":a===ProductActionType.Purchase?"purchase":a===ProductActionType.Refund?"refund":a===ProductActionType.AddToWishlist?"add_to_wishlist":a===ProductActionType.RemoveFromWishlist?"remove_from_wishlist":"unknown"};var PromotionActionType={Unknown:0,PromotionView:1,PromotionClick:2};PromotionActionType.getName=function(a){return a===PromotionActionType.PromotionView?"view":a===PromotionActionType.PromotionClick?"click":"unknown"},PromotionActionType.getExpansionName=function(a){return a===PromotionActionType.PromotionView?"view":a===PromotionActionType.PromotionClick?"click":"unknown"};var ProfileMessageType={Logout:3},ApplicationTransitionType$1={AppInit:1},Environment={Production:"production",Development:"development"};var Types = {MessageType:MessageType$1,EventType:EventType,CommerceEventType:CommerceEventType,IdentityType:IdentityType,ProfileMessageType:ProfileMessageType,ApplicationTransitionType:ApplicationTransitionType$1,ProductActionType:ProductActionType,PromotionActionType:PromotionActionType,TriggerUploadType:TriggerUploadType,Environment:Environment};
|
|
34
34
|
|
|
35
|
-
var version = "2.
|
|
35
|
+
var version = "2.19.0";
|
|
36
36
|
|
|
37
37
|
var Constants={sdkVersion:version,sdkVendor:"mparticle",platform:"web",Messages:{ErrorMessages:{NoToken:"A token must be specified.",EventNameInvalidType:"Event name must be a valid string value.",EventDataInvalidType:"Event data must be a valid object hash.",LoggingDisabled:"Event logging is currently disabled.",CookieParseError:"Could not parse cookie",EventEmpty:"Event object is null or undefined, cancelling send",APIRequestEmpty:"APIRequest is null or undefined, cancelling send",NoEventType:"Event type must be specified.",TransactionIdRequired:"Transaction ID is required",TransactionRequired:"A transaction attributes object is required",PromotionIdRequired:"Promotion ID is required",BadAttribute:"Attribute value cannot be object or array",BadKey:"Key value cannot be object or array",BadLogPurchase:"Transaction attributes and a product are both required to log a purchase, https://docs.mparticle.com/?javascript#measuring-transactions"},InformationMessages:{CookieSearch:"Searching for cookie",CookieFound:"Cookie found, parsing values",CookieNotFound:"Cookies not found",CookieSet:"Setting cookie",CookieSync:"Performing cookie sync",SendBegin:"Starting to send event",SendIdentityBegin:"Starting to send event to identity server",SendWindowsPhone:"Sending event to Windows Phone container",SendIOS:"Calling iOS path: ",SendAndroid:"Calling Android JS interface method: ",SendHttp:"Sending event to mParticle HTTP service",SendAliasHttp:"Sending alias request to mParticle HTTP service",SendIdentityHttp:"Sending event to mParticle HTTP service",StartingNewSession:"Starting new Session",StartingLogEvent:"Starting to log event",StartingLogOptOut:"Starting to log user opt in/out",StartingEndSession:"Starting to end session",StartingInitialization:"Starting to initialize",StartingLogCommerceEvent:"Starting to log commerce event",StartingAliasRequest:"Starting to Alias MPIDs",LoadingConfig:"Loading configuration options",AbandonLogEvent:"Cannot log event, logging disabled or developer token not set",AbandonAliasUsers:"Cannot Alias Users, logging disabled or developer token not set",AbandonStartSession:"Cannot start session, logging disabled or developer token not set",AbandonEndSession:"Cannot end session, logging disabled or developer token not set",NoSessionToEnd:"Cannot end session, no active session found"},ValidationMessages:{ModifyIdentityRequestUserIdentitiesPresent:"identityRequests to modify require userIdentities to be present. Request not sent to server. Please fix and try again",IdentityRequesetInvalidKey:"There is an invalid key on your identityRequest object. It can only contain a `userIdentities` object and a `onUserAlias` function. Request not sent to server. Please fix and try again.",OnUserAliasType:"The onUserAlias value must be a function.",UserIdentities:"The userIdentities key must be an object with keys of identityTypes and values of strings. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidKey:"There is an invalid identity key on your `userIdentities` object within the identityRequest. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidValues:"All user identity values must be strings or null. Request not sent to server. Please fix and try again.",AliasMissingMpid:"Alias Request must contain both a destinationMpid and a sourceMpid",AliasNonUniqueMpid:"Alias Request's destinationMpid and sourceMpid must be unique",AliasMissingTime:"Alias Request must have both a startTime and an endTime",AliasStartBeforeEndTime:"Alias Request's endTime must be later than its startTime"}},NativeSdkPaths:{LogEvent:"logEvent",SetUserTag:"setUserTag",RemoveUserTag:"removeUserTag",SetUserAttribute:"setUserAttribute",RemoveUserAttribute:"removeUserAttribute",SetSessionAttribute:"setSessionAttribute",AddToCart:"addToCart",RemoveFromCart:"removeFromCart",ClearCart:"clearCart",LogOut:"logOut",SetUserAttributeList:"setUserAttributeList",RemoveAllUserAttributes:"removeAllUserAttributes",GetUserAttributesLists:"getUserAttributesLists",GetAllUserAttributes:"getAllUserAttributes",Identify:"identify",Logout:"logout",Login:"login",Modify:"modify",Alias:"aliasUsers",Upload:"upload"},StorageNames:{localStorageName:"mprtcl-api",localStorageNameV3:"mprtcl-v3",cookieName:"mprtcl-api",cookieNameV2:"mprtcl-v2",cookieNameV3:"mprtcl-v3",localStorageNameV4:"mprtcl-v4",localStorageProductsV4:"mprtcl-prodv4",cookieNameV4:"mprtcl-v4",currentStorageName:"mprtcl-v4",currentStorageProductsName:"mprtcl-prodv4"},DefaultConfig:{cookieDomain:null,cookieExpiration:365,logLevel:null,timeout:300,sessionTimeout:30,maxProducts:20,forwarderStatsTimeout:5e3,integrationDelayTimeout:5e3,maxCookieSize:3e3,aliasMaxWindow:90,uploadInterval:0// Maximum milliseconds in between batch uploads, below 500 will mean immediate upload
|
|
38
38
|
},DefaultUrls:{v1SecureServiceUrl:"jssdks.mparticle.com/v1/JS/",v2SecureServiceUrl:"jssdks.mparticle.com/v2/JS/",v3SecureServiceUrl:"jssdks.mparticle.com/v3/JS/",configUrl:"jssdkcdns.mparticle.com/JS/v2/",identityUrl:"identity.mparticle.com/v1/",aliasUrl:"jssdks.mparticle.com/v1/identity/"},Base64CookieKeys:{csm:1,sa:1,ss:1,ua:1,ui:1,csd:1,ia:1,con:1},SDKv2NonMPIDCookieKeys:{gs:1,cu:1,l:1,globalSettings:1,currentUserMPID:1},HTTPCodes:{noHttpCoverage:-1,activeIdentityRequest:-2,activeSession:-3,validationIssue:-4,nativeIdentityRequest:-5,loggingDisabledOrMissingAPIKey:-6,tooManyRequests:429},FeatureFlags:{ReportBatching:"reportBatching",EventsV3:"eventsV3",EventBatchingIntervalMillis:"eventBatchingIntervalMillis"},DefaultInstance:"default_instance"};
|
|
@@ -438,11 +438,28 @@ return null;case Types.MessageType.SessionEnd:return convertSessionEndEvent(a);c
|
|
|
438
438
|
//spanning_mpids: sdkEvent.SessionMpids
|
|
439
439
|
};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.sessionEnd,data:c}}function convertSessionStartEvent(a){var b=convertBaseEventData(a),c={};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.sessionStart,data:c}}function convertPageViewEvent(a){var b=convertBaseEventData(a),c={custom_flags:a.CustomFlags,screen_name:a.EventName};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.screenView,data:c}}function convertOptOutEvent(a){var b=convertBaseEventData(a),c={is_opted_out:a.OptOut};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.optOut,data:c}}function convertCustomEvent(a){var b=convertBaseEventData(a),c={custom_event_type:convertSdkEventType(a.EventCategory),custom_flags:a.CustomFlags,event_name:a.EventName};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.customEvent,data:c}}function convertSdkEventType(a){return a===Types.EventType.Other?dist.CustomEventDataCustomEventTypeEnum.other:a===Types.EventType.Location?dist.CustomEventDataCustomEventTypeEnum.location:a===Types.EventType.Navigation?dist.CustomEventDataCustomEventTypeEnum.navigation:a===Types.EventType.Search?dist.CustomEventDataCustomEventTypeEnum.search:a===Types.EventType.Social?dist.CustomEventDataCustomEventTypeEnum.social:a===Types.EventType.Transaction?dist.CustomEventDataCustomEventTypeEnum.transaction:a===Types.EventType.UserContent?dist.CustomEventDataCustomEventTypeEnum.userContent:a===Types.EventType.UserPreference?dist.CustomEventDataCustomEventTypeEnum.userPreference:a===Types.EventType.Media?dist.CustomEventDataCustomEventTypeEnum.media:a===Types.CommerceEventType.ProductAddToCart?dist.CommerceEventDataCustomEventTypeEnum.addToCart:a===Types.CommerceEventType.ProductAddToWishlist?dist.CommerceEventDataCustomEventTypeEnum.addToWishlist:a===Types.CommerceEventType.ProductCheckout?dist.CommerceEventDataCustomEventTypeEnum.checkout:a===Types.CommerceEventType.ProductCheckoutOption?dist.CommerceEventDataCustomEventTypeEnum.checkoutOption:a===Types.CommerceEventType.ProductClick?dist.CommerceEventDataCustomEventTypeEnum.click:a===Types.CommerceEventType.ProductImpression?dist.CommerceEventDataCustomEventTypeEnum.impression:a===Types.CommerceEventType.ProductPurchase?dist.CommerceEventDataCustomEventTypeEnum.purchase:a===Types.CommerceEventType.ProductRefund?dist.CommerceEventDataCustomEventTypeEnum.refund:a===Types.CommerceEventType.ProductRemoveFromCart?dist.CommerceEventDataCustomEventTypeEnum.removeFromCart:a===Types.CommerceEventType.ProductRemoveFromWishlist?dist.CommerceEventDataCustomEventTypeEnum.removeFromWishlist:a===Types.CommerceEventType.ProductViewDetail?dist.CommerceEventDataCustomEventTypeEnum.viewDetail:a===Types.CommerceEventType.PromotionClick?dist.CommerceEventDataCustomEventTypeEnum.promotionClick:a===Types.CommerceEventType.PromotionView?dist.CommerceEventDataCustomEventTypeEnum.promotionView:dist.CustomEventDataCustomEventTypeEnum.unknown}function convertBaseEventData(a){var b={timestamp_unixtime_ms:a.Timestamp,session_uuid:a.SessionId,session_start_unixtime_ms:a.SessionStartDate,custom_attributes:a.EventAttributes,location:convertSDKLocation(a.Location),source_message_id:a.SourceMessageId};return b}function convertSDKLocation(a){return a&&Object.keys(a).length?{latitude:a.lat,longitude:a.lng}:null}function convertUserAttributeChangeEvent(a){var b=convertBaseEventData(a),c={user_attribute_name:a.UserAttributeChanges.UserAttributeName,new:a.UserAttributeChanges.New,old:a.UserAttributeChanges.Old,deleted:a.UserAttributeChanges.Deleted,is_new_attribute:a.UserAttributeChanges.IsNewAttribute};return c=__assign(__assign({},c),b),{event_type:dist.EventTypeEnum.userAttributeChange,data:c}}function convertUserIdentityChangeEvent(a){var b=convertBaseEventData(a),c={new:{identity_type:convertUserIdentityTypeToServerIdentityType(a.UserIdentityChanges.New.IdentityType),identity:a.UserIdentityChanges.New.Identity||null,timestamp_unixtime_ms:a.Timestamp,created_this_batch:a.UserIdentityChanges.New.CreatedThisBatch},old:{identity_type:convertUserIdentityTypeToServerIdentityType(a.UserIdentityChanges.Old.IdentityType),identity:a.UserIdentityChanges.Old.Identity||null,timestamp_unixtime_ms:a.Timestamp,created_this_batch:a.UserIdentityChanges.Old.CreatedThisBatch}};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.userIdentityChange,data:c}}function convertUserIdentityTypeToServerIdentityType(a){return a===SDKIdentityTypeEnum.other?dist.IdentityTypeEnum.other:a===SDKIdentityTypeEnum.customerId?dist.IdentityTypeEnum.customerId:a===SDKIdentityTypeEnum.facebook?dist.IdentityTypeEnum.facebook:a===SDKIdentityTypeEnum.twitter?dist.IdentityTypeEnum.twitter:a===SDKIdentityTypeEnum.google?dist.IdentityTypeEnum.google:a===SDKIdentityTypeEnum.microsoft?dist.IdentityTypeEnum.microsoft:a===SDKIdentityTypeEnum.yahoo?dist.IdentityTypeEnum.yahoo:a===SDKIdentityTypeEnum.email?dist.IdentityTypeEnum.email:a===SDKIdentityTypeEnum.alias?dist.IdentityTypeEnum.alias:a===SDKIdentityTypeEnum.facebookCustomAudienceId?dist.IdentityTypeEnum.facebookCustomAudienceId:a===SDKIdentityTypeEnum.otherId2?dist.IdentityTypeEnum.otherId2:a===SDKIdentityTypeEnum.otherId3?dist.IdentityTypeEnum.otherId3:a===SDKIdentityTypeEnum.otherId4?dist.IdentityTypeEnum.otherId4:a===SDKIdentityTypeEnum.otherId5?dist.IdentityTypeEnum.otherId5:a===SDKIdentityTypeEnum.otherId6?dist.IdentityTypeEnum.otherId6:a===SDKIdentityTypeEnum.otherId7?dist.IdentityTypeEnum.otherId7:a===SDKIdentityTypeEnum.otherId8?dist.IdentityTypeEnum.otherId8:a===SDKIdentityTypeEnum.otherId9?dist.IdentityTypeEnum.otherId9:a===SDKIdentityTypeEnum.otherId10?dist.IdentityTypeEnum.otherId10:a===SDKIdentityTypeEnum.mobileNumber?dist.IdentityTypeEnum.mobileNumber:a===SDKIdentityTypeEnum.phoneNumber2?dist.IdentityTypeEnum.phoneNumber2:a===SDKIdentityTypeEnum.phoneNumber3?dist.IdentityTypeEnum.phoneNumber3:void 0}
|
|
440
440
|
|
|
441
|
-
|
|
441
|
+
/**
|
|
442
|
+
* BatchUploader contains all the logic to upload batches to mParticle.
|
|
443
|
+
* It queues events as they come in and at set intervals turns them into batches.
|
|
444
|
+
* It then attempts to upload them to mParticle.
|
|
445
|
+
*
|
|
446
|
+
* These uploads happen on an interval basis using window.fetch or XHR
|
|
447
|
+
* requests, depending on what is available in the browser.
|
|
448
|
+
*
|
|
449
|
+
* Uploads can also be triggered on browser visibility/focus changes via an
|
|
450
|
+
* event listener, which then uploads to mPartice via the browser's Beacon API.
|
|
451
|
+
*/var BatchUploader=/** @class */function(){/**
|
|
452
|
+
* Creates an instance of a BatchUploader
|
|
453
|
+
* @param {MParticleWebSDK} mpInstance - the mParticle SDK instance
|
|
454
|
+
* @param {number} uploadInterval - the desired upload interval in milliseconds
|
|
455
|
+
*/function a(b,c){this.mpInstance=b,this.uploadIntervalMillis=c,this.batchingEnabled=c>=a.MINIMUM_INTERVAL_MILLIS,this.uploadIntervalMillis<a.MINIMUM_INTERVAL_MILLIS&&(this.uploadIntervalMillis=a.MINIMUM_INTERVAL_MILLIS),this.eventsQueuedForProcessing=[],this.batchesQueuedForProcessing=[];var d=this.mpInstance._Store,e=d.SDKConfig,f=d.devToken,g=this.mpInstance._Helpers.createServiceUrl(e.v3SecureServiceUrl,f);this.uploadUrl="".concat(g,"/events"),this.uploader=window.fetch?new FetchUploader(this.uploadUrl):new XHRUploader(this.uploadUrl),this.triggerUploadInterval(!0,!1),this.addEventListeners();}// Adds listeners to be used trigger Navigator.sendBeacon if the browser
|
|
456
|
+
// loses focus for any reason, such as closing browser tab or minimizing window
|
|
457
|
+
return a.prototype.addEventListeners=function(){var a=this;// visibility change is a document property, not window
|
|
458
|
+
document.addEventListener("visibilitychange",function(){a.prepareAndUpload(!1,a.isBeaconAvailable());}),window.addEventListener("beforeunload",function(){a.prepareAndUpload(!1,a.isBeaconAvailable());}),window.addEventListener("pagehide",function(){a.prepareAndUpload(!1,a.isBeaconAvailable());});},a.prototype.isBeaconAvailable=function(){return !!navigator.sendBeacon},a.prototype.triggerUploadInterval=function(a,b){var c=this;void 0===a&&(a=!1),void 0===b&&(b=!1),setTimeout(function(){c.prepareAndUpload(a,b);},this.uploadIntervalMillis);},a.prototype.queueEvent=function(a){isEmpty(a)||(this.eventsQueuedForProcessing.push(a),this.mpInstance.Logger.verbose("Queuing event: ".concat(JSON.stringify(a))),this.mpInstance.Logger.verbose("Queued event count: ".concat(this.eventsQueuedForProcessing.length)),(!this.batchingEnabled||Types.TriggerUploadType[a.EventDataType])&&this.prepareAndUpload(!1,!1));},a.createNewBatches=function(a,b,c){if(!b||!a||!a.length)return null;//bucket by MPID, and then by session, ordered by timestamp
|
|
442
459
|
for(var d,e=[],f=new Map,g=0,h=a;g<h.length;g++){//on initial startup, there may be events logged without an mpid.
|
|
443
|
-
if(d=h[g],!d.MPID){var i=b.getMPID();d.MPID=i;}var j=f.get(d.MPID);j||(j=[]),j.push(d),f.set(d.MPID,j);}for(var k=0,l=Array.from(f.entries());k<l.length;k++){for(var m=l[k],i=m[0],n=m[1],o=new Map,p=0,q=n;p<q.length;p++){var d=q[p],j=o.get(d.SessionId);j||(j=[]),j.push(d),o.set(d.SessionId,j);}for(var r=0,s=Array.from(o.entries());r<s.length;r++){var t=s[r],u=convertEvents(i,t[1],c),v=c._Store.SDKConfig.onCreateBatch;v&&(u=v(u),u?u.modified=!0:c.Logger.warning("Skiping batch upload because no batch was returned from onCreateBatch callback")),u&&e.push(u);}}return e},a.prototype.prepareAndUpload=function(b,c){return __awaiter(this,void 0,void 0,function(){var d,e,f,g,h,i,j,k=this;return __generator(this,function(
|
|
444
|
-
return b.
|
|
445
|
-
return b.error("HTTP error status ".concat(
|
|
460
|
+
if(d=h[g],!d.MPID){var i=b.getMPID();d.MPID=i;}var j=f.get(d.MPID);j||(j=[]),j.push(d),f.set(d.MPID,j);}for(var k=0,l=Array.from(f.entries());k<l.length;k++){for(var m=l[k],i=m[0],n=m[1],o=new Map,p=0,q=n;p<q.length;p++){var d=q[p],j=o.get(d.SessionId);j||(j=[]),j.push(d),o.set(d.SessionId,j);}for(var r=0,s=Array.from(o.entries());r<s.length;r++){var t=s[r],u=convertEvents(i,t[1],c),v=c._Store.SDKConfig.onCreateBatch;v&&(u=v(u),u?u.modified=!0:c.Logger.warning("Skiping batch upload because no batch was returned from onCreateBatch callback")),u&&e.push(u);}}return e},a.prototype.prepareAndUpload=function(b,c){return __awaiter(this,void 0,void 0,function(){var d,e,f,g,h,i,j,k=this;return __generator(this,function(){return d=this.mpInstance.Identity.getCurrentUser(),e=this.eventsQueuedForProcessing,this.eventsQueuedForProcessing=[],f=a.createNewBatches(e,d,this.mpInstance),isEmpty(f)||(j=this.batchesQueuedForProcessing).push.apply(j,f),g=this.batchesQueuedForProcessing,h=[],this.batchesQueuedForProcessing=[],i=g.map(function(a){return k.upload(k.mpInstance.Logger,a,c)}),isEmpty(i)||Promise.all(i).then(function(a){a.forEach(function(a){return isEmpty(a)?null:h.push(a)});})["catch"](function(a){k.mpInstance.Logger.error("Error processing batches during upload attempt: ".concat(a));})["finally"](function(){var a;// Any batches that did not upload should be put back into the queue for processing
|
|
461
|
+
isEmpty(h)||(a=k.batchesQueuedForProcessing).unshift.apply(a,h);}),b&&this.triggerUploadInterval(b,!1),[2/*return*/]})})},a.prototype.upload=function(b,c,d){return __awaiter(this,void 0,void 0,function(){var e,f,g,h;return __generator(this,function(i){switch(i.label){case 0:return isEmpty(c)||isEmpty(c.events)?[2/*return*/,null]:(b.verbose("Uploading batches: ".concat(JSON.stringify(c))),e={method:"POST",headers:{Accept:a.CONTENT_TYPE,"Content-Type":"text/plain;charset=UTF-8"},body:JSON.stringify(c)},!(d&&this.isBeaconAvailable()))?[3/*break*/,1]:(f=new Blob([e.body],{type:"text/plain;charset=UTF-8"}),navigator.sendBeacon(this.uploadUrl,f),[3/*break*/,4]);case 1:return i.trys.push([1,3,,4]),[4/*yield*/,this.uploader.upload(e)];case 2:// TODO: Should we make this a switch statement instead?
|
|
462
|
+
return (g=i.sent(),200<=g.status&&300>g.status)?(b.verbose("Upload success for request ID: ".concat(c.source_request_id)),[2/*return*/,null]):500<=g.status||429===g.status?(b.error("HTTP error status ".concat(g.status," received")),[2/*return*/,c]):401<=g.status?(b.error("HTTP error status ".concat(g.status," while uploading - please verify your API key.")),[2/*return*/,c]):[3/*break*/,4];case 3:return h=i.sent(),b.error("Error sending event to mParticle servers. ".concat(h)),[2/*return*/,c];case 4:return [2/*return*/,null];}})})},a.CONTENT_TYPE="text/plain;charset=UTF-8",a.MINIMUM_INTERVAL_MILLIS=500,a}();var AsyncUploader=/** @class */function(){function a(a){this.url=a;}return a}(),FetchUploader=/** @class */function(a){function b(){return null!==a&&a.apply(this,arguments)||this}return __extends(b,a),b.prototype.upload=function(a){return __awaiter(this,void 0,void 0,function(){var b;return __generator(this,function(c){switch(c.label){case 0:return [4/*yield*/,fetch(this.url,a)];case 1:return b=c.sent(),[2/*return*/,b];}})})},b}(AsyncUploader),XHRUploader=/** @class */function(a){function b(){return null!==a&&a.apply(this,arguments)||this}return __extends(b,a),b.prototype.upload=function(a){return __awaiter(this,void 0,void 0,function(){var b;return __generator(this,function(c){switch(c.label){case 0:return [4/*yield*/,this.makeRequest(this.url,a.body)];case 1:return b=c.sent(),[2/*return*/,b];}})})},b.prototype.makeRequest=function(a,b){return __awaiter(this,void 0,void 0,function(){var c;return __generator(this,function(){return c=new XMLHttpRequest,[2/*return*/,new Promise(function(d,e){c.onreadystatechange=function(){4!==c.readyState||(200<=c.status&&300>c.status?d(c):e(c));},c.open("post",a),c.send(b);})]})})},b}(AsyncUploader);
|
|
446
463
|
|
|
447
464
|
var Messages$9=Constants.Messages;function APIClient(a,b){this.uploader=null;var c=this;this.queueEventForBatchUpload=function(b){if(!this.uploader){var c=a._Helpers.getFeatureFlag(Constants.FeatureFlags.EventBatchingIntervalMillis);this.uploader=new BatchUploader(a,c);}this.uploader.queueEvent(b),a._Persistence.update();},this.shouldEnableBatching=function(){// Returns a string of a number that must be parsed
|
|
448
465
|
// Invalid strings will be parsed to NaN which is falsey
|
package/dist/mparticle.esm.js
CHANGED
|
@@ -32,7 +32,7 @@ function _defineProperty(obj, key, value) {
|
|
|
32
32
|
|
|
33
33
|
var _TriggerUploadType,MessageType$1={SessionStart:1,SessionEnd:2,PageView:3,PageEvent:4,CrashReport:5,OptOut:6,AppStateTransition:10,Profile:14,Commerce:16,Media:20,UserAttributeChange:17,UserIdentityChange:18},TriggerUploadType=(_TriggerUploadType={},_defineProperty(_TriggerUploadType,MessageType$1.Commerce,1),_defineProperty(_TriggerUploadType,MessageType$1.UserAttributeChange,1),_defineProperty(_TriggerUploadType,MessageType$1.UserIdentityChange,1),_TriggerUploadType),EventType={Unknown:0,Navigation:1,Location:2,Search:3,Transaction:4,UserContent:5,UserPreference:6,Social:7,Other:8,Media:9,getName:function getName(a){return a===EventType.Unknown?"Unknown":a===EventType.Navigation?"Navigation":a===EventType.Location?"Location":a===EventType.Search?"Search":a===EventType.Transaction?"Transaction":a===EventType.UserContent?"User Content":a===EventType.UserPreference?"User Preference":a===EventType.Social?"Social":a===CommerceEventType.ProductAddToCart?"Product Added to Cart":a===CommerceEventType.ProductAddToWishlist?"Product Added to Wishlist":a===CommerceEventType.ProductCheckout?"Product Checkout":a===CommerceEventType.ProductCheckoutOption?"Product Checkout Options":a===CommerceEventType.ProductClick?"Product Click":a===CommerceEventType.ProductImpression?"Product Impression":a===CommerceEventType.ProductPurchase?"Product Purchased":a===CommerceEventType.ProductRefund?"Product Refunded":a===CommerceEventType.ProductRemoveFromCart?"Product Removed From Cart":a===CommerceEventType.ProductRemoveFromWishlist?"Product Removed from Wishlist":a===CommerceEventType.ProductViewDetail?"Product View Details":a===CommerceEventType.PromotionClick?"Promotion Click":a===CommerceEventType.PromotionView?"Promotion View":"Other"}},CommerceEventType={ProductAddToCart:10,ProductRemoveFromCart:11,ProductCheckout:12,ProductCheckoutOption:13,ProductClick:14,ProductViewDetail:15,ProductPurchase:16,ProductRefund:17,PromotionView:18,PromotionClick:19,ProductAddToWishlist:20,ProductRemoveFromWishlist:21,ProductImpression:22},IdentityType={Other:0,CustomerId:1,Facebook:2,Twitter:3,Google:4,Microsoft:5,Yahoo:6,Email:7,FacebookCustomAudienceId:9,Other2:10,Other3:11,Other4:12,Other5:13,Other6:14,Other7:15,Other8:16,Other9:17,Other10:18,MobileNumber:19,PhoneNumber2:20,PhoneNumber3:21};IdentityType.isValid=function(a){if("number"==typeof a)for(var b in IdentityType)if(IdentityType.hasOwnProperty(b)&&IdentityType[b]===a)return !0;return !1},IdentityType.getName=function(a){return a===window.mParticle.IdentityType.CustomerId?"Customer ID":a===window.mParticle.IdentityType.Facebook?"Facebook ID":a===window.mParticle.IdentityType.Twitter?"Twitter ID":a===window.mParticle.IdentityType.Google?"Google ID":a===window.mParticle.IdentityType.Microsoft?"Microsoft ID":a===window.mParticle.IdentityType.Yahoo?"Yahoo ID":a===window.mParticle.IdentityType.Email?"Email":a===window.mParticle.IdentityType.FacebookCustomAudienceId?"Facebook App User ID":"Other ID"},IdentityType.getIdentityType=function(a){return "other"===a?IdentityType.Other:"customerid"===a?IdentityType.CustomerId:"facebook"===a?IdentityType.Facebook:"twitter"===a?IdentityType.Twitter:"google"===a?IdentityType.Google:"microsoft"===a?IdentityType.Microsoft:"yahoo"===a?IdentityType.Yahoo:"email"===a?IdentityType.Email:"facebookcustomaudienceid"===a?IdentityType.FacebookCustomAudienceId:"other2"===a?IdentityType.Other2:"other3"===a?IdentityType.Other3:"other4"===a?IdentityType.Other4:"other5"===a?IdentityType.Other5:"other6"===a?IdentityType.Other6:"other7"===a?IdentityType.Other7:"other8"===a?IdentityType.Other8:"other9"===a?IdentityType.Other9:"other10"===a?IdentityType.Other10:"mobile_number"===a?IdentityType.MobileNumber:"phone_number_2"===a?IdentityType.PhoneNumber2:!("phone_number_3"!=a)&&IdentityType.PhoneNumber3},IdentityType.getIdentityName=function(a){return a===IdentityType.Other?"other":a===IdentityType.CustomerId?"customerid":a===IdentityType.Facebook?"facebook":a===IdentityType.Twitter?"twitter":a===IdentityType.Google?"google":a===IdentityType.Microsoft?"microsoft":a===IdentityType.Yahoo?"yahoo":a===IdentityType.Email?"email":a===IdentityType.FacebookCustomAudienceId?"facebookcustomaudienceid":a===IdentityType.Other2?"other2":a===IdentityType.Other3?"other3":a===IdentityType.Other4?"other4":a===IdentityType.Other5?"other5":a===IdentityType.Other6?"other6":a===IdentityType.Other7?"other7":a===IdentityType.Other8?"other8":a===IdentityType.Other9?"other9":a===IdentityType.Other10?"other10":a===IdentityType.MobileNumber?"mobile_number":a===IdentityType.PhoneNumber2?"phone_number_2":a===IdentityType.PhoneNumber3?"phone_number_3":void 0};var ProductActionType={Unknown:0,AddToCart:1,RemoveFromCart:2,Checkout:3,CheckoutOption:4,Click:5,ViewDetail:6,Purchase:7,Refund:8,AddToWishlist:9,RemoveFromWishlist:10};ProductActionType.getName=function(a){return a===ProductActionType.AddToCart?"Add to Cart":a===ProductActionType.RemoveFromCart?"Remove from Cart":a===ProductActionType.Checkout?"Checkout":a===ProductActionType.CheckoutOption?"Checkout Option":a===ProductActionType.Click?"Click":a===ProductActionType.ViewDetail?"View Detail":a===ProductActionType.Purchase?"Purchase":a===ProductActionType.Refund?"Refund":a===ProductActionType.AddToWishlist?"Add to Wishlist":a===ProductActionType.RemoveFromWishlist?"Remove from Wishlist":"Unknown"},ProductActionType.getExpansionName=function(a){return a===ProductActionType.AddToCart?"add_to_cart":a===ProductActionType.RemoveFromCart?"remove_from_cart":a===ProductActionType.Checkout?"checkout":a===ProductActionType.CheckoutOption?"checkout_option":a===ProductActionType.Click?"click":a===ProductActionType.ViewDetail?"view_detail":a===ProductActionType.Purchase?"purchase":a===ProductActionType.Refund?"refund":a===ProductActionType.AddToWishlist?"add_to_wishlist":a===ProductActionType.RemoveFromWishlist?"remove_from_wishlist":"unknown"};var PromotionActionType={Unknown:0,PromotionView:1,PromotionClick:2};PromotionActionType.getName=function(a){return a===PromotionActionType.PromotionView?"view":a===PromotionActionType.PromotionClick?"click":"unknown"},PromotionActionType.getExpansionName=function(a){return a===PromotionActionType.PromotionView?"view":a===PromotionActionType.PromotionClick?"click":"unknown"};var ProfileMessageType={Logout:3},ApplicationTransitionType$1={AppInit:1},Environment={Production:"production",Development:"development"};var Types = {MessageType:MessageType$1,EventType:EventType,CommerceEventType:CommerceEventType,IdentityType:IdentityType,ProfileMessageType:ProfileMessageType,ApplicationTransitionType:ApplicationTransitionType$1,ProductActionType:ProductActionType,PromotionActionType:PromotionActionType,TriggerUploadType:TriggerUploadType,Environment:Environment};
|
|
34
34
|
|
|
35
|
-
var version = "2.
|
|
35
|
+
var version = "2.19.0";
|
|
36
36
|
|
|
37
37
|
var Constants={sdkVersion:version,sdkVendor:"mparticle",platform:"web",Messages:{ErrorMessages:{NoToken:"A token must be specified.",EventNameInvalidType:"Event name must be a valid string value.",EventDataInvalidType:"Event data must be a valid object hash.",LoggingDisabled:"Event logging is currently disabled.",CookieParseError:"Could not parse cookie",EventEmpty:"Event object is null or undefined, cancelling send",APIRequestEmpty:"APIRequest is null or undefined, cancelling send",NoEventType:"Event type must be specified.",TransactionIdRequired:"Transaction ID is required",TransactionRequired:"A transaction attributes object is required",PromotionIdRequired:"Promotion ID is required",BadAttribute:"Attribute value cannot be object or array",BadKey:"Key value cannot be object or array",BadLogPurchase:"Transaction attributes and a product are both required to log a purchase, https://docs.mparticle.com/?javascript#measuring-transactions"},InformationMessages:{CookieSearch:"Searching for cookie",CookieFound:"Cookie found, parsing values",CookieNotFound:"Cookies not found",CookieSet:"Setting cookie",CookieSync:"Performing cookie sync",SendBegin:"Starting to send event",SendIdentityBegin:"Starting to send event to identity server",SendWindowsPhone:"Sending event to Windows Phone container",SendIOS:"Calling iOS path: ",SendAndroid:"Calling Android JS interface method: ",SendHttp:"Sending event to mParticle HTTP service",SendAliasHttp:"Sending alias request to mParticle HTTP service",SendIdentityHttp:"Sending event to mParticle HTTP service",StartingNewSession:"Starting new Session",StartingLogEvent:"Starting to log event",StartingLogOptOut:"Starting to log user opt in/out",StartingEndSession:"Starting to end session",StartingInitialization:"Starting to initialize",StartingLogCommerceEvent:"Starting to log commerce event",StartingAliasRequest:"Starting to Alias MPIDs",LoadingConfig:"Loading configuration options",AbandonLogEvent:"Cannot log event, logging disabled or developer token not set",AbandonAliasUsers:"Cannot Alias Users, logging disabled or developer token not set",AbandonStartSession:"Cannot start session, logging disabled or developer token not set",AbandonEndSession:"Cannot end session, logging disabled or developer token not set",NoSessionToEnd:"Cannot end session, no active session found"},ValidationMessages:{ModifyIdentityRequestUserIdentitiesPresent:"identityRequests to modify require userIdentities to be present. Request not sent to server. Please fix and try again",IdentityRequesetInvalidKey:"There is an invalid key on your identityRequest object. It can only contain a `userIdentities` object and a `onUserAlias` function. Request not sent to server. Please fix and try again.",OnUserAliasType:"The onUserAlias value must be a function.",UserIdentities:"The userIdentities key must be an object with keys of identityTypes and values of strings. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidKey:"There is an invalid identity key on your `userIdentities` object within the identityRequest. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidValues:"All user identity values must be strings or null. Request not sent to server. Please fix and try again.",AliasMissingMpid:"Alias Request must contain both a destinationMpid and a sourceMpid",AliasNonUniqueMpid:"Alias Request's destinationMpid and sourceMpid must be unique",AliasMissingTime:"Alias Request must have both a startTime and an endTime",AliasStartBeforeEndTime:"Alias Request's endTime must be later than its startTime"}},NativeSdkPaths:{LogEvent:"logEvent",SetUserTag:"setUserTag",RemoveUserTag:"removeUserTag",SetUserAttribute:"setUserAttribute",RemoveUserAttribute:"removeUserAttribute",SetSessionAttribute:"setSessionAttribute",AddToCart:"addToCart",RemoveFromCart:"removeFromCart",ClearCart:"clearCart",LogOut:"logOut",SetUserAttributeList:"setUserAttributeList",RemoveAllUserAttributes:"removeAllUserAttributes",GetUserAttributesLists:"getUserAttributesLists",GetAllUserAttributes:"getAllUserAttributes",Identify:"identify",Logout:"logout",Login:"login",Modify:"modify",Alias:"aliasUsers",Upload:"upload"},StorageNames:{localStorageName:"mprtcl-api",localStorageNameV3:"mprtcl-v3",cookieName:"mprtcl-api",cookieNameV2:"mprtcl-v2",cookieNameV3:"mprtcl-v3",localStorageNameV4:"mprtcl-v4",localStorageProductsV4:"mprtcl-prodv4",cookieNameV4:"mprtcl-v4",currentStorageName:"mprtcl-v4",currentStorageProductsName:"mprtcl-prodv4"},DefaultConfig:{cookieDomain:null,cookieExpiration:365,logLevel:null,timeout:300,sessionTimeout:30,maxProducts:20,forwarderStatsTimeout:5e3,integrationDelayTimeout:5e3,maxCookieSize:3e3,aliasMaxWindow:90,uploadInterval:0// Maximum milliseconds in between batch uploads, below 500 will mean immediate upload
|
|
38
38
|
},DefaultUrls:{v1SecureServiceUrl:"jssdks.mparticle.com/v1/JS/",v2SecureServiceUrl:"jssdks.mparticle.com/v2/JS/",v3SecureServiceUrl:"jssdks.mparticle.com/v3/JS/",configUrl:"jssdkcdns.mparticle.com/JS/v2/",identityUrl:"identity.mparticle.com/v1/",aliasUrl:"jssdks.mparticle.com/v1/identity/"},Base64CookieKeys:{csm:1,sa:1,ss:1,ua:1,ui:1,csd:1,ia:1,con:1},SDKv2NonMPIDCookieKeys:{gs:1,cu:1,l:1,globalSettings:1,currentUserMPID:1},HTTPCodes:{noHttpCoverage:-1,activeIdentityRequest:-2,activeSession:-3,validationIssue:-4,nativeIdentityRequest:-5,loggingDisabledOrMissingAPIKey:-6,tooManyRequests:429},FeatureFlags:{ReportBatching:"reportBatching",EventsV3:"eventsV3",EventBatchingIntervalMillis:"eventBatchingIntervalMillis"},DefaultInstance:"default_instance"};
|
|
@@ -438,11 +438,28 @@ return null;case Types.MessageType.SessionEnd:return convertSessionEndEvent(a);c
|
|
|
438
438
|
//spanning_mpids: sdkEvent.SessionMpids
|
|
439
439
|
};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.sessionEnd,data:c}}function convertSessionStartEvent(a){var b=convertBaseEventData(a),c={};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.sessionStart,data:c}}function convertPageViewEvent(a){var b=convertBaseEventData(a),c={custom_flags:a.CustomFlags,screen_name:a.EventName};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.screenView,data:c}}function convertOptOutEvent(a){var b=convertBaseEventData(a),c={is_opted_out:a.OptOut};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.optOut,data:c}}function convertCustomEvent(a){var b=convertBaseEventData(a),c={custom_event_type:convertSdkEventType(a.EventCategory),custom_flags:a.CustomFlags,event_name:a.EventName};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.customEvent,data:c}}function convertSdkEventType(a){return a===Types.EventType.Other?dist.CustomEventDataCustomEventTypeEnum.other:a===Types.EventType.Location?dist.CustomEventDataCustomEventTypeEnum.location:a===Types.EventType.Navigation?dist.CustomEventDataCustomEventTypeEnum.navigation:a===Types.EventType.Search?dist.CustomEventDataCustomEventTypeEnum.search:a===Types.EventType.Social?dist.CustomEventDataCustomEventTypeEnum.social:a===Types.EventType.Transaction?dist.CustomEventDataCustomEventTypeEnum.transaction:a===Types.EventType.UserContent?dist.CustomEventDataCustomEventTypeEnum.userContent:a===Types.EventType.UserPreference?dist.CustomEventDataCustomEventTypeEnum.userPreference:a===Types.EventType.Media?dist.CustomEventDataCustomEventTypeEnum.media:a===Types.CommerceEventType.ProductAddToCart?dist.CommerceEventDataCustomEventTypeEnum.addToCart:a===Types.CommerceEventType.ProductAddToWishlist?dist.CommerceEventDataCustomEventTypeEnum.addToWishlist:a===Types.CommerceEventType.ProductCheckout?dist.CommerceEventDataCustomEventTypeEnum.checkout:a===Types.CommerceEventType.ProductCheckoutOption?dist.CommerceEventDataCustomEventTypeEnum.checkoutOption:a===Types.CommerceEventType.ProductClick?dist.CommerceEventDataCustomEventTypeEnum.click:a===Types.CommerceEventType.ProductImpression?dist.CommerceEventDataCustomEventTypeEnum.impression:a===Types.CommerceEventType.ProductPurchase?dist.CommerceEventDataCustomEventTypeEnum.purchase:a===Types.CommerceEventType.ProductRefund?dist.CommerceEventDataCustomEventTypeEnum.refund:a===Types.CommerceEventType.ProductRemoveFromCart?dist.CommerceEventDataCustomEventTypeEnum.removeFromCart:a===Types.CommerceEventType.ProductRemoveFromWishlist?dist.CommerceEventDataCustomEventTypeEnum.removeFromWishlist:a===Types.CommerceEventType.ProductViewDetail?dist.CommerceEventDataCustomEventTypeEnum.viewDetail:a===Types.CommerceEventType.PromotionClick?dist.CommerceEventDataCustomEventTypeEnum.promotionClick:a===Types.CommerceEventType.PromotionView?dist.CommerceEventDataCustomEventTypeEnum.promotionView:dist.CustomEventDataCustomEventTypeEnum.unknown}function convertBaseEventData(a){var b={timestamp_unixtime_ms:a.Timestamp,session_uuid:a.SessionId,session_start_unixtime_ms:a.SessionStartDate,custom_attributes:a.EventAttributes,location:convertSDKLocation(a.Location),source_message_id:a.SourceMessageId};return b}function convertSDKLocation(a){return a&&Object.keys(a).length?{latitude:a.lat,longitude:a.lng}:null}function convertUserAttributeChangeEvent(a){var b=convertBaseEventData(a),c={user_attribute_name:a.UserAttributeChanges.UserAttributeName,new:a.UserAttributeChanges.New,old:a.UserAttributeChanges.Old,deleted:a.UserAttributeChanges.Deleted,is_new_attribute:a.UserAttributeChanges.IsNewAttribute};return c=__assign(__assign({},c),b),{event_type:dist.EventTypeEnum.userAttributeChange,data:c}}function convertUserIdentityChangeEvent(a){var b=convertBaseEventData(a),c={new:{identity_type:convertUserIdentityTypeToServerIdentityType(a.UserIdentityChanges.New.IdentityType),identity:a.UserIdentityChanges.New.Identity||null,timestamp_unixtime_ms:a.Timestamp,created_this_batch:a.UserIdentityChanges.New.CreatedThisBatch},old:{identity_type:convertUserIdentityTypeToServerIdentityType(a.UserIdentityChanges.Old.IdentityType),identity:a.UserIdentityChanges.Old.Identity||null,timestamp_unixtime_ms:a.Timestamp,created_this_batch:a.UserIdentityChanges.Old.CreatedThisBatch}};return c=Object.assign(c,b),{event_type:dist.EventTypeEnum.userIdentityChange,data:c}}function convertUserIdentityTypeToServerIdentityType(a){return a===SDKIdentityTypeEnum.other?dist.IdentityTypeEnum.other:a===SDKIdentityTypeEnum.customerId?dist.IdentityTypeEnum.customerId:a===SDKIdentityTypeEnum.facebook?dist.IdentityTypeEnum.facebook:a===SDKIdentityTypeEnum.twitter?dist.IdentityTypeEnum.twitter:a===SDKIdentityTypeEnum.google?dist.IdentityTypeEnum.google:a===SDKIdentityTypeEnum.microsoft?dist.IdentityTypeEnum.microsoft:a===SDKIdentityTypeEnum.yahoo?dist.IdentityTypeEnum.yahoo:a===SDKIdentityTypeEnum.email?dist.IdentityTypeEnum.email:a===SDKIdentityTypeEnum.alias?dist.IdentityTypeEnum.alias:a===SDKIdentityTypeEnum.facebookCustomAudienceId?dist.IdentityTypeEnum.facebookCustomAudienceId:a===SDKIdentityTypeEnum.otherId2?dist.IdentityTypeEnum.otherId2:a===SDKIdentityTypeEnum.otherId3?dist.IdentityTypeEnum.otherId3:a===SDKIdentityTypeEnum.otherId4?dist.IdentityTypeEnum.otherId4:a===SDKIdentityTypeEnum.otherId5?dist.IdentityTypeEnum.otherId5:a===SDKIdentityTypeEnum.otherId6?dist.IdentityTypeEnum.otherId6:a===SDKIdentityTypeEnum.otherId7?dist.IdentityTypeEnum.otherId7:a===SDKIdentityTypeEnum.otherId8?dist.IdentityTypeEnum.otherId8:a===SDKIdentityTypeEnum.otherId9?dist.IdentityTypeEnum.otherId9:a===SDKIdentityTypeEnum.otherId10?dist.IdentityTypeEnum.otherId10:a===SDKIdentityTypeEnum.mobileNumber?dist.IdentityTypeEnum.mobileNumber:a===SDKIdentityTypeEnum.phoneNumber2?dist.IdentityTypeEnum.phoneNumber2:a===SDKIdentityTypeEnum.phoneNumber3?dist.IdentityTypeEnum.phoneNumber3:void 0}
|
|
440
440
|
|
|
441
|
-
|
|
441
|
+
/**
|
|
442
|
+
* BatchUploader contains all the logic to upload batches to mParticle.
|
|
443
|
+
* It queues events as they come in and at set intervals turns them into batches.
|
|
444
|
+
* It then attempts to upload them to mParticle.
|
|
445
|
+
*
|
|
446
|
+
* These uploads happen on an interval basis using window.fetch or XHR
|
|
447
|
+
* requests, depending on what is available in the browser.
|
|
448
|
+
*
|
|
449
|
+
* Uploads can also be triggered on browser visibility/focus changes via an
|
|
450
|
+
* event listener, which then uploads to mPartice via the browser's Beacon API.
|
|
451
|
+
*/var BatchUploader=/** @class */function(){/**
|
|
452
|
+
* Creates an instance of a BatchUploader
|
|
453
|
+
* @param {MParticleWebSDK} mpInstance - the mParticle SDK instance
|
|
454
|
+
* @param {number} uploadInterval - the desired upload interval in milliseconds
|
|
455
|
+
*/function a(b,c){this.mpInstance=b,this.uploadIntervalMillis=c,this.batchingEnabled=c>=a.MINIMUM_INTERVAL_MILLIS,this.uploadIntervalMillis<a.MINIMUM_INTERVAL_MILLIS&&(this.uploadIntervalMillis=a.MINIMUM_INTERVAL_MILLIS),this.eventsQueuedForProcessing=[],this.batchesQueuedForProcessing=[];var d=this.mpInstance._Store,e=d.SDKConfig,f=d.devToken,g=this.mpInstance._Helpers.createServiceUrl(e.v3SecureServiceUrl,f);this.uploadUrl="".concat(g,"/events"),this.uploader=window.fetch?new FetchUploader(this.uploadUrl):new XHRUploader(this.uploadUrl),this.triggerUploadInterval(!0,!1),this.addEventListeners();}// Adds listeners to be used trigger Navigator.sendBeacon if the browser
|
|
456
|
+
// loses focus for any reason, such as closing browser tab or minimizing window
|
|
457
|
+
return a.prototype.addEventListeners=function(){var a=this;// visibility change is a document property, not window
|
|
458
|
+
document.addEventListener("visibilitychange",function(){a.prepareAndUpload(!1,a.isBeaconAvailable());}),window.addEventListener("beforeunload",function(){a.prepareAndUpload(!1,a.isBeaconAvailable());}),window.addEventListener("pagehide",function(){a.prepareAndUpload(!1,a.isBeaconAvailable());});},a.prototype.isBeaconAvailable=function(){return !!navigator.sendBeacon},a.prototype.triggerUploadInterval=function(a,b){var c=this;void 0===a&&(a=!1),void 0===b&&(b=!1),setTimeout(function(){c.prepareAndUpload(a,b);},this.uploadIntervalMillis);},a.prototype.queueEvent=function(a){isEmpty(a)||(this.eventsQueuedForProcessing.push(a),this.mpInstance.Logger.verbose("Queuing event: ".concat(JSON.stringify(a))),this.mpInstance.Logger.verbose("Queued event count: ".concat(this.eventsQueuedForProcessing.length)),(!this.batchingEnabled||Types.TriggerUploadType[a.EventDataType])&&this.prepareAndUpload(!1,!1));},a.createNewBatches=function(a,b,c){if(!b||!a||!a.length)return null;//bucket by MPID, and then by session, ordered by timestamp
|
|
442
459
|
for(var d,e=[],f=new Map,g=0,h=a;g<h.length;g++){//on initial startup, there may be events logged without an mpid.
|
|
443
|
-
if(d=h[g],!d.MPID){var i=b.getMPID();d.MPID=i;}var j=f.get(d.MPID);j||(j=[]),j.push(d),f.set(d.MPID,j);}for(var k=0,l=Array.from(f.entries());k<l.length;k++){for(var m=l[k],i=m[0],n=m[1],o=new Map,p=0,q=n;p<q.length;p++){var d=q[p],j=o.get(d.SessionId);j||(j=[]),j.push(d),o.set(d.SessionId,j);}for(var r=0,s=Array.from(o.entries());r<s.length;r++){var t=s[r],u=convertEvents(i,t[1],c),v=c._Store.SDKConfig.onCreateBatch;v&&(u=v(u),u?u.modified=!0:c.Logger.warning("Skiping batch upload because no batch was returned from onCreateBatch callback")),u&&e.push(u);}}return e},a.prototype.prepareAndUpload=function(b,c){return __awaiter(this,void 0,void 0,function(){var d,e,f,g,h,i,j,k=this;return __generator(this,function(
|
|
444
|
-
return b.
|
|
445
|
-
return b.error("HTTP error status ".concat(
|
|
460
|
+
if(d=h[g],!d.MPID){var i=b.getMPID();d.MPID=i;}var j=f.get(d.MPID);j||(j=[]),j.push(d),f.set(d.MPID,j);}for(var k=0,l=Array.from(f.entries());k<l.length;k++){for(var m=l[k],i=m[0],n=m[1],o=new Map,p=0,q=n;p<q.length;p++){var d=q[p],j=o.get(d.SessionId);j||(j=[]),j.push(d),o.set(d.SessionId,j);}for(var r=0,s=Array.from(o.entries());r<s.length;r++){var t=s[r],u=convertEvents(i,t[1],c),v=c._Store.SDKConfig.onCreateBatch;v&&(u=v(u),u?u.modified=!0:c.Logger.warning("Skiping batch upload because no batch was returned from onCreateBatch callback")),u&&e.push(u);}}return e},a.prototype.prepareAndUpload=function(b,c){return __awaiter(this,void 0,void 0,function(){var d,e,f,g,h,i,j,k=this;return __generator(this,function(){return d=this.mpInstance.Identity.getCurrentUser(),e=this.eventsQueuedForProcessing,this.eventsQueuedForProcessing=[],f=a.createNewBatches(e,d,this.mpInstance),isEmpty(f)||(j=this.batchesQueuedForProcessing).push.apply(j,f),g=this.batchesQueuedForProcessing,h=[],this.batchesQueuedForProcessing=[],i=g.map(function(a){return k.upload(k.mpInstance.Logger,a,c)}),isEmpty(i)||Promise.all(i).then(function(a){a.forEach(function(a){return isEmpty(a)?null:h.push(a)});})["catch"](function(a){k.mpInstance.Logger.error("Error processing batches during upload attempt: ".concat(a));})["finally"](function(){var a;// Any batches that did not upload should be put back into the queue for processing
|
|
461
|
+
isEmpty(h)||(a=k.batchesQueuedForProcessing).unshift.apply(a,h);}),b&&this.triggerUploadInterval(b,!1),[2/*return*/]})})},a.prototype.upload=function(b,c,d){return __awaiter(this,void 0,void 0,function(){var e,f,g,h;return __generator(this,function(i){switch(i.label){case 0:return isEmpty(c)||isEmpty(c.events)?[2/*return*/,null]:(b.verbose("Uploading batches: ".concat(JSON.stringify(c))),e={method:"POST",headers:{Accept:a.CONTENT_TYPE,"Content-Type":"text/plain;charset=UTF-8"},body:JSON.stringify(c)},!(d&&this.isBeaconAvailable()))?[3/*break*/,1]:(f=new Blob([e.body],{type:"text/plain;charset=UTF-8"}),navigator.sendBeacon(this.uploadUrl,f),[3/*break*/,4]);case 1:return i.trys.push([1,3,,4]),[4/*yield*/,this.uploader.upload(e)];case 2:// TODO: Should we make this a switch statement instead?
|
|
462
|
+
return (g=i.sent(),200<=g.status&&300>g.status)?(b.verbose("Upload success for request ID: ".concat(c.source_request_id)),[2/*return*/,null]):500<=g.status||429===g.status?(b.error("HTTP error status ".concat(g.status," received")),[2/*return*/,c]):401<=g.status?(b.error("HTTP error status ".concat(g.status," while uploading - please verify your API key.")),[2/*return*/,c]):[3/*break*/,4];case 3:return h=i.sent(),b.error("Error sending event to mParticle servers. ".concat(h)),[2/*return*/,c];case 4:return [2/*return*/,null];}})})},a.CONTENT_TYPE="text/plain;charset=UTF-8",a.MINIMUM_INTERVAL_MILLIS=500,a}();var AsyncUploader=/** @class */function(){function a(a){this.url=a;}return a}(),FetchUploader=/** @class */function(a){function b(){return null!==a&&a.apply(this,arguments)||this}return __extends(b,a),b.prototype.upload=function(a){return __awaiter(this,void 0,void 0,function(){var b;return __generator(this,function(c){switch(c.label){case 0:return [4/*yield*/,fetch(this.url,a)];case 1:return b=c.sent(),[2/*return*/,b];}})})},b}(AsyncUploader),XHRUploader=/** @class */function(a){function b(){return null!==a&&a.apply(this,arguments)||this}return __extends(b,a),b.prototype.upload=function(a){return __awaiter(this,void 0,void 0,function(){var b;return __generator(this,function(c){switch(c.label){case 0:return [4/*yield*/,this.makeRequest(this.url,a.body)];case 1:return b=c.sent(),[2/*return*/,b];}})})},b.prototype.makeRequest=function(a,b){return __awaiter(this,void 0,void 0,function(){var c;return __generator(this,function(){return c=new XMLHttpRequest,[2/*return*/,new Promise(function(d,e){c.onreadystatechange=function(){4!==c.readyState||(200<=c.status&&300>c.status?d(c):e(c));},c.open("post",a),c.send(b);})]})})},b}(AsyncUploader);
|
|
446
463
|
|
|
447
464
|
var Messages$9=Constants.Messages;function APIClient(a,b){this.uploader=null;var c=this;this.queueEventForBatchUpload=function(b){if(!this.uploader){var c=a._Helpers.getFeatureFlag(Constants.FeatureFlags.EventBatchingIntervalMillis);this.uploader=new BatchUploader(a,c);}this.uploader.queueEvent(b),a._Persistence.update();},this.shouldEnableBatching=function(){// Returns a string of a number that must be parsed
|
|
448
465
|
// Invalid strings will be parsed to NaN which is falsey
|
package/dist/mparticle.js
CHANGED
|
@@ -725,7 +725,7 @@ var mParticle = (function () {
|
|
|
725
725
|
Environment: Environment
|
|
726
726
|
};
|
|
727
727
|
|
|
728
|
-
var version = "2.
|
|
728
|
+
var version = "2.19.0";
|
|
729
729
|
|
|
730
730
|
var Constants = {
|
|
731
731
|
sdkVersion: version,
|
|
@@ -2111,12 +2111,27 @@ var mParticle = (function () {
|
|
|
2111
2111
|
}
|
|
2112
2112
|
}
|
|
2113
2113
|
|
|
2114
|
+
/**
|
|
2115
|
+
* BatchUploader contains all the logic to upload batches to mParticle.
|
|
2116
|
+
* It queues events as they come in and at set intervals turns them into batches.
|
|
2117
|
+
* It then attempts to upload them to mParticle.
|
|
2118
|
+
*
|
|
2119
|
+
* These uploads happen on an interval basis using window.fetch or XHR
|
|
2120
|
+
* requests, depending on what is available in the browser.
|
|
2121
|
+
*
|
|
2122
|
+
* Uploads can also be triggered on browser visibility/focus changes via an
|
|
2123
|
+
* event listener, which then uploads to mPartice via the browser's Beacon API.
|
|
2124
|
+
*/
|
|
2125
|
+
|
|
2114
2126
|
var BatchUploader =
|
|
2115
2127
|
/** @class */
|
|
2116
2128
|
function () {
|
|
2129
|
+
/**
|
|
2130
|
+
* Creates an instance of a BatchUploader
|
|
2131
|
+
* @param {MParticleWebSDK} mpInstance - the mParticle SDK instance
|
|
2132
|
+
* @param {number} uploadInterval - the desired upload interval in milliseconds
|
|
2133
|
+
*/
|
|
2117
2134
|
function BatchUploader(mpInstance, uploadInterval) {
|
|
2118
|
-
var _this_1 = this;
|
|
2119
|
-
|
|
2120
2135
|
this.mpInstance = mpInstance;
|
|
2121
2136
|
this.uploadIntervalMillis = uploadInterval;
|
|
2122
2137
|
this.batchingEnabled = uploadInterval >= BatchUploader.MINIMUM_INTERVAL_MILLIS;
|
|
@@ -2125,8 +2140,8 @@ var mParticle = (function () {
|
|
|
2125
2140
|
this.uploadIntervalMillis = BatchUploader.MINIMUM_INTERVAL_MILLIS;
|
|
2126
2141
|
}
|
|
2127
2142
|
|
|
2128
|
-
this.
|
|
2129
|
-
this.
|
|
2143
|
+
this.eventsQueuedForProcessing = [];
|
|
2144
|
+
this.batchesQueuedForProcessing = [];
|
|
2130
2145
|
var _a = this.mpInstance._Store,
|
|
2131
2146
|
SDKConfig = _a.SDKConfig,
|
|
2132
2147
|
devToken = _a.devToken;
|
|
@@ -2134,14 +2149,16 @@ var mParticle = (function () {
|
|
|
2134
2149
|
var baseUrl = this.mpInstance._Helpers.createServiceUrl(SDKConfig.v3SecureServiceUrl, devToken);
|
|
2135
2150
|
|
|
2136
2151
|
this.uploadUrl = "".concat(baseUrl, "/events");
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
}, this.uploadIntervalMillis);
|
|
2152
|
+
this.uploader = window.fetch ? new FetchUploader(this.uploadUrl) : new XHRUploader(this.uploadUrl);
|
|
2153
|
+
this.triggerUploadInterval(true, false);
|
|
2140
2154
|
this.addEventListeners();
|
|
2141
|
-
}
|
|
2155
|
+
} // Adds listeners to be used trigger Navigator.sendBeacon if the browser
|
|
2156
|
+
// loses focus for any reason, such as closing browser tab or minimizing window
|
|
2157
|
+
|
|
2142
2158
|
|
|
2143
2159
|
BatchUploader.prototype.addEventListeners = function () {
|
|
2144
|
-
var _this = this;
|
|
2160
|
+
var _this = this; // visibility change is a document property, not window
|
|
2161
|
+
|
|
2145
2162
|
|
|
2146
2163
|
document.addEventListener('visibilitychange', function () {
|
|
2147
2164
|
_this.prepareAndUpload(false, _this.isBeaconAvailable());
|
|
@@ -2160,13 +2177,36 @@ var mParticle = (function () {
|
|
|
2160
2177
|
}
|
|
2161
2178
|
|
|
2162
2179
|
return false;
|
|
2180
|
+
}; // Triggers a setTimeout for prepareAndUpload
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
BatchUploader.prototype.triggerUploadInterval = function (triggerFuture, useBeacon) {
|
|
2184
|
+
var _this_1 = this;
|
|
2185
|
+
|
|
2186
|
+
if (triggerFuture === void 0) {
|
|
2187
|
+
triggerFuture = false;
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
if (useBeacon === void 0) {
|
|
2191
|
+
useBeacon = false;
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
setTimeout(function () {
|
|
2195
|
+
_this_1.prepareAndUpload(triggerFuture, useBeacon);
|
|
2196
|
+
}, this.uploadIntervalMillis);
|
|
2163
2197
|
};
|
|
2198
|
+
/**
|
|
2199
|
+
* This method will queue a single Event which will eventually be processed into a Batch
|
|
2200
|
+
* @param event event that should be queued
|
|
2201
|
+
*/
|
|
2202
|
+
|
|
2164
2203
|
|
|
2165
2204
|
BatchUploader.prototype.queueEvent = function (event) {
|
|
2166
2205
|
if (!isEmpty(event)) {
|
|
2167
|
-
this.
|
|
2206
|
+
this.eventsQueuedForProcessing.push(event);
|
|
2168
2207
|
this.mpInstance.Logger.verbose("Queuing event: ".concat(JSON.stringify(event)));
|
|
2169
|
-
this.mpInstance.Logger.verbose("Queued event count: ".concat(this.
|
|
2208
|
+
this.mpInstance.Logger.verbose("Queued event count: ".concat(this.eventsQueuedForProcessing.length)); // TODO: Remove this check once the v2 code path is removed
|
|
2209
|
+
// https://go.mparticle.com/work/SQDSDKS-3720
|
|
2170
2210
|
|
|
2171
2211
|
if (!this.batchingEnabled || Types.TriggerUploadType[event.EventDataType]) {
|
|
2172
2212
|
this.prepareAndUpload(false, false);
|
|
@@ -2184,7 +2224,7 @@ var mParticle = (function () {
|
|
|
2184
2224
|
*/
|
|
2185
2225
|
|
|
2186
2226
|
|
|
2187
|
-
BatchUploader.
|
|
2227
|
+
BatchUploader.createNewBatches = function (sdkEvents, defaultUser, mpInstance) {
|
|
2188
2228
|
if (!defaultUser || !sdkEvents || !sdkEvents.length) {
|
|
2189
2229
|
return null;
|
|
2190
2230
|
} //bucket by MPID, and then by session, ordered by timestamp
|
|
@@ -2264,157 +2304,139 @@ var mParticle = (function () {
|
|
|
2264
2304
|
|
|
2265
2305
|
BatchUploader.prototype.prepareAndUpload = function (triggerFuture, useBeacon) {
|
|
2266
2306
|
return __awaiter(this, void 0, void 0, function () {
|
|
2267
|
-
var currentUser, currentEvents,
|
|
2307
|
+
var currentUser, currentEvents, newBatches, batchesToUpload, batchesThatDidNotUpload, promises;
|
|
2268
2308
|
|
|
2269
|
-
var _a
|
|
2309
|
+
var _a;
|
|
2270
2310
|
|
|
2271
2311
|
var _this_1 = this;
|
|
2272
2312
|
|
|
2273
|
-
return __generator(this, function (
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
this.pendingEvents = [];
|
|
2279
|
-
newUploads = BatchUploader.createNewUploads(currentEvents, currentUser, this.mpInstance);
|
|
2313
|
+
return __generator(this, function (_b) {
|
|
2314
|
+
currentUser = this.mpInstance.Identity.getCurrentUser();
|
|
2315
|
+
currentEvents = this.eventsQueuedForProcessing;
|
|
2316
|
+
this.eventsQueuedForProcessing = [];
|
|
2317
|
+
newBatches = BatchUploader.createNewBatches(currentEvents, currentUser, this.mpInstance);
|
|
2280
2318
|
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2319
|
+
if (!isEmpty(newBatches)) {
|
|
2320
|
+
(_a = this.batchesQueuedForProcessing).push.apply(_a, newBatches);
|
|
2321
|
+
}
|
|
2284
2322
|
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2323
|
+
batchesToUpload = this.batchesQueuedForProcessing;
|
|
2324
|
+
batchesThatDidNotUpload = [];
|
|
2325
|
+
this.batchesQueuedForProcessing = [];
|
|
2326
|
+
promises = batchesToUpload.map(function (upload) {
|
|
2327
|
+
return _this_1.upload(_this_1.mpInstance.Logger, upload, useBeacon);
|
|
2328
|
+
}); // Iterate through fulfilled promises and store any remaining batches
|
|
2329
|
+
// for future re-transmission attempts
|
|
2290
2330
|
|
|
2291
|
-
|
|
2292
|
-
|
|
2331
|
+
if (!isEmpty(promises)) {
|
|
2332
|
+
Promise.all(promises).then(function (batchResponses) {
|
|
2333
|
+
batchResponses.forEach(function (batch) {
|
|
2334
|
+
return !isEmpty(batch) ? batchesThatDidNotUpload.push(batch) : null;
|
|
2335
|
+
});
|
|
2336
|
+
})["catch"](function (error) {
|
|
2337
|
+
_this_1.mpInstance.Logger.error("Error processing batches during upload attempt: ".concat(error));
|
|
2338
|
+
})["finally"](function () {
|
|
2339
|
+
var _a; // Any batches that did not upload should be put back into the queue for processing
|
|
2293
2340
|
|
|
2294
|
-
if (remainingUploads && remainingUploads.length) {
|
|
2295
|
-
(_b = this.pendingUploads).unshift.apply(_b, remainingUploads);
|
|
2296
|
-
}
|
|
2297
2341
|
|
|
2298
|
-
if (
|
|
2299
|
-
|
|
2300
|
-
_this_1.prepareAndUpload(true, false);
|
|
2301
|
-
}, this.uploadIntervalMillis);
|
|
2342
|
+
if (!isEmpty(batchesThatDidNotUpload)) {
|
|
2343
|
+
(_a = _this_1.batchesQueuedForProcessing).unshift.apply(_a, batchesThatDidNotUpload);
|
|
2302
2344
|
}
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2303
2347
|
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
];
|
|
2348
|
+
if (triggerFuture) {
|
|
2349
|
+
this.triggerUploadInterval(triggerFuture, false);
|
|
2307
2350
|
}
|
|
2351
|
+
|
|
2352
|
+
return [2
|
|
2353
|
+
/*return*/
|
|
2354
|
+
];
|
|
2308
2355
|
});
|
|
2309
2356
|
});
|
|
2310
2357
|
};
|
|
2311
2358
|
|
|
2312
|
-
BatchUploader.prototype.upload = function (logger,
|
|
2359
|
+
BatchUploader.prototype.upload = function (logger, batch, useBeacon) {
|
|
2313
2360
|
return __awaiter(this, void 0, void 0, function () {
|
|
2314
|
-
var
|
|
2361
|
+
var fetchPayload, blob, response, error_1;
|
|
2315
2362
|
return __generator(this, function (_a) {
|
|
2316
2363
|
switch (_a.label) {
|
|
2317
2364
|
case 0:
|
|
2318
|
-
|
|
2319
|
-
return !isEmpty(upload.events);
|
|
2320
|
-
});
|
|
2321
|
-
|
|
2322
|
-
if (isEmpty(uploads)) {
|
|
2365
|
+
if (isEmpty(batch) || isEmpty(batch.events)) {
|
|
2323
2366
|
return [2
|
|
2324
2367
|
/*return*/
|
|
2325
2368
|
, null];
|
|
2326
2369
|
}
|
|
2327
2370
|
|
|
2328
|
-
logger.verbose("Uploading batches: ".concat(JSON.stringify(
|
|
2329
|
-
logger.verbose("Batch count: ".concat(uploads.length));
|
|
2330
|
-
i = 0;
|
|
2331
|
-
_a.label = 1;
|
|
2332
|
-
|
|
2333
|
-
case 1:
|
|
2334
|
-
if (!(i < uploads.length)) return [3
|
|
2335
|
-
/*break*/
|
|
2336
|
-
, 7];
|
|
2371
|
+
logger.verbose("Uploading batches: ".concat(JSON.stringify(batch)));
|
|
2337
2372
|
fetchPayload = {
|
|
2338
2373
|
method: 'POST',
|
|
2339
2374
|
headers: {
|
|
2340
2375
|
Accept: BatchUploader.CONTENT_TYPE,
|
|
2341
2376
|
'Content-Type': 'text/plain;charset=UTF-8'
|
|
2342
2377
|
},
|
|
2343
|
-
body: JSON.stringify(
|
|
2378
|
+
body: JSON.stringify(batch)
|
|
2344
2379
|
};
|
|
2345
2380
|
if (!(useBeacon && this.isBeaconAvailable())) return [3
|
|
2346
2381
|
/*break*/
|
|
2347
|
-
,
|
|
2382
|
+
, 1];
|
|
2348
2383
|
blob = new Blob([fetchPayload.body], {
|
|
2349
2384
|
type: 'text/plain;charset=UTF-8'
|
|
2350
2385
|
});
|
|
2351
2386
|
navigator.sendBeacon(this.uploadUrl, blob);
|
|
2352
2387
|
return [3
|
|
2353
2388
|
/*break*/
|
|
2354
|
-
,
|
|
2389
|
+
, 4];
|
|
2355
2390
|
|
|
2356
|
-
case
|
|
2357
|
-
|
|
2358
|
-
if (window.fetch) {
|
|
2359
|
-
uploader = new FetchUploader(this.uploadUrl, logger);
|
|
2360
|
-
} else {
|
|
2361
|
-
uploader = new XHRUploader(this.uploadUrl, logger);
|
|
2362
|
-
}
|
|
2363
|
-
}
|
|
2364
|
-
|
|
2365
|
-
_a.label = 3;
|
|
2366
|
-
|
|
2367
|
-
case 3:
|
|
2368
|
-
_a.trys.push([3, 5,, 6]);
|
|
2391
|
+
case 1:
|
|
2392
|
+
_a.trys.push([1, 3,, 4]);
|
|
2369
2393
|
|
|
2370
2394
|
return [4
|
|
2371
2395
|
/*yield*/
|
|
2372
|
-
, uploader.upload(fetchPayload
|
|
2396
|
+
, this.uploader.upload(fetchPayload)];
|
|
2373
2397
|
|
|
2374
|
-
case
|
|
2375
|
-
response = _a.sent();
|
|
2398
|
+
case 2:
|
|
2399
|
+
response = _a.sent(); // TODO: Should we make this a switch statement instead?
|
|
2376
2400
|
|
|
2377
2401
|
if (response.status >= 200 && response.status < 300) {
|
|
2378
|
-
logger.verbose("Upload success for request ID: ".concat(
|
|
2402
|
+
logger.verbose("Upload success for request ID: ".concat(batch.source_request_id));
|
|
2403
|
+
return [2
|
|
2404
|
+
/*return*/
|
|
2405
|
+
, null];
|
|
2379
2406
|
} else if (response.status >= 500 || response.status === 429) {
|
|
2380
|
-
logger.error("HTTP error status ".concat(response.status, " received")); //
|
|
2407
|
+
logger.error("HTTP error status ".concat(response.status, " received")); // Server error, return current batch and try again later
|
|
2381
2408
|
|
|
2382
2409
|
return [2
|
|
2383
2410
|
/*return*/
|
|
2384
|
-
,
|
|
2411
|
+
, batch];
|
|
2385
2412
|
} else if (response.status >= 401) {
|
|
2386
|
-
logger.error("HTTP error status ".concat(response.status, " while uploading - please verify your API key.")); //if we're getting a 401, assume we'll keep getting a 401
|
|
2413
|
+
logger.error("HTTP error status ".concat(response.status, " while uploading - please verify your API key.")); // if we're getting a 401, assume we'll keep getting a 401
|
|
2414
|
+
// so return the upload so it can be stored for later use
|
|
2387
2415
|
|
|
2388
2416
|
return [2
|
|
2389
2417
|
/*return*/
|
|
2390
|
-
,
|
|
2418
|
+
, batch];
|
|
2391
2419
|
}
|
|
2392
2420
|
|
|
2393
2421
|
return [3
|
|
2394
2422
|
/*break*/
|
|
2395
|
-
,
|
|
2423
|
+
, 4];
|
|
2396
2424
|
|
|
2397
|
-
case
|
|
2398
|
-
|
|
2399
|
-
logger.error("Error sending event to mParticle servers. ".concat(
|
|
2425
|
+
case 3:
|
|
2426
|
+
error_1 = _a.sent();
|
|
2427
|
+
logger.error("Error sending event to mParticle servers. ".concat(error_1));
|
|
2400
2428
|
return [2
|
|
2401
2429
|
/*return*/
|
|
2402
|
-
,
|
|
2403
|
-
|
|
2404
|
-
case 6:
|
|
2405
|
-
i++;
|
|
2406
|
-
return [3
|
|
2407
|
-
/*break*/
|
|
2408
|
-
, 1];
|
|
2430
|
+
, batch];
|
|
2409
2431
|
|
|
2410
|
-
case
|
|
2432
|
+
case 4:
|
|
2411
2433
|
return [2
|
|
2412
2434
|
/*return*/
|
|
2413
2435
|
, null];
|
|
2414
2436
|
}
|
|
2415
2437
|
});
|
|
2416
2438
|
});
|
|
2417
|
-
}; //
|
|
2439
|
+
}; // We upload JSON, but this content type is required to avoid a CORS preflight request
|
|
2418
2440
|
|
|
2419
2441
|
|
|
2420
2442
|
BatchUploader.CONTENT_TYPE = 'text/plain;charset=UTF-8';
|
|
@@ -2425,9 +2447,8 @@ var mParticle = (function () {
|
|
|
2425
2447
|
var AsyncUploader =
|
|
2426
2448
|
/** @class */
|
|
2427
2449
|
function () {
|
|
2428
|
-
function AsyncUploader(url
|
|
2450
|
+
function AsyncUploader(url) {
|
|
2429
2451
|
this.url = url;
|
|
2430
|
-
this.logger = logger;
|
|
2431
2452
|
}
|
|
2432
2453
|
|
|
2433
2454
|
return AsyncUploader;
|
|
@@ -2442,7 +2463,7 @@ var mParticle = (function () {
|
|
|
2442
2463
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
2443
2464
|
}
|
|
2444
2465
|
|
|
2445
|
-
FetchUploader.prototype.upload = function (fetchPayload
|
|
2466
|
+
FetchUploader.prototype.upload = function (fetchPayload) {
|
|
2446
2467
|
return __awaiter(this, void 0, void 0, function () {
|
|
2447
2468
|
var response;
|
|
2448
2469
|
return __generator(this, function (_a) {
|
|
@@ -2474,7 +2495,7 @@ var mParticle = (function () {
|
|
|
2474
2495
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
2475
2496
|
}
|
|
2476
2497
|
|
|
2477
|
-
XHRUploader.prototype.upload = function (fetchPayload
|
|
2498
|
+
XHRUploader.prototype.upload = function (fetchPayload) {
|
|
2478
2499
|
return __awaiter(this, void 0, void 0, function () {
|
|
2479
2500
|
var response;
|
|
2480
2501
|
return __generator(this, function (_a) {
|
|
@@ -2482,7 +2503,7 @@ var mParticle = (function () {
|
|
|
2482
2503
|
case 0:
|
|
2483
2504
|
return [4
|
|
2484
2505
|
/*yield*/
|
|
2485
|
-
, this.makeRequest(this.url,
|
|
2506
|
+
, this.makeRequest(this.url, fetchPayload.body)];
|
|
2486
2507
|
|
|
2487
2508
|
case 1:
|
|
2488
2509
|
response = _a.sent();
|
|
@@ -2494,7 +2515,7 @@ var mParticle = (function () {
|
|
|
2494
2515
|
});
|
|
2495
2516
|
};
|
|
2496
2517
|
|
|
2497
|
-
XHRUploader.prototype.makeRequest = function (url,
|
|
2518
|
+
XHRUploader.prototype.makeRequest = function (url, data) {
|
|
2498
2519
|
return __awaiter(this, void 0, void 0, function () {
|
|
2499
2520
|
var xhr;
|
|
2500
2521
|
return __generator(this, function (_a) {
|
package/package.json
CHANGED
package/src/batchUploader.ts
CHANGED
|
@@ -9,17 +9,35 @@ import { convertEvents } from './sdkToEventsApiConverter';
|
|
|
9
9
|
import Types from './types';
|
|
10
10
|
import { isEmpty } from './utils';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* BatchUploader contains all the logic to upload batches to mParticle.
|
|
14
|
+
* It queues events as they come in and at set intervals turns them into batches.
|
|
15
|
+
* It then attempts to upload them to mParticle.
|
|
16
|
+
*
|
|
17
|
+
* These uploads happen on an interval basis using window.fetch or XHR
|
|
18
|
+
* requests, depending on what is available in the browser.
|
|
19
|
+
*
|
|
20
|
+
* Uploads can also be triggered on browser visibility/focus changes via an
|
|
21
|
+
* event listener, which then uploads to mPartice via the browser's Beacon API.
|
|
22
|
+
*/
|
|
23
|
+
|
|
12
24
|
export class BatchUploader {
|
|
13
|
-
//
|
|
25
|
+
// We upload JSON, but this content type is required to avoid a CORS preflight request
|
|
14
26
|
static readonly CONTENT_TYPE: string = 'text/plain;charset=UTF-8';
|
|
15
27
|
static readonly MINIMUM_INTERVAL_MILLIS: number = 500;
|
|
16
28
|
uploadIntervalMillis: number;
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
eventsQueuedForProcessing: SDKEvent[];
|
|
30
|
+
batchesQueuedForProcessing: Batch[];
|
|
19
31
|
mpInstance: MParticleWebSDK;
|
|
20
32
|
uploadUrl: string;
|
|
21
33
|
batchingEnabled: boolean;
|
|
34
|
+
private uploader: AsyncUploader;
|
|
22
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Creates an instance of a BatchUploader
|
|
38
|
+
* @param {MParticleWebSDK} mpInstance - the mParticle SDK instance
|
|
39
|
+
* @param {number} uploadInterval - the desired upload interval in milliseconds
|
|
40
|
+
*/
|
|
23
41
|
constructor(mpInstance: MParticleWebSDK, uploadInterval: number) {
|
|
24
42
|
this.mpInstance = mpInstance;
|
|
25
43
|
this.uploadIntervalMillis = uploadInterval;
|
|
@@ -28,8 +46,8 @@ export class BatchUploader {
|
|
|
28
46
|
if (this.uploadIntervalMillis < BatchUploader.MINIMUM_INTERVAL_MILLIS) {
|
|
29
47
|
this.uploadIntervalMillis = BatchUploader.MINIMUM_INTERVAL_MILLIS;
|
|
30
48
|
}
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
49
|
+
this.eventsQueuedForProcessing = [];
|
|
50
|
+
this.batchesQueuedForProcessing = [];
|
|
33
51
|
|
|
34
52
|
const { SDKConfig, devToken } = this.mpInstance._Store;
|
|
35
53
|
const baseUrl = this.mpInstance._Helpers.createServiceUrl(
|
|
@@ -38,15 +56,20 @@ export class BatchUploader {
|
|
|
38
56
|
);
|
|
39
57
|
this.uploadUrl = `${baseUrl}/events`;
|
|
40
58
|
|
|
41
|
-
|
|
42
|
-
this.
|
|
43
|
-
|
|
59
|
+
this.uploader = window.fetch
|
|
60
|
+
? new FetchUploader(this.uploadUrl)
|
|
61
|
+
: new XHRUploader(this.uploadUrl);
|
|
62
|
+
|
|
63
|
+
this.triggerUploadInterval(true, false);
|
|
44
64
|
this.addEventListeners();
|
|
45
65
|
}
|
|
46
66
|
|
|
67
|
+
// Adds listeners to be used trigger Navigator.sendBeacon if the browser
|
|
68
|
+
// loses focus for any reason, such as closing browser tab or minimizing window
|
|
47
69
|
private addEventListeners() {
|
|
48
70
|
const _this = this;
|
|
49
71
|
|
|
72
|
+
// visibility change is a document property, not window
|
|
50
73
|
document.addEventListener('visibilitychange', () => {
|
|
51
74
|
_this.prepareAndUpload(false, _this.isBeaconAvailable());
|
|
52
75
|
});
|
|
@@ -65,16 +88,32 @@ export class BatchUploader {
|
|
|
65
88
|
return false;
|
|
66
89
|
}
|
|
67
90
|
|
|
91
|
+
// Triggers a setTimeout for prepareAndUpload
|
|
92
|
+
private triggerUploadInterval(
|
|
93
|
+
triggerFuture: boolean = false,
|
|
94
|
+
useBeacon: boolean = false
|
|
95
|
+
): void {
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
this.prepareAndUpload(triggerFuture, useBeacon);
|
|
98
|
+
}, this.uploadIntervalMillis);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* This method will queue a single Event which will eventually be processed into a Batch
|
|
103
|
+
* @param event event that should be queued
|
|
104
|
+
*/
|
|
68
105
|
queueEvent(event: SDKEvent): void {
|
|
69
106
|
if (!isEmpty(event)) {
|
|
70
|
-
this.
|
|
107
|
+
this.eventsQueuedForProcessing.push(event);
|
|
71
108
|
this.mpInstance.Logger.verbose(
|
|
72
109
|
`Queuing event: ${JSON.stringify(event)}`
|
|
73
110
|
);
|
|
74
111
|
this.mpInstance.Logger.verbose(
|
|
75
|
-
`Queued event count: ${this.
|
|
112
|
+
`Queued event count: ${this.eventsQueuedForProcessing.length}`
|
|
76
113
|
);
|
|
77
114
|
|
|
115
|
+
// TODO: Remove this check once the v2 code path is removed
|
|
116
|
+
// https://go.mparticle.com/work/SQDSDKS-3720
|
|
78
117
|
if (
|
|
79
118
|
!this.batchingEnabled ||
|
|
80
119
|
Types.TriggerUploadType[event.EventDataType]
|
|
@@ -93,7 +132,7 @@ export class BatchUploader {
|
|
|
93
132
|
* @param sdkEvents current pending events
|
|
94
133
|
* @param defaultUser the user to reference for events that are missing data
|
|
95
134
|
*/
|
|
96
|
-
private static
|
|
135
|
+
private static createNewBatches(
|
|
97
136
|
sdkEvents: SDKEvent[],
|
|
98
137
|
defaultUser: MParticleUser,
|
|
99
138
|
mpInstance: MParticleWebSDK
|
|
@@ -141,9 +180,8 @@ export class BatchUploader {
|
|
|
141
180
|
mpInstance._Store.SDKConfig.onCreateBatch;
|
|
142
181
|
|
|
143
182
|
if (onCreateBatchCallback) {
|
|
144
|
-
uploadBatchObject =
|
|
145
|
-
uploadBatchObject
|
|
146
|
-
);
|
|
183
|
+
uploadBatchObject =
|
|
184
|
+
onCreateBatchCallback(uploadBatchObject);
|
|
147
185
|
if (uploadBatchObject) {
|
|
148
186
|
uploadBatchObject.modified = true;
|
|
149
187
|
} else {
|
|
@@ -169,112 +207,122 @@ export class BatchUploader {
|
|
|
169
207
|
* @param triggerFuture whether to trigger the loop again - for manual/forced uploads this should be false
|
|
170
208
|
* @param useBeacon whether to use the beacon API - used when the page is being unloaded
|
|
171
209
|
*/
|
|
172
|
-
private async prepareAndUpload(
|
|
210
|
+
private async prepareAndUpload(
|
|
211
|
+
triggerFuture: boolean,
|
|
212
|
+
useBeacon: boolean
|
|
213
|
+
): Promise<void> {
|
|
173
214
|
const currentUser = this.mpInstance.Identity.getCurrentUser();
|
|
174
215
|
|
|
175
|
-
const currentEvents = this.
|
|
176
|
-
this.
|
|
177
|
-
|
|
216
|
+
const currentEvents = this.eventsQueuedForProcessing;
|
|
217
|
+
this.eventsQueuedForProcessing = [];
|
|
218
|
+
|
|
219
|
+
const newBatches = BatchUploader.createNewBatches(
|
|
178
220
|
currentEvents,
|
|
179
221
|
currentUser,
|
|
180
222
|
this.mpInstance
|
|
181
223
|
);
|
|
182
|
-
if (
|
|
183
|
-
this.
|
|
224
|
+
if (!isEmpty(newBatches)) {
|
|
225
|
+
this.batchesQueuedForProcessing.push(...newBatches);
|
|
184
226
|
}
|
|
185
227
|
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
228
|
+
const batchesToUpload = this.batchesQueuedForProcessing;
|
|
229
|
+
const batchesThatDidNotUpload: Batch[] = [];
|
|
230
|
+
this.batchesQueuedForProcessing = [];
|
|
231
|
+
|
|
232
|
+
// Create an array of promises as we try to upload each batch indvidually
|
|
233
|
+
const promises: Promise<Batch>[] = batchesToUpload.map((upload) => {
|
|
234
|
+
return this.upload(this.mpInstance.Logger, upload, useBeacon);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Iterate through fulfilled promises and store any remaining batches
|
|
238
|
+
// for future re-transmission attempts
|
|
239
|
+
if (!isEmpty(promises)) {
|
|
240
|
+
Promise.all(promises)
|
|
241
|
+
.then((batchResponses) => {
|
|
242
|
+
batchResponses.forEach((batch) =>
|
|
243
|
+
!isEmpty(batch)
|
|
244
|
+
? batchesThatDidNotUpload.push(batch)
|
|
245
|
+
: null
|
|
246
|
+
);
|
|
247
|
+
})
|
|
248
|
+
.catch((error) => {
|
|
249
|
+
this.mpInstance.Logger.error(
|
|
250
|
+
`Error processing batches during upload attempt: ${error}`
|
|
251
|
+
);
|
|
252
|
+
})
|
|
253
|
+
.finally(() => {
|
|
254
|
+
// Any batches that did not upload should be put back into the queue for processing
|
|
255
|
+
if (!isEmpty(batchesThatDidNotUpload)) {
|
|
256
|
+
this.batchesQueuedForProcessing.unshift(
|
|
257
|
+
...batchesThatDidNotUpload
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
195
261
|
}
|
|
196
262
|
|
|
197
263
|
if (triggerFuture) {
|
|
198
|
-
|
|
199
|
-
this.prepareAndUpload(true, false);
|
|
200
|
-
}, this.uploadIntervalMillis);
|
|
264
|
+
this.triggerUploadInterval(triggerFuture, false);
|
|
201
265
|
}
|
|
202
266
|
}
|
|
203
267
|
|
|
204
268
|
private async upload(
|
|
205
269
|
logger: SDKLoggerApi,
|
|
206
|
-
|
|
270
|
+
batch: Batch,
|
|
207
271
|
useBeacon: boolean
|
|
208
|
-
): Promise<Batch
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// Filter out any batches that don't have events
|
|
212
|
-
const uploads = _uploads.filter(upload => !isEmpty(upload.events));
|
|
213
|
-
|
|
214
|
-
if (isEmpty(uploads)) {
|
|
272
|
+
): Promise<Batch | null> {
|
|
273
|
+
if (isEmpty(batch) || isEmpty(batch.events)) {
|
|
215
274
|
return null;
|
|
216
275
|
}
|
|
217
276
|
|
|
218
|
-
logger.verbose(`Uploading batches: ${JSON.stringify(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
277
|
+
logger.verbose(`Uploading batches: ${JSON.stringify(batch)}`);
|
|
278
|
+
|
|
279
|
+
const fetchPayload: fetchPayload = {
|
|
280
|
+
method: 'POST',
|
|
281
|
+
headers: {
|
|
282
|
+
Accept: BatchUploader.CONTENT_TYPE,
|
|
283
|
+
'Content-Type': 'text/plain;charset=UTF-8',
|
|
284
|
+
},
|
|
285
|
+
body: JSON.stringify(batch),
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// TODO: Make beacon its own function
|
|
289
|
+
// beacon is only used on onbeforeunload onpagehide events
|
|
290
|
+
if (useBeacon && this.isBeaconAvailable()) {
|
|
291
|
+
let blob = new Blob([fetchPayload.body], {
|
|
292
|
+
type: 'text/plain;charset=UTF-8',
|
|
293
|
+
});
|
|
294
|
+
navigator.sendBeacon(this.uploadUrl, blob);
|
|
295
|
+
} else {
|
|
296
|
+
try {
|
|
297
|
+
const response = await this.uploader.upload(fetchPayload);
|
|
298
|
+
|
|
299
|
+
// TODO: Should we make this a switch statement instead?
|
|
300
|
+
if (response.status >= 200 && response.status < 300) {
|
|
301
|
+
logger.verbose(
|
|
302
|
+
`Upload success for request ID: ${batch.source_request_id}`
|
|
303
|
+
);
|
|
230
304
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
});
|
|
236
|
-
navigator.sendBeacon(this.uploadUrl, blob);
|
|
237
|
-
} else {
|
|
238
|
-
if (!uploader) {
|
|
239
|
-
if (window.fetch) {
|
|
240
|
-
uploader = new FetchUploader(this.uploadUrl, logger);
|
|
241
|
-
} else {
|
|
242
|
-
uploader = new XHRUploader(this.uploadUrl, logger);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
try {
|
|
246
|
-
const response = await uploader.upload(
|
|
247
|
-
fetchPayload,
|
|
248
|
-
uploads,
|
|
249
|
-
i
|
|
305
|
+
return null;
|
|
306
|
+
} else if (response.status >= 500 || response.status === 429) {
|
|
307
|
+
logger.error(
|
|
308
|
+
`HTTP error status ${response.status} received`
|
|
250
309
|
);
|
|
251
310
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
);
|
|
256
|
-
} else if (
|
|
257
|
-
response.status >= 500 ||
|
|
258
|
-
response.status === 429
|
|
259
|
-
) {
|
|
260
|
-
logger.error(
|
|
261
|
-
`HTTP error status ${response.status} received`
|
|
262
|
-
);
|
|
263
|
-
//server error, add back current events and try again later
|
|
264
|
-
return uploads.slice(i, uploads.length);
|
|
265
|
-
} else if (response.status >= 401) {
|
|
266
|
-
logger.error(
|
|
267
|
-
`HTTP error status ${response.status} while uploading - please verify your API key.`
|
|
268
|
-
);
|
|
269
|
-
//if we're getting a 401, assume we'll keep getting a 401 and clear the uploads.
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
|
-
} catch (e) {
|
|
311
|
+
// Server error, return current batch and try again later
|
|
312
|
+
return batch;
|
|
313
|
+
} else if (response.status >= 401) {
|
|
273
314
|
logger.error(
|
|
274
|
-
`
|
|
315
|
+
`HTTP error status ${response.status} while uploading - please verify your API key.`
|
|
275
316
|
);
|
|
276
|
-
|
|
317
|
+
// if we're getting a 401, assume we'll keep getting a 401
|
|
318
|
+
// so return the upload so it can be stored for later use
|
|
319
|
+
return batch;
|
|
277
320
|
}
|
|
321
|
+
} catch (error) {
|
|
322
|
+
logger.error(
|
|
323
|
+
`Error sending event to mParticle servers. ${error}`
|
|
324
|
+
);
|
|
325
|
+
return batch;
|
|
278
326
|
}
|
|
279
327
|
}
|
|
280
328
|
return null;
|
|
@@ -283,34 +331,24 @@ export class BatchUploader {
|
|
|
283
331
|
|
|
284
332
|
abstract class AsyncUploader {
|
|
285
333
|
url: string;
|
|
286
|
-
|
|
334
|
+
public abstract upload(fetchPayload: fetchPayload): Promise<XHRResponse>;
|
|
287
335
|
|
|
288
|
-
constructor(url: string
|
|
336
|
+
constructor(url: string) {
|
|
289
337
|
this.url = url;
|
|
290
|
-
this.logger = logger;
|
|
291
338
|
}
|
|
292
339
|
}
|
|
293
340
|
|
|
294
341
|
class FetchUploader extends AsyncUploader {
|
|
295
|
-
|
|
296
|
-
fetchPayload: fetchPayload,
|
|
297
|
-
uploads: Batch[],
|
|
298
|
-
i: number
|
|
299
|
-
) {
|
|
342
|
+
public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
|
|
300
343
|
const response: XHRResponse = await fetch(this.url, fetchPayload);
|
|
301
344
|
return response;
|
|
302
345
|
}
|
|
303
346
|
}
|
|
304
347
|
|
|
305
348
|
class XHRUploader extends AsyncUploader {
|
|
306
|
-
|
|
307
|
-
fetchPayload: fetchPayload,
|
|
308
|
-
uploads: Batch[],
|
|
309
|
-
i: number
|
|
310
|
-
) {
|
|
349
|
+
public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
|
|
311
350
|
const response: XHRResponse = await this.makeRequest(
|
|
312
351
|
this.url,
|
|
313
|
-
this.logger,
|
|
314
352
|
fetchPayload.body
|
|
315
353
|
);
|
|
316
354
|
return response;
|
|
@@ -318,7 +356,6 @@ class XHRUploader extends AsyncUploader {
|
|
|
318
356
|
|
|
319
357
|
private async makeRequest(
|
|
320
358
|
url: string,
|
|
321
|
-
logger: SDKLoggerApi,
|
|
322
359
|
data: string
|
|
323
360
|
): Promise<XMLHttpRequest> {
|
|
324
361
|
const xhr: XMLHttpRequest = new XMLHttpRequest();
|
package/src/vault.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Logger } from '@mparticle/web-sdk';
|
|
2
|
+
import { Dictionary, isEmpty } from './utils';
|
|
3
|
+
|
|
4
|
+
interface IVaultOptions {
|
|
5
|
+
logger?: Logger;
|
|
6
|
+
offlineStorageEnabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default class Vault<StorableItem extends Dictionary> {
|
|
10
|
+
public contents: Dictionary<StorableItem>;
|
|
11
|
+
private readonly _storageKey: string;
|
|
12
|
+
private readonly _itemKey: keyof StorableItem;
|
|
13
|
+
private logger?: Logger;
|
|
14
|
+
private offlineStorageEnabled: boolean = false;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* @param {string} storageKey the local storage key string
|
|
19
|
+
* @param {string} itemKey an element within your StorableItem to use as a key
|
|
20
|
+
* @param {IVaultOptions} options A Dictionary of IVaultOptions
|
|
21
|
+
*/
|
|
22
|
+
constructor(
|
|
23
|
+
storageKey: string,
|
|
24
|
+
itemKey: keyof StorableItem,
|
|
25
|
+
options?: IVaultOptions
|
|
26
|
+
) {
|
|
27
|
+
this._storageKey = storageKey;
|
|
28
|
+
this._itemKey = itemKey;
|
|
29
|
+
this.contents = this.getItems() || {};
|
|
30
|
+
|
|
31
|
+
this.offlineStorageEnabled = options?.offlineStorageEnabled;
|
|
32
|
+
|
|
33
|
+
// Add a fake logger in case one is not provided or needed
|
|
34
|
+
this.logger = options?.logger || {
|
|
35
|
+
verbose: () => {},
|
|
36
|
+
warning: () => {},
|
|
37
|
+
error: () => {},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Stores a single Item using `itemId` as an index
|
|
43
|
+
* @method storeItem
|
|
44
|
+
* @param item {StorableItem} a Dictonary with key to store
|
|
45
|
+
*/
|
|
46
|
+
public storeItem(item: StorableItem): void {
|
|
47
|
+
this.contents = this.getItems();
|
|
48
|
+
|
|
49
|
+
if (item[this._itemKey]) {
|
|
50
|
+
this.contents[item[this._itemKey]] = item;
|
|
51
|
+
this.logger.verbose(
|
|
52
|
+
`Saved items to vault with key: ${item[this._itemKey]}`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.saveItems(this.contents);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Stores Items using `itemId` as an index
|
|
61
|
+
* @method storeItems
|
|
62
|
+
* @param {StorableItem[]} an Array of StorableItems
|
|
63
|
+
*/
|
|
64
|
+
public storeItems(items: StorableItem[]): void {
|
|
65
|
+
items.forEach((item) => this.storeItem(item));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Removes a single StorableItem based on `indexId`
|
|
70
|
+
* @method removeItem
|
|
71
|
+
* @param {String} indexId
|
|
72
|
+
*/
|
|
73
|
+
public removeItem(indexId: string): void {
|
|
74
|
+
this.logger.verbose(`Removing from vault: ${indexId}`);
|
|
75
|
+
this.contents = this.getItems() || {};
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
delete this.contents[indexId];
|
|
79
|
+
|
|
80
|
+
this.saveItems(this.contents);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
this.logger.error(
|
|
83
|
+
`Unable to remove item without a matching ID ${indexId}`
|
|
84
|
+
);
|
|
85
|
+
this.logger.error(error as string);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Retrieves all StorableItems from local storage as an array
|
|
91
|
+
* @method retrieveItems
|
|
92
|
+
* @returns {StorableItem[]} an array of Items
|
|
93
|
+
*/
|
|
94
|
+
public retrieveItems(): StorableItem[] {
|
|
95
|
+
this.contents = this.getItems();
|
|
96
|
+
|
|
97
|
+
return Object.keys(this.contents).map((item) => this.contents[item]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Removes all persisted data from local storage based on this vault's `key`
|
|
102
|
+
* @method purge
|
|
103
|
+
*/
|
|
104
|
+
public purge(): void {
|
|
105
|
+
this.contents = {};
|
|
106
|
+
this.removeItems();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private saveItems(items: Dictionary<StorableItem>): void {
|
|
110
|
+
if (!this.offlineStorageEnabled) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
window.localStorage.setItem(
|
|
115
|
+
this._storageKey,
|
|
116
|
+
!isEmpty(items) ? JSON.stringify(items) : ''
|
|
117
|
+
);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
this.logger.error(`Cannot Save items to Local Storage: ${items}`);
|
|
120
|
+
this.logger.error(error as string);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private getItems(): Dictionary<StorableItem> {
|
|
125
|
+
if (!this.offlineStorageEnabled) {
|
|
126
|
+
return this.contents;
|
|
127
|
+
}
|
|
128
|
+
// TODO: Handle cases where Local Storage is unavailable
|
|
129
|
+
// https://go.mparticle.com/work/SQDSDKS-5022
|
|
130
|
+
const itemString = window.localStorage.getItem(this._storageKey);
|
|
131
|
+
|
|
132
|
+
return itemString ? JSON.parse(itemString) : {};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private removeItems(): void {
|
|
136
|
+
if (!this.offlineStorageEnabled) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
window.localStorage.removeItem(this._storageKey);
|
|
140
|
+
}
|
|
141
|
+
}
|