Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ export default function APIClient(
this.queueEventForBatchUpload(event);
}

if (event.EventName !== Types.MessageType.AppStateTransition) {
// https://go.mparticle.com/work/SQDSDKS-6935
// While Event Name is 'usually' a string, there are some cases where it is a number
// in that it could be a type of MessageType Enum
if (event.EventName as unknown as number !== Types.MessageType.AppStateTransition) {
if (kitBlocker && kitBlocker.kitBlockingEnabled) {
event = kitBlocker.createBlockedEvent(event);
}
Expand Down
46 changes: 26 additions & 20 deletions src/batchUploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Batch } from '@mparticle/event-models';
import Constants from './constants';
import { SDKEvent, MParticleWebSDK, SDKLoggerApi } from './sdkRuntimeModels';
import { convertEvents } from './sdkToEventsApiConverter';
import Types from './types';
import { MessageType } from './types';
import { getRampNumber, isEmpty } from './utils';
import { SessionStorageVault, LocalStorageVault } from './vault';
import {
Expand Down Expand Up @@ -167,29 +167,35 @@ export class BatchUploader {
* @param event event that should be queued
*/
public queueEvent(event: SDKEvent): void {
if (!isEmpty(event)) {
this.eventsQueuedForProcessing.push(event);
if (this.offlineStorageEnabled && this.eventVault) {
this.eventVault.store(this.eventsQueuedForProcessing);
}
this.mpInstance.Logger.verbose(
`Queuing event: ${JSON.stringify(event)}`
);
this.mpInstance.Logger.verbose(
`Queued event count: ${this.eventsQueuedForProcessing.length}`
);
if (isEmpty(event)) {
return;
}

// TODO: Remove this check once the v2 code path is removed
// https://go.mparticle.com/work/SQDSDKS-3720
if (
!this.batchingEnabled ||
Types.TriggerUploadType[event.EventDataType]
) {
this.prepareAndUpload(false, false);
}
const { verbose } = this.mpInstance.Logger;

this.eventsQueuedForProcessing.push(event);
if (this.offlineStorageEnabled && this.eventVault) {
this.eventVault.store(this.eventsQueuedForProcessing);
}

verbose(`Queuing event: ${JSON.stringify(event)}`);
verbose(`Queued event count: ${this.eventsQueuedForProcessing.length}`);

if (this.shouldTriggerImmediateUpload(event.EventDataType)) {
this.prepareAndUpload(false, false);
}
}

// https://go.mparticle.com/work/SQDSDKS-3720
private shouldTriggerImmediateUpload (eventDataType: number): boolean {
const priorityEvents = [
MessageType.Commerce,
MessageType.UserIdentityChange,
] as const;

return !this.batchingEnabled || priorityEvents.includes(eventDataType as typeof priorityEvents[number]);
};

/**
* This implements crucial logic to:
* - bucket pending events by MPID, and then by Session, and upload individual batches for each bucket.
Expand Down
8 changes: 8 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ const Constants = {
Login: 'login',
Identify: 'identify',
},

Environment: {
Development: 'development',
Production: 'production',
},
} as const;

export default Constants;
Expand All @@ -196,4 +201,7 @@ export const MILLIS_IN_ONE_SEC = 1000;
export const HTTP_OK = 200 as const;
export const HTTP_ACCEPTED = 202 as const;
export const HTTP_BAD_REQUEST = 400 as const;
export const HTTP_UNAUTHORIZED = 401 as const;
export const HTTP_FORBIDDEN = 403 as const;
export const HTTP_NOT_FOUND = 404 as const;
export const HTTP_SERVER_ERROR = 500 as const;
201 changes: 201 additions & 0 deletions src/ecommerce.interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import {
ProductAction,
Product,
Promotion,
CommerceEvent,
} from '@mparticle/event-models';
import {
SDKEventAttrs,
SDKEventOptions,
TransactionAttributes,
} from '@mparticle/web-sdk';
import { valueof } from './utils';
import {
ProductActionType,
PromotionActionType,
CommerceEventType,
EventType,
} from './types';
import {
SDKEvent,
SDKEventCustomFlags,
SDKImpression,
SDKProduct,
SDKProductImpression,
SDKPromotion,
} from './sdkRuntimeModels';

interface IECommerceShared {
createProduct(
name: string,
sku: string | number,
price: string | number,
quantity?: string | number,
variant?: string,
category?: string,
brand?: string,
position?: number,
couponCode?: string,
attributes?: SDKEventAttrs
): SDKProduct | null;
createImpression(name: string, product: Product): SDKImpression | null;
createPromotion(
id: string | number,
creative?: string,
name?: string,
position?: number
): SDKPromotion | null;
createTransactionAttributes(
id: string | number,
affiliation?: string,
couponCode?: string,
revenue?: string | number,
shipping?: string | number,
tax?: number
): TransactionAttributes | null;
expandCommerceEvent(event: CommerceEvent): SDKEvent[] | null;
}

export interface SDKCart {
add(product: SDKProduct | SDKProduct[], logEvent?: boolean): void;
remove(product: SDKProduct | SDKProduct[], logEvent?: boolean): void;
clear(): void;
}

// Used for the public `eCommerce` namespace
export interface SDKECommerceAPI extends IECommerceShared {
logCheckout(
step: number,
option?: string,
attrs?: SDKEventAttrs,
customFlags?: SDKEventCustomFlags
): void;
logImpression(
impression: SDKProductImpression,
attrs?: SDKEventAttrs,
customFlags?: SDKEventCustomFlags,
eventOptions?: SDKEventOptions
): void;
logProductAction(
productActionType: valueof<typeof ProductActionType>,
product: SDKProduct | SDKProduct[],
attrs?: SDKEventAttrs,
customFlags?: SDKEventCustomFlags,
transactionAttributes?: TransactionAttributes,
eventOptions?: SDKEventOptions
): void;
logPromotion(
type: valueof<typeof PromotionActionType>,
promotion: SDKPromotion,
attrs?: SDKEventAttrs,
customFlags?: SDKEventCustomFlags,
eventOptions?: SDKEventOptions
): void;
setCurrencyCode(code: string): void;

/*
* @deprecated
*/
Cart: SDKCart;

/*
* @deprecated
*/
logPurchase(
transactionAttributes: TransactionAttributes,
product: SDKProduct | SDKProduct[],
clearCart?: boolean,
attrs?: SDKEventAttrs,
customFlags?: SDKEventCustomFlags
): void;

/*
* @deprecated
*/
logRefund(
transactionAttributes: TransactionAttributes,
product: SDKProduct | SDKProduct[],
clearCart?: boolean,
attrs?: SDKEventAttrs,
customFlags?: SDKEventCustomFlags
): void;
}

interface ExtractedActionAttributes {
Affiliation?: string;
'Coupon Code'?: string;
'Total Amount'?: number;
'Shipping Amount'?: number;
'Tax Amount'?: number;
'Checkout Option'?: string;
'Checkout Step'?: number;
'Transaction ID'?: string;
}
interface ExtractedProductAttributes {
'Coupon Code'?: string;
Brand?: string;
Category?: string;
Name?: string;
Id?: string;
'Item Price'?: number;
Quantity?: number;
Position?: number;
Variant?: string;
'Total Product Amount': number;
}
interface ExtractedPromotionAttributes {
Id?: string;
Creative?: string;
Name?: string;
Position?: number;
}
interface ExtractedTransactionId {
'Transaction ID'?: string;
}

// Used for the private `_Ecommerce` namespace
export interface IECommerce extends IECommerceShared {
buildProductList(event: SDKEvent, product: Product | Product[]): Product[];
convertProductActionToEventType(
productActionType: valueof<typeof ProductActionType>
): // https://go.mparticle.com/work/SQDSDKS-4801
typeof CommerceEventType | typeof EventType | null;
convertPromotionActionToEventType(
promotionActionType: valueof<typeof PromotionActionType>
): typeof CommerceEventType | null;
convertTransactionAttributesToProductAction(
transactionAttributes: TransactionAttributes,
productAction: ProductAction
): void;
createCommerceEventObject(
customFlags: SDKEventCustomFlags,
options?: SDKEventOptions
): SDKEvent | null;
expandProductAction(commerceEvent: CommerceEvent): SDKEvent[];
expandProductImpression(commerceEvent: CommerceEvent): SDKEvent[];
expandPromotionAction(commerceEvent: CommerceEvent): SDKEvent[];
extractActionAttributes(
attributes: ExtractedActionAttributes,
productAction: ProductAction
): void;
extractProductAttributes(
attributes: ExtractedProductAttributes,
product: Product
): void;
extractPromotionAttributes(
attributes: ExtractedPromotionAttributes,
promotion: Promotion
): void;
extractTransactionId(
attributes: ExtractedTransactionId,
productAction: ProductAction
): void;
generateExpandedEcommerceName(eventName: string, plusOne: boolean): string;
getProductActionEventName(
productActionType: valueof<typeof ProductActionType>
): string;
getPromotionActionEventName(
promotionActionType: valueof<typeof PromotionActionType>
): string;
sanitizeAmount(amount: string | number, category: string): number;
}
9 changes: 9 additions & 0 deletions src/ecommerce.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ var Messages = Constants.Messages;

export default function Ecommerce(mpInstance) {
var self = this;

// https://go.mparticle.com/work/SQDSDKS-4801
this.convertTransactionAttributesToProductAction = function(
transactionAttributes,
productAction
Expand Down Expand Up @@ -103,8 +105,11 @@ export default function Ecommerce(mpInstance) {
return Types.CommerceEventType.ProductRemoveFromCart;
case Types.ProductActionType.RemoveFromWishlist:
return Types.CommerceEventType.ProductRemoveFromWishlist;

// https://go.mparticle.com/work/SQDSDKS-4801
case Types.ProductActionType.Unknown:
return Types.EventType.Unknown;

case Types.ProductActionType.ViewDetail:
return Types.CommerceEventType.ProductViewDetail;
default:
Expand Down Expand Up @@ -139,6 +144,7 @@ export default function Ecommerce(mpInstance) {
);
};

// https://go.mparticle.com/work/SQDSDKS-4801
this.extractProductAttributes = function(attributes, product) {
if (product.CouponCode) {
attributes['Coupon Code'] = product.CouponCode;
Expand Down Expand Up @@ -170,12 +176,14 @@ export default function Ecommerce(mpInstance) {
attributes['Total Product Amount'] = product.TotalAmount || 0;
};

// https://go.mparticle.com/work/SQDSDKS-4801
this.extractTransactionId = function(attributes, productAction) {
if (productAction.TransactionId) {
attributes['Transaction Id'] = productAction.TransactionId;
}
};

// https://go.mparticle.com/work/SQDSDKS-4801
this.extractActionAttributes = function(attributes, productAction) {
self.extractTransactionId(attributes, productAction);

Expand Down Expand Up @@ -208,6 +216,7 @@ export default function Ecommerce(mpInstance) {
}
};

// https://go.mparticle.com/work/SQDSDKS-4801
this.extractPromotionAttributes = function(attributes, promotion) {
if (promotion.Id) {
attributes['Id'] = promotion.Id;
Expand Down
Loading
Loading