react-marketing-tools 1.0.0-alpha.1 → 1.0.0-alpha.2

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.
@@ -0,0 +1,154 @@
1
+ //#region lib/destinations/gtm.ts
2
+ var e = /^GTM-[A-Z0-9]+$/, t = () => window.dataLayer ??= [], n = (e) => Array.from(document.scripts).some((t) => t.src === e), r = ({ src: e, nonce: t }) => {
3
+ let n = document.createElement("script");
4
+ n.async = !0, n.src = e, t && n.setAttribute("nonce", t), document.head.append(n);
5
+ }, i = ({ containerId: i, loadScript: a = !0, nonce: o }) => {
6
+ if (!e.test(i)) throw Error(`[react-marketing-tools] gtm.containerId must look like "GTM-XXXXXXX" (received ${JSON.stringify(i)}).`);
7
+ let s = `https://www.googletagmanager.com/gtm.js?id=${i}`;
8
+ return {
9
+ name: "gtm",
10
+ start() {
11
+ let e = t();
12
+ a && !n(s) && (e.push({
13
+ "gtm.start": Date.now(),
14
+ event: "gtm.js"
15
+ }), r({
16
+ src: s,
17
+ nonce: o
18
+ }));
19
+ },
20
+ track({ name: e, params: n, eventId: r }) {
21
+ t().push({
22
+ ...n,
23
+ event: e,
24
+ event_id: r
25
+ });
26
+ },
27
+ identify({ userId: e }) {
28
+ t().push({
29
+ event: "identify",
30
+ user_id: e
31
+ });
32
+ },
33
+ reset() {
34
+ t().push({
35
+ event: "reset",
36
+ user_id: void 0
37
+ });
38
+ }
39
+ };
40
+ }, a = class extends Error {
41
+ code;
42
+ constructor(e, t, n) {
43
+ super(`[react-marketing-tools] ${t}`, n), this.name = "AnalyticsError", this.code = e;
44
+ }
45
+ }, o = /^[A-Za-z][A-Za-z0-9_]{0,39}$/, s = [
46
+ "google_",
47
+ "ga_",
48
+ "firebase_"
49
+ ], c = 25, l = 100, u = {
50
+ page_location: 1e3,
51
+ page_referrer: 420,
52
+ page_title: 300
53
+ }, d = [
54
+ "email",
55
+ "phone",
56
+ "first_name",
57
+ "last_name",
58
+ "address",
59
+ "password"
60
+ ], f = String.raw`[\w.+-]+(?:@|%40)[\w-]+(?:\.[\w-]+)+`, p = "[redacted]", m = (e) => {
61
+ if (!o.test(e)) return "must start with a letter, contain only letters, digits and underscores, and be at most 40 characters";
62
+ let t = s.find((t) => e.toLowerCase().startsWith(t));
63
+ return t && `must not start with the reserved prefix "${t}"`;
64
+ }, h = (e) => {
65
+ let t = m(e);
66
+ return t && `event name "${e}" ${t}`;
67
+ }, g = (e) => {
68
+ let t = Object.keys(e), n = t.flatMap((t) => {
69
+ let n = m(t);
70
+ if (n) return [`param "${t}" ${n}`];
71
+ let r = e[t], i = u[t] ?? l;
72
+ return typeof r == "string" && r.length > i ? [`param "${t}" is longer than ${i} characters`] : [];
73
+ });
74
+ return t.length > c ? [`has ${t.length} params; the limit is ${c}`, ...n] : n;
75
+ }, _ = (e) => new RegExp(f, "i").test(e), v = (e, t) => (typeof t == "string" || typeof t == "number") && d.some((t) => e.toLowerCase().includes(t)) ? p : typeof t == "string" ? t.replace(new RegExp(f, "gi"), p) : t, y = (e) => {
76
+ let t = Object.entries(e).map(([e, t]) => [
77
+ e,
78
+ t,
79
+ v(e, t)
80
+ ]);
81
+ return {
82
+ params: Object.fromEntries(t.map(([e, , t]) => [e, t])),
83
+ redactedKeys: t.filter(([, e, t]) => t !== e).map(([e]) => e)
84
+ };
85
+ }, b = () => typeof window < "u", x = () => 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)), S = (e) => {
86
+ 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
+ }, C = (e) => {
88
+ S(e);
89
+ let { debug: t = !1, onError: n = console.error } = e, r = [...e.gtm ? [i({
90
+ ...e.gtm,
91
+ nonce: e.nonce
92
+ })] : [], ...e.destinations ?? []], o = [], s = !1, c = (e) => {
93
+ if (t) throw e;
94
+ n(e);
95
+ }, l = (e) => {
96
+ for (let t of r) try {
97
+ e(t);
98
+ } catch (e) {
99
+ n(new a("destination_failed", `destination "${t.name}" failed`, { cause: e }));
100
+ }
101
+ }, u = (e) => {
102
+ s ? l(e) : o.push(e);
103
+ }, d = (e, t) => {
104
+ let n = h(e);
105
+ if (n) {
106
+ c(new a("invalid_event", n));
107
+ return;
108
+ }
109
+ for (let n of g(t)) c(new a("invalid_param", `event "${e}" ${n}`));
110
+ let { params: r, redactedKeys: i } = y(t);
111
+ return i.length > 0 && c(new a("pii_redacted", `event "${e}": personal data redacted from ${i.join(", ")}`)), {
112
+ name: e,
113
+ params: r,
114
+ eventId: x(),
115
+ timestamp: Date.now()
116
+ };
117
+ };
118
+ return {
119
+ start() {
120
+ !s && b() && (s = !0, l((e) => e.start()), o.splice(0).forEach(l));
121
+ },
122
+ track(e, t = {}) {
123
+ if (!b()) return;
124
+ let n = d(e, t);
125
+ n && u((e) => e.track(n));
126
+ },
127
+ page(e = {}) {
128
+ if (!b()) return;
129
+ let t = d("page_view", {
130
+ page_location: location.href,
131
+ page_title: document.title,
132
+ ...e
133
+ });
134
+ t && u((e) => e.page ? e.page(t) : e.track(t));
135
+ },
136
+ identify(e, t = {}) {
137
+ if (b()) {
138
+ if (!e || _(e)) {
139
+ c(new a("invalid_user_id", "identify() needs a non-empty user id that is not personal data such as an email address"));
140
+ return;
141
+ }
142
+ u((n) => n.identify?.({
143
+ userId: e,
144
+ traits: t
145
+ }));
146
+ }
147
+ },
148
+ reset() {
149
+ b() && u((e) => e.reset?.());
150
+ }
151
+ };
152
+ };
153
+ //#endregion
154
+ export { a as n, C as t };
package/dist/core.js CHANGED
@@ -1,154 +1,2 @@
1
- //#region lib/destinations/gtm.ts
2
- var e = /^GTM-[A-Z0-9]+$/, t = () => window.dataLayer ??= [], n = (e) => Array.from(document.scripts).some((t) => t.src === e), r = ({ src: e, nonce: t }) => {
3
- let n = document.createElement("script");
4
- n.async = !0, n.src = e, t && n.setAttribute("nonce", t), document.head.append(n);
5
- }, i = ({ containerId: i, loadScript: a = !0, nonce: o }) => {
6
- if (!e.test(i)) throw Error(`[react-marketing-tools] gtm.containerId must look like "GTM-XXXXXXX" (received ${JSON.stringify(i)}).`);
7
- let s = `https://www.googletagmanager.com/gtm.js?id=${i}`;
8
- return {
9
- name: "gtm",
10
- start() {
11
- let e = t();
12
- a && !n(s) && (e.push({
13
- "gtm.start": Date.now(),
14
- event: "gtm.js"
15
- }), r({
16
- src: s,
17
- nonce: o
18
- }));
19
- },
20
- track({ name: e, params: n, eventId: r }) {
21
- t().push({
22
- ...n,
23
- event: e,
24
- event_id: r
25
- });
26
- },
27
- identify({ userId: e }) {
28
- t().push({
29
- event: "identify",
30
- user_id: e
31
- });
32
- },
33
- reset() {
34
- t().push({
35
- event: "reset",
36
- user_id: void 0
37
- });
38
- }
39
- };
40
- }, a = class extends Error {
41
- code;
42
- constructor(e, t, n) {
43
- super(`[react-marketing-tools] ${t}`, n), this.name = "AnalyticsError", this.code = e;
44
- }
45
- }, o = /^[A-Za-z][A-Za-z0-9_]{0,39}$/, s = [
46
- "google_",
47
- "ga_",
48
- "firebase_"
49
- ], c = 25, l = 100, u = {
50
- page_location: 1e3,
51
- page_referrer: 420,
52
- page_title: 300
53
- }, d = [
54
- "email",
55
- "phone",
56
- "first_name",
57
- "last_name",
58
- "address",
59
- "password"
60
- ], f = String.raw`[\w.+-]+(?:@|%40)[\w-]+(?:\.[\w-]+)+`, p = "[redacted]", m = (e) => {
61
- if (!o.test(e)) return "must start with a letter, contain only letters, digits and underscores, and be at most 40 characters";
62
- let t = s.find((t) => e.toLowerCase().startsWith(t));
63
- return t && `must not start with the reserved prefix "${t}"`;
64
- }, h = (e) => {
65
- let t = m(e);
66
- return t && `event name "${e}" ${t}`;
67
- }, g = (e) => {
68
- let t = Object.keys(e), n = t.flatMap((t) => {
69
- let n = m(t);
70
- if (n) return [`param "${t}" ${n}`];
71
- let r = e[t], i = u[t] ?? l;
72
- return typeof r == "string" && r.length > i ? [`param "${t}" is longer than ${i} characters`] : [];
73
- });
74
- return t.length > c ? [`has ${t.length} params; the limit is ${c}`, ...n] : n;
75
- }, _ = (e) => new RegExp(f, "i").test(e), v = (e, t) => (typeof t == "string" || typeof t == "number") && d.some((t) => e.toLowerCase().includes(t)) ? p : typeof t == "string" ? t.replace(new RegExp(f, "gi"), p) : t, y = (e) => {
76
- let t = Object.entries(e).map(([e, t]) => [
77
- e,
78
- t,
79
- v(e, t)
80
- ]);
81
- return {
82
- params: Object.fromEntries(t.map(([e, , t]) => [e, t])),
83
- redactedKeys: t.filter(([, e, t]) => t !== e).map(([e]) => e)
84
- };
85
- }, b = () => typeof window < "u", x = () => 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)), S = (e) => {
86
- 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
- }, C = (e) => {
88
- S(e);
89
- let { debug: t = !1, onError: n = console.error } = e, r = [...e.gtm ? [i({
90
- ...e.gtm,
91
- nonce: e.nonce
92
- })] : [], ...e.destinations ?? []], o = [], s = !1, c = (e) => {
93
- if (t) throw e;
94
- n(e);
95
- }, l = (e) => {
96
- for (let t of r) try {
97
- e(t);
98
- } catch (e) {
99
- n(new a("destination_failed", `destination "${t.name}" failed`, { cause: e }));
100
- }
101
- }, u = (e) => {
102
- s ? l(e) : o.push(e);
103
- }, d = (e, t) => {
104
- let n = h(e);
105
- if (n) {
106
- c(new a("invalid_event", n));
107
- return;
108
- }
109
- for (let n of g(t)) c(new a("invalid_param", `event "${e}" ${n}`));
110
- let { params: r, redactedKeys: i } = y(t);
111
- return i.length > 0 && c(new a("pii_redacted", `event "${e}": personal data redacted from ${i.join(", ")}`)), {
112
- name: e,
113
- params: r,
114
- eventId: x(),
115
- timestamp: Date.now()
116
- };
117
- };
118
- return {
119
- start() {
120
- !s && b() && (s = !0, l((e) => e.start()), o.splice(0).forEach(l));
121
- },
122
- track(e, t = {}) {
123
- if (!b()) return;
124
- let n = d(e, t);
125
- n && u((e) => e.track(n));
126
- },
127
- page(e = {}) {
128
- if (!b()) return;
129
- let t = d("page_view", {
130
- page_location: location.href,
131
- page_title: document.title,
132
- ...e
133
- });
134
- t && u((e) => e.page ? e.page(t) : e.track(t));
135
- },
136
- identify(e, t = {}) {
137
- if (b()) {
138
- if (!e || _(e)) {
139
- c(new a("invalid_user_id", "identify() needs a non-empty user id that is not personal data such as an email address"));
140
- return;
141
- }
142
- u((n) => n.identify?.({
143
- userId: e,
144
- traits: t
145
- }));
146
- }
147
- },
148
- reset() {
149
- b() && u((e) => e.reset?.());
150
- }
151
- };
152
- };
153
- //#endregion
154
- export { a as AnalyticsError, C as createAnalytics };
1
+ import { n as e, t } from "./chunks/core.js";
2
+ export { e as AnalyticsError, t as createAnalytics };
package/dist/index.d.ts CHANGED
@@ -1,26 +1,2 @@
1
- import { ReactElement, ReactNode, Context } from 'react';
2
- import type { ProviderStateProps, ProviderApiProps } from './types/index.js';
3
- export type { Event, GooglePayload, EventNameInfo, AllowedTypes, TrackAnalyticsEventOptions, GlobalVars, DataLayer, ConsoleLogData, AnalyticsTrackerDataOptions, HandleDataLayerPushOptions, ServerLocationData, IpInfo, Ga4GoogleAnalyticsEventTracking, Platform, AnalyticsPlatform, Tokens, Config, BuildConfigOptions, ProviderStateProps, ProviderApiProps, AnalyticsEventActionPrefix, AnalyticsGlobalEventAction, } from './types/index.js';
4
- export { config, analyticsPlatform, buildConfig, showMeBuildInAnalyticsPlatform, showMeBuildInGlobalEventActionList, showMeBuildInEventActionPrefixList, } from './buildConfig/index.js';
5
- export { trackAnalyticsEvent } from './analytics/analyticsEventService.js';
6
- export declare const ContextState: Context<ProviderStateProps>;
7
- export declare const ContextApi: Context<ProviderApiProps>;
8
- type ReactMarketingProviderProps = {
9
- children: ReactNode;
10
- };
11
- export declare const ReactMarketingProvider: ({ children, }: ReactMarketingProviderProps) => ReactElement;
12
- /**
13
- * @property {string} appName
14
- * @property {string} appSessionCookieName
15
- * @property {AnalyticsPlatform} analyticsPlatform
16
- * @property {AnalyticsEventActionPrefix} eventActionPrefixList
17
- * @property {AnalyticsGlobalEventAction} analyticsGlobalEventActionList
18
- */
19
- export declare const useMarketingState: () => ProviderStateProps;
20
- /**
21
- * @property {function} trackAnalyticsEvent(options)
22
- * @property {function} showMeBuildInAnalyticsPlatform
23
- * @property {function} showMeBuildInEventActionPrefixList
24
- * @property {function} showMeBuildInGlobalEventActionList
25
- */
26
- export declare const useMarketingApi: () => ProviderApiProps;
1
+ export * from './core.js';
2
+ export { AnalyticsProvider, useAnalytics } from './react/AnalyticsProvider.js';