@shware/analytics 8.8.0 → 8.10.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 +34 -0
- package/dist/attribution/index.cjs +274 -0
- package/dist/attribution/index.cjs.map +1 -0
- package/dist/attribution/index.d.cts +103 -0
- package/dist/attribution/index.d.cts.map +1 -0
- package/dist/attribution/index.d.mts +103 -0
- package/dist/attribution/index.d.mts.map +1 -0
- package/dist/attribution/index.mjs +257 -0
- package/dist/attribution/index.mjs.map +1 -0
- package/dist/schema/index.cjs +0 -1
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +0 -1
- package/dist/schema/index.d.cts.map +1 -1
- package/dist/schema/index.d.mts +0 -1
- package/dist/schema/index.d.mts.map +1 -1
- package/dist/schema/index.mjs +0 -1
- package/dist/schema/index.mjs.map +1 -1
- package/dist/third-parties/posthog.cjs +7 -1
- package/dist/third-parties/posthog.cjs.map +1 -1
- package/dist/third-parties/posthog.d.cts +8 -2
- package/dist/third-parties/posthog.d.cts.map +1 -1
- package/dist/third-parties/posthog.d.mts +8 -2
- package/dist/third-parties/posthog.d.mts.map +1 -1
- package/dist/third-parties/posthog.mjs +7 -1
- package/dist/third-parties/posthog.mjs.map +1 -1
- package/dist/visitor/index.cjs +5 -1
- package/dist/visitor/index.cjs.map +1 -1
- package/dist/visitor/index.mjs +5 -1
- package/dist/visitor/index.mjs.map +1 -1
- package/dist/visitor/types.d.cts +14 -2
- package/dist/visitor/types.d.cts.map +1 -1
- package/dist/visitor/types.d.mts +14 -2
- package/dist/visitor/types.d.mts.map +1 -1
- package/package.json +11 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
//#region src/attribution/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* The vocabulary attribution is built from, shared by every product's `touchpoint` view and by the
|
|
4
|
+
* dashboards that read it. Data only, no SQL: a product turns these into its view. What stays with
|
|
5
|
+
* the product is its own hostnames (referrer exclusions) and its landing-page convention.
|
|
6
|
+
*/
|
|
7
|
+
/** A session that arrived through nothing we can name. GA's spelling, so dashboards read as GA. */
|
|
8
|
+
const DIRECT_CHANNEL = "(direct)";
|
|
9
|
+
/** The medium of a direct session. */
|
|
10
|
+
const NO_MEDIUM = "(none)";
|
|
11
|
+
/** The medium of a tagged link that named a source but no medium. */
|
|
12
|
+
const MEDIUM_NOT_SET = "(not set)";
|
|
13
|
+
/** The channels the rules below can name. A `utm_source` outside this list is its own channel. */
|
|
14
|
+
const CHANNELS = [
|
|
15
|
+
"meta",
|
|
16
|
+
"google",
|
|
17
|
+
"dv360",
|
|
18
|
+
"microsoft",
|
|
19
|
+
"tiktok",
|
|
20
|
+
"reddit",
|
|
21
|
+
"linkedin",
|
|
22
|
+
"snapchat",
|
|
23
|
+
"x",
|
|
24
|
+
"kakao",
|
|
25
|
+
"yandex",
|
|
26
|
+
"yahoo",
|
|
27
|
+
"duckduckgo",
|
|
28
|
+
"baidu",
|
|
29
|
+
"ecosia",
|
|
30
|
+
"naver",
|
|
31
|
+
"brave",
|
|
32
|
+
"pinterest",
|
|
33
|
+
"youtube"
|
|
34
|
+
];
|
|
35
|
+
/** GA4's default channel groups, as identifiers; a dashboard maps them to display names. */
|
|
36
|
+
const CHANNEL_GROUPS = [
|
|
37
|
+
"direct",
|
|
38
|
+
"paid_search",
|
|
39
|
+
"paid_social",
|
|
40
|
+
"paid_other",
|
|
41
|
+
"display",
|
|
42
|
+
"organic_search",
|
|
43
|
+
"organic_social",
|
|
44
|
+
"organic_video",
|
|
45
|
+
"referral",
|
|
46
|
+
"email",
|
|
47
|
+
"affiliate",
|
|
48
|
+
"unassigned"
|
|
49
|
+
];
|
|
50
|
+
/** `utm_source` spellings that mean the same channel: Meta's `{{site_source_name}}` values and the usual synonyms. */
|
|
51
|
+
const SOURCE_ALIASES = {
|
|
52
|
+
fb: "meta",
|
|
53
|
+
ig: "meta",
|
|
54
|
+
an: "meta",
|
|
55
|
+
msg: "meta",
|
|
56
|
+
facebook: "meta",
|
|
57
|
+
instagram: "meta",
|
|
58
|
+
bing: "microsoft",
|
|
59
|
+
twitter: "x"
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Which click id belongs to which channel, in priority order. Every key is a field this SDK
|
|
63
|
+
* collects (`AdvertisingInfo`); `fbp` and `rdt_uuid` are deliberately absent — they are pixel
|
|
64
|
+
* browser ids, present with or without a click.
|
|
65
|
+
*/
|
|
66
|
+
const CLICK_ID_CHANNELS = [
|
|
67
|
+
["fbclid", "meta"],
|
|
68
|
+
["fbc", "meta"],
|
|
69
|
+
["gclid", "google"],
|
|
70
|
+
["gbraid", "google"],
|
|
71
|
+
["wbraid", "google"],
|
|
72
|
+
["gad_source", "google"],
|
|
73
|
+
["gad_campaignid", "google"],
|
|
74
|
+
["dclid", "dv360"],
|
|
75
|
+
["msclkid", "microsoft"],
|
|
76
|
+
["ttclid", "tiktok"],
|
|
77
|
+
["rdt_cid", "reddit"],
|
|
78
|
+
["li_fat_id", "linkedin"],
|
|
79
|
+
["sccid", "snapchat"],
|
|
80
|
+
["twclid", "x"],
|
|
81
|
+
["ko_click_id", "kakao"],
|
|
82
|
+
["yclid", "yandex"]
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* A landing page reserved for one channel's ads, for ads that lost their parameters:
|
|
86
|
+
* `/lp/<channel>`, with or without host, query and hash; the capture is the channel. A product
|
|
87
|
+
* that names its landing pages differently replaces this.
|
|
88
|
+
*/
|
|
89
|
+
const AD_LANDING_PAGE = "^(?:https?://[^/]+)?/lp/([a-z]+)(?:[/?#]|$)";
|
|
90
|
+
/**
|
|
91
|
+
* Referrer hosts that name a channel, as POSIX regular expressions over the lower-cased host,
|
|
92
|
+
* with the medium GA4 gives that kind of site. Anything else that refers is `referral`, kept as
|
|
93
|
+
* its host. A country TLD is one or two labels (`google.com`, `google.co.uk`, `google.com.hk`),
|
|
94
|
+
* never an open tail, so `google.com.evil.io` is not Google.
|
|
95
|
+
*/
|
|
96
|
+
const REFERRER_SITES = [
|
|
97
|
+
[
|
|
98
|
+
"google",
|
|
99
|
+
"organic",
|
|
100
|
+
String.raw`(^|\.)google\.[a-z]{2,}(\.[a-z]{2,3})?$`
|
|
101
|
+
],
|
|
102
|
+
[
|
|
103
|
+
"microsoft",
|
|
104
|
+
"organic",
|
|
105
|
+
String.raw`(^|\.)bing\.com$`
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
"yahoo",
|
|
109
|
+
"organic",
|
|
110
|
+
String.raw`(^|\.)yahoo\.[a-z]{2,}(\.[a-z]{2,3})?$`
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
"duckduckgo",
|
|
114
|
+
"organic",
|
|
115
|
+
String.raw`(^|\.)duckduckgo\.com$`
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
"baidu",
|
|
119
|
+
"organic",
|
|
120
|
+
String.raw`(^|\.)baidu\.com$`
|
|
121
|
+
],
|
|
122
|
+
[
|
|
123
|
+
"yandex",
|
|
124
|
+
"organic",
|
|
125
|
+
String.raw`(^|\.)yandex\.[a-z]{2,}(\.[a-z]{2,3})?$`
|
|
126
|
+
],
|
|
127
|
+
[
|
|
128
|
+
"ecosia",
|
|
129
|
+
"organic",
|
|
130
|
+
String.raw`(^|\.)ecosia\.org$`
|
|
131
|
+
],
|
|
132
|
+
[
|
|
133
|
+
"naver",
|
|
134
|
+
"organic",
|
|
135
|
+
String.raw`(^|\.)naver\.com$`
|
|
136
|
+
],
|
|
137
|
+
[
|
|
138
|
+
"brave",
|
|
139
|
+
"organic",
|
|
140
|
+
String.raw`^search\.brave\.com$`
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
"meta",
|
|
144
|
+
"social",
|
|
145
|
+
String.raw`(^|\.)(facebook\.com|instagram\.com|fb\.com|threads\.net)$`
|
|
146
|
+
],
|
|
147
|
+
[
|
|
148
|
+
"x",
|
|
149
|
+
"social",
|
|
150
|
+
String.raw`(^|\.)(twitter\.com|x\.com|t\.co)$`
|
|
151
|
+
],
|
|
152
|
+
[
|
|
153
|
+
"linkedin",
|
|
154
|
+
"social",
|
|
155
|
+
String.raw`(^|\.)(linkedin\.com|lnkd\.in)$`
|
|
156
|
+
],
|
|
157
|
+
[
|
|
158
|
+
"reddit",
|
|
159
|
+
"social",
|
|
160
|
+
String.raw`(^|\.)reddit\.com$`
|
|
161
|
+
],
|
|
162
|
+
[
|
|
163
|
+
"tiktok",
|
|
164
|
+
"social",
|
|
165
|
+
String.raw`(^|\.)tiktok\.com$`
|
|
166
|
+
],
|
|
167
|
+
[
|
|
168
|
+
"pinterest",
|
|
169
|
+
"social",
|
|
170
|
+
String.raw`(^|\.)pinterest\.[a-z]{2,}(\.[a-z]{2,3})?$`
|
|
171
|
+
],
|
|
172
|
+
[
|
|
173
|
+
"snapchat",
|
|
174
|
+
"social",
|
|
175
|
+
String.raw`(^|\.)snapchat\.com$`
|
|
176
|
+
],
|
|
177
|
+
[
|
|
178
|
+
"youtube",
|
|
179
|
+
"video",
|
|
180
|
+
String.raw`(^|\.)(youtube\.com|youtu\.be)$`
|
|
181
|
+
]
|
|
182
|
+
];
|
|
183
|
+
/**
|
|
184
|
+
* Referrer hosts that are navigation, not acquisition: the payment and sign-in providers a
|
|
185
|
+
* visitor is bounced through and back from, and the local dev host. A product appends its own
|
|
186
|
+
* hostnames — a session that starts from an internal link after the session timeout refers to
|
|
187
|
+
* them. POSIX regular expressions over the lower-cased host.
|
|
188
|
+
*/
|
|
189
|
+
const REFERRERS_NOT_A_TOUCH = [
|
|
190
|
+
String.raw`^localhost(:|$)`,
|
|
191
|
+
String.raw`(^|\.)stripe\.com$`,
|
|
192
|
+
String.raw`^(pay|accounts)\.google\.com$`,
|
|
193
|
+
String.raw`^(appleid|apps)\.apple\.com$`,
|
|
194
|
+
String.raw`^play\.google\.com$`,
|
|
195
|
+
String.raw`^login\.microsoftonline\.com$`
|
|
196
|
+
];
|
|
197
|
+
/** GA4's paid mediums: cpc, cpm, ppc, retargeting, paid_social, … */
|
|
198
|
+
const PAID_MEDIUM = "^(.*cp.*|ppc|retargeting|paid.*)$";
|
|
199
|
+
const DISPLAY_MEDIUMS = [
|
|
200
|
+
"display",
|
|
201
|
+
"banner",
|
|
202
|
+
"expandable",
|
|
203
|
+
"interstitial"
|
|
204
|
+
];
|
|
205
|
+
const EMAIL_MEDIUMS = [
|
|
206
|
+
"email",
|
|
207
|
+
"e-mail",
|
|
208
|
+
"e_mail",
|
|
209
|
+
"e mail"
|
|
210
|
+
];
|
|
211
|
+
/** Where a touch came from: a tracked session, or a report by the user or staff. */
|
|
212
|
+
const TOUCH_SOURCES = ["tracked", "reported"];
|
|
213
|
+
/**
|
|
214
|
+
* How a reported touch was learned:
|
|
215
|
+
* - survey: the user answered "how did you hear about us" (onboarding, checkout)
|
|
216
|
+
* - promo_code: the user redeemed a code that belongs to a channel
|
|
217
|
+
* - phone: a call came in on a channel's dedicated number, marked by staff or the phone system
|
|
218
|
+
* - manual: staff recorded what a customer told them
|
|
219
|
+
*/
|
|
220
|
+
const REPORTED_TOUCH_KINDS = [
|
|
221
|
+
"survey",
|
|
222
|
+
"promo_code",
|
|
223
|
+
"phone",
|
|
224
|
+
"manual"
|
|
225
|
+
];
|
|
226
|
+
/**
|
|
227
|
+
* How much a touch is worth against another when attribution has to choose between sessions;
|
|
228
|
+
* lower wins, and the latest wins among equals. Derived in the views, never stored, so
|
|
229
|
+
* renumbering is a view regeneration.
|
|
230
|
+
*
|
|
231
|
+
* This ranks touches against each other. Within one session the rules that name its channel have
|
|
232
|
+
* their own order — `utm_source`, then a click id, then the ad landing page, then the referrer —
|
|
233
|
+
* and the first that says something wins; the session's priority is then the tier of that rule.
|
|
234
|
+
* So two sessions tagged with utm and gclid respectively are equal here (both `campaign`) and the
|
|
235
|
+
* later one is credited, while one session carrying both is named by its utm.
|
|
236
|
+
*/
|
|
237
|
+
const TOUCH_PRIORITY = {
|
|
238
|
+
/** utm, click id, ad landing page: someone tagged that link (in that order within a session) */
|
|
239
|
+
campaign: 1,
|
|
240
|
+
/** a reported touch staff stand behind: a call on a channel's number, a recorded conversation */
|
|
241
|
+
verified: 1,
|
|
242
|
+
/** the browser said where the visitor came from; nobody chose it */
|
|
243
|
+
referrer: 2,
|
|
244
|
+
/** a reported touch that is the user's claim: a survey answer, a code that may have been shared */
|
|
245
|
+
claimed: 3
|
|
246
|
+
};
|
|
247
|
+
/** Which reported kinds are staff facts and which are the user's claims. */
|
|
248
|
+
const REPORTED_TOUCH_PRIORITY = {
|
|
249
|
+
phone: TOUCH_PRIORITY.verified,
|
|
250
|
+
manual: TOUCH_PRIORITY.verified,
|
|
251
|
+
survey: TOUCH_PRIORITY.claimed,
|
|
252
|
+
promo_code: TOUCH_PRIORITY.claimed
|
|
253
|
+
};
|
|
254
|
+
//#endregion
|
|
255
|
+
export { AD_LANDING_PAGE, CHANNELS, CHANNEL_GROUPS, CLICK_ID_CHANNELS, DIRECT_CHANNEL, DISPLAY_MEDIUMS, EMAIL_MEDIUMS, MEDIUM_NOT_SET, NO_MEDIUM, PAID_MEDIUM, REFERRERS_NOT_A_TOUCH, REFERRER_SITES, REPORTED_TOUCH_KINDS, REPORTED_TOUCH_PRIORITY, SOURCE_ALIASES, TOUCH_PRIORITY, TOUCH_SOURCES };
|
|
256
|
+
|
|
257
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/attribution/index.ts"],"sourcesContent":["import type { AdvertisingInfo } from '../track/types';\n\n/**\n * The vocabulary attribution is built from, shared by every product's `touchpoint` view and by the\n * dashboards that read it. Data only, no SQL: a product turns these into its view. What stays with\n * the product is its own hostnames (referrer exclusions) and its landing-page convention.\n */\n\n/** A session that arrived through nothing we can name. GA's spelling, so dashboards read as GA. */\nexport const DIRECT_CHANNEL = '(direct)';\n/** The medium of a direct session. */\nexport const NO_MEDIUM = '(none)';\n/** The medium of a tagged link that named a source but no medium. */\nexport const MEDIUM_NOT_SET = '(not set)';\n\n/** The channels the rules below can name. A `utm_source` outside this list is its own channel. */\nexport const CHANNELS = [\n 'meta',\n 'google',\n 'dv360',\n 'microsoft',\n 'tiktok',\n 'reddit',\n 'linkedin',\n 'snapchat',\n 'x',\n 'kakao',\n 'yandex',\n 'yahoo',\n 'duckduckgo',\n 'baidu',\n 'ecosia',\n 'naver',\n 'brave',\n 'pinterest',\n 'youtube',\n] as const;\n\nexport type Channel = (typeof CHANNELS)[number];\n\n/** GA4's default channel groups, as identifiers; a dashboard maps them to display names. */\nexport const CHANNEL_GROUPS = [\n 'direct',\n 'paid_search',\n 'paid_social',\n 'paid_other',\n 'display',\n 'organic_search',\n 'organic_social',\n 'organic_video',\n 'referral',\n 'email',\n 'affiliate',\n 'unassigned',\n] as const;\n\nexport type ChannelGroup = (typeof CHANNEL_GROUPS)[number];\n\n/** `utm_source` spellings that mean the same channel: Meta's `{{site_source_name}}` values and the usual synonyms. */\nexport const SOURCE_ALIASES = {\n fb: 'meta',\n ig: 'meta',\n an: 'meta',\n msg: 'meta',\n facebook: 'meta',\n instagram: 'meta',\n bing: 'microsoft',\n twitter: 'x',\n} as const satisfies Record<string, Channel>;\n\n/**\n * Which click id belongs to which channel, in priority order. Every key is a field this SDK\n * collects (`AdvertisingInfo`); `fbp` and `rdt_uuid` are deliberately absent — they are pixel\n * browser ids, present with or without a click.\n */\nexport const CLICK_ID_CHANNELS = [\n ['fbclid', 'meta'],\n ['fbc', 'meta'],\n ['gclid', 'google'],\n ['gbraid', 'google'],\n ['wbraid', 'google'],\n ['gad_source', 'google'],\n ['gad_campaignid', 'google'],\n ['dclid', 'dv360'],\n ['msclkid', 'microsoft'],\n ['ttclid', 'tiktok'],\n ['rdt_cid', 'reddit'],\n ['li_fat_id', 'linkedin'],\n ['sccid', 'snapchat'],\n ['twclid', 'x'],\n ['ko_click_id', 'kakao'],\n ['yclid', 'yandex'],\n] as const satisfies readonly (readonly [keyof AdvertisingInfo, Channel])[];\n\n/**\n * A landing page reserved for one channel's ads, for ads that lost their parameters:\n * `/lp/<channel>`, with or without host, query and hash; the capture is the channel. A product\n * that names its landing pages differently replaces this.\n */\nexport const AD_LANDING_PAGE = '^(?:https?://[^/]+)?/lp/([a-z]+)(?:[/?#]|$)';\n\nexport type ReferrerMedium = 'organic' | 'social' | 'video';\n\n/**\n * Referrer hosts that name a channel, as POSIX regular expressions over the lower-cased host,\n * with the medium GA4 gives that kind of site. Anything else that refers is `referral`, kept as\n * its host. A country TLD is one or two labels (`google.com`, `google.co.uk`, `google.com.hk`),\n * never an open tail, so `google.com.evil.io` is not Google.\n */\nexport const REFERRER_SITES = [\n ['google', 'organic', String.raw`(^|\\.)google\\.[a-z]{2,}(\\.[a-z]{2,3})?$`],\n ['microsoft', 'organic', String.raw`(^|\\.)bing\\.com$`],\n ['yahoo', 'organic', String.raw`(^|\\.)yahoo\\.[a-z]{2,}(\\.[a-z]{2,3})?$`],\n ['duckduckgo', 'organic', String.raw`(^|\\.)duckduckgo\\.com$`],\n ['baidu', 'organic', String.raw`(^|\\.)baidu\\.com$`],\n ['yandex', 'organic', String.raw`(^|\\.)yandex\\.[a-z]{2,}(\\.[a-z]{2,3})?$`],\n ['ecosia', 'organic', String.raw`(^|\\.)ecosia\\.org$`],\n ['naver', 'organic', String.raw`(^|\\.)naver\\.com$`],\n ['brave', 'organic', String.raw`^search\\.brave\\.com$`],\n ['meta', 'social', String.raw`(^|\\.)(facebook\\.com|instagram\\.com|fb\\.com|threads\\.net)$`],\n ['x', 'social', String.raw`(^|\\.)(twitter\\.com|x\\.com|t\\.co)$`],\n ['linkedin', 'social', String.raw`(^|\\.)(linkedin\\.com|lnkd\\.in)$`],\n ['reddit', 'social', String.raw`(^|\\.)reddit\\.com$`],\n ['tiktok', 'social', String.raw`(^|\\.)tiktok\\.com$`],\n ['pinterest', 'social', String.raw`(^|\\.)pinterest\\.[a-z]{2,}(\\.[a-z]{2,3})?$`],\n ['snapchat', 'social', String.raw`(^|\\.)snapchat\\.com$`],\n ['youtube', 'video', String.raw`(^|\\.)(youtube\\.com|youtu\\.be)$`],\n] as const satisfies readonly (readonly [Channel, ReferrerMedium, string])[];\n\n/**\n * Referrer hosts that are navigation, not acquisition: the payment and sign-in providers a\n * visitor is bounced through and back from, and the local dev host. A product appends its own\n * hostnames — a session that starts from an internal link after the session timeout refers to\n * them. POSIX regular expressions over the lower-cased host.\n */\nexport const REFERRERS_NOT_A_TOUCH = [\n String.raw`^localhost(:|$)`,\n String.raw`(^|\\.)stripe\\.com$`,\n String.raw`^(pay|accounts)\\.google\\.com$`,\n String.raw`^(appleid|apps)\\.apple\\.com$`,\n String.raw`^play\\.google\\.com$`,\n String.raw`^login\\.microsoftonline\\.com$`,\n] as const;\n\n/** GA4's paid mediums: cpc, cpm, ppc, retargeting, paid_social, … */\nexport const PAID_MEDIUM = '^(.*cp.*|ppc|retargeting|paid.*)$';\nexport const DISPLAY_MEDIUMS = ['display', 'banner', 'expandable', 'interstitial'] as const;\nexport const EMAIL_MEDIUMS = ['email', 'e-mail', 'e_mail', 'e mail'] as const;\n\n/** Where a touch came from: a tracked session, or a report by the user or staff. */\nexport const TOUCH_SOURCES = ['tracked', 'reported'] as const;\nexport type TouchSource = (typeof TOUCH_SOURCES)[number];\n\n/**\n * How a reported touch was learned:\n * - survey: the user answered \"how did you hear about us\" (onboarding, checkout)\n * - promo_code: the user redeemed a code that belongs to a channel\n * - phone: a call came in on a channel's dedicated number, marked by staff or the phone system\n * - manual: staff recorded what a customer told them\n */\nexport const REPORTED_TOUCH_KINDS = ['survey', 'promo_code', 'phone', 'manual'] as const;\nexport type ReportedTouchKind = (typeof REPORTED_TOUCH_KINDS)[number];\n\n/**\n * How much a touch is worth against another when attribution has to choose between sessions;\n * lower wins, and the latest wins among equals. Derived in the views, never stored, so\n * renumbering is a view regeneration.\n *\n * This ranks touches against each other. Within one session the rules that name its channel have\n * their own order — `utm_source`, then a click id, then the ad landing page, then the referrer —\n * and the first that says something wins; the session's priority is then the tier of that rule.\n * So two sessions tagged with utm and gclid respectively are equal here (both `campaign`) and the\n * later one is credited, while one session carrying both is named by its utm.\n */\nexport const TOUCH_PRIORITY = {\n /** utm, click id, ad landing page: someone tagged that link (in that order within a session) */\n campaign: 1,\n /** a reported touch staff stand behind: a call on a channel's number, a recorded conversation */\n verified: 1,\n /** the browser said where the visitor came from; nobody chose it */\n referrer: 2,\n /** a reported touch that is the user's claim: a survey answer, a code that may have been shared */\n claimed: 3,\n} as const satisfies Record<string, number>;\n\n/** Which reported kinds are staff facts and which are the user's claims. */\nexport const REPORTED_TOUCH_PRIORITY = {\n phone: TOUCH_PRIORITY.verified,\n manual: TOUCH_PRIORITY.verified,\n survey: TOUCH_PRIORITY.claimed,\n promo_code: TOUCH_PRIORITY.claimed,\n} as const satisfies Record<ReportedTouchKind, number>;\n"],"mappings":";;;;;;;AASA,MAAa,iBAAiB;;AAE9B,MAAa,YAAY;;AAEzB,MAAa,iBAAiB;;AAG9B,MAAa,WAAW;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAKA,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAKA,MAAa,iBAAiB;CAC5B,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,KAAK;CACL,UAAU;CACV,WAAW;CACX,MAAM;CACN,SAAS;AACX;;;;;;AAOA,MAAa,oBAAoB;CAC/B,CAAC,UAAU,MAAM;CACjB,CAAC,OAAO,MAAM;CACd,CAAC,SAAS,QAAQ;CAClB,CAAC,UAAU,QAAQ;CACnB,CAAC,UAAU,QAAQ;CACnB,CAAC,cAAc,QAAQ;CACvB,CAAC,kBAAkB,QAAQ;CAC3B,CAAC,SAAS,OAAO;CACjB,CAAC,WAAW,WAAW;CACvB,CAAC,UAAU,QAAQ;CACnB,CAAC,WAAW,QAAQ;CACpB,CAAC,aAAa,UAAU;CACxB,CAAC,SAAS,UAAU;CACpB,CAAC,UAAU,GAAG;CACd,CAAC,eAAe,OAAO;CACvB,CAAC,SAAS,QAAQ;AACpB;;;;;;AAOA,MAAa,kBAAkB;;;;;;;AAU/B,MAAa,iBAAiB;CAC5B;EAAC;EAAU;EAAW,OAAO,GAAG;CAAyC;CACzE;EAAC;EAAa;EAAW,OAAO,GAAG;CAAkB;CACrD;EAAC;EAAS;EAAW,OAAO,GAAG;CAAwC;CACvE;EAAC;EAAc;EAAW,OAAO,GAAG;CAAwB;CAC5D;EAAC;EAAS;EAAW,OAAO,GAAG;CAAmB;CAClD;EAAC;EAAU;EAAW,OAAO,GAAG;CAAyC;CACzE;EAAC;EAAU;EAAW,OAAO,GAAG;CAAoB;CACpD;EAAC;EAAS;EAAW,OAAO,GAAG;CAAmB;CAClD;EAAC;EAAS;EAAW,OAAO,GAAG;CAAsB;CACrD;EAAC;EAAQ;EAAU,OAAO,GAAG;CAA4D;CACzF;EAAC;EAAK;EAAU,OAAO,GAAG;CAAoC;CAC9D;EAAC;EAAY;EAAU,OAAO,GAAG;CAAiC;CAClE;EAAC;EAAU;EAAU,OAAO,GAAG;CAAoB;CACnD;EAAC;EAAU;EAAU,OAAO,GAAG;CAAoB;CACnD;EAAC;EAAa;EAAU,OAAO,GAAG;CAA4C;CAC9E;EAAC;EAAY;EAAU,OAAO,GAAG;CAAsB;CACvD;EAAC;EAAW;EAAS,OAAO,GAAG;CAAiC;AAClE;;;;;;;AAQA,MAAa,wBAAwB;CACnC,OAAO,GAAG;CACV,OAAO,GAAG;CACV,OAAO,GAAG;CACV,OAAO,GAAG;CACV,OAAO,GAAG;CACV,OAAO,GAAG;AACZ;;AAGA,MAAa,cAAc;AAC3B,MAAa,kBAAkB;CAAC;CAAW;CAAU;CAAc;AAAc;AACjF,MAAa,gBAAgB;CAAC;CAAS;CAAU;CAAU;AAAQ;;AAGnE,MAAa,gBAAgB,CAAC,WAAW,UAAU;;;;;;;;AAUnD,MAAa,uBAAuB;CAAC;CAAU;CAAc;CAAS;AAAQ;;;;;;;;;;;;AAc9E,MAAa,iBAAiB;;CAE5B,UAAU;;CAEV,UAAU;;CAEV,UAAU;;CAEV,SAAS;AACX;;AAGA,MAAa,0BAA0B;CACrC,OAAO,eAAe;CACtB,QAAQ,eAAe;CACvB,QAAQ,eAAe;CACvB,YAAY,eAAe;AAC7B"}
|
package/dist/schema/index.cjs
CHANGED
|
@@ -185,7 +185,6 @@ const userProvidedDataSchema = (0, zod_mini.object)({
|
|
|
185
185
|
const updateVisitorSchema = (0, zod_mini.object)({
|
|
186
186
|
user_id: (0, zod_mini.optional)((0, zod_mini.uuid)()),
|
|
187
187
|
user_data: (0, zod_mini.optional)(userProvidedDataSchema),
|
|
188
|
-
distinct_id: (0, zod_mini.optional)((0, zod_mini.string)().check((0, zod_mini.trim)(), (0, zod_mini.minLength)(1), (0, zod_mini.maxLength)(36))),
|
|
189
188
|
tags: tagsSchema,
|
|
190
189
|
properties: visitorPropertiesSchema
|
|
191
190
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["pipe","string","transform","array","record","union","number","boolean","_null","object","optional","trim","minLength","maxLength","regex","uuid","_enum","iso","toLowerCase","email","e164","toUpperCase","url"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n page_load_id: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["pipe","string","transform","array","record","union","number","boolean","_null","object","optional","trim","minLength","maxLength","regex","uuid","_enum","iso","toLowerCase","email","e164","toUpperCase","url"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n page_load_id: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
|
package/dist/schema/index.d.cts
CHANGED
|
@@ -277,7 +277,6 @@ declare const updateVisitorSchema: z.ZodMiniObject<{
|
|
|
277
277
|
country: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
278
278
|
}, z.core.$strip>>]>>;
|
|
279
279
|
}, z.core.$strip>>;
|
|
280
|
-
distinct_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
281
280
|
tags: z.ZodMiniObject<{
|
|
282
281
|
os: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
283
282
|
os_name: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6ErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6ErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAK9B,EAAA,KAAA;cAEW,sBAAoB,EAAA;;;;GAI/B,EAAA,KAAA;;;;;cAWW,kBAAgB,EAAA;;;;;;;;;;;GA+C3B,EAAA,KAAA;KAEU,sBAAsB,EAAE,cAAc;KACtC,oBAAoB,EAAE,cAAc;KACpC,gBAAgB,EAAE,cAAc;KAChC,mBAAmB,EAAE,cAAc;KACnC,sBAAsB,EAAE,cAAc;KACtC,mBAAmB,EAAE,cAAc"}
|
package/dist/schema/index.d.mts
CHANGED
|
@@ -277,7 +277,6 @@ declare const updateVisitorSchema: z.ZodMiniObject<{
|
|
|
277
277
|
country: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
278
278
|
}, z.core.$strip>>]>>;
|
|
279
279
|
}, z.core.$strip>>;
|
|
280
|
-
distinct_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
281
280
|
tags: z.ZodMiniObject<{
|
|
282
281
|
os: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
283
282
|
os_name: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6ErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6ErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAK9B,EAAA,KAAA;cAEW,sBAAoB,EAAA;;;;GAI/B,EAAA,KAAA;;;;;cAWW,kBAAgB,EAAA;;;;;;;;;;;GA+C3B,EAAA,KAAA;KAEU,sBAAsB,EAAE,cAAc;KACtC,oBAAoB,EAAE,cAAc;KACpC,gBAAgB,EAAE,cAAc;KAChC,mBAAmB,EAAE,cAAc;KACnC,sBAAsB,EAAE,cAAc;KACtC,mBAAmB,EAAE,cAAc"}
|
package/dist/schema/index.mjs
CHANGED
|
@@ -184,7 +184,6 @@ const userProvidedDataSchema = object({
|
|
|
184
184
|
const updateVisitorSchema = object({
|
|
185
185
|
user_id: optional(uuid()),
|
|
186
186
|
user_data: optional(userProvidedDataSchema),
|
|
187
|
-
distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),
|
|
188
187
|
tags: tagsSchema,
|
|
189
188
|
properties: visitorPropertiesSchema
|
|
190
189
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["_null","_enum"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n page_load_id: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["_null","_enum"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n page_load_id: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
|
|
@@ -18,8 +18,14 @@ function sendPosthogEvent(name, properties) {
|
|
|
18
18
|
posthog_js.posthog.capture(name, properties);
|
|
19
19
|
if (name === "logout") posthog_js.posthog.reset();
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Identify the visitor to PostHog as the person the server says it is — `distinct_id`, the user's
|
|
23
|
+
* id once someone has signed in. Only then: identifying an anonymous visitor by its own id would
|
|
24
|
+
* make PostHog treat it as an identified person, and PostHog does not merge one identified person
|
|
25
|
+
* into another when the user later signs in, so the pre-sign-in events would stay split off.
|
|
26
|
+
*/
|
|
21
27
|
function setPosthogUser({ user_id, distinct_id, user_data }) {
|
|
22
|
-
if (!
|
|
28
|
+
if (!user_id) return;
|
|
23
29
|
posthog_js.posthog.identify(distinct_id ?? user_id, { email: require_utils_field.getFirst(user_data?.email) });
|
|
24
30
|
}
|
|
25
31
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog.cjs","names":["getFirst"],"sources":["../../src/third-parties/posthog.ts"],"sourcesContent":["import { posthog } from 'posthog-js';\nimport type {
|
|
1
|
+
{"version":3,"file":"posthog.cjs","names":["getFirst"],"sources":["../../src/third-parties/posthog.ts"],"sourcesContent":["import { posthog } from 'posthog-js';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\nimport type { VisitorIdentity } from '../visitor/types';\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendPosthogEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n // `document`, not `window`: React Native defines `window` as an alias of `global`, so a\n // window check would pass there and then throw on `window.location`, which it has no such\n // alias for. `posthog-js` is the browser SDK and cannot run there anyway.\n if (typeof document === 'undefined') return;\n if (metrics.includes(name)) return;\n if (window.location.host.includes('127.0.0.1')) return;\n if (window.location.host.includes('localhost')) return;\n\n posthog.capture(name, properties);\n if (name === 'logout') {\n posthog.reset();\n }\n}\n\n/**\n * Identify the visitor to PostHog as the person the server says it is — `distinct_id`, the user's\n * id once someone has signed in. Only then: identifying an anonymous visitor by its own id would\n * make PostHog treat it as an identified person, and PostHog does not merge one identified person\n * into another when the user later signs in, so the pre-sign-in events would stay split off.\n */\nexport function setPosthogUser({ user_id, distinct_id, user_data }: VisitorIdentity) {\n if (!user_id) return;\n posthog.identify(distinct_id ?? user_id, { email: getFirst(user_data?.email) });\n}\n"],"mappings":";;;;AAKA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,iBACd,MACA,YACA;CAIA,IAAI,OAAO,aAAa,aAAa;CACrC,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,WAAA,QAAQ,QAAQ,MAAM,UAAU;CAChC,IAAI,SAAS,UACX,WAAA,QAAQ,MAAM;AAElB;;;;;;;AAQA,SAAgB,eAAe,EAAE,SAAS,aAAa,aAA8B;CACnF,IAAI,CAAC,SAAS;CACd,WAAA,QAAQ,SAAS,eAAe,SAAS,EAAE,OAAOA,oBAAAA,SAAS,WAAW,KAAK,EAAE,CAAC;AAChF"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { UpdateVisitorDTO } from "../schema/index.cjs";
|
|
2
1
|
import { EventName, TrackName, TrackProperties } from "../track/types.cjs";
|
|
2
|
+
import { VisitorIdentity } from "../visitor/types.cjs";
|
|
3
3
|
//#region src/third-parties/posthog.d.ts
|
|
4
4
|
declare function sendPosthogEvent<T extends EventName>(name: TrackName<T>, properties?: TrackProperties<T>): void;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Identify the visitor to PostHog as the person the server says it is — `distinct_id`, the user's
|
|
7
|
+
* id once someone has signed in. Only then: identifying an anonymous visitor by its own id would
|
|
8
|
+
* make PostHog treat it as an identified person, and PostHog does not merge one identified person
|
|
9
|
+
* into another when the user later signs in, so the pre-sign-in events would stay split off.
|
|
10
|
+
*/
|
|
11
|
+
declare function setPosthogUser({ user_id, distinct_id, user_data }: VisitorIdentity): void;
|
|
6
12
|
//#endregion
|
|
7
13
|
export { sendPosthogEvent, setPosthogUser };
|
|
8
14
|
//# sourceMappingURL=posthog.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog.d.cts","names":[],"sources":["../../src/third-parties/posthog.ts"],"mappings":";;;iBAOgB,iBAAiB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB
|
|
1
|
+
{"version":3,"file":"posthog.d.cts","names":[],"sources":["../../src/third-parties/posthog.ts"],"mappings":";;;iBAOgB,iBAAiB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB;;;;;;;iBAsBf,iBAAiB,SAAS,aAAa,aAAa"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { UpdateVisitorDTO } from "../schema/index.mjs";
|
|
2
1
|
import { EventName, TrackName, TrackProperties } from "../track/types.mjs";
|
|
2
|
+
import { VisitorIdentity } from "../visitor/types.mjs";
|
|
3
3
|
//#region src/third-parties/posthog.d.ts
|
|
4
4
|
declare function sendPosthogEvent<T extends EventName>(name: TrackName<T>, properties?: TrackProperties<T>): void;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Identify the visitor to PostHog as the person the server says it is — `distinct_id`, the user's
|
|
7
|
+
* id once someone has signed in. Only then: identifying an anonymous visitor by its own id would
|
|
8
|
+
* make PostHog treat it as an identified person, and PostHog does not merge one identified person
|
|
9
|
+
* into another when the user later signs in, so the pre-sign-in events would stay split off.
|
|
10
|
+
*/
|
|
11
|
+
declare function setPosthogUser({ user_id, distinct_id, user_data }: VisitorIdentity): void;
|
|
6
12
|
//#endregion
|
|
7
13
|
export { sendPosthogEvent, setPosthogUser };
|
|
8
14
|
//# sourceMappingURL=posthog.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog.d.mts","names":[],"sources":["../../src/third-parties/posthog.ts"],"mappings":";;;iBAOgB,iBAAiB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB
|
|
1
|
+
{"version":3,"file":"posthog.d.mts","names":[],"sources":["../../src/third-parties/posthog.ts"],"mappings":";;;iBAOgB,iBAAiB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB;;;;;;;iBAsBf,iBAAiB,SAAS,aAAa,aAAa"}
|
|
@@ -17,8 +17,14 @@ function sendPosthogEvent(name, properties) {
|
|
|
17
17
|
posthog.capture(name, properties);
|
|
18
18
|
if (name === "logout") posthog.reset();
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Identify the visitor to PostHog as the person the server says it is — `distinct_id`, the user's
|
|
22
|
+
* id once someone has signed in. Only then: identifying an anonymous visitor by its own id would
|
|
23
|
+
* make PostHog treat it as an identified person, and PostHog does not merge one identified person
|
|
24
|
+
* into another when the user later signs in, so the pre-sign-in events would stay split off.
|
|
25
|
+
*/
|
|
20
26
|
function setPosthogUser({ user_id, distinct_id, user_data }) {
|
|
21
|
-
if (!
|
|
27
|
+
if (!user_id) return;
|
|
22
28
|
posthog.identify(distinct_id ?? user_id, { email: getFirst(user_data?.email) });
|
|
23
29
|
}
|
|
24
30
|
//#endregion
|