@mparticle/web-sdk 3.30.0 → 3.32.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/README.md +186 -9
- package/dist/mparticle.common.js +1 -1
- package/dist/mparticle.esm.js +1 -1
- package/dist/mparticle.js +105 -56
- package/dist/types/src/buttonTracking/buttonTracker.d.ts +1 -0
- package/dist/types/src/buttonTracking/checkoutIntent.d.ts +6 -2
- package/dist/types/src/internal-types.d.ts +1 -1
- package/dist/types/src/reporting/types.d.ts +1 -0
- package/dist/types/src/roktManager.d.ts +4 -1
- package/package.json +1 -1
- package/src/buttonTracking/buttonTracker.ts +18 -2
- package/src/buttonTracking/checkoutIntent.ts +62 -7
- package/src/ecommerce.ts +3 -3
- package/src/events.ts +2 -2
- package/src/forwarders.ts +3 -3
- package/src/identity.ts +4 -3
- package/src/internal-types.ts +1 -0
- package/src/kitBlocking.ts +4 -3
- package/src/mp-instance.ts +6 -6
- package/src/persistence.ts +9 -9
- package/src/reporting/types.ts +1 -0
- package/src/roktManager.ts +22 -8
|
@@ -96,7 +96,7 @@ const steps = new RegExp(
|
|
|
96
96
|
'ir a caja|continuar al pago|tramitar pedido',
|
|
97
97
|
"procedi al checkout|procedi all'acquisto|procedi al pagamento|vai alla cassa",
|
|
98
98
|
'afrekenen|verder naar betalen|doorgaan naar betalen',
|
|
99
|
-
'レジに進む|ご?(?:購入|注文)手続き(?:へ|に)(?:進む)?|お?支払い(?:へ|に)進む|(?:ご注文内容の)?確認画面へ(?:進む)?',
|
|
99
|
+
'レジに進む|ご?(?:購入|注文)手続き(?:(?:へ|に)(?:進む)?)?|お?支払い(?:へ|に)進む|(?:ご注文内容の)?確認画面へ(?:進む)?',
|
|
100
100
|
].join('|') +
|
|
101
101
|
')$'
|
|
102
102
|
);
|
|
@@ -280,7 +280,34 @@ export type CheckoutIntentSource =
|
|
|
280
280
|
| 'frame'
|
|
281
281
|
| 'submit'
|
|
282
282
|
| 'name'
|
|
283
|
-
| 'api'
|
|
283
|
+
| 'api'
|
|
284
|
+
| 'selector';
|
|
285
|
+
|
|
286
|
+
// CSS selectors a kit supplies for the page's own confirm and checkout-step
|
|
287
|
+
// buttons. A control matching one counts as that kind before any label rule,
|
|
288
|
+
// except that a confirm, wallet or add-to-cart label beats a checkout-step
|
|
289
|
+
// selector.
|
|
290
|
+
export interface ICheckoutIntentSelectors {
|
|
291
|
+
commit?: readonly string[];
|
|
292
|
+
checkout_step?: readonly string[];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// A selector the browser can't parse is skipped rather than thrown.
|
|
296
|
+
function matchesAnySelector(
|
|
297
|
+
control: Element,
|
|
298
|
+
selectors: readonly string[] | undefined
|
|
299
|
+
): boolean {
|
|
300
|
+
if (!selectors) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
return selectors.some(selector => {
|
|
304
|
+
try {
|
|
305
|
+
return control.matches(selector);
|
|
306
|
+
} catch (e) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
284
311
|
|
|
285
312
|
export interface ICheckoutIntent {
|
|
286
313
|
kind: Exclude<CheckoutIntentKind, 'frame'>;
|
|
@@ -328,13 +355,17 @@ function isCommitLabel(text: string, isLink: boolean, pathname: string, control:
|
|
|
328
355
|
|
|
329
356
|
// Classifies a clicked or submitting control found by findControl, in order:
|
|
330
357
|
// pickers, toggles and pay-later messages never count; a vendor's own wallet
|
|
331
|
-
// button
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
//
|
|
358
|
+
// button keeps its vendor kind; a control matching a kit-supplied commit
|
|
359
|
+
// selector counts as a commit before any label rule, and one matching a
|
|
360
|
+
// checkout-step selector as a step unless its labels make it a confirm, a
|
|
361
|
+
// wallet or an add-to-cart click; a confirm label on any source
|
|
362
|
+
// counts before the look-alike exclusions veto; then a wallet-named control,
|
|
363
|
+
// wallet phrases and steps. An add-to-cart label, links included, or a control
|
|
364
|
+
// that opens the cart on the page counts only where none of those do.
|
|
335
365
|
export function classifyIntent(
|
|
336
366
|
control: Element,
|
|
337
|
-
pathname: string
|
|
367
|
+
pathname: string,
|
|
368
|
+
selectors?: ICheckoutIntentSelectors
|
|
338
369
|
): ICheckoutIntent | undefined {
|
|
339
370
|
const vendor = vendorButtonKind(control);
|
|
340
371
|
if (vendor === 'none') {
|
|
@@ -345,6 +376,30 @@ export function classifyIntent(
|
|
|
345
376
|
? undefined
|
|
346
377
|
: { kind: vendor, source: 'vendor' };
|
|
347
378
|
}
|
|
379
|
+
if (selectors && !isQuietIntentControl(control, false)) {
|
|
380
|
+
if (matchesAnySelector(control, selectors.commit)) {
|
|
381
|
+
return { kind: 'commit', source: 'selector' };
|
|
382
|
+
}
|
|
383
|
+
if (matchesAnySelector(control, selectors.checkout_step)) {
|
|
384
|
+
// A confirm, wallet or add-to-cart label still wins, so a class those
|
|
385
|
+
// buttons share with a step button can't turn their clicks into steps.
|
|
386
|
+
const byLabel = classifyLabels(control, pathname);
|
|
387
|
+
return byLabel &&
|
|
388
|
+
(byLabel.kind === 'commit' ||
|
|
389
|
+
byLabel.kind === 'wallet' ||
|
|
390
|
+
byLabel.adds === true)
|
|
391
|
+
? byLabel
|
|
392
|
+
: { kind: 'checkout_step', source: 'selector' };
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return classifyLabels(control, pathname);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// The label rules, read once the vendor and selector checks have passed.
|
|
399
|
+
function classifyLabels(
|
|
400
|
+
control: Element,
|
|
401
|
+
pathname: string
|
|
402
|
+
): ICheckoutIntent | undefined {
|
|
348
403
|
const texts = labels(control);
|
|
349
404
|
const cores = texts.map(coreLabel);
|
|
350
405
|
const cartAction = cartControlAction(control, cores);
|
package/src/ecommerce.ts
CHANGED
|
@@ -369,7 +369,7 @@ export default function Ecommerce(
|
|
|
369
369
|
);
|
|
370
370
|
return null;
|
|
371
371
|
} else {
|
|
372
|
-
price =
|
|
372
|
+
price = parseNumber(price);
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
if (position && !mpInstance._Helpers.Validators.isNumber(position)) {
|
|
@@ -382,7 +382,7 @@ export default function Ecommerce(
|
|
|
382
382
|
if (!mpInstance._Helpers.Validators.isStringOrNumber(quantity)) {
|
|
383
383
|
quantity = 1;
|
|
384
384
|
} else {
|
|
385
|
-
quantity =
|
|
385
|
+
quantity = parseNumber(quantity);
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
return {
|
|
@@ -680,6 +680,6 @@ export default function Ecommerce(
|
|
|
680
680
|
}
|
|
681
681
|
|
|
682
682
|
// if amount is a string, it will be parsed into a number if possible, or set to 0
|
|
683
|
-
return
|
|
683
|
+
return parseNumber(amount);
|
|
684
684
|
};
|
|
685
685
|
}
|
package/src/events.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
SDKEventOptions,
|
|
21
21
|
TransactionAttributes,
|
|
22
22
|
} from '@mparticle/web-sdk';
|
|
23
|
-
import { getHref, valueof } from './utils';
|
|
23
|
+
import { getHref, valueof, isObject } from './utils';
|
|
24
24
|
import {
|
|
25
25
|
allowedQueryParams,
|
|
26
26
|
autoPageViewAttribute,
|
|
@@ -242,7 +242,7 @@ export default function Events(
|
|
|
242
242
|
);
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
if (
|
|
245
|
+
if (isObject(transactionAttributes)) {
|
|
246
246
|
mpInstance._Ecommerce.convertTransactionAttributesToProductAction(
|
|
247
247
|
transactionAttributes,
|
|
248
248
|
event.ProductAction
|
package/src/forwarders.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import filteredMparticleUser, {
|
|
2
2
|
isIdentityAllowed,
|
|
3
3
|
} from './filteredMparticleUser';
|
|
4
|
-
import { isEmpty, extend, hasOwnProp, Dictionary } from './utils';
|
|
4
|
+
import { isEmpty, extend, hasOwnProp, Dictionary, isObject } from './utils';
|
|
5
5
|
import KitFilterHelper from './kitFilterHelper';
|
|
6
6
|
import Constants from './constants';
|
|
7
7
|
import APIClient, { IForwardingStatsData } from './apiClient';
|
|
@@ -197,7 +197,7 @@ export default function Forwarders(
|
|
|
197
197
|
): boolean {
|
|
198
198
|
if (
|
|
199
199
|
!filterObject ||
|
|
200
|
-
!
|
|
200
|
+
!isObject(filterObject) ||
|
|
201
201
|
!Object.keys(filterObject).length
|
|
202
202
|
) {
|
|
203
203
|
return true;
|
|
@@ -212,7 +212,7 @@ export default function Forwarders(
|
|
|
212
212
|
try {
|
|
213
213
|
const hasUserAttributes =
|
|
214
214
|
userAttributes &&
|
|
215
|
-
|
|
215
|
+
isObject(userAttributes) &&
|
|
216
216
|
Object.keys(userAttributes).length > 0;
|
|
217
217
|
|
|
218
218
|
const isMatch = hasUserAttributes
|
package/src/identity.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
isReservedStoredPropertyName,
|
|
21
21
|
isFunction,
|
|
22
22
|
isObject,
|
|
23
|
+
findKeyInObject,
|
|
23
24
|
} from './utils';
|
|
24
25
|
import { getIdentityTypeFromStoredKey } from './types';
|
|
25
26
|
import { hasMPIDAndUserLoginChanged, hasMPIDChanged } from './user-utils';
|
|
@@ -990,7 +991,7 @@ export default function Identity(
|
|
|
990
991
|
let previousUserAttributeValue;
|
|
991
992
|
let isNewAttribute;
|
|
992
993
|
|
|
993
|
-
const existingProp =
|
|
994
|
+
const existingProp = findKeyInObject(
|
|
994
995
|
userAttributes,
|
|
995
996
|
key
|
|
996
997
|
);
|
|
@@ -1080,7 +1081,7 @@ export default function Identity(
|
|
|
1080
1081
|
|
|
1081
1082
|
userAttributes = this.getAllUserAttributes();
|
|
1082
1083
|
|
|
1083
|
-
const existingProp =
|
|
1084
|
+
const existingProp = findKeyInObject(
|
|
1084
1085
|
userAttributes,
|
|
1085
1086
|
key
|
|
1086
1087
|
);
|
|
@@ -1157,7 +1158,7 @@ export default function Identity(
|
|
|
1157
1158
|
let isNewAttribute;
|
|
1158
1159
|
let userAttributeChange;
|
|
1159
1160
|
|
|
1160
|
-
const existingProp =
|
|
1161
|
+
const existingProp = findKeyInObject(
|
|
1161
1162
|
userAttributes,
|
|
1162
1163
|
key
|
|
1163
1164
|
);
|
package/src/internal-types.ts
CHANGED
package/src/kitBlocking.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { BaseEvent, EventTypeEnum, CommerceEvent, ScreenViewEvent, CustomEvent }
|
|
|
4
4
|
import Types from './types'
|
|
5
5
|
import { DataPlanPoint } from '@mparticle/data-planning-models';
|
|
6
6
|
import { IMParticleWebSDKInstance } from './mp-instance';
|
|
7
|
+
import { isObject, parseNumber } from './utils';
|
|
7
8
|
|
|
8
9
|
/*
|
|
9
10
|
TODO: Including this as a workaround because attempting to import it from
|
|
@@ -476,7 +477,7 @@ export default class KitBlocker {
|
|
|
476
477
|
const clonedEvent = {...event};
|
|
477
478
|
if (this.blockUserAttributes) {
|
|
478
479
|
const matchedAttributes = this.dataPlanMatchLookups['user_attributes'];
|
|
479
|
-
if (
|
|
480
|
+
if (isObject(matchedAttributes) && clonedEvent.UserAttributes) {
|
|
480
481
|
const plannedUserAttributes = {};
|
|
481
482
|
for (const ua of Object.keys(clonedEvent.UserAttributes)) {
|
|
482
483
|
if (matchedAttributes[ua] === true) {
|
|
@@ -545,11 +546,11 @@ export default class KitBlocker {
|
|
|
545
546
|
|
|
546
547
|
if (this.blockUserIdentities) {
|
|
547
548
|
const matchedIdentities = this.dataPlanMatchLookups['user_identities'];
|
|
548
|
-
if (
|
|
549
|
+
if (isObject(matchedIdentities)) {
|
|
549
550
|
if (clonedEvent?.UserIdentities?.length) {
|
|
550
551
|
clonedEvent.UserIdentities = clonedEvent.UserIdentities.filter(uiByType => {
|
|
551
552
|
const identityName = Types.IdentityType.getIdentityName(
|
|
552
|
-
|
|
553
|
+
parseNumber(uiByType.Type)
|
|
553
554
|
);
|
|
554
555
|
|
|
555
556
|
return matchedIdentities[identityName];
|
package/src/mp-instance.ts
CHANGED
|
@@ -39,7 +39,7 @@ import Consent, { IConsent } from './consent';
|
|
|
39
39
|
import KitBlocker from './kitBlocking';
|
|
40
40
|
import ConfigAPIClient, { IKitConfigs } from './configAPIClient';
|
|
41
41
|
import IdentityAPIClient, { IIdentityApiClient } from './identityApiClient';
|
|
42
|
-
import { isFunction, parseConfig, valueof, generateDeprecationMessage, extend } from './utils';
|
|
42
|
+
import { isFunction, parseConfig, valueof, generateDeprecationMessage, extend, findKeyInObject, isObject } from './utils';
|
|
43
43
|
import { DisabledVault, LocalStorageVault } from './vault';
|
|
44
44
|
import { removeExpiredIdentityCacheDates, hasExplicitIdentifier } from './identity-utils';
|
|
45
45
|
import IntegrationCapture, { isIntegrationCaptureEnabled } from './integrationCapture';
|
|
@@ -703,7 +703,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
703
703
|
hostname: window.location.hostname,
|
|
704
704
|
title: window.document.title,
|
|
705
705
|
};
|
|
706
|
-
} else if (!
|
|
706
|
+
} else if (!isObject(attrs)) {
|
|
707
707
|
self.Logger.error(
|
|
708
708
|
'The attributes argument must be an object. A ' +
|
|
709
709
|
typeof attrs +
|
|
@@ -711,7 +711,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
711
711
|
);
|
|
712
712
|
return;
|
|
713
713
|
}
|
|
714
|
-
if (customFlags && !
|
|
714
|
+
if (customFlags && !isObject(customFlags)) {
|
|
715
715
|
self.Logger.error(
|
|
716
716
|
'The customFlags argument must be an object. A ' +
|
|
717
717
|
typeof customFlags +
|
|
@@ -1108,7 +1108,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
1108
1108
|
JSON.stringify({ key: key, value: value })
|
|
1109
1109
|
);
|
|
1110
1110
|
} else {
|
|
1111
|
-
const existingProp =
|
|
1111
|
+
const existingProp = findKeyInObject(
|
|
1112
1112
|
self._Store.sessionAttributes,
|
|
1113
1113
|
key
|
|
1114
1114
|
);
|
|
@@ -1190,7 +1190,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
1190
1190
|
}
|
|
1191
1191
|
if (attrs === null) {
|
|
1192
1192
|
self._Store.integrationAttributes[integrationId] = {};
|
|
1193
|
-
} else if (
|
|
1193
|
+
} else if (isObject(attrs)) {
|
|
1194
1194
|
if (Object.keys(attrs).length === 0) {
|
|
1195
1195
|
self._Store.integrationAttributes[integrationId] = {};
|
|
1196
1196
|
} else {
|
|
@@ -1198,7 +1198,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
1198
1198
|
if (typeof key === 'string') {
|
|
1199
1199
|
if (typeof attrs[key] === 'string') {
|
|
1200
1200
|
if (
|
|
1201
|
-
|
|
1201
|
+
isObject(
|
|
1202
1202
|
self._Store.integrationAttributes[
|
|
1203
1203
|
integrationId
|
|
1204
1204
|
]
|
package/src/persistence.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { IMParticleWebSDKInstance } from './mp-instance';
|
|
|
5
5
|
import { IPersistence, IPersistenceMinified } from './persistence.interfaces';
|
|
6
6
|
import { MPID } from '@mparticle/web-sdk';
|
|
7
7
|
import { CookieSyncDates } from './cookieSyncManager';
|
|
8
|
-
import { Dictionary } from './utils';
|
|
8
|
+
import { Dictionary, isObject } from './utils';
|
|
9
9
|
import { IMParticleInstanceManager } from './sdkRuntimeModels';
|
|
10
10
|
|
|
11
11
|
const Base64 = Polyfill.Base64,
|
|
@@ -370,7 +370,7 @@ export default function _Persistence(
|
|
|
370
370
|
return null;
|
|
371
371
|
}
|
|
372
372
|
const record = JSON.parse(decoded);
|
|
373
|
-
return
|
|
373
|
+
return isObject(record) &&
|
|
374
374
|
Object.keys(record).length
|
|
375
375
|
? (record as IPersistenceMinified)
|
|
376
376
|
: null;
|
|
@@ -737,7 +737,7 @@ export default function _Persistence(
|
|
|
737
737
|
if (Array.isArray(value)) {
|
|
738
738
|
return value.length > 0;
|
|
739
739
|
}
|
|
740
|
-
if (!
|
|
740
|
+
if (!isObject(value)) {
|
|
741
741
|
return false;
|
|
742
742
|
}
|
|
743
743
|
return Object.keys(value).length > 0;
|
|
@@ -773,7 +773,7 @@ export default function _Persistence(
|
|
|
773
773
|
function encodeMpidBase64Field(container, key: string): void {
|
|
774
774
|
const value = container[key];
|
|
775
775
|
if (
|
|
776
|
-
|
|
776
|
+
isObject(value) &&
|
|
777
777
|
Object.keys(value).length
|
|
778
778
|
) {
|
|
779
779
|
container[key] = Base64.encode(JSON.stringify(value));
|
|
@@ -855,7 +855,7 @@ export default function _Persistence(
|
|
|
855
855
|
continue;
|
|
856
856
|
}
|
|
857
857
|
if (!SDKv2NonMPIDCookieKeys[mpid]) {
|
|
858
|
-
if (!
|
|
858
|
+
if (!isObject(persistence[mpid])) {
|
|
859
859
|
delete persistence[mpid];
|
|
860
860
|
continue;
|
|
861
861
|
}
|
|
@@ -881,7 +881,7 @@ export default function _Persistence(
|
|
|
881
881
|
Utils.revertCookieString(persistenceString)
|
|
882
882
|
) as IPersistenceMinified;
|
|
883
883
|
if (
|
|
884
|
-
|
|
884
|
+
isObject(persistence) &&
|
|
885
885
|
Object.keys(persistence).length
|
|
886
886
|
) {
|
|
887
887
|
decodeGlobalSettings(persistence.gs);
|
|
@@ -935,7 +935,7 @@ export default function _Persistence(
|
|
|
935
935
|
if (csd) {
|
|
936
936
|
let persistence = self.getPersistence();
|
|
937
937
|
if (persistence) {
|
|
938
|
-
if (
|
|
938
|
+
if (isObject(persistence[mpid])) {
|
|
939
939
|
persistence[mpid].csd = csd;
|
|
940
940
|
} else {
|
|
941
941
|
persistence[mpid] = {
|
|
@@ -1053,7 +1053,7 @@ export default function _Persistence(
|
|
|
1053
1053
|
}
|
|
1054
1054
|
let persistence = self.getPersistence();
|
|
1055
1055
|
if (persistence) {
|
|
1056
|
-
if (!
|
|
1056
|
+
if (!isObject(persistence[mpid])) {
|
|
1057
1057
|
persistence[mpid] = {};
|
|
1058
1058
|
}
|
|
1059
1059
|
if (!persistence[mpid].fst) {
|
|
@@ -1093,7 +1093,7 @@ export default function _Persistence(
|
|
|
1093
1093
|
time = new Date().getTime();
|
|
1094
1094
|
}
|
|
1095
1095
|
let persistence = self.getPersistence();
|
|
1096
|
-
if (persistence &&
|
|
1096
|
+
if (persistence && isObject(persistence[mpid])) {
|
|
1097
1097
|
persistence[mpid].lst = time;
|
|
1098
1098
|
self.savePersistence(persistence);
|
|
1099
1099
|
}
|
package/src/reporting/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ export const ErrorCodes = {
|
|
|
6
6
|
IDENTITY_REQUEST: 'IDENTITY_REQUEST',
|
|
7
7
|
IDENTITY_MISMATCH: 'IDENTITY_MISMATCH',
|
|
8
8
|
MP_DEPRECATED_METHOD_USAGE: 'MP_DEPRECATED_METHOD_USAGE',
|
|
9
|
+
SELECT_PLACEMENTS_IDENTITY_IN_FLIGHT: 'SELECT_PLACEMENTS_IDENTITY_IN_FLIGHT',
|
|
9
10
|
} as const;
|
|
10
11
|
|
|
11
12
|
export type ErrorCodes = valueof<typeof ErrorCodes>;
|
package/src/roktManager.ts
CHANGED
|
@@ -23,7 +23,8 @@ import { PARTNER_MODULE_IDS } from "./cookieSyncManager";
|
|
|
23
23
|
import IntegrationCapture from "./integrationCapture";
|
|
24
24
|
import Constants from "./constants";
|
|
25
25
|
import { subscribeToRouteChange } from "./routeChangeMonitor";
|
|
26
|
-
import type { CheckoutIntentKind, CheckoutIntentSource, PaymentFrameFamily } from "./buttonTracking/checkoutIntent";
|
|
26
|
+
import type { CheckoutIntentKind, CheckoutIntentSource, ICheckoutIntentSelectors, PaymentFrameFamily } from "./buttonTracking/checkoutIntent";
|
|
27
|
+
export type { ICheckoutIntentSelectors } from "./buttonTracking/checkoutIntent";
|
|
27
28
|
|
|
28
29
|
const PASSBACK_CONVERSION_TRACKING_ID = 'passbackconversiontrackingid';
|
|
29
30
|
// One signal per kind (commit, wallet, checkout_step, frame and cart), with an
|
|
@@ -123,6 +124,9 @@ export interface IRoktKit {
|
|
|
123
124
|
onRouteChange?: () => void;
|
|
124
125
|
// Set by the kit only when it wants checkout intent signals.
|
|
125
126
|
onCheckoutIntent?: (signal: ICheckoutIntentSignal) => void;
|
|
127
|
+
// Set by the kit when its config names the page's confirm or checkout-step
|
|
128
|
+
// buttons. Older kits leave it unset, and the label rules apply alone.
|
|
129
|
+
checkoutIntentSelectors?: ICheckoutIntentSelectors;
|
|
126
130
|
// Set by the kit only when it wants payment picks.
|
|
127
131
|
onPaymentPick?: (signal: IPaymentPickSignal) => void;
|
|
128
132
|
launcherOptions?: Dictionary<any>;
|
|
@@ -415,6 +419,13 @@ export default class RoktManager {
|
|
|
415
419
|
}
|
|
416
420
|
}
|
|
417
421
|
|
|
422
|
+
// Read at click time, so selectors from a kit that attaches later apply to
|
|
423
|
+
// the next click.
|
|
424
|
+
public getCheckoutIntentSelectors(): ICheckoutIntentSelectors | undefined {
|
|
425
|
+
const kit = this.kit;
|
|
426
|
+
return kit ? kit.checkoutIntentSelectors : undefined;
|
|
427
|
+
}
|
|
428
|
+
|
|
418
429
|
public discardCheckoutIntents(): void {
|
|
419
430
|
this.pendingCheckoutIntents = [];
|
|
420
431
|
}
|
|
@@ -484,11 +495,19 @@ export default class RoktManager {
|
|
|
484
495
|
public async selectPlacements(options: IRoktSelectPlacementsOptions): Promise<IRoktSelection> {
|
|
485
496
|
this.captureTiming?.(PerformanceMarkType.JointSdkSelectPlacements);
|
|
486
497
|
|
|
487
|
-
|
|
488
|
-
if (!this.isReady() || this.store?.identityCallInFlight) {
|
|
498
|
+
if (!this.isReady()) {
|
|
489
499
|
return this.deferredCall<IRoktSelection>('selectPlacements', options);
|
|
490
500
|
}
|
|
491
501
|
|
|
502
|
+
// Like the iOS and Android SDKs, this does not wait for an identity request, so the
|
|
503
|
+
// selection can go out for the user from before it. The log counts how often that happens.
|
|
504
|
+
if (this.store?.identityCallInFlight) {
|
|
505
|
+
this.loggingService?.log({
|
|
506
|
+
message: 'RoktManager: selectPlacements ran while an identity request was in flight',
|
|
507
|
+
code: ErrorCodes.SELECT_PLACEMENTS_IDENTITY_IN_FLIGHT,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
492
511
|
try {
|
|
493
512
|
const { attributes } = options;
|
|
494
513
|
const sandboxValue = attributes?.sandbox || null;
|
|
@@ -570,10 +589,6 @@ export default class RoktManager {
|
|
|
570
589
|
);
|
|
571
590
|
}
|
|
572
591
|
this.setUserAttributes(result?.getUser?.(), userAttributes, newIdentities);
|
|
573
|
-
// Drain any selectPlacements calls that were deferred while
|
|
574
|
-
// identify was in-flight. By the time this callback fires,
|
|
575
|
-
// identityCallInFlight has already been reset to false.
|
|
576
|
-
this.processMessageQueue();
|
|
577
592
|
}
|
|
578
593
|
);
|
|
579
594
|
} catch (error) {
|
|
@@ -896,7 +911,6 @@ export default class RoktManager {
|
|
|
896
911
|
public onIdentityComplete(): void {
|
|
897
912
|
if (this.isReady()) {
|
|
898
913
|
this.currentUser = this.identityService.getCurrentUser();
|
|
899
|
-
// Process any queued selectPlacements calls that were waiting for identity
|
|
900
914
|
this.processMessageQueue();
|
|
901
915
|
}
|
|
902
916
|
}
|