@mparticle/web-sdk 3.23.0 → 3.24.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.
@@ -1,5 +1,9 @@
1
+ import { IKitFilterSettings } from '../configAPIClient';
2
+ import type KitBlocker from '../kitBlocking';
1
3
  import { BaseEvent } from '../sdkRuntimeModels';
2
4
  import { IButtonClick } from './buttonDescription';
3
5
  export declare const AUTO_BUTTON_ATTRIBUTE = "is_auto_button_click";
4
6
  export declare const BUTTON_CLICK_EVENT_NAME = "Auto Button Click";
5
7
  export declare const buildButtonClickEvent: (click: IButtonClick, pathname: string) => BaseEvent;
8
+ export type ButtonClickBlocker = 'data plan' | 'forwarding rule' | 'event name filter' | 'event type filter';
9
+ export declare const getButtonClickBlocker: (forwarder: IKitFilterSettings, kitBlocker?: KitBlocker) => ButtonClickBlocker | undefined;
@@ -1,6 +1,6 @@
1
1
  export type ButtonElementKind = 'button' | 'input' | 'role' | 'wallet' | 'link';
2
2
  export type LinkType = 'same_page' | 'outbound' | 'download';
3
- export type ButtonLabelSource = 'labelledby' | 'aria' | 'text' | 'label' | 'alt' | 'title' | 'value' | 'none';
3
+ export type ButtonLabelSource = 'labelledby' | 'aria' | 'text' | 'alt' | 'title' | 'value' | 'none';
4
4
  export interface IButtonClick {
5
5
  label?: string;
6
6
  labelSource: ButtonLabelSource;
@@ -18,4 +18,4 @@ export interface IButtonClick {
18
18
  fileExtension?: string;
19
19
  checked?: boolean;
20
20
  }
21
- export declare function describeButtonClick(control: Element): IButtonClick | undefined;
21
+ export declare function describeButtonClick(control: Element, path?: Array<EventTarget | null>): IButtonClick | undefined;
@@ -11,6 +11,7 @@ export declare class ButtonTracker {
11
11
  private hasRoktKit;
12
12
  private generation;
13
13
  private lastCommitClick;
14
+ private lastClick;
14
15
  private lastSent;
15
16
  private pagePath;
16
17
  private pageEvents;
@@ -21,6 +22,7 @@ export declare class ButtonTracker {
21
22
  constructor(mpInstance: IMParticleWebSDKInstance);
22
23
  get isActive(): boolean;
23
24
  init(options: IButtonTrackerOptions): void;
25
+ onApplePayBegin(): void;
24
26
  teardown(): void;
25
27
  clearPending(): void;
26
28
  private reset;
@@ -1,5 +1,5 @@
1
- export type CheckoutIntentKind = 'commit' | 'wallet' | 'checkout_step' | 'frame';
2
- export type CheckoutIntentSource = 'vendor' | 'label' | 'brand' | 'frame' | 'submit';
1
+ export type CheckoutIntentKind = 'commit' | 'wallet' | 'checkout_step' | 'frame' | 'cart';
2
+ export type CheckoutIntentSource = 'vendor' | 'label' | 'brand' | 'frame' | 'submit' | 'name' | 'api';
3
3
  export interface ICheckoutIntent {
4
4
  kind: Exclude<CheckoutIntentKind, 'frame'>;
5
5
  source: CheckoutIntentSource;
@@ -1,9 +1,12 @@
1
1
  export declare const CONTROL_SELECTOR = "button, input[type=\"submit\"], input[type=\"button\"], input[type=\"image\"], [role=\"button\"]";
2
+ export declare function someComposedAncestor(element: Element, test: (node: Element) => boolean, until?: Element): boolean;
2
3
  export declare function hasComposedAncestor(element: Element, selector: string): boolean;
3
4
  export declare function isRoktElement(element: Element): boolean;
4
5
  export declare function vendorButtonKind(control: Element): 'wallet' | 'checkout_step' | 'none' | undefined;
6
+ export declare function isWalletNamed(element: Element): boolean;
5
7
  export declare function isWalletElement(element: Element): boolean;
6
- export declare function isQuietIntentControl(control: Element, isVendorWallet: boolean): boolean;
7
- export declare function findControl(path: Array<EventTarget | null>): Element | undefined;
8
+ export declare function isQuietIntentControl(control: Element, isVendorWallet: boolean, isCart?: boolean): boolean;
9
+ export declare function isWalletNamedControl(element: Element): boolean;
10
+ export declare function isExcludedPath(path: Array<EventTarget | null>): boolean;
11
+ export declare function findControl(path: Array<EventTarget | null>, included?: boolean): Element | undefined;
8
12
  export declare function isUnsafeTextSource(element: Element): boolean;
9
- export declare function isUnsafeLabelSource(label: Element): boolean;
@@ -1 +1,2 @@
1
+ export declare const MAX_RAW_LABEL_LENGTH = 128;
1
2
  export declare function maskLabel(raw: string | null | undefined): string | undefined;
@@ -59,6 +59,7 @@ export interface IConfigResponse {
59
59
  workspaceToken: string;
60
60
  pixelConfigs: IPixelConfiguration[];
61
61
  flags: SDKEventCustomFlags;
62
+ autoLogPageViewQueryParams?: string;
62
63
  }
63
64
  export interface IConfigAPIClient {
64
65
  apiKey: string;
@@ -1,8 +1,11 @@
1
1
  import * as EventsApi from '@mparticle/event-models';
2
2
  import { IKitFilterSettings } from './configAPIClient';
3
+ import type { SDKEvent } from './sdkRuntimeModels';
4
+ import type KitBlocker from './kitBlocking';
3
5
  type ForwarderFilterConfig = Pick<IKitFilterSettings, 'eventNameFilters' | 'eventTypeFilters' | 'screenNameFilters' | 'screenAttributeFilters' | 'attributeFilters' | 'userIdentityFilters' | 'filteringEventAttributeValue'>;
4
6
  export declare function isBlockedByForwardingRule(messageType: number, attributes: Record<string, unknown> | null, forwarder: ForwarderFilterConfig): boolean;
5
7
  export declare function isBlockedByEventFilter(messageType: number, hashedEventName: number, hashedEventType: number, forwarder: ForwarderFilterConfig): boolean;
8
+ export declare function isEventForwarded(event: SDKEvent, forwarder: ForwarderFilterConfig, kitBlocker?: KitBlocker): boolean;
6
9
  export declare function filterEventAttributes(messageType: number, eventCategory: number, eventName: string, attributes: Record<string, unknown> | null, forwarder: ForwarderFilterConfig): Record<string, unknown> | null;
7
10
  export declare function filterUserIdentities(userIdentities: Array<{
8
11
  Type: number;
@@ -3,11 +3,23 @@ import { BaseEvent } from './sdkRuntimeModels';
3
3
  import { Dictionary } from './utils';
4
4
  export declare const WIN_APV_KEY = "__mpApv__";
5
5
  export declare const ALLOWED_QUERY_PARAMS: string[];
6
+ export declare const AUTO_PAGE_VIEW_ATTRIBUTE = "is_auto_page_view";
7
+ export declare const MAX_CUSTOM_QUERY_PARAMS = 25;
8
+ export interface IQueryParamAllowlist {
9
+ allowed: string[];
10
+ rejectedPositions: number[];
11
+ overLimit: number;
12
+ }
13
+ export declare const MAX_CUSTOM_QUERY_PARAM_VALUE_LENGTH = 512;
14
+ export interface ICapturedParam {
15
+ name: string;
16
+ value: string;
17
+ }
6
18
  export declare const ALLOWED_QUERY_PARAM_PREFIXES: string[];
7
19
  export declare const isAllowedQueryParam: (name: string) => boolean;
8
20
  interface IPageSnapshot {
9
21
  path: string;
10
- params: Dictionary<string>;
22
+ params: ICapturedParam[];
11
23
  }
12
24
  interface IPageViewData extends IPageSnapshot {
13
25
  hostname: string;
@@ -17,8 +29,10 @@ interface IPageViewData extends IPageSnapshot {
17
29
  export interface IPageViewOptions {
18
30
  isAutoPageView?: boolean;
19
31
  }
20
- export declare const allowedQueryParams: (href: string) => Dictionary<string>;
21
- export declare const AUTO_PAGE_VIEW_ATTRIBUTE = "is_auto_page_view";
32
+ export declare const parseQueryParamAllowlist: (configured: unknown) => IQueryParamAllowlist;
33
+ export declare const effectiveAllowlist: (extras?: string[]) => string[];
34
+ export declare const allowedQueryParams: (href: string, extras?: string[]) => ICapturedParam[];
35
+ export declare const paramsToAttributes: (params: ICapturedParam[]) => Dictionary<string>;
22
36
  export declare const autoPageViewAttribute: (isAutoPageView?: boolean) => Dictionary<boolean>;
23
37
  export declare const pageKey: (page: IPageSnapshot) => string;
24
38
  export declare const isNewPage: (lastKey: string | null, candidateKey: string) => boolean;
@@ -31,6 +45,7 @@ export declare class PageViewTracker {
31
45
  private readonly mpInstance;
32
46
  private lastPage;
33
47
  private active;
48
+ private customQueryParams;
34
49
  private pendingNavigations;
35
50
  private undoHistoryPatch;
36
51
  private readonly isAutoPageView;
@@ -38,6 +53,7 @@ export declare class PageViewTracker {
38
53
  get isActive(): boolean;
39
54
  init(): void;
40
55
  teardown(): void;
56
+ private readCustomQueryParams;
41
57
  private retire;
42
58
  private takePendingNavigations;
43
59
  private safeHandleNavigation;
@@ -102,6 +102,7 @@ export default class RoktManager {
102
102
  private isShoppableAdsLoaded;
103
103
  private stopRouteChangeWatch;
104
104
  private pendingCheckoutIntents;
105
+ private autoButtonClicksForwarded;
105
106
  constructor(instanceName?: string);
106
107
  /**
107
108
  * Sets a callback to be invoked when RoktManager becomes ready
@@ -127,12 +128,13 @@ export default class RoktManager {
127
128
  attachKit(kit: IRoktKit): void;
128
129
  private watchRouteChanges;
129
130
  private notifyRouteChange;
131
+ setAutoButtonClicksForwarded(forwarded: boolean): void;
130
132
  isCheckoutIntentSuppressed(): boolean;
131
133
  isCheckoutIntentLive(): boolean;
132
134
  notifyCheckoutIntent(signal: ICheckoutIntentSignal, pathname?: string): void;
133
135
  discardCheckoutIntents(): void;
134
136
  private flushCheckoutIntents;
135
- private isAutoLogPageViewEnabled;
137
+ isAutoLogPageViewEnabled(): boolean;
136
138
  /**
137
139
  * Renders ads based on the options provided
138
140
  *
@@ -223,6 +223,7 @@ export interface SDKInitConfig extends Omit<MPConfiguration, 'dataPlan' | 'logLe
223
223
  dataPlanOptions?: KitBlockerOptions;
224
224
  flags?: Dictionary;
225
225
  pixelConfigs?: IPixelConfiguration[];
226
+ autoLogPageViewQueryParams?: string;
226
227
  aliasMaxWindow?: number;
227
228
  deviceId?: string;
228
229
  forceHttps?: boolean;
@@ -1,6 +1,7 @@
1
1
  import { Batch } from '@mparticle/event-models';
2
2
  import { MPID, IdentifyRequest, SDKEventCustomFlags, ConsentState, UserIdentities } from '@mparticle/web-sdk';
3
3
  import { IKitConfigs } from './configAPIClient';
4
+ import { IQueryParamAllowlist } from './pageViewTracker';
4
5
  import { DataPlanResult, KitBlockerOptions, LogLevelType, SDKDataPlan, SDKEvent, SDKGeoLocation, SDKInitConfig, SDKProduct } from './sdkRuntimeModels';
5
6
  import { Dictionary, AttributeValue } from './utils';
6
7
  import { SDKConsentState } from './consent';
@@ -25,6 +26,7 @@ export interface SDKConfig {
25
26
  appVersion?: string;
26
27
  package?: string;
27
28
  flags?: IFeatureFlags;
29
+ autoLogPageViewQueryParams?: IQueryParamAllowlist;
28
30
  kitConfigs: IKitConfigs[];
29
31
  kits: Dictionary<UnregisteredKit>;
30
32
  logLevel?: LogLevelType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-sdk",
3
- "version": "3.23.0",
3
+ "version": "3.24.0",
4
4
  "description": "mParticle core SDK for web applications",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -101,20 +101,18 @@
101
101
  "lint"
102
102
  ],
103
103
  "devDependencies": {
104
- "@babel/core": "^7.18.6",
105
- "@babel/eslint-parser": "^7.18.2",
106
- "@babel/eslint-plugin": "^7.17.7",
107
- "@babel/plugin-proposal-class-properties": "^7.5.5",
108
- "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
109
- "@babel/plugin-transform-runtime": "^7.6.0",
110
- "@babel/preset-env": "^7.6.0",
111
- "@babel/preset-typescript": "^7.6.0",
104
+ "@babel/core": "^8.0.7",
105
+ "@babel/plugin-transform-runtime": "^8.0.6",
106
+ "@babel/preset-env": "^8.0.7",
107
+ "@babel/preset-typescript": "^8.0.7",
108
+ "@babel/runtime": "^8.0.7",
112
109
  "@mparticle/data-planning-models": "^0.1.0",
113
110
  "@mparticle/event-models": "^1.3.1",
114
- "@rollup/plugin-babel": "6.0.3",
111
+ "@rollup/plugin-babel": "^7.1.0",
115
112
  "@rollup/plugin-commonjs": "25.0.4",
116
113
  "@rollup/plugin-json": "^5.0.2",
117
114
  "@rollup/plugin-node-resolve": "15.2.1",
115
+ "@rollup/plugin-terser": "^1.0.1",
118
116
  "@rollup/plugin-typescript": "^11.1.0",
119
117
  "@semantic-release/changelog": "^6.0.3",
120
118
  "@semantic-release/exec": "^6.0.3",
@@ -126,7 +124,7 @@
126
124
  "@types/mocha": "^9.0.0",
127
125
  "@types/mparticle__web-sdk": "^2.66.0",
128
126
  "@types/node": "^20.1.0",
129
- "babel-preset-minify": "^0.5.1",
127
+ "babel-plugin-polyfill-corejs3": "^1.0.0",
130
128
  "browser-sync": "^2.26.3",
131
129
  "browserify": "^17.0.0",
132
130
  "chai": "^4.2.0",
@@ -159,7 +157,7 @@
159
157
  "shelljs": "^0.8.4",
160
158
  "should": "^7.1.0",
161
159
  "sinon": "^16.1.3",
162
- "ts-jest": "^29.1.0",
160
+ "ts-jest": "^29.4.15",
163
161
  "tslib": "^2.1.0",
164
162
  "typescript": "^5.0.2",
165
163
  "uglify-js": "^3.4.9",
@@ -169,7 +167,16 @@
169
167
  "peerDependencies": {
170
168
  "@mparticle/event-models": "^1.3.1"
171
169
  },
172
- "dependencies": {
173
- "@babel/runtime": "^7.23.2"
170
+ "overrides": {
171
+ "@rollup/plugin-babel": {
172
+ "@babel/core": "$@babel/core"
173
+ }
174
+ },
175
+ "devEngines": {
176
+ "runtime": {
177
+ "name": "node",
178
+ "version": "^22.18.0 || >=24.11.0",
179
+ "onFail": "warn"
180
+ }
174
181
  }
175
182
  }
@@ -1,4 +1,8 @@
1
- import { BaseEvent } from '../sdkRuntimeModels';
1
+ import { IKitFilterSettings } from '../configAPIClient';
2
+ import { isEventForwarded } from '../forwarder-utils';
3
+ import type KitBlocker from '../kitBlocking';
4
+ import KitFilterHelper from '../kitFilterHelper';
5
+ import { BaseEvent, SDKEvent } from '../sdkRuntimeModels';
2
6
  import { EventType, MessageType } from '../types';
3
7
  import { IButtonClick } from './buttonDescription';
4
8
 
@@ -52,3 +56,74 @@ export const buildButtonClickEvent = (
52
56
  eventType: EventType.Other,
53
57
  };
54
58
  };
59
+
60
+ // Every attribute buildButtonClickEvent can set apart from the marker and the
61
+ // hostname, which is the same on every click on this page. A spec checks the
62
+ // two stay in step.
63
+ const CLICK_ATTRIBUTES = [
64
+ 'label_source',
65
+ 'element',
66
+ 'type',
67
+ 'path',
68
+ 'label',
69
+ 'aria_label',
70
+ 'icon',
71
+ 'element_id',
72
+ 'element_name',
73
+ 'test_id',
74
+ 'controls',
75
+ 'form',
76
+ 'link_type',
77
+ 'link_domain',
78
+ 'file_extension',
79
+ 'checked',
80
+ ];
81
+
82
+ export type ButtonClickBlocker =
83
+ | 'data plan'
84
+ | 'forwarding rule'
85
+ | 'event name filter'
86
+ | 'event type filter';
87
+
88
+ // Which check keeps some or all auto button clicks from a kit, or undefined
89
+ // when the kit receives every one. A forwarding rule on an attribute whose
90
+ // value differs between clicks lets some through and not others. Each other
91
+ // check goes through isEventForwarded on its own, so together they decide as
92
+ // it does for each click.
93
+ export const getButtonClickBlocker = (
94
+ forwarder: IKitFilterSettings,
95
+ kitBlocker?: KitBlocker
96
+ ): ButtonClickBlocker | undefined => {
97
+ const rule = forwarder.filteringEventAttributeValue;
98
+ if (
99
+ rule &&
100
+ rule.eventAttributeValue &&
101
+ CLICK_ATTRIBUTES.some(
102
+ name =>
103
+ KitFilterHelper.hashAttributeConditionalForwarding(name) ===
104
+ rule.eventAttributeName
105
+ )
106
+ ) {
107
+ return 'forwarding rule';
108
+ }
109
+ const click = ({
110
+ EventName: BUTTON_CLICK_EVENT_NAME,
111
+ EventCategory: EventType.Other,
112
+ EventDataType: MessageType.PageEvent,
113
+ EventAttributes: {
114
+ [AUTO_BUTTON_ATTRIBUTE]: true,
115
+ hostname: window.location.hostname,
116
+ },
117
+ } as unknown) as SDKEvent;
118
+ const checks: Array<[ButtonClickBlocker, Partial<IKitFilterSettings>]> = [
119
+ ['data plan', {}],
120
+ ['forwarding rule', { filteringEventAttributeValue: rule }],
121
+ ['event name filter', { eventNameFilters: forwarder.eventNameFilters }],
122
+ ['event type filter', { eventTypeFilters: forwarder.eventTypeFilters }],
123
+ ];
124
+ const failed = checks.find(
125
+ ([, filters]) =>
126
+ !isEventForwarded(click, filters as IKitFilterSettings, kitBlocker)
127
+ );
128
+ return failed ? failed[0] : undefined;
129
+ };