react-marketing-tools 1.0.0-alpha.2 → 1.0.0-alpha.3
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/dist/chunks/core.js +170 -66
- package/dist/core/consent.d.ts +20 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/types.d.ts +48 -3
- package/dist/core.d.ts +1 -1
- package/dist/destinations/ga4.d.ts +6 -0
- package/dist/destinations/googleTag.d.ts +22 -0
- package/dist/destinations/gtm.d.ts +1 -1
- package/dist/destinations/loadScript.d.ts +6 -0
- package/package.json +1 -16
- package/dist/analytics/analyticsEventService.d.ts +0 -13
- package/dist/analytics/ga4GoogleAnalyticsEventTracking.d.ts +0 -3
- package/dist/analytics/handleDataLayerPush.d.ts +0 -3
- package/dist/analytics/helpers.d.ts +0 -41
- package/dist/buildConfig/index.d.ts +0 -8
- package/dist/ipInfo/index.d.ts +0 -3
- package/dist/types/index.d.ts +0 -130
- package/dist/utilities/assertValueCheckers.d.ts +0 -1
- package/dist/utilities/commonFunctions.d.ts +0 -5
- package/dist/utilities/cookies.d.ts +0 -1
package/dist/chunks/core.js
CHANGED
|
@@ -1,154 +1,258 @@
|
|
|
1
|
-
//#region lib/
|
|
2
|
-
var e =
|
|
1
|
+
//#region lib/core/consent.ts
|
|
2
|
+
var e = [
|
|
3
|
+
"analytics",
|
|
4
|
+
"ads",
|
|
5
|
+
"adUserData",
|
|
6
|
+
"adPersonalization"
|
|
7
|
+
], t = (e) => e === "granted" || e === "denied", n = ({ consent: e, gpc: t }) => {
|
|
8
|
+
let n = t ? "denied" : e;
|
|
9
|
+
return {
|
|
10
|
+
analytics: e,
|
|
11
|
+
ads: n,
|
|
12
|
+
adUserData: n,
|
|
13
|
+
adPersonalization: n
|
|
14
|
+
};
|
|
15
|
+
}, r = (e, t) => ({
|
|
16
|
+
analytics: t.analytics ?? e.analytics,
|
|
17
|
+
ads: t.ads ?? e.ads,
|
|
18
|
+
adUserData: t.adUserData ?? t.ads ?? e.adUserData,
|
|
19
|
+
adPersonalization: t.adPersonalization ?? t.ads ?? e.adPersonalization
|
|
20
|
+
}), i = (e) => ({
|
|
21
|
+
analytics_storage: e.analytics,
|
|
22
|
+
ad_storage: e.ads,
|
|
23
|
+
ad_user_data: e.adUserData,
|
|
24
|
+
ad_personalization: e.adPersonalization
|
|
25
|
+
}), a = (e) => Object.values(e).includes("denied"), o = () => typeof navigator < "u" && navigator.globalPrivacyControl === !0, s = () => window.dataLayer ??= [], c = () => Array.from(document.scripts).some((e) => URL.canParse(e.src) && new URL(e.src).pathname.endsWith("/gtag/js")), l = () => window.gtag ??= function() {
|
|
26
|
+
s().push(arguments);
|
|
27
|
+
}, u = ({ consent: e, waitForUpdate: t }) => {
|
|
28
|
+
l()("consent", "default", {
|
|
29
|
+
...i(e),
|
|
30
|
+
...a(e) ? { wait_for_update: t } : {}
|
|
31
|
+
});
|
|
32
|
+
}, d = (e) => {
|
|
33
|
+
l()("consent", "update", i(e));
|
|
34
|
+
}, f = (e, t) => {
|
|
35
|
+
let n = URL.canParse(e) ? new URL(e) : void 0;
|
|
36
|
+
if (n?.protocol !== "https:") throw Error(`[react-marketing-tools] ${t} must be an https:// URL (received ${JSON.stringify(e)}).`);
|
|
37
|
+
return n;
|
|
38
|
+
}, p = (e) => Array.from(document.scripts).some((t) => t.src === e), m = ({ src: e, nonce: t }) => {
|
|
3
39
|
let n = document.createElement("script");
|
|
4
40
|
n.async = !0, n.src = e, t && n.setAttribute("nonce", t), document.head.append(n);
|
|
5
|
-
},
|
|
6
|
-
if (!
|
|
7
|
-
|
|
41
|
+
}, h = /^G-[A-Z0-9]+$/, g = ({ measurementId: e, pageViews: t = "auto", loadScript: n = !0, serverContainerUrl: r, waitForUpdate: i = 500, nonce: a }) => {
|
|
42
|
+
if (!h.test(e)) throw Error(`[react-marketing-tools] ga4.measurementId must look like "G-XXXXXXX" (received ${JSON.stringify(e)}).`);
|
|
43
|
+
r !== void 0 && f(r, "ga4.serverContainerUrl");
|
|
44
|
+
let o = `https://www.googletagmanager.com/gtag/js?id=${e}`, s = (e, t) => r ? {
|
|
45
|
+
...e,
|
|
46
|
+
event_id: t
|
|
47
|
+
} : e;
|
|
48
|
+
return {
|
|
49
|
+
name: "ga4",
|
|
50
|
+
start({ consent: s }) {
|
|
51
|
+
u({
|
|
52
|
+
consent: s,
|
|
53
|
+
waitForUpdate: i
|
|
54
|
+
}), c() || (l()("js", /* @__PURE__ */ new Date()), n && m({
|
|
55
|
+
src: o,
|
|
56
|
+
nonce: a
|
|
57
|
+
})), l()("config", e, {
|
|
58
|
+
...t === "manual" ? { send_page_view: !1 } : {},
|
|
59
|
+
...r ? { server_container_url: r } : {}
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
track({ name: e, params: t, eventId: n }) {
|
|
63
|
+
l()("event", e, s(t, n));
|
|
64
|
+
},
|
|
65
|
+
consent(e) {
|
|
66
|
+
d(e);
|
|
67
|
+
},
|
|
68
|
+
page({ params: e, eventId: n }) {
|
|
69
|
+
t === "manual" && l()("event", "page_view", s(e, n));
|
|
70
|
+
},
|
|
71
|
+
identify({ userId: e }) {
|
|
72
|
+
l()("set", { user_id: e });
|
|
73
|
+
},
|
|
74
|
+
reset() {
|
|
75
|
+
l()("set", { user_id: null });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}, _ = /^GTM-[A-Z0-9]+$/, v = (e, t) => {
|
|
79
|
+
let n = f(t ?? "https://www.googletagmanager.com/gtm.js", "gtm.scriptUrl");
|
|
80
|
+
return n.searchParams.set("id", e), n.href;
|
|
81
|
+
}, y = ({ containerId: e, loadScript: t = !0, scriptUrl: n, waitForUpdate: r = 500, nonce: i }) => {
|
|
82
|
+
if (!_.test(e)) throw Error(`[react-marketing-tools] gtm.containerId must look like "GTM-XXXXXXX" (received ${JSON.stringify(e)}).`);
|
|
83
|
+
let a = v(e, n);
|
|
8
84
|
return {
|
|
9
85
|
name: "gtm",
|
|
10
|
-
start() {
|
|
11
|
-
|
|
12
|
-
|
|
86
|
+
start({ consent: e }) {
|
|
87
|
+
u({
|
|
88
|
+
consent: e,
|
|
89
|
+
waitForUpdate: r
|
|
90
|
+
}), t && !p(a) && (s().push({
|
|
13
91
|
"gtm.start": Date.now(),
|
|
14
92
|
event: "gtm.js"
|
|
15
|
-
}),
|
|
16
|
-
src:
|
|
17
|
-
nonce:
|
|
93
|
+
}), m({
|
|
94
|
+
src: a,
|
|
95
|
+
nonce: i
|
|
18
96
|
}));
|
|
19
97
|
},
|
|
20
|
-
track({ name: e, params:
|
|
21
|
-
|
|
22
|
-
...
|
|
98
|
+
track({ name: e, params: t, eventId: n }) {
|
|
99
|
+
s().push({
|
|
100
|
+
...t,
|
|
23
101
|
event: e,
|
|
24
|
-
event_id:
|
|
102
|
+
event_id: n
|
|
25
103
|
});
|
|
26
104
|
},
|
|
105
|
+
consent(e) {
|
|
106
|
+
d(e);
|
|
107
|
+
},
|
|
27
108
|
identify({ userId: e }) {
|
|
28
|
-
|
|
109
|
+
s().push({
|
|
29
110
|
event: "identify",
|
|
30
111
|
user_id: e
|
|
31
112
|
});
|
|
32
113
|
},
|
|
33
114
|
reset() {
|
|
34
|
-
|
|
115
|
+
s().push({
|
|
35
116
|
event: "reset",
|
|
36
117
|
user_id: void 0
|
|
37
118
|
});
|
|
38
119
|
}
|
|
39
120
|
};
|
|
40
|
-
},
|
|
121
|
+
}, b = class extends Error {
|
|
41
122
|
code;
|
|
42
123
|
constructor(e, t, n) {
|
|
43
124
|
super(`[react-marketing-tools] ${t}`, n), this.name = "AnalyticsError", this.code = e;
|
|
44
125
|
}
|
|
45
|
-
},
|
|
126
|
+
}, x = /^[A-Za-z][A-Za-z0-9_]{0,39}$/, S = [
|
|
46
127
|
"google_",
|
|
47
128
|
"ga_",
|
|
48
129
|
"firebase_"
|
|
49
|
-
],
|
|
130
|
+
], C = 25, w = 100, T = {
|
|
50
131
|
page_location: 1e3,
|
|
51
132
|
page_referrer: 420,
|
|
52
133
|
page_title: 300
|
|
53
|
-
},
|
|
134
|
+
}, E = [
|
|
54
135
|
"email",
|
|
55
136
|
"phone",
|
|
56
137
|
"first_name",
|
|
57
138
|
"last_name",
|
|
58
139
|
"address",
|
|
59
140
|
"password"
|
|
60
|
-
],
|
|
61
|
-
if (!
|
|
62
|
-
let t =
|
|
141
|
+
], D = String.raw`[\w.+-]+(?:@|%40)[\w-]+(?:\.[\w-]+)+`, O = "[redacted]", k = (e) => {
|
|
142
|
+
if (!x.test(e)) return "must start with a letter, contain only letters, digits and underscores, and be at most 40 characters";
|
|
143
|
+
let t = S.find((t) => e.toLowerCase().startsWith(t));
|
|
63
144
|
return t && `must not start with the reserved prefix "${t}"`;
|
|
64
|
-
},
|
|
65
|
-
let t =
|
|
145
|
+
}, A = (e) => {
|
|
146
|
+
let t = k(e);
|
|
66
147
|
return t && `event name "${e}" ${t}`;
|
|
67
|
-
},
|
|
148
|
+
}, j = (e) => {
|
|
68
149
|
let t = Object.keys(e), n = t.flatMap((t) => {
|
|
69
|
-
let n =
|
|
150
|
+
let n = k(t);
|
|
70
151
|
if (n) return [`param "${t}" ${n}`];
|
|
71
|
-
let r = e[t], i =
|
|
152
|
+
let r = e[t], i = T[t] ?? w;
|
|
72
153
|
return typeof r == "string" && r.length > i ? [`param "${t}" is longer than ${i} characters`] : [];
|
|
73
154
|
});
|
|
74
|
-
return t.length >
|
|
75
|
-
},
|
|
155
|
+
return t.length > C ? [`has ${t.length} params; the limit is ${C}`, ...n] : n;
|
|
156
|
+
}, M = (e) => new RegExp(D, "i").test(e), N = (e, t) => (typeof t == "string" || typeof t == "number") && E.some((t) => e.toLowerCase().includes(t)) ? O : typeof t == "string" ? t.replace(new RegExp(D, "gi"), O) : t, P = (e) => {
|
|
76
157
|
let t = Object.entries(e).map(([e, t]) => [
|
|
77
158
|
e,
|
|
78
159
|
t,
|
|
79
|
-
|
|
160
|
+
N(e, t)
|
|
80
161
|
]);
|
|
81
162
|
return {
|
|
82
163
|
params: Object.fromEntries(t.map(([e, , t]) => [e, t])),
|
|
83
164
|
redactedKeys: t.filter(([, e, t]) => t !== e).map(([e]) => e)
|
|
84
165
|
};
|
|
85
|
-
},
|
|
166
|
+
}, F = () => typeof window < "u", I = () => typeof crypto.randomUUID == "function" ? crypto.randomUUID() : "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (e) => (Number(e) ^ crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(1))[0] & 15 >> Number(e) / 4).toString(16)), L = (e) => {
|
|
86
167
|
if (e.consent !== "granted" && e.consent !== "denied") throw Error(`[react-marketing-tools] createAnalytics: "consent" must be 'granted' or 'denied' (received ${JSON.stringify(e.consent)}).`);
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
let { debug:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
168
|
+
}, R = (i) => {
|
|
169
|
+
L(i);
|
|
170
|
+
let { debug: a = !1, onError: s = console.error, respectGpc: c = !0 } = i, l = n({
|
|
171
|
+
consent: i.consent,
|
|
172
|
+
gpc: c && o()
|
|
173
|
+
}), u = l, d = [
|
|
174
|
+
...i.gtm ? [y({
|
|
175
|
+
...i.gtm,
|
|
176
|
+
nonce: i.nonce
|
|
177
|
+
})] : [],
|
|
178
|
+
...i.ga4 ? [g({
|
|
179
|
+
...i.ga4,
|
|
180
|
+
nonce: i.nonce
|
|
181
|
+
})] : [],
|
|
182
|
+
...i.destinations ?? []
|
|
183
|
+
], f = [], p = !1, m = (e) => {
|
|
184
|
+
if (a) throw e;
|
|
185
|
+
s(e);
|
|
186
|
+
}, h = (e) => {
|
|
187
|
+
for (let t of d) try {
|
|
97
188
|
e(t);
|
|
98
189
|
} catch (e) {
|
|
99
|
-
|
|
190
|
+
s(new b("destination_failed", `destination "${t.name}" failed`, { cause: e }));
|
|
100
191
|
}
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
},
|
|
104
|
-
let n =
|
|
192
|
+
}, _ = (e) => {
|
|
193
|
+
p ? h(e) : f.push(e);
|
|
194
|
+
}, v = (e, t) => {
|
|
195
|
+
let n = A(e);
|
|
105
196
|
if (n) {
|
|
106
|
-
|
|
197
|
+
m(new b("invalid_event", n));
|
|
107
198
|
return;
|
|
108
199
|
}
|
|
109
|
-
for (let n of
|
|
110
|
-
let { params: r, redactedKeys: i } =
|
|
111
|
-
return i.length > 0 &&
|
|
200
|
+
for (let n of j(t)) m(new b("invalid_param", `event "${e}" ${n}`));
|
|
201
|
+
let { params: r, redactedKeys: i } = P(t);
|
|
202
|
+
return i.length > 0 && m(new b("pii_redacted", `event "${e}": personal data redacted from ${i.join(", ")}`)), {
|
|
112
203
|
name: e,
|
|
113
204
|
params: r,
|
|
114
|
-
eventId:
|
|
205
|
+
eventId: I(),
|
|
115
206
|
timestamp: Date.now()
|
|
116
207
|
};
|
|
117
208
|
};
|
|
118
209
|
return {
|
|
119
210
|
start() {
|
|
120
|
-
!
|
|
211
|
+
!p && F() && (p = !0, h((e) => e.start({ consent: l })), f.splice(0).forEach(h));
|
|
121
212
|
},
|
|
122
213
|
track(e, t = {}) {
|
|
123
|
-
if (!
|
|
124
|
-
let n =
|
|
125
|
-
n &&
|
|
214
|
+
if (!F()) return;
|
|
215
|
+
let n = v(e, t);
|
|
216
|
+
n && _((e) => e.track(n));
|
|
126
217
|
},
|
|
127
218
|
page(e = {}) {
|
|
128
|
-
if (!
|
|
129
|
-
let t =
|
|
219
|
+
if (!F()) return;
|
|
220
|
+
let t = v("page_view", {
|
|
130
221
|
page_location: location.href,
|
|
131
222
|
page_title: document.title,
|
|
132
223
|
...e
|
|
133
224
|
});
|
|
134
|
-
t &&
|
|
225
|
+
t && _((e) => e.page ? e.page(t) : e.track(t));
|
|
135
226
|
},
|
|
136
227
|
identify(e, t = {}) {
|
|
137
|
-
if (
|
|
138
|
-
if (!e ||
|
|
139
|
-
|
|
228
|
+
if (F()) {
|
|
229
|
+
if (!e || M(e)) {
|
|
230
|
+
m(new b("invalid_user_id", "identify() needs a non-empty user id that is not personal data such as an email address"));
|
|
140
231
|
return;
|
|
141
232
|
}
|
|
142
|
-
|
|
233
|
+
_((n) => n.identify?.({
|
|
143
234
|
userId: e,
|
|
144
235
|
traits: t
|
|
145
236
|
}));
|
|
146
237
|
}
|
|
147
238
|
},
|
|
148
239
|
reset() {
|
|
149
|
-
|
|
240
|
+
F() && _((e) => e.reset?.());
|
|
241
|
+
},
|
|
242
|
+
consent: {
|
|
243
|
+
update(n) {
|
|
244
|
+
if (!F()) return;
|
|
245
|
+
let i = Object.entries(n).filter(([n, r]) => r !== void 0 && !(e.includes(n) && t(r)));
|
|
246
|
+
if (i.length > 0) {
|
|
247
|
+
m(new b("invalid_consent", `consent.update() ignored: ${i.map(([e, t]) => `${e}=${JSON.stringify(t)}`).join(", ")}. Use analytics, ads, adUserData or adPersonalization with 'granted' or 'denied'.`));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
let a = r(u, n);
|
|
251
|
+
u = a, _((e) => e.consent?.(a));
|
|
252
|
+
},
|
|
253
|
+
get: () => u
|
|
150
254
|
}
|
|
151
255
|
};
|
|
152
256
|
};
|
|
153
257
|
//#endregion
|
|
154
|
-
export {
|
|
258
|
+
export { b as n, R as t };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ConsentState, ConsentStatus, ConsentUpdate } from './types.js';
|
|
2
|
+
export declare const CONSENT_KEYS: readonly (keyof ConsentState)[];
|
|
3
|
+
export declare const isConsentStatus: (value: unknown) => value is ConsentStatus;
|
|
4
|
+
/** Every signal follows `consent`, except that Global Privacy Control (an ad opt-out) denies the advertising signals. */
|
|
5
|
+
export declare const initialConsentState: ({ consent, gpc, }: {
|
|
6
|
+
consent: ConsentStatus;
|
|
7
|
+
gpc: boolean;
|
|
8
|
+
}) => ConsentState;
|
|
9
|
+
/** `ads` also sets `adUserData` and `adPersonalization`, unless the update gives them explicitly (e.g. TCF-style CMPs). */
|
|
10
|
+
export declare const applyConsentUpdate: (state: ConsentState, update: ConsentUpdate) => ConsentState;
|
|
11
|
+
/** Google Consent Mode v2 signals. */
|
|
12
|
+
export declare const toGoogleConsent: (state: ConsentState) => {
|
|
13
|
+
analytics_storage: ConsentStatus;
|
|
14
|
+
ad_storage: ConsentStatus;
|
|
15
|
+
ad_user_data: ConsentStatus;
|
|
16
|
+
ad_personalization: ConsentStatus;
|
|
17
|
+
};
|
|
18
|
+
export declare const hasDeniedSignal: (state: ConsentState) => boolean;
|
|
19
|
+
/** Global Privacy Control: a browser-level "do not sell or share" signal. Absent in browsers that don't support it. */
|
|
20
|
+
export declare const readGlobalPrivacyControl: () => boolean;
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type AnalyticsErrorCode = 'invalid_event' | 'invalid_param' | 'invalid_user_id' | 'pii_redacted' | 'destination_failed';
|
|
1
|
+
export type AnalyticsErrorCode = 'invalid_event' | 'invalid_param' | 'invalid_user_id' | 'invalid_consent' | 'pii_redacted' | 'destination_failed';
|
|
2
2
|
/** Every problem the library reports to `onError`, or throws when `debug` is on. */
|
|
3
3
|
export declare class AnalyticsError extends Error {
|
|
4
4
|
readonly code: AnalyticsErrorCode;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { AnalyticsError } from './errors.js';
|
|
2
2
|
export type ConsentStatus = 'granted' | 'denied';
|
|
3
|
+
/**
|
|
4
|
+
* The visitor's consent, per purpose. `ads` covers advertising storage; `adUserData` (sending user data to ad platforms)
|
|
5
|
+
* and `adPersonalization` follow `ads` unless set explicitly.
|
|
6
|
+
*/
|
|
7
|
+
export type ConsentState = {
|
|
8
|
+
analytics: ConsentStatus;
|
|
9
|
+
ads: ConsentStatus;
|
|
10
|
+
adUserData: ConsentStatus;
|
|
11
|
+
adPersonalization: ConsentStatus;
|
|
12
|
+
};
|
|
13
|
+
export type ConsentUpdate = Partial<ConsentState>;
|
|
3
14
|
/** Event parameters, passed to every destination as-is. */
|
|
4
15
|
export type EventParams = Record<string, unknown>;
|
|
5
16
|
export type AnalyticsEvent = {
|
|
@@ -27,9 +38,13 @@ export type Identity = {
|
|
|
27
38
|
/** Somewhere events are sent. Built-in destinations are configured by key; custom ones go in `destinations`. */
|
|
28
39
|
export type Destination = {
|
|
29
40
|
name: string;
|
|
30
|
-
/** Called once, in the browser, by `analytics.start()
|
|
31
|
-
start(
|
|
41
|
+
/** Called once, in the browser, by `analytics.start()`, with the consent state the page started with. */
|
|
42
|
+
start(context: {
|
|
43
|
+
consent: ConsentState;
|
|
44
|
+
}): void;
|
|
32
45
|
track(event: AnalyticsEvent): void;
|
|
46
|
+
/** Receives every consent change, in order with events. */
|
|
47
|
+
consent?(state: ConsentState): void;
|
|
33
48
|
/** Receives `page_view` events. Destinations without it get them through `track`. */
|
|
34
49
|
page?(event: AnalyticsEvent): void;
|
|
35
50
|
identify?(identity: Identity): void;
|
|
@@ -41,11 +56,36 @@ export type GtmConfig = {
|
|
|
41
56
|
containerId: string;
|
|
42
57
|
/** Set to `false` when the page already includes the GTM snippet. Defaults to `true`. */
|
|
43
58
|
loadScript?: boolean;
|
|
59
|
+
/** Load `gtm.js` from this https URL instead of googletagmanager.com, e.g. your server-side GTM domain. */
|
|
60
|
+
scriptUrl?: string;
|
|
61
|
+
/** Milliseconds tags wait for a consent update when a Consent Mode signal starts denied. Defaults to 500. */
|
|
62
|
+
waitForUpdate?: number;
|
|
63
|
+
};
|
|
64
|
+
export type Ga4Config = {
|
|
65
|
+
/** Google Analytics 4 measurement ID, e.g. `G-XXXXXXX`. */
|
|
66
|
+
measurementId: string;
|
|
67
|
+
/**
|
|
68
|
+
* `'auto'` (default): GA4 records page views itself, including history changes when Enhanced Measurement is on.
|
|
69
|
+
* `'manual'`: only `analytics.page()` sends page views.
|
|
70
|
+
*/
|
|
71
|
+
pageViews?: 'auto' | 'manual';
|
|
72
|
+
/** Set to `false` when the page already loads gtag.js. Defaults to `true`. */
|
|
73
|
+
loadScript?: boolean;
|
|
74
|
+
/** Your server-side GTM URL (https). Hits go there instead of Google, and events carry `event_id`. */
|
|
75
|
+
serverContainerUrl?: string;
|
|
76
|
+
/** Milliseconds tags wait for a consent update when a Consent Mode signal starts denied. Defaults to 500. */
|
|
77
|
+
waitForUpdate?: number;
|
|
44
78
|
};
|
|
45
79
|
export type AnalyticsConfig = {
|
|
46
|
-
/** Initial consent
|
|
80
|
+
/** Initial consent for every purpose. Required, so every site makes an explicit choice. */
|
|
47
81
|
consent: ConsentStatus;
|
|
82
|
+
/**
|
|
83
|
+
* Honour the browser's Global Privacy Control signal by starting the advertising signals denied. Defaults to `true`.
|
|
84
|
+
* An explicit `analytics.consent.update()` still wins.
|
|
85
|
+
*/
|
|
86
|
+
respectGpc?: boolean;
|
|
48
87
|
gtm?: GtmConfig;
|
|
88
|
+
ga4?: Ga4Config;
|
|
49
89
|
/** Custom destinations, in addition to the built-in ones. */
|
|
50
90
|
destinations?: Destination[];
|
|
51
91
|
/** Content-Security-Policy nonce added to every script the library injects. */
|
|
@@ -66,4 +106,9 @@ export type Analytics = {
|
|
|
66
106
|
identify(userId: string, traits?: IdentityTraits): void;
|
|
67
107
|
/** Forgets the identified user, e.g. on logout. */
|
|
68
108
|
reset(): void;
|
|
109
|
+
consent: {
|
|
110
|
+
/** Records the visitor's choice, e.g. from your consent banner. Omitted purposes keep their current state. */
|
|
111
|
+
update(update: ConsentUpdate): void;
|
|
112
|
+
get(): ConsentState;
|
|
113
|
+
};
|
|
69
114
|
};
|
package/dist/core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { createAnalytics } from './core/createAnalytics.js';
|
|
2
2
|
export { AnalyticsError } from './core/errors.js';
|
|
3
3
|
export type { AnalyticsErrorCode } from './core/errors.js';
|
|
4
|
-
export type { Analytics, AnalyticsConfig, AnalyticsEvent, ConsentStatus, Destination, EventParams, GtmConfig, Identity, IdentityTraits, } from './core/types.js';
|
|
4
|
+
export type { Analytics, AnalyticsConfig, AnalyticsEvent, ConsentState, ConsentStatus, ConsentUpdate, Destination, EventParams, Ga4Config, GtmConfig, Identity, IdentityTraits, } from './core/types.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Destination, Ga4Config } from '../core/types.js';
|
|
2
|
+
type Ga4DestinationOptions = Ga4Config & {
|
|
3
|
+
nonce?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const createGa4Destination: ({ measurementId, pageViews, loadScript, serverContainerUrl, waitForUpdate, nonce, }: Ga4DestinationOptions) => Destination;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ConsentState } from '../core/types.js';
|
|
2
|
+
type Gtag = (...args: unknown[]) => void;
|
|
3
|
+
export declare const dataLayer: () => unknown[];
|
|
4
|
+
/**
|
|
5
|
+
* Whether the page already loads the gtag.js library (any stream, Google- or first-party-hosted). Checked by script rather
|
|
6
|
+
* than by `window.gtag`, because the Consent Mode default defines the gtag stub before any library loads.
|
|
7
|
+
*/
|
|
8
|
+
export declare const isGtagLibraryOnPage: () => boolean;
|
|
9
|
+
/** The page's `gtag()`, defining Google's official command-queue stub when the page doesn't have one yet. */
|
|
10
|
+
export declare const gtag: () => Gtag;
|
|
11
|
+
/**
|
|
12
|
+
* Consent Mode v2 default. It must be queued before any config or container load. When a signal starts denied, tags
|
|
13
|
+
* wait `waitForUpdate` ms for the visitor's choice before firing.
|
|
14
|
+
*/
|
|
15
|
+
export declare const setDefaultConsent: ({ consent, waitForUpdate, }: {
|
|
16
|
+
consent: ConsentState;
|
|
17
|
+
waitForUpdate: number;
|
|
18
|
+
}) => void;
|
|
19
|
+
export declare const updateConsent: (consent: ConsentState) => void;
|
|
20
|
+
/** Parses an option that must be an https:// URL, failing fast with the option's name. */
|
|
21
|
+
export declare const toHttpsUrl: (value: string, option: string) => URL;
|
|
22
|
+
export {};
|
|
@@ -2,5 +2,5 @@ import type { Destination, GtmConfig } from '../core/types.js';
|
|
|
2
2
|
type GtmDestinationOptions = GtmConfig & {
|
|
3
3
|
nonce?: string;
|
|
4
4
|
};
|
|
5
|
-
export declare const createGtmDestination: ({ containerId, loadScript, nonce, }: GtmDestinationOptions) => Destination;
|
|
5
|
+
export declare const createGtmDestination: ({ containerId, loadScript, scriptUrl, waitForUpdate, nonce, }: GtmDestinationOptions) => Destination;
|
|
6
6
|
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-marketing-tools",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-alpha.
|
|
4
|
+
"version": "1.0.0-alpha.3",
|
|
5
5
|
"description": "React Marketing Tools are a set of tools to make it easier for you to implement analytics and track user journeys, interactions throughout your App. using dataLayer/Google Tag Manager, GA4 fetch directly or coming soon facebook pixel.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "bronz3beard <exempli.gratia.webdesign@gmail.com> (https://www.heyrory.com/)",
|
|
@@ -63,21 +63,6 @@
|
|
|
63
63
|
"test:watch": "vitest",
|
|
64
64
|
"typecheck": "tsc --noEmit"
|
|
65
65
|
},
|
|
66
|
-
"browserslist": {
|
|
67
|
-
"production": [
|
|
68
|
-
">0.2%",
|
|
69
|
-
"not dead",
|
|
70
|
-
"not op_mini all"
|
|
71
|
-
],
|
|
72
|
-
"development": [
|
|
73
|
-
"last 1 chrome version",
|
|
74
|
-
"last 1 firefox version",
|
|
75
|
-
"last 1 safari version"
|
|
76
|
-
]
|
|
77
|
-
},
|
|
78
|
-
"dependencies": {
|
|
79
|
-
"device-detector-js": "^3.0.3"
|
|
80
|
-
},
|
|
81
66
|
"peerDependencies": {
|
|
82
67
|
"react": ">=18.0.0"
|
|
83
68
|
},
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { TrackAnalyticsEventOptions } from '../types/index.js';
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* @paramType {object} options
|
|
5
|
-
* @property {object} data this is an object of any data you want to collect in analytics
|
|
6
|
-
* @property {object} eventNameInfo
|
|
7
|
-
* @property {string} analyticsType
|
|
8
|
-
* @property {array | undefined} userDataKeysToHashArray default for this value is null, when used it should include an array of strings you wish to hash.
|
|
9
|
-
* @property {boolean} dataLayerCheck
|
|
10
|
-
* @property {object} consoleLogData (optional) is an object with the following attributes, "showGlobalVars", "showJourneyPropsPayload", "showUserProps" if any of the values are true you will be able to see the respective payload in your console.
|
|
11
|
-
*/
|
|
12
|
-
declare const trackAnalyticsEvent: (options: TrackAnalyticsEventOptions) => Promise<void>;
|
|
13
|
-
export { trackAnalyticsEvent };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import DeviceDetector from 'device-detector-js';
|
|
2
|
-
import { AllowedTypes, EventNameInfo } from '../types';
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
* @param {object} user the structure of this data is dictated by you, aka your API or DB.
|
|
6
|
-
* @param {[string]} includeUserKeys is an array of strings that represent keys from your user data that you want to whitelist, the value for each key in the whitelist will be hashed.
|
|
7
|
-
* @returns a new user object with all values hashed including only the whitelisted key value pairs
|
|
8
|
-
*/
|
|
9
|
-
export declare const hashUserData: (user: Record<AllowedTypes, AllowedTypes>, includeUserKeys: Array<string>) => Promise<Record<AllowedTypes, AllowedTypes>>;
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
12
|
-
* @param {object} user the structure of this data is dictated by you, aka your API or DB.
|
|
13
|
-
* @param {[string]} includeUserKeys is an array of strings that represent keys from your user data that you want to map over, if no keys are supplied the original passed in user data is returned.
|
|
14
|
-
* @param {boolean} showMissingUserAttributesInConsole a boolean condition to show or hide "user" attributes that are not included in the "includeUserKeys" array, by console logging in dev tools.
|
|
15
|
-
* @returns If no "includeUserKeys" are supplied the original ser object is returned, otherwise, a new user object with only the key value pairs that you included in your includeUserKeys array is returned.
|
|
16
|
-
*/
|
|
17
|
-
export declare const buildNewUserData: (user: Record<AllowedTypes, AllowedTypes>, includeUserKeys: Array<string>, showMissingUserAttributesInConsole: boolean | undefined) => Record<string, string>;
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
* @paramType {Object} eventNameInfo
|
|
21
|
-
* @property {analyticsPrefixActionList} actionPrefix either a built in value of JOURNEY | INTERACTION or a custom value added to the analyticsPrefixActionList object.
|
|
22
|
-
* @property {string} description an OPTIONAL value passed in that is formatted like the following from 'Very descriptive description' to VERY_DESCRIPTIVE_DESCRIPTION.
|
|
23
|
-
* @property {string} globalAppEvent the current event name for this track event selected from the analyticsGlobalEventActionList
|
|
24
|
-
* @property {string} previousGlobalAppEvent an OPTIONAL value, the previous event name for this track event selected from the analyticsGlobalEventActionList.
|
|
25
|
-
* @returns string eventName for this specific tracked event
|
|
26
|
-
*/
|
|
27
|
-
export declare const buildAnalyticsEventName: (eventNameInfo: EventNameInfo) => string;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
* @param {object} data
|
|
31
|
-
* @param {string} globalAppEvent
|
|
32
|
-
* @returns dataObject
|
|
33
|
-
*/
|
|
34
|
-
export declare const buildEventDataObject: (data: Record<AllowedTypes, AllowedTypes>, globalAppEvent: string) => Promise<Record<AllowedTypes, AllowedTypes>>;
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
* @param {string} eventName
|
|
38
|
-
* @returns a Boolean value, true if the event name is already in the dataLayer.
|
|
39
|
-
*/
|
|
40
|
-
export declare const defaultDataLayerEventCheck: (eventName: string) => boolean;
|
|
41
|
-
export declare const deviceDetectorInfo: (userAgent: string) => DeviceDetector.DeviceDetectorResult;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { BuildConfigOptions, Config, AnalyticsPlatform } from '../types/index.js';
|
|
2
|
-
declare const analyticsPlatform: AnalyticsPlatform;
|
|
3
|
-
declare const showMeBuildInAnalyticsPlatform: () => void;
|
|
4
|
-
declare const showMeBuildInEventActionPrefixList: () => void;
|
|
5
|
-
declare const showMeBuildInGlobalEventActionList: () => void;
|
|
6
|
-
declare let config: Config;
|
|
7
|
-
declare const buildConfig: (options: BuildConfigOptions) => void;
|
|
8
|
-
export { config, analyticsPlatform, buildConfig, showMeBuildInAnalyticsPlatform, showMeBuildInGlobalEventActionList, showMeBuildInEventActionPrefixList, };
|
package/dist/ipInfo/index.d.ts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { IpInfo, ServerLocationData } from '../types';
|
|
2
|
-
export declare const buildServerLocationData: (withServerLocationInfo: boolean | undefined, IP_INFO_TOKEN: string | undefined) => Promise<ServerLocationData | undefined>;
|
|
3
|
-
export declare const getIpInfo: (IP_INFO_TOKEN: string) => Promise<IpInfo>;
|
package/dist/types/index.d.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
export interface AnalyticsEventActionPrefix extends Record<string, string> {
|
|
2
|
-
}
|
|
3
|
-
export interface AnalyticsGlobalEventAction extends Record<string, string> {
|
|
4
|
-
}
|
|
5
|
-
export type Event = {
|
|
6
|
-
name: string;
|
|
7
|
-
params: Record<AllowedTypes, AllowedTypes>;
|
|
8
|
-
};
|
|
9
|
-
export type GooglePayload = {
|
|
10
|
-
non_personalized_ads: boolean;
|
|
11
|
-
client_id: string;
|
|
12
|
-
user_id: string;
|
|
13
|
-
user_properties: {
|
|
14
|
-
user_id: string;
|
|
15
|
-
user_type: string;
|
|
16
|
-
client_id: string;
|
|
17
|
-
};
|
|
18
|
-
events: Event[];
|
|
19
|
-
};
|
|
20
|
-
export type EventNameInfo = {
|
|
21
|
-
eventName?: string;
|
|
22
|
-
description?: string;
|
|
23
|
-
actionPrefix: string;
|
|
24
|
-
globalAppEvent: string;
|
|
25
|
-
previousGlobalAppEvent?: string;
|
|
26
|
-
};
|
|
27
|
-
export type AllowedTypes = string | number;
|
|
28
|
-
export type TrackAnalyticsEventOptions = {
|
|
29
|
-
data: Record<AllowedTypes, AllowedTypes>;
|
|
30
|
-
eventNameInfo: EventNameInfo;
|
|
31
|
-
analyticsType: string;
|
|
32
|
-
userDataKeysToHashArray?: Array<string> | null;
|
|
33
|
-
dataLayerCheck?: boolean;
|
|
34
|
-
consoleLogData?: object;
|
|
35
|
-
};
|
|
36
|
-
export type GlobalVars = {
|
|
37
|
-
app: string;
|
|
38
|
-
device_category?: string | undefined;
|
|
39
|
-
device_os?: string | undefined;
|
|
40
|
-
device_browser?: string | undefined;
|
|
41
|
-
};
|
|
42
|
-
export type DataLayer = {
|
|
43
|
-
event: string;
|
|
44
|
-
globalVars: GlobalVars;
|
|
45
|
-
journeyProps: Record<any, any>;
|
|
46
|
-
userProps: Record<any, any>;
|
|
47
|
-
};
|
|
48
|
-
export type ConsoleLogData = {
|
|
49
|
-
showGlobalVars?: boolean;
|
|
50
|
-
showJourneyPropsPayload?: boolean;
|
|
51
|
-
showUserProps?: boolean;
|
|
52
|
-
};
|
|
53
|
-
export interface AnalyticsTrackerDataOptions {
|
|
54
|
-
consoleLogData: ConsoleLogData | null;
|
|
55
|
-
data: Record<any, any>;
|
|
56
|
-
eventName: string;
|
|
57
|
-
globalAppEvent: string;
|
|
58
|
-
userDetails: Record<any, any>;
|
|
59
|
-
}
|
|
60
|
-
export interface HandleDataLayerPushOptions extends AnalyticsTrackerDataOptions {
|
|
61
|
-
dataLayerCheck: boolean;
|
|
62
|
-
}
|
|
63
|
-
export type ServerLocationData = {
|
|
64
|
-
SERVER_CITY: string;
|
|
65
|
-
SERVER_COUNTRY: string;
|
|
66
|
-
SERVER_HOSTNAME: string;
|
|
67
|
-
SERVER_IP: string;
|
|
68
|
-
SERVER_LOCATION: string;
|
|
69
|
-
SERVER_POSTAL: string;
|
|
70
|
-
SERVER_REGION: string;
|
|
71
|
-
SERVER_TIMEZONE: string;
|
|
72
|
-
};
|
|
73
|
-
export type IpInfo = {
|
|
74
|
-
city: string;
|
|
75
|
-
country: string;
|
|
76
|
-
SERVER_HOSTNAME: string;
|
|
77
|
-
hostname: string;
|
|
78
|
-
ip: string;
|
|
79
|
-
loc: string;
|
|
80
|
-
postal: string;
|
|
81
|
-
region: string;
|
|
82
|
-
timezone: string;
|
|
83
|
-
};
|
|
84
|
-
export type Ga4GoogleAnalyticsEventTracking = AnalyticsTrackerDataOptions;
|
|
85
|
-
export type Platform = 'GOOGLE' | 'FACEBOOK' | 'DATALAYER_PUSH';
|
|
86
|
-
export type AnalyticsPlatform = {
|
|
87
|
-
[key in Platform]: Platform;
|
|
88
|
-
};
|
|
89
|
-
export type Tokens = {
|
|
90
|
-
IP_INFO_TOKEN?: string;
|
|
91
|
-
GA4_PUBLIC_API_SECRET?: string;
|
|
92
|
-
GA4_PUBLIC_MEASUREMENT_ID?: string;
|
|
93
|
-
};
|
|
94
|
-
export type Config = {
|
|
95
|
-
TOKENS?: Tokens;
|
|
96
|
-
appName: string;
|
|
97
|
-
appSessionCookieName: string;
|
|
98
|
-
withDeviceInfo?: boolean;
|
|
99
|
-
includeUserKeys: Array<string>;
|
|
100
|
-
showMissingUserAttributesInConsole: boolean | undefined;
|
|
101
|
-
withServerLocationInfo: boolean | undefined;
|
|
102
|
-
eventActionPrefixList: AnalyticsEventActionPrefix;
|
|
103
|
-
analyticsGlobalEventActionList: AnalyticsGlobalEventAction;
|
|
104
|
-
};
|
|
105
|
-
export type BuildConfigOptions = {
|
|
106
|
-
appName: string;
|
|
107
|
-
appSessionCookieName: string;
|
|
108
|
-
eventActionPrefix?: AnalyticsEventActionPrefix;
|
|
109
|
-
globalEventActionList?: AnalyticsGlobalEventAction;
|
|
110
|
-
includeUserKeys?: Array<string> | undefined;
|
|
111
|
-
showMissingUserAttributesInConsole?: boolean;
|
|
112
|
-
showMeBuildInEventActionPrefixList?: boolean;
|
|
113
|
-
TOKENS?: Tokens;
|
|
114
|
-
withDeviceInfo?: boolean;
|
|
115
|
-
withServerLocationInfo?: boolean;
|
|
116
|
-
};
|
|
117
|
-
export declare let config: Config;
|
|
118
|
-
export type ProviderStateProps = {
|
|
119
|
-
appName: string;
|
|
120
|
-
appSessionCookieName: string;
|
|
121
|
-
analyticsPlatform: AnalyticsPlatform;
|
|
122
|
-
eventActionPrefixList: AnalyticsEventActionPrefix;
|
|
123
|
-
analyticsGlobalEventActionList: AnalyticsGlobalEventAction;
|
|
124
|
-
};
|
|
125
|
-
export type ProviderApiProps = {
|
|
126
|
-
trackAnalyticsEvent: (options: TrackAnalyticsEventOptions) => Promise<void>;
|
|
127
|
-
showMeBuildInAnalyticsPlatform: () => void;
|
|
128
|
-
showMeBuildInEventActionPrefixList: () => void;
|
|
129
|
-
showMeBuildInGlobalEventActionList: () => void;
|
|
130
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const assertIsTrue: (condition: boolean, errorMessage?: string) => void;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare const isClientSide: () => boolean;
|
|
2
|
-
export declare const objectHasAttributes: (obj: object, key?: string) => boolean;
|
|
3
|
-
export declare const replaceWhiteSpace: (stringValue: string, replaceValue: string) => string;
|
|
4
|
-
export declare const checkAllArrayValuesReturnTrue: (valueArray: boolean[]) => boolean;
|
|
5
|
-
export declare const hashString: (value: string) => Promise<string>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const getCookieValueByName: (name: string) => string | undefined;
|