clarity-js 0.8.15 → 0.8.16
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/build/clarity.extended.js +1 -1
- package/build/clarity.insight.js +1 -1
- package/build/clarity.js +105 -27
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +105 -27
- package/build/clarity.performance.js +1 -1
- package/package.json +1 -1
- package/rollup.config.ts +5 -3
- package/src/clarity.ts +1 -1
- package/src/core/version.ts +1 -1
- package/src/data/consent.ts +21 -3
- package/src/data/encode.ts +8 -0
- package/src/data/index.ts +3 -1
- package/src/data/metadata.ts +57 -12
- package/src/data/upload.ts +4 -0
- package/src/interaction/scroll.ts +4 -0
- package/src/layout/style.ts +1 -1
- package/src/performance/observer.ts +10 -3
- package/types/data.d.ts +22 -3
- package/types/index.d.ts +1 -0
package/src/data/metadata.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Time } from "@clarity-types/core";
|
|
2
|
-
import { BooleanFlag, Constant, Dimension, Metadata, MetadataCallback, MetadataCallbackOptions, Metric, Session, User, Setting } from "@clarity-types/data";
|
|
2
|
+
import { BooleanFlag, Constant, Dimension, Metadata, MetadataCallback, MetadataCallbackOptions, Metric, Session, User, Setting, ConsentState, ConsentSource, ConsentData } from "@clarity-types/data";
|
|
3
3
|
import * as clarity from "@src/clarity";
|
|
4
4
|
import * as core from "@src/core";
|
|
5
5
|
import config from "@src/core/config";
|
|
@@ -15,6 +15,8 @@ export let data: Metadata = null;
|
|
|
15
15
|
export let callbacks: MetadataCallbackOptions[] = [];
|
|
16
16
|
export let electron = BooleanFlag.False;
|
|
17
17
|
let rootDomain = null;
|
|
18
|
+
let consentStatus: ConsentState = null;
|
|
19
|
+
let defaultStatus: ConsentState = {ad_Storage: Constant.Denied, analytics_Storage: Constant.Denied};
|
|
18
20
|
|
|
19
21
|
export function start(): void {
|
|
20
22
|
rootDomain = null;
|
|
@@ -84,8 +86,12 @@ export function start(): void {
|
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
// Track consent config
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
consentStatus = {
|
|
90
|
+
ad_Storage: config.track ? Constant.Granted : Constant.Denied,
|
|
91
|
+
analytics_Storage: config.track ? Constant.Granted : Constant.Denied,
|
|
92
|
+
}
|
|
93
|
+
const consent = getConsentData(consentStatus, ConsentSource.Implicit);
|
|
94
|
+
trackConsent.config(consent);
|
|
89
95
|
// Track ids using a cookie if configuration allows it
|
|
90
96
|
track(u);
|
|
91
97
|
}
|
|
@@ -106,10 +112,11 @@ function userAgentData(): void {
|
|
|
106
112
|
export function stop(): void {
|
|
107
113
|
rootDomain = null;
|
|
108
114
|
data = null;
|
|
115
|
+
consentStatus = null;
|
|
109
116
|
callbacks.forEach(cb => { cb.called = false; });
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
export function metadata(cb: MetadataCallback, wait: boolean = true, recall: boolean = false): void {
|
|
119
|
+
export function metadata(cb: MetadataCallback, wait: boolean = true, recall: boolean = false, consentInfo: boolean = false): void {
|
|
113
120
|
let upgraded = config.lean ? BooleanFlag.False : BooleanFlag.True;
|
|
114
121
|
let called = false;
|
|
115
122
|
// if caller hasn't specified that they want to skip waiting for upgrade but we've already upgraded, we need to
|
|
@@ -117,11 +124,11 @@ export function metadata(cb: MetadataCallback, wait: boolean = true, recall: boo
|
|
|
117
124
|
// we go through the upgrading flow.
|
|
118
125
|
if (data && (upgraded || wait === false)) {
|
|
119
126
|
// Immediately invoke the callback if the caller explicitly doesn't want to wait for the upgrade confirmation
|
|
120
|
-
cb(data, !config.lean);
|
|
127
|
+
cb(data, !config.lean, consentInfo? consentStatus : undefined);
|
|
121
128
|
called = true;
|
|
122
129
|
}
|
|
123
130
|
if (recall || !called) {
|
|
124
|
-
callbacks.push({ callback: cb, wait, recall, called });
|
|
131
|
+
callbacks.push({ callback: cb, wait, recall, called, consentInfo });
|
|
125
132
|
}
|
|
126
133
|
}
|
|
127
134
|
|
|
@@ -129,8 +136,27 @@ export function id(): string {
|
|
|
129
136
|
return data ? [data.userId, data.sessionId, data.pageNum].join(Constant.Dot) : Constant.Empty;
|
|
130
137
|
}
|
|
131
138
|
|
|
132
|
-
|
|
139
|
+
//TODO: Remove this function once consentv2 is fully released
|
|
140
|
+
export function consent(status = true): void {
|
|
133
141
|
if (!status) {
|
|
142
|
+
consentv2();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
consentv2({ ad_Storage: Constant.Granted, analytics_Storage: Constant.Granted });
|
|
147
|
+
trackConsent.consent();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function consentv2(consentState: ConsentState = defaultStatus, source: number = ConsentSource.API): void {
|
|
151
|
+
consentStatus = {
|
|
152
|
+
ad_Storage: normalizeConsent(consentState.ad_Storage),
|
|
153
|
+
analytics_Storage: normalizeConsent(consentState.analytics_Storage)
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
callback(true);
|
|
157
|
+
const consentData = getConsentData(consentStatus, source);
|
|
158
|
+
|
|
159
|
+
if (!consentData.analytics_Storage) {
|
|
134
160
|
config.track = false;
|
|
135
161
|
setCookie(Constant.SessionKey, Constant.Empty, -Number.MAX_VALUE);
|
|
136
162
|
setCookie(Constant.CookieKey, Constant.Empty, -Number.MAX_VALUE);
|
|
@@ -143,10 +169,25 @@ export function consent(status: boolean = true): void {
|
|
|
143
169
|
config.track = true;
|
|
144
170
|
track(user(), BooleanFlag.True);
|
|
145
171
|
save();
|
|
172
|
+
trackConsent.consentv2(consentData);
|
|
146
173
|
trackConsent.consent();
|
|
147
174
|
}
|
|
148
175
|
}
|
|
149
176
|
|
|
177
|
+
function getConsentData(consentState: ConsentState, source : ConsentSource): ConsentData {
|
|
178
|
+
let consent: ConsentData = {
|
|
179
|
+
source: source,
|
|
180
|
+
ad_Storage: consentState.ad_Storage === Constant.Granted ? BooleanFlag.True : BooleanFlag.False,
|
|
181
|
+
analytics_Storage: consentState.analytics_Storage === Constant.Granted ? BooleanFlag.True : BooleanFlag.False,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return consent;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function normalizeConsent(value: unknown): string {
|
|
188
|
+
return typeof value === 'string' ? value.toLowerCase() : Constant.Denied;
|
|
189
|
+
}
|
|
190
|
+
|
|
150
191
|
export function clear(): void {
|
|
151
192
|
// Clear any stored information in the cookie that tracks session information so we can restart fresh the next time
|
|
152
193
|
setCookie(Constant.SessionKey, Constant.Empty, 0);
|
|
@@ -162,9 +203,9 @@ function tab(): string {
|
|
|
162
203
|
return id;
|
|
163
204
|
}
|
|
164
205
|
|
|
165
|
-
export function callback(): void {
|
|
206
|
+
export function callback(consentUpdate:boolean = false): void {
|
|
166
207
|
let upgrade = config.lean ? BooleanFlag.False : BooleanFlag.True;
|
|
167
|
-
processCallback(upgrade);
|
|
208
|
+
processCallback(upgrade, consentUpdate);
|
|
168
209
|
}
|
|
169
210
|
|
|
170
211
|
export function save(): void {
|
|
@@ -175,12 +216,16 @@ export function save(): void {
|
|
|
175
216
|
setCookie(Constant.SessionKey, [data.sessionId, ts, data.pageNum, upgrade, upload].join(Constant.Pipe), Setting.SessionExpire);
|
|
176
217
|
}
|
|
177
218
|
|
|
178
|
-
function processCallback(upgrade: BooleanFlag) {
|
|
219
|
+
function processCallback(upgrade: BooleanFlag, consentUpdate: boolean = false): void {
|
|
179
220
|
if (callbacks.length > 0) {
|
|
180
221
|
for (let i = 0; i < callbacks.length; i++) {
|
|
181
222
|
const cb = callbacks[i];
|
|
182
|
-
if (
|
|
183
|
-
cb.callback
|
|
223
|
+
if (
|
|
224
|
+
cb.callback &&
|
|
225
|
+
((!cb.called && !consentUpdate) || (cb.consentInfo && consentUpdate)) && //If consentUpdate is true, we only call the callback if it has consentInfo
|
|
226
|
+
(!cb.wait || upgrade)
|
|
227
|
+
) {
|
|
228
|
+
cb.callback(data, !config.lean, cb.consentInfo ? consentStatus : undefined);
|
|
184
229
|
cb.called = true;
|
|
185
230
|
if (!cb.recall) {
|
|
186
231
|
callbacks.splice(i, 1);
|
package/src/data/upload.ts
CHANGED
|
@@ -134,6 +134,10 @@ async function upload(final: boolean = false): Promise<void> {
|
|
|
134
134
|
// could inject function arguments for internal tracking (likely stack traces for script errors).
|
|
135
135
|
// For these edge cases, we want to ensure that an injected object (e.g. {"key": "value"}) isn't mistaken to be true.
|
|
136
136
|
let last = final === true;
|
|
137
|
+
|
|
138
|
+
// In some cases envelope has null data because it's part of the shutdown process while there's one upload call queued which might introduce runtime error
|
|
139
|
+
if(!envelope.data) return;
|
|
140
|
+
|
|
137
141
|
let e = JSON.stringify(envelope.envelope(last));
|
|
138
142
|
let a = `[${analysis.join()}]`;
|
|
139
143
|
|
|
@@ -33,6 +33,10 @@ function recompute(event: UIEvent = null): void {
|
|
|
33
33
|
let de = document.documentElement;
|
|
34
34
|
let element = event ? target(event) : de;
|
|
35
35
|
|
|
36
|
+
// In some edge cases, it's possible for target to be null.
|
|
37
|
+
// In those cases, we cannot proceed with scroll event instrumentation.
|
|
38
|
+
if (!element) { return; }
|
|
39
|
+
|
|
36
40
|
// If the target is a Document node, then identify corresponding documentElement and window for this document
|
|
37
41
|
if (element && element.nodeType === Node.DOCUMENT_NODE) {
|
|
38
42
|
let frame = iframe(element);
|
package/src/layout/style.ts
CHANGED
|
@@ -99,10 +99,17 @@ export function stop(): void {
|
|
|
99
99
|
if (observer) { observer.disconnect(); }
|
|
100
100
|
observer = null;
|
|
101
101
|
interaction.resetInteractions();
|
|
102
|
+
anchorCache = null;
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
// Cached anchor element for optimal performance & memory management
|
|
106
|
+
let anchorCache: HTMLAnchorElement | null = null;
|
|
107
|
+
|
|
104
108
|
function host(url: string): string {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
if (!anchorCache) {
|
|
110
|
+
anchorCache = document.createElement("a");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
anchorCache.href = url;
|
|
114
|
+
return anchorCache.host;
|
|
108
115
|
}
|
package/types/data.d.ts
CHANGED
|
@@ -3,12 +3,13 @@ export type Target = (number | Node);
|
|
|
3
3
|
export type Token = (string | number | number[] | string[] | (string | number)[]);
|
|
4
4
|
export type DecodedToken = (any | any[]);
|
|
5
5
|
|
|
6
|
-
export type MetadataCallback = (data: Metadata, playback: boolean) => void;
|
|
6
|
+
export type MetadataCallback = (data: Metadata, playback: boolean, consentStatus?: ConsentState) => void;
|
|
7
7
|
export interface MetadataCallbackOptions {
|
|
8
8
|
callback: MetadataCallback,
|
|
9
9
|
wait: boolean,
|
|
10
10
|
recall: boolean,
|
|
11
|
-
called: boolean
|
|
11
|
+
called: boolean,
|
|
12
|
+
consentInfo: boolean
|
|
12
13
|
}
|
|
13
14
|
export type SignalCallback = (data: ClaritySignal) => void
|
|
14
15
|
|
|
@@ -71,6 +72,7 @@ export const enum Event {
|
|
|
71
72
|
Animation = 44,
|
|
72
73
|
StyleSheetAdoption = 45,
|
|
73
74
|
StyleSheetUpdate = 46,
|
|
75
|
+
Consent = 47,
|
|
74
76
|
|
|
75
77
|
// Apps specific events
|
|
76
78
|
WebViewDiscover = 100,
|
|
@@ -347,6 +349,8 @@ export const enum Constant {
|
|
|
347
349
|
SHA256 = "SHA-256",
|
|
348
350
|
Electron = "Electron",
|
|
349
351
|
Caret = "^",
|
|
352
|
+
Granted = "granted",
|
|
353
|
+
Denied = "denied",
|
|
350
354
|
}
|
|
351
355
|
|
|
352
356
|
export const enum XMLReadyState {
|
|
@@ -357,6 +361,10 @@ export const enum XMLReadyState {
|
|
|
357
361
|
Done = 4
|
|
358
362
|
}
|
|
359
363
|
|
|
364
|
+
export const enum ConsentSource{
|
|
365
|
+
Implicit = 0,
|
|
366
|
+
API = 1
|
|
367
|
+
}
|
|
360
368
|
|
|
361
369
|
/* Helper Interfaces */
|
|
362
370
|
|
|
@@ -514,4 +522,15 @@ export interface PerformanceEventTiming extends PerformanceEntry {
|
|
|
514
522
|
export interface Interaction {
|
|
515
523
|
id: number;
|
|
516
524
|
latency: number;
|
|
517
|
-
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export interface ConsentState {
|
|
528
|
+
ad_Storage?: string;
|
|
529
|
+
analytics_Storage?: string;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export interface ConsentData {
|
|
533
|
+
source: ConsentSource;
|
|
534
|
+
ad_Storage: BooleanFlag;
|
|
535
|
+
analytics_Storage: BooleanFlag;
|
|
536
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ interface Clarity {
|
|
|
12
12
|
resume: () => void;
|
|
13
13
|
upgrade: (key: string) => void;
|
|
14
14
|
consent: () => void;
|
|
15
|
+
consentv2: () => void;
|
|
15
16
|
event: (name: string, value: string) => void;
|
|
16
17
|
set: (variable: string, value: string | string[]) => void;
|
|
17
18
|
identify: (userId: string, sessionId?: string, pageId?: string, userHint?: string) => void;
|