@mparticle/web-sdk 3.16.1 → 3.17.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 +4 -3
- package/dist/mparticle.common.js +32 -15
- package/dist/mparticle.esm.js +32 -15
- package/dist/mparticle.js +435 -4
- package/dist/types/src/checkoutIntentClassifier.d.ts +4 -0
- package/dist/types/src/checkoutIntentTracker.d.ts +23 -0
- package/dist/types/src/constants.d.ts +1 -0
- package/dist/types/src/internal-types.d.ts +1 -1
- package/dist/types/src/mp-instance.d.ts +2 -0
- package/dist/types/src/roktManager.d.ts +11 -0
- package/dist/types/src/store.d.ts +1 -0
- package/package.json +1 -1
- package/src/checkoutIntentClassifier.ts +231 -0
- package/src/checkoutIntentTracker.ts +244 -0
- package/src/constants.ts +1 -0
- package/src/internal-types.ts +1 -0
- package/src/mp-instance.ts +38 -1
- package/src/roktManager.ts +76 -0
- package/src/store.ts +4 -1
package/src/roktManager.ts
CHANGED
|
@@ -23,8 +23,11 @@ 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 } from "./checkoutIntentClassifier";
|
|
26
27
|
|
|
27
28
|
const PASSBACK_CONVERSION_TRACKING_ID = 'passbackconversiontrackingid';
|
|
29
|
+
const CHECKOUT_INTENT_BUFFER_LIMIT = 4;
|
|
30
|
+
const CHECKOUT_INTENT_MAX_AGE_MS = 30000;
|
|
28
31
|
|
|
29
32
|
type AttributeTargetUser = Pick<IMParticleUser, 'getUserIdentities' | 'setUserAttributes'>;
|
|
30
33
|
|
|
@@ -71,6 +74,11 @@ export interface RoktKitFilterSettings {
|
|
|
71
74
|
filteredUser?: IMParticleUser | null;
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
export interface ICheckoutIntentSignal {
|
|
78
|
+
kind: CheckoutIntentKind;
|
|
79
|
+
t: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
74
82
|
export interface IRoktKitSettings {
|
|
75
83
|
accountId?: string;
|
|
76
84
|
placementAttributesMapping?: string;
|
|
@@ -93,6 +101,8 @@ export interface IRoktKit {
|
|
|
93
101
|
// Set by the kit only when it wants route changes; nothing subscribes otherwise. The
|
|
94
102
|
// manager also calls it once on attach.
|
|
95
103
|
onRouteChange?: () => void;
|
|
104
|
+
// Set by the kit only when it wants checkout intent signals.
|
|
105
|
+
onCheckoutIntent?: (signal: ICheckoutIntentSignal) => void;
|
|
96
106
|
launcherOptions?: Dictionary<any>;
|
|
97
107
|
settings?: IRoktKitSettings;
|
|
98
108
|
integrationName?: string;
|
|
@@ -138,6 +148,8 @@ export default class RoktManager {
|
|
|
138
148
|
private initialized: boolean = false;
|
|
139
149
|
private isShoppableAdsLoaded: boolean = false;
|
|
140
150
|
private stopRouteChangeWatch: (() => void) | null = null;
|
|
151
|
+
// Checkout intent raised before the kit attached: latest per kind.
|
|
152
|
+
private pendingCheckoutIntents: Array<{ signal: ICheckoutIntentSignal; pathname: string }> = [];
|
|
141
153
|
|
|
142
154
|
// Keys this manager's route subscription, so a re-executed bundle's manager replaces
|
|
143
155
|
// it while a second named instance keeps its own.
|
|
@@ -232,6 +244,7 @@ export default class RoktManager {
|
|
|
232
244
|
this.kit = kit;
|
|
233
245
|
|
|
234
246
|
this.watchRouteChanges();
|
|
247
|
+
this.flushCheckoutIntents();
|
|
235
248
|
|
|
236
249
|
if (kit.settings?.accountId) {
|
|
237
250
|
this.store.setRoktAccountId(kit.settings.accountId);
|
|
@@ -286,6 +299,69 @@ export default class RoktManager {
|
|
|
286
299
|
}
|
|
287
300
|
}
|
|
288
301
|
|
|
302
|
+
// Checkout intent is off unless the flag is on, and under opt-out, any Rokt
|
|
303
|
+
// privacy launcher option, or Global Privacy Control.
|
|
304
|
+
public isCheckoutIntentSuppressed(): boolean {
|
|
305
|
+
const flags = this.store?.SDKConfig?.flags;
|
|
306
|
+
if (!flags || flags[Constants.FeatureFlags.CheckoutIntent] !== true || !this.store.isEnabled) {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
const options = this.launcherOptions || {};
|
|
310
|
+
if (options.noFunctional || options.noTargeting || options.doNotShareOrSell) {
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
const nav = typeof navigator === 'undefined' ? undefined : (navigator as Navigator & { globalPrivacyControl?: boolean });
|
|
314
|
+
return !!nav && nav.globalPrivacyControl === true;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Reads `this.kit` at call time; before a kit attaches the signal is buffered
|
|
318
|
+
// with the path it was raised on.
|
|
319
|
+
public notifyCheckoutIntent(signal: ICheckoutIntentSignal, pathname: string = window.location.pathname): void {
|
|
320
|
+
if (this.isCheckoutIntentSuppressed()) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const kit = this.kit;
|
|
325
|
+
if (!kit) {
|
|
326
|
+
this.pendingCheckoutIntents = this.pendingCheckoutIntents
|
|
327
|
+
.filter(pending => pending.signal.kind !== signal.kind)
|
|
328
|
+
.concat({ signal, pathname })
|
|
329
|
+
.slice(-CHECKOUT_INTENT_BUFFER_LIMIT);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
if (isFunction(kit.onCheckoutIntent)) {
|
|
335
|
+
kit.onCheckoutIntent(signal);
|
|
336
|
+
}
|
|
337
|
+
} catch (e) {
|
|
338
|
+
this.logger?.error(
|
|
339
|
+
`RoktManager: Error in onCheckoutIntent: ${getErrorMessage(e)}`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
public discardCheckoutIntents(): void {
|
|
345
|
+
this.pendingCheckoutIntents = [];
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Replays recent buffered signals raised on the current page, oldest first.
|
|
349
|
+
private flushCheckoutIntents(): void {
|
|
350
|
+
const pending = this.pendingCheckoutIntents;
|
|
351
|
+
this.pendingCheckoutIntents = [];
|
|
352
|
+
|
|
353
|
+
const now = Date.now();
|
|
354
|
+
const pathname = window.location.pathname;
|
|
355
|
+
pending
|
|
356
|
+
.filter(
|
|
357
|
+
({ signal, pathname: signalPathname }) =>
|
|
358
|
+
now - signal.t < CHECKOUT_INTENT_MAX_AGE_MS &&
|
|
359
|
+
signalPathname === pathname
|
|
360
|
+
)
|
|
361
|
+
.sort((a, b) => a.signal.t - b.signal.t)
|
|
362
|
+
.forEach(({ signal }) => this.notifyCheckoutIntent(signal));
|
|
363
|
+
}
|
|
364
|
+
|
|
289
365
|
private isAutoLogPageViewEnabled(): boolean {
|
|
290
366
|
return (
|
|
291
367
|
this.store?.SDKConfig?.flags?.[
|
package/src/store.ts
CHANGED
|
@@ -153,6 +153,7 @@ export interface IFeatureFlags {
|
|
|
153
153
|
'captureIntegrationSpecificIds.V2'?: string;
|
|
154
154
|
astBackgroundEvents?: boolean;
|
|
155
155
|
autoLogPageView?: boolean;
|
|
156
|
+
checkoutIntent?: boolean;
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
// Temporary Interface until Store can be refactored as a class
|
|
@@ -776,7 +777,8 @@ export function processFlags(config: SDKInitConfig): IFeatureFlags {
|
|
|
776
777
|
CaptureIntegrationSpecificIds,
|
|
777
778
|
CaptureIntegrationSpecificIdsV2,
|
|
778
779
|
AstBackgroundEvents,
|
|
779
|
-
AutoLogPageView
|
|
780
|
+
AutoLogPageView,
|
|
781
|
+
CheckoutIntent,
|
|
780
782
|
} = Constants.FeatureFlags;
|
|
781
783
|
|
|
782
784
|
if (!config.flags) {
|
|
@@ -798,6 +800,7 @@ export function processFlags(config: SDKInitConfig): IFeatureFlags {
|
|
|
798
800
|
flags[CaptureIntegrationSpecificIdsV2] = (config.flags[CaptureIntegrationSpecificIdsV2] || 'none');
|
|
799
801
|
flags[AstBackgroundEvents] = config.flags[AstBackgroundEvents] === 'True';
|
|
800
802
|
flags[AutoLogPageView] = config.flags[AutoLogPageView] === 'True';
|
|
803
|
+
flags[CheckoutIntent] = config.flags[CheckoutIntent] === 'True';
|
|
801
804
|
return flags;
|
|
802
805
|
}
|
|
803
806
|
|