@shware/analytics 7.1.0 → 7.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/use-outbound-click-analytics.cjs +1 -1
- package/dist/hooks/use-outbound-click-analytics.cjs.map +1 -1
- package/dist/hooks/use-outbound-click-analytics.mjs +1 -1
- package/dist/hooks/use-outbound-click-analytics.mjs.map +1 -1
- package/dist/schema/index.cjs +47 -18
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +4 -4
- package/dist/schema/index.d.cts.map +1 -1
- package/dist/schema/index.d.mts +4 -4
- package/dist/schema/index.d.mts.map +1 -1
- package/dist/schema/index.mjs +48 -19
- package/dist/schema/index.mjs.map +1 -1
- package/dist/third-parties/google-analytics.cjs +2 -2
- package/dist/third-parties/google-analytics.cjs.map +1 -1
- package/dist/third-parties/google-analytics.mjs +2 -2
- package/dist/third-parties/google-analytics.mjs.map +1 -1
- package/dist/third-parties/meta-pixel.cjs.map +1 -1
- package/dist/third-parties/meta-pixel.d.cts.map +1 -1
- package/dist/third-parties/meta-pixel.d.mts.map +1 -1
- package/dist/third-parties/meta-pixel.mjs.map +1 -1
- package/dist/third-parties/posthog.cjs +1 -0
- package/dist/third-parties/posthog.cjs.map +1 -1
- package/dist/third-parties/posthog.d.cts.map +1 -1
- package/dist/third-parties/posthog.d.mts.map +1 -1
- package/dist/third-parties/posthog.mjs +1 -0
- package/dist/third-parties/posthog.mjs.map +1 -1
- package/dist/third-parties/reddit-pixel.cjs +1 -1
- package/dist/third-parties/reddit-pixel.cjs.map +1 -1
- package/dist/third-parties/reddit-pixel.d.cts.map +1 -1
- package/dist/third-parties/reddit-pixel.d.mts.map +1 -1
- package/dist/third-parties/reddit-pixel.mjs +1 -1
- package/dist/third-parties/reddit-pixel.mjs.map +1 -1
- package/dist/track/index.cjs +7 -1
- package/dist/track/index.cjs.map +1 -1
- package/dist/track/index.d.cts.map +1 -1
- package/dist/track/index.d.mts.map +1 -1
- package/dist/track/index.mjs +7 -1
- package/dist/track/index.mjs.map +1 -1
- package/dist/visitor/index.cjs +7 -1
- package/dist/visitor/index.cjs.map +1 -1
- package/dist/visitor/index.mjs +7 -1
- package/dist/visitor/index.mjs.map +1 -1
- package/package.json +14 -14
|
@@ -17,7 +17,7 @@ function useOutboundClickAnalytics() {
|
|
|
17
17
|
outbound: true,
|
|
18
18
|
link_id: anchor.id || "",
|
|
19
19
|
link_url: anchor.href,
|
|
20
|
-
link_text: anchor.textContent.trim()
|
|
20
|
+
link_text: anchor.textContent.trim().slice(0, 512),
|
|
21
21
|
link_domain: url.hostname,
|
|
22
22
|
link_classes: anchor.className || ""
|
|
23
23
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-outbound-click-analytics.cjs","names":[],"sources":["../../src/hooks/use-outbound-click-analytics.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { track } from '../track/index';\n\n/**\n * Tracks outbound link clicks - when a user clicks a link that leads away\n * from the current domain to another website.\n */\nexport function useOutboundClickAnalytics() {\n useEffect(() => {\n const onClick = (event: MouseEvent) => {\n // Find the closest anchor element from the clicked target\n const target = event.target as HTMLElement;\n const anchor = target.closest('a');\n if (!anchor?.href) return;\n\n try {\n const url = new URL(anchor.href, window.location.origin);\n\n // Check if it's an external link (different hostname)\n if (url.hostname !== window.location.hostname) {\n track('click', {\n outbound: true,\n link_id: anchor.id || '',\n link_url: anchor.href,\n link_text: anchor.textContent.trim()
|
|
1
|
+
{"version":3,"file":"use-outbound-click-analytics.cjs","names":[],"sources":["../../src/hooks/use-outbound-click-analytics.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { track } from '../track/index';\n\n/**\n * Tracks outbound link clicks - when a user clicks a link that leads away\n * from the current domain to another website.\n */\nexport function useOutboundClickAnalytics() {\n useEffect(() => {\n const onClick = (event: MouseEvent) => {\n // Find the closest anchor element from the clicked target\n const target = event.target as HTMLElement;\n const anchor = target.closest('a');\n if (!anchor?.href) return;\n\n try {\n const url = new URL(anchor.href, window.location.origin);\n\n // Check if it's an external link (different hostname)\n if (url.hostname !== window.location.hostname) {\n track('click', {\n outbound: true,\n link_id: anchor.id || '',\n link_url: anchor.href,\n // An anchor can wrap a whole card, so its text runs to kilobytes of markup content\n // that no report ever looks at. 100 characters is what GA4 keeps of a text event\n // parameter, and the transport limit is well above it either way.\n link_text: anchor.textContent.trim().slice(0, 512),\n link_domain: url.hostname,\n link_classes: anchor.className || '',\n });\n }\n } catch {\n // Invalid URL, ignore\n }\n };\n\n document.addEventListener('click', onClick, { passive: true, capture: true });\n return () => document.removeEventListener('click', onClick, { capture: true });\n }, []);\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,4BAA4B;CAC1C,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,WAAW,UAAsB;GAGrC,MAAM,SADS,MAAM,OACC,QAAQ,GAAG;GACjC,IAAI,CAAC,QAAQ,MAAM;GAEnB,IAAI;IACF,MAAM,MAAM,IAAI,IAAI,OAAO,MAAM,OAAO,SAAS,MAAM;IAGvD,IAAI,IAAI,aAAa,OAAO,SAAS,UACnC,oBAAA,MAAM,SAAS;KACb,UAAU;KACV,SAAS,OAAO,MAAM;KACtB,UAAU,OAAO;KAIjB,WAAW,OAAO,YAAY,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG;KACjD,aAAa,IAAI;KACjB,cAAc,OAAO,aAAa;IACpC,CAAC;GAEL,QAAQ,CAER;EACF;EAEA,SAAS,iBAAiB,SAAS,SAAS;GAAE,SAAS;GAAM,SAAS;EAAK,CAAC;EAC5E,aAAa,SAAS,oBAAoB,SAAS,SAAS,EAAE,SAAS,KAAK,CAAC;CAC/E,GAAG,CAAC,CAAC;AACP"}
|
|
@@ -16,7 +16,7 @@ function useOutboundClickAnalytics() {
|
|
|
16
16
|
outbound: true,
|
|
17
17
|
link_id: anchor.id || "",
|
|
18
18
|
link_url: anchor.href,
|
|
19
|
-
link_text: anchor.textContent.trim()
|
|
19
|
+
link_text: anchor.textContent.trim().slice(0, 512),
|
|
20
20
|
link_domain: url.hostname,
|
|
21
21
|
link_classes: anchor.className || ""
|
|
22
22
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-outbound-click-analytics.mjs","names":[],"sources":["../../src/hooks/use-outbound-click-analytics.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { track } from '../track/index';\n\n/**\n * Tracks outbound link clicks - when a user clicks a link that leads away\n * from the current domain to another website.\n */\nexport function useOutboundClickAnalytics() {\n useEffect(() => {\n const onClick = (event: MouseEvent) => {\n // Find the closest anchor element from the clicked target\n const target = event.target as HTMLElement;\n const anchor = target.closest('a');\n if (!anchor?.href) return;\n\n try {\n const url = new URL(anchor.href, window.location.origin);\n\n // Check if it's an external link (different hostname)\n if (url.hostname !== window.location.hostname) {\n track('click', {\n outbound: true,\n link_id: anchor.id || '',\n link_url: anchor.href,\n link_text: anchor.textContent.trim()
|
|
1
|
+
{"version":3,"file":"use-outbound-click-analytics.mjs","names":[],"sources":["../../src/hooks/use-outbound-click-analytics.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { track } from '../track/index';\n\n/**\n * Tracks outbound link clicks - when a user clicks a link that leads away\n * from the current domain to another website.\n */\nexport function useOutboundClickAnalytics() {\n useEffect(() => {\n const onClick = (event: MouseEvent) => {\n // Find the closest anchor element from the clicked target\n const target = event.target as HTMLElement;\n const anchor = target.closest('a');\n if (!anchor?.href) return;\n\n try {\n const url = new URL(anchor.href, window.location.origin);\n\n // Check if it's an external link (different hostname)\n if (url.hostname !== window.location.hostname) {\n track('click', {\n outbound: true,\n link_id: anchor.id || '',\n link_url: anchor.href,\n // An anchor can wrap a whole card, so its text runs to kilobytes of markup content\n // that no report ever looks at. 100 characters is what GA4 keeps of a text event\n // parameter, and the transport limit is well above it either way.\n link_text: anchor.textContent.trim().slice(0, 512),\n link_domain: url.hostname,\n link_classes: anchor.className || '',\n });\n }\n } catch {\n // Invalid URL, ignore\n }\n };\n\n document.addEventListener('click', onClick, { passive: true, capture: true });\n return () => document.removeEventListener('click', onClick, { capture: true });\n }, []);\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,4BAA4B;CAC1C,gBAAgB;EACd,MAAM,WAAW,UAAsB;GAGrC,MAAM,SADS,MAAM,OACC,QAAQ,GAAG;GACjC,IAAI,CAAC,QAAQ,MAAM;GAEnB,IAAI;IACF,MAAM,MAAM,IAAI,IAAI,OAAO,MAAM,OAAO,SAAS,MAAM;IAGvD,IAAI,IAAI,aAAa,OAAO,SAAS,UACnC,MAAM,SAAS;KACb,UAAU;KACV,SAAS,OAAO,MAAM;KACtB,UAAU,OAAO;KAIjB,WAAW,OAAO,YAAY,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG;KACjD,aAAa,IAAI;KACjB,cAAc,OAAO,aAAa;IACpC,CAAC;GAEL,QAAQ,CAER;EACF;EAEA,SAAS,iBAAiB,SAAS,SAAS;GAAE,SAAS;GAAM,SAAS;EAAK,CAAC;EAC5E,aAAa,SAAS,oBAAoB,SAAS,SAAS,EAAE,SAAS,KAAK,CAAC;CAC/E,GAAG,CAAC,CAAC;AACP"}
|
package/dist/schema/index.cjs
CHANGED
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let zod_mini = require("zod/mini");
|
|
3
3
|
//#region src/schema/index.ts
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const MAX_KEY_LENGTH = 128;
|
|
5
|
+
const MAX_VALUE_LENGTH = 512;
|
|
6
|
+
const MAX_PROPERTIES = 64;
|
|
7
|
+
/**
|
|
8
|
+
* Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one
|
|
9
|
+
* oversized value costs every event that traveled with it — and the values that overrun are the
|
|
10
|
+
* ones derived from the page (a link's text, a URL carrying a long query), which no client can
|
|
11
|
+
* bound in advance. A shortened value is worth more than a lost batch.
|
|
12
|
+
*/
|
|
13
|
+
const propertyText = (0, zod_mini.pipe)((0, zod_mini.string)(), (0, zod_mini.transform)((value) => value.slice(0, MAX_VALUE_LENGTH)));
|
|
14
|
+
/**
|
|
15
|
+
* Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host
|
|
16
|
+
* rather than something the visitor typed. It is still dropped rather than rejected, for the same
|
|
17
|
+
* reason: the mistake should cost that property, not the batch it happens to be in. Truncating a
|
|
18
|
+
* key is not an option — two long keys would silently become one field.
|
|
19
|
+
*
|
|
20
|
+
* The key schema below is deliberately permissive so that this transform is reached at all; the
|
|
21
|
+
* trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion
|
|
22
|
+
* order.
|
|
23
|
+
*/
|
|
24
|
+
function takeProperties(data) {
|
|
25
|
+
const result = {};
|
|
26
|
+
let count = 0;
|
|
27
|
+
for (const [rawKey, value] of Object.entries(data)) {
|
|
28
|
+
if (count >= MAX_PROPERTIES) break;
|
|
29
|
+
const key = rawKey.trim();
|
|
30
|
+
if (!key || key.length > MAX_KEY_LENGTH) continue;
|
|
31
|
+
result[key] = value;
|
|
32
|
+
count++;
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
const items = (0, zod_mini.array)((0, zod_mini.pipe)((0, zod_mini.record)((0, zod_mini.string)(), (0, zod_mini.union)([
|
|
37
|
+
propertyText,
|
|
6
38
|
(0, zod_mini.number)(),
|
|
7
39
|
(0, zod_mini.boolean)(),
|
|
8
40
|
(0, zod_mini.null)()
|
|
9
|
-
])));
|
|
41
|
+
])), (0, zod_mini.transform)(takeProperties)));
|
|
10
42
|
const ALL_PLATFORMS = [
|
|
11
43
|
"ios",
|
|
12
44
|
"android",
|
|
@@ -76,13 +108,20 @@ const tagsSchema = (0, zod_mini.object)({
|
|
|
76
108
|
utm_creative_format: (0, zod_mini.optional)((0, zod_mini.string)()),
|
|
77
109
|
utm_marketing_tactic: (0, zod_mini.optional)((0, zod_mini.string)())
|
|
78
110
|
});
|
|
79
|
-
const propertiesSchema = (0, zod_mini.optional)((0, zod_mini.
|
|
80
|
-
|
|
111
|
+
const propertiesSchema = (0, zod_mini.optional)((0, zod_mini.pipe)((0, zod_mini.record)((0, zod_mini.string)(), (0, zod_mini.union)([
|
|
112
|
+
propertyText,
|
|
81
113
|
(0, zod_mini.number)(),
|
|
82
114
|
(0, zod_mini.boolean)(),
|
|
83
115
|
(0, zod_mini.null)(),
|
|
84
116
|
items
|
|
85
|
-
]))
|
|
117
|
+
])), (0, zod_mini.transform)(takeProperties)));
|
|
118
|
+
/** Visitor properties differ from event properties only in taking no nested item lists. */
|
|
119
|
+
const visitorPropertiesSchema = (0, zod_mini.optional)((0, zod_mini.pipe)((0, zod_mini.record)((0, zod_mini.string)(), (0, zod_mini.union)([
|
|
120
|
+
propertyText,
|
|
121
|
+
(0, zod_mini.number)(),
|
|
122
|
+
(0, zod_mini.boolean)(),
|
|
123
|
+
(0, zod_mini.null)()
|
|
124
|
+
])), (0, zod_mini.transform)(takeProperties)));
|
|
86
125
|
const createTrackEventSchema = (0, zod_mini.array)((0, zod_mini.object)({
|
|
87
126
|
name: (0, zod_mini.string)().check((0, zod_mini.trim)(), (0, zod_mini.minLength)(1), (0, zod_mini.maxLength)(64)),
|
|
88
127
|
visitor_id: (0, zod_mini.uuid)(),
|
|
@@ -98,12 +137,7 @@ const createVisitorSchema = (0, zod_mini.object)({
|
|
|
98
137
|
platform: (0, zod_mini.enum)(ALL_PLATFORMS),
|
|
99
138
|
environment: (0, zod_mini.enum)(ALL_ENVIRONMENTS),
|
|
100
139
|
tags: tagsSchema,
|
|
101
|
-
properties:
|
|
102
|
-
(0, zod_mini.string)().check((0, zod_mini.maxLength)(512)),
|
|
103
|
-
(0, zod_mini.number)(),
|
|
104
|
-
(0, zod_mini.boolean)(),
|
|
105
|
-
(0, zod_mini.null)()
|
|
106
|
-
])).check((0, zod_mini.refine)((data) => Object.keys(data).length <= 64)))
|
|
140
|
+
properties: visitorPropertiesSchema
|
|
107
141
|
});
|
|
108
142
|
const emailValue = (0, zod_mini.pipe)((0, zod_mini.string)().check((0, zod_mini.trim)(), (0, zod_mini.toLowerCase)(), (0, zod_mini.maxLength)(320)), (0, zod_mini.email)());
|
|
109
143
|
/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */
|
|
@@ -139,12 +173,7 @@ const updateVisitorSchema = (0, zod_mini.object)({
|
|
|
139
173
|
user_data: (0, zod_mini.optional)(userProvidedDataSchema),
|
|
140
174
|
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))),
|
|
141
175
|
tags: tagsSchema,
|
|
142
|
-
properties:
|
|
143
|
-
(0, zod_mini.string)().check((0, zod_mini.maxLength)(512)),
|
|
144
|
-
(0, zod_mini.number)(),
|
|
145
|
-
(0, zod_mini.boolean)(),
|
|
146
|
-
(0, zod_mini.null)()
|
|
147
|
-
])).check((0, zod_mini.refine)((data) => Object.keys(data).length <= 64)))
|
|
176
|
+
properties: visitorPropertiesSchema
|
|
148
177
|
});
|
|
149
178
|
const createFeedbackSchema = (0, zod_mini.object)({
|
|
150
179
|
name: (0, zod_mini.string)().check((0, zod_mini.minLength)(1), (0, zod_mini.maxLength)(256)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["iso"],"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 refine,\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 items = array(\n record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null()])\n )\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 // 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 site_source_name: 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 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 record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null(), items])\n ).check(refine((data) => Object.keys(data).length <= 64))\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: optional(\n record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null()])\n ).check(refine((data) => Object.keys(data).length <= 64))\n ),\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: optional(\n record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null()])\n ).check(refine((data) => Object.keys(data).length <= 64))\n ),\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":["iso"],"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\nconst items = array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\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 // 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 site_source_name: 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 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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"}
|
package/dist/schema/index.d.cts
CHANGED
|
@@ -61,7 +61,7 @@ declare const tagsSchema: z.ZodMiniObject<{
|
|
|
61
61
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
62
62
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
63
63
|
}, z.core.$strip>;
|
|
64
|
-
declare const propertiesSchema: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
64
|
+
declare const propertiesSchema: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>]>>, z.ZodMiniTransform<Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>, Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>>>>;
|
|
65
65
|
declare const createTrackEventSchema: z.ZodMiniArray<z.ZodMiniObject<{
|
|
66
66
|
name: z.ZodMiniString<string>;
|
|
67
67
|
visitor_id: z.ZodMiniUUID;
|
|
@@ -139,7 +139,7 @@ declare const createTrackEventSchema: z.ZodMiniArray<z.ZodMiniObject<{
|
|
|
139
139
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
140
140
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
141
141
|
}, z.core.$strip>;
|
|
142
|
-
properties: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
142
|
+
properties: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>]>>, z.ZodMiniTransform<Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>, Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>>>>;
|
|
143
143
|
}, z.core.$strip>>;
|
|
144
144
|
declare const createVisitorSchema: z.ZodMiniObject<{
|
|
145
145
|
device_id: z.ZodMiniString<string>;
|
|
@@ -215,7 +215,7 @@ declare const createVisitorSchema: z.ZodMiniObject<{
|
|
|
215
215
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
216
216
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
217
217
|
}, z.core.$strip>;
|
|
218
|
-
properties: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
218
|
+
properties: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>;
|
|
219
219
|
}, z.core.$strip>;
|
|
220
220
|
/**
|
|
221
221
|
* User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.
|
|
@@ -331,7 +331,7 @@ declare const updateVisitorSchema: z.ZodMiniObject<{
|
|
|
331
331
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
332
332
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
333
333
|
}, z.core.$strip>;
|
|
334
|
-
properties: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
334
|
+
properties: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>;
|
|
335
335
|
}, z.core.$strip>;
|
|
336
336
|
declare const createFeedbackSchema: z.ZodMiniObject<{
|
|
337
337
|
name: z.ZodMiniString<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAyEa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqErB,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,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,wDAAA,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,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
|
@@ -61,7 +61,7 @@ declare const tagsSchema: z.ZodMiniObject<{
|
|
|
61
61
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
62
62
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
63
63
|
}, z.core.$strip>;
|
|
64
|
-
declare const propertiesSchema: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
64
|
+
declare const propertiesSchema: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>]>>, z.ZodMiniTransform<Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>, Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>>>>;
|
|
65
65
|
declare const createTrackEventSchema: z.ZodMiniArray<z.ZodMiniObject<{
|
|
66
66
|
name: z.ZodMiniString<string>;
|
|
67
67
|
visitor_id: z.ZodMiniUUID;
|
|
@@ -139,7 +139,7 @@ declare const createTrackEventSchema: z.ZodMiniArray<z.ZodMiniObject<{
|
|
|
139
139
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
140
140
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
141
141
|
}, z.core.$strip>;
|
|
142
|
-
properties: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
142
|
+
properties: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull, z.ZodMiniArray<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>]>>, z.ZodMiniTransform<Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>, Record<string, string | number | boolean | Record<string, string | number | boolean | null>[] | null>>>>;
|
|
143
143
|
}, z.core.$strip>>;
|
|
144
144
|
declare const createVisitorSchema: z.ZodMiniObject<{
|
|
145
145
|
device_id: z.ZodMiniString<string>;
|
|
@@ -215,7 +215,7 @@ declare const createVisitorSchema: z.ZodMiniObject<{
|
|
|
215
215
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
216
216
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
217
217
|
}, z.core.$strip>;
|
|
218
|
-
properties: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
218
|
+
properties: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>;
|
|
219
219
|
}, z.core.$strip>;
|
|
220
220
|
/**
|
|
221
221
|
* User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.
|
|
@@ -331,7 +331,7 @@ declare const updateVisitorSchema: z.ZodMiniObject<{
|
|
|
331
331
|
utm_creative_format: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
332
332
|
utm_marketing_tactic: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
333
333
|
}, z.core.$strip>;
|
|
334
|
-
properties: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]
|
|
334
|
+
properties: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniString<string>, z.ZodMiniTransform<string, string>>, z.ZodMiniNumber<number>, z.ZodMiniBoolean<boolean>, z.ZodMiniNull]>>, z.ZodMiniTransform<Record<string, string | number | boolean | null>, Record<string, string | number | boolean | null>>>>;
|
|
335
335
|
}, z.core.$strip>;
|
|
336
336
|
declare const createFeedbackSchema: z.ZodMiniObject<{
|
|
337
337
|
name: z.ZodMiniString<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAyEa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqErB,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,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,wDAAA,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,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
|
@@ -1,11 +1,43 @@
|
|
|
1
|
-
import { array, boolean, e164, email, enum as enum$1, iso, maxLength, minLength, null as null$1, number, object, optional, pipe, record,
|
|
1
|
+
import { array, boolean, e164, email, enum as enum$1, iso, maxLength, minLength, null as null$1, number, object, optional, pipe, record, regex, string, toLowerCase, toUpperCase, transform, trim, union, url, uuid } from "zod/mini";
|
|
2
2
|
//#region src/schema/index.ts
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const MAX_KEY_LENGTH = 128;
|
|
4
|
+
const MAX_VALUE_LENGTH = 512;
|
|
5
|
+
const MAX_PROPERTIES = 64;
|
|
6
|
+
/**
|
|
7
|
+
* Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one
|
|
8
|
+
* oversized value costs every event that traveled with it — and the values that overrun are the
|
|
9
|
+
* ones derived from the page (a link's text, a URL carrying a long query), which no client can
|
|
10
|
+
* bound in advance. A shortened value is worth more than a lost batch.
|
|
11
|
+
*/
|
|
12
|
+
const propertyText = pipe(string(), transform((value) => value.slice(0, MAX_VALUE_LENGTH)));
|
|
13
|
+
/**
|
|
14
|
+
* Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host
|
|
15
|
+
* rather than something the visitor typed. It is still dropped rather than rejected, for the same
|
|
16
|
+
* reason: the mistake should cost that property, not the batch it happens to be in. Truncating a
|
|
17
|
+
* key is not an option — two long keys would silently become one field.
|
|
18
|
+
*
|
|
19
|
+
* The key schema below is deliberately permissive so that this transform is reached at all; the
|
|
20
|
+
* trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion
|
|
21
|
+
* order.
|
|
22
|
+
*/
|
|
23
|
+
function takeProperties(data) {
|
|
24
|
+
const result = {};
|
|
25
|
+
let count = 0;
|
|
26
|
+
for (const [rawKey, value] of Object.entries(data)) {
|
|
27
|
+
if (count >= MAX_PROPERTIES) break;
|
|
28
|
+
const key = rawKey.trim();
|
|
29
|
+
if (!key || key.length > MAX_KEY_LENGTH) continue;
|
|
30
|
+
result[key] = value;
|
|
31
|
+
count++;
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
const items = array(pipe(record(string(), union([
|
|
36
|
+
propertyText,
|
|
5
37
|
number(),
|
|
6
38
|
boolean(),
|
|
7
39
|
null$1()
|
|
8
|
-
])));
|
|
40
|
+
])), transform(takeProperties)));
|
|
9
41
|
const ALL_PLATFORMS = [
|
|
10
42
|
"ios",
|
|
11
43
|
"android",
|
|
@@ -75,13 +107,20 @@ const tagsSchema = object({
|
|
|
75
107
|
utm_creative_format: optional(string()),
|
|
76
108
|
utm_marketing_tactic: optional(string())
|
|
77
109
|
});
|
|
78
|
-
const propertiesSchema = optional(record(string()
|
|
79
|
-
|
|
110
|
+
const propertiesSchema = optional(pipe(record(string(), union([
|
|
111
|
+
propertyText,
|
|
80
112
|
number(),
|
|
81
113
|
boolean(),
|
|
82
114
|
null$1(),
|
|
83
115
|
items
|
|
84
|
-
]))
|
|
116
|
+
])), transform(takeProperties)));
|
|
117
|
+
/** Visitor properties differ from event properties only in taking no nested item lists. */
|
|
118
|
+
const visitorPropertiesSchema = optional(pipe(record(string(), union([
|
|
119
|
+
propertyText,
|
|
120
|
+
number(),
|
|
121
|
+
boolean(),
|
|
122
|
+
null$1()
|
|
123
|
+
])), transform(takeProperties)));
|
|
85
124
|
const createTrackEventSchema = array(object({
|
|
86
125
|
name: string().check(trim(), minLength(1), maxLength(64)),
|
|
87
126
|
visitor_id: uuid(),
|
|
@@ -97,12 +136,7 @@ const createVisitorSchema = object({
|
|
|
97
136
|
platform: enum$1(ALL_PLATFORMS),
|
|
98
137
|
environment: enum$1(ALL_ENVIRONMENTS),
|
|
99
138
|
tags: tagsSchema,
|
|
100
|
-
properties:
|
|
101
|
-
string().check(maxLength(512)),
|
|
102
|
-
number(),
|
|
103
|
-
boolean(),
|
|
104
|
-
null$1()
|
|
105
|
-
])).check(refine((data) => Object.keys(data).length <= 64)))
|
|
139
|
+
properties: visitorPropertiesSchema
|
|
106
140
|
});
|
|
107
141
|
const emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());
|
|
108
142
|
/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */
|
|
@@ -138,12 +172,7 @@ const updateVisitorSchema = object({
|
|
|
138
172
|
user_data: optional(userProvidedDataSchema),
|
|
139
173
|
distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),
|
|
140
174
|
tags: tagsSchema,
|
|
141
|
-
properties:
|
|
142
|
-
string().check(maxLength(512)),
|
|
143
|
-
number(),
|
|
144
|
-
boolean(),
|
|
145
|
-
null$1()
|
|
146
|
-
])).check(refine((data) => Object.keys(data).length <= 64)))
|
|
175
|
+
properties: visitorPropertiesSchema
|
|
147
176
|
});
|
|
148
177
|
const createFeedbackSchema = object({
|
|
149
178
|
name: string().check(minLength(1), maxLength(256)),
|
|
@@ -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 refine,\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 items = array(\n record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null()])\n )\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 // 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 site_source_name: 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 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 record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null(), items])\n ).check(refine((data) => Object.keys(data).length <= 64))\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: optional(\n record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null()])\n ).check(refine((data) => Object.keys(data).length <= 64))\n ),\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: optional(\n record(\n string().check(trim(), minLength(1), maxLength(128)),\n union([string().check(maxLength(512)), number(), boolean(), _null()])\n ).check(refine((data) => Object.keys(data).length <= 64))\n ),\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\nconst items = array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\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 // 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 site_source_name: 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 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,14 +1,14 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
//#region src/third-parties/google-analytics.ts
|
|
3
3
|
function sendGAEvent(name, properties) {
|
|
4
|
-
if (!window.gtag) {
|
|
4
|
+
if (typeof window === "undefined" || !window.gtag) {
|
|
5
5
|
console.warn("GA has not been initialized");
|
|
6
6
|
return;
|
|
7
7
|
}
|
|
8
8
|
window.gtag("event", name, properties);
|
|
9
9
|
}
|
|
10
10
|
function setGAUser({ user_id, user_data, properties }) {
|
|
11
|
-
if (!window.gtag) {
|
|
11
|
+
if (typeof window === "undefined" || !window.gtag) {
|
|
12
12
|
console.warn("GA has not been initialized");
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-analytics.cjs","names":[],"sources":["../../src/third-parties/google-analytics.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport type { Gtag } from '../track/gtag';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\n\ndeclare global {\n interface Window {\n /** Undefined until the Google tag (gtag.js) script has loaded. */\n gtag?: Gtag['gtag'];\n }\n}\n\nexport function sendGAEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n window.gtag('event', name, properties);\n}\n\nexport function setGAUser({ user_id, user_data, properties }: UpdateVisitorDTO) {\n if (!window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n if (user_id) window.gtag('set', 'user_id', user_id);\n if (user_data) window.gtag('set', 'user_data', user_data);\n if (properties) window.gtag('set', 'user_properties', properties as never);\n}\n"],"mappings":";;AAWA,SAAgB,YACd,MACA,YACA;CACA,IAAI,CAAC,OAAO,MAAM;
|
|
1
|
+
{"version":3,"file":"google-analytics.cjs","names":[],"sources":["../../src/third-parties/google-analytics.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport type { Gtag } from '../track/gtag';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\n\ndeclare global {\n interface Window {\n /** Undefined until the Google tag (gtag.js) script has loaded. */\n gtag?: Gtag['gtag'];\n }\n}\n\nexport function sendGAEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (typeof window === 'undefined' || !window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n window.gtag('event', name, properties);\n}\n\nexport function setGAUser({ user_id, user_data, properties }: UpdateVisitorDTO) {\n if (typeof window === 'undefined' || !window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n if (user_id) window.gtag('set', 'user_id', user_id);\n if (user_data) window.gtag('set', 'user_data', user_data);\n if (properties) window.gtag('set', 'user_properties', properties as never);\n}\n"],"mappings":";;AAWA,SAAgB,YACd,MACA,YACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;EACjD,QAAQ,KAAK,6BAA6B;EAC1C;CACF;CACA,OAAO,KAAK,SAAS,MAAM,UAAU;AACvC;AAEA,SAAgB,UAAU,EAAE,SAAS,WAAW,cAAgC;CAC9E,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;EACjD,QAAQ,KAAK,6BAA6B;EAC1C;CACF;CACA,IAAI,SAAS,OAAO,KAAK,OAAO,WAAW,OAAO;CAClD,IAAI,WAAW,OAAO,KAAK,OAAO,aAAa,SAAS;CACxD,IAAI,YAAY,OAAO,KAAK,OAAO,mBAAmB,UAAmB;AAC3E"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
//#region src/third-parties/google-analytics.ts
|
|
2
2
|
function sendGAEvent(name, properties) {
|
|
3
|
-
if (!window.gtag) {
|
|
3
|
+
if (typeof window === "undefined" || !window.gtag) {
|
|
4
4
|
console.warn("GA has not been initialized");
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
7
|
window.gtag("event", name, properties);
|
|
8
8
|
}
|
|
9
9
|
function setGAUser({ user_id, user_data, properties }) {
|
|
10
|
-
if (!window.gtag) {
|
|
10
|
+
if (typeof window === "undefined" || !window.gtag) {
|
|
11
11
|
console.warn("GA has not been initialized");
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-analytics.mjs","names":[],"sources":["../../src/third-parties/google-analytics.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport type { Gtag } from '../track/gtag';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\n\ndeclare global {\n interface Window {\n /** Undefined until the Google tag (gtag.js) script has loaded. */\n gtag?: Gtag['gtag'];\n }\n}\n\nexport function sendGAEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n window.gtag('event', name, properties);\n}\n\nexport function setGAUser({ user_id, user_data, properties }: UpdateVisitorDTO) {\n if (!window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n if (user_id) window.gtag('set', 'user_id', user_id);\n if (user_data) window.gtag('set', 'user_data', user_data);\n if (properties) window.gtag('set', 'user_properties', properties as never);\n}\n"],"mappings":";AAWA,SAAgB,YACd,MACA,YACA;CACA,IAAI,CAAC,OAAO,MAAM;
|
|
1
|
+
{"version":3,"file":"google-analytics.mjs","names":[],"sources":["../../src/third-parties/google-analytics.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport type { Gtag } from '../track/gtag';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\n\ndeclare global {\n interface Window {\n /** Undefined until the Google tag (gtag.js) script has loaded. */\n gtag?: Gtag['gtag'];\n }\n}\n\nexport function sendGAEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (typeof window === 'undefined' || !window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n window.gtag('event', name, properties);\n}\n\nexport function setGAUser({ user_id, user_data, properties }: UpdateVisitorDTO) {\n if (typeof window === 'undefined' || !window.gtag) {\n console.warn('GA has not been initialized');\n return;\n }\n if (user_id) window.gtag('set', 'user_id', user_id);\n if (user_data) window.gtag('set', 'user_data', user_data);\n if (properties) window.gtag('set', 'user_properties', properties as never);\n}\n"],"mappings":";AAWA,SAAgB,YACd,MACA,YACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;EACjD,QAAQ,KAAK,6BAA6B;EAC1C;CACF;CACA,OAAO,KAAK,SAAS,MAAM,UAAU;AACvC;AAEA,SAAgB,UAAU,EAAE,SAAS,WAAW,cAAgC;CAC9E,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,MAAM;EACjD,QAAQ,KAAK,6BAA6B;EAC1C;CACF;CACA,IAAI,SAAS,OAAO,KAAK,OAAO,WAAW,OAAO;CAClD,IAAI,WAAW,OAAO,KAAK,OAAO,aAAa,SAAS;CACxD,IAAI,YAAY,OAAO,KAAK,OAAO,mBAAmB,UAAmB;AAC3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-pixel.cjs","names":["mapFBEvent","getFirst"],"sources":["../../src/third-parties/meta-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type FBQ, type PixelId, mapFBEvent } from '../track/fbq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Meta Pixel script has loaded. */\n fbq?: FBQ['fbq'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendFBEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n event_id?: string\n) {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\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 const options = { eventID: event_id };\n const [type, fbEventName, fbEventProperties] = mapFBEvent(name, properties);\n if (type === 'track') {\n window.fbq(type, fbEventName, fbEventProperties, options);\n } else {\n window.fbq(type, fbEventName, fbEventProperties, options);\n }\n}\n\nexport function setFBUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\n\n const address = getFirst(user_data?.address);\n\n window.fbq('init', pixelId, {\n em: getFirst(user_data?.email),\n fn: address?.first_name,\n ln: address?.last_name,\n ph: getFirst(user_data?.phone_number),\n external_id: user_id,\n ct: address?.city,\n st: address?.street,\n zp: address?.postal_code,\n country: address?.country,\n });\n };\n}\n"],"mappings":";;;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,YACd,MACA,YACA,UACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,UAAU,EAAE,SAAS,SAAS;CACpC,MAAM,CAAC,MAAM,aAAa,qBAAqBA,kBAAAA,WAAW,MAAM,UAAU;
|
|
1
|
+
{"version":3,"file":"meta-pixel.cjs","names":["mapFBEvent","getFirst"],"sources":["../../src/third-parties/meta-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type FBQ, type PixelId, mapFBEvent } from '../track/fbq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Meta Pixel script has loaded. */\n fbq?: FBQ['fbq'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendFBEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n event_id?: string\n) {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\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 const options = { eventID: event_id };\n const [type, fbEventName, fbEventProperties] = mapFBEvent(name, properties);\n // The two branches are identical on purpose. `fbq` is overloaded per `type` — 'track' takes a\n // standard event name with its typed properties, 'trackCustom' an arbitrary string — and what\n // `mapFBEvent` returns is a union of both shapes. Narrowing `type` is what picks a single\n // overload; collapsing the branches leaves the call matching none of them.\n if (type === 'track') {\n window.fbq(type, fbEventName, fbEventProperties, options);\n } else {\n window.fbq(type, fbEventName, fbEventProperties, options);\n }\n}\n\nexport function setFBUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\n\n const address = getFirst(user_data?.address);\n\n window.fbq('init', pixelId, {\n em: getFirst(user_data?.email),\n fn: address?.first_name,\n ln: address?.last_name,\n ph: getFirst(user_data?.phone_number),\n external_id: user_id,\n ct: address?.city,\n st: address?.street,\n zp: address?.postal_code,\n country: address?.country,\n });\n };\n}\n"],"mappings":";;;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,YACd,MACA,YACA,UACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,UAAU,EAAE,SAAS,SAAS;CACpC,MAAM,CAAC,MAAM,aAAa,qBAAqBA,kBAAAA,WAAW,MAAM,UAAU;CAK1E,IAAI,SAAS,SACX,OAAO,IAAI,MAAM,aAAa,mBAAmB,OAAO;MAExD,OAAO,IAAI,MAAM,aAAa,mBAAmB,OAAO;AAE5D;AAEA,SAAgB,UAAU,SAAkB;CAC1C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;GAChD,QAAQ,KAAK,8BAA8B;GAC3C;EACF;EAEA,MAAM,UAAUC,oBAAAA,SAAS,WAAW,OAAO;EAE3C,OAAO,IAAI,QAAQ,SAAS;GAC1B,IAAIA,oBAAAA,SAAS,WAAW,KAAK;GAC7B,IAAI,SAAS;GACb,IAAI,SAAS;GACb,IAAIA,oBAAAA,SAAS,WAAW,YAAY;GACpC,aAAa;GACb,IAAI,SAAS;GACb,IAAI,SAAS;GACb,IAAI,SAAS;GACb,SAAS,SAAS;EACpB,CAAC;CACH;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-pixel.d.cts","names":[],"sources":["../../src/third-parties/meta-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,YAAY,UAAU,WACpC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;
|
|
1
|
+
{"version":3,"file":"meta-pixel.d.cts","names":[],"sources":["../../src/third-parties/meta-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,YAAY,UAAU,WACpC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAuBc,UAAU,SAAS,aAAO,SAAA,aACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-pixel.d.mts","names":[],"sources":["../../src/third-parties/meta-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,YAAY,UAAU,WACpC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;
|
|
1
|
+
{"version":3,"file":"meta-pixel.d.mts","names":[],"sources":["../../src/third-parties/meta-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,YAAY,UAAU,WACpC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAuBc,UAAU,SAAS,aAAO,SAAA,aACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-pixel.mjs","names":[],"sources":["../../src/third-parties/meta-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type FBQ, type PixelId, mapFBEvent } from '../track/fbq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Meta Pixel script has loaded. */\n fbq?: FBQ['fbq'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendFBEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n event_id?: string\n) {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\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 const options = { eventID: event_id };\n const [type, fbEventName, fbEventProperties] = mapFBEvent(name, properties);\n if (type === 'track') {\n window.fbq(type, fbEventName, fbEventProperties, options);\n } else {\n window.fbq(type, fbEventName, fbEventProperties, options);\n }\n}\n\nexport function setFBUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\n\n const address = getFirst(user_data?.address);\n\n window.fbq('init', pixelId, {\n em: getFirst(user_data?.email),\n fn: address?.first_name,\n ln: address?.last_name,\n ph: getFirst(user_data?.phone_number),\n external_id: user_id,\n ct: address?.city,\n st: address?.street,\n zp: address?.postal_code,\n country: address?.country,\n });\n };\n}\n"],"mappings":";;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,YACd,MACA,YACA,UACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,UAAU,EAAE,SAAS,SAAS;CACpC,MAAM,CAAC,MAAM,aAAa,qBAAqB,WAAW,MAAM,UAAU;
|
|
1
|
+
{"version":3,"file":"meta-pixel.mjs","names":[],"sources":["../../src/third-parties/meta-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type FBQ, type PixelId, mapFBEvent } from '../track/fbq';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Meta Pixel script has loaded. */\n fbq?: FBQ['fbq'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendFBEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n event_id?: string\n) {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\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 const options = { eventID: event_id };\n const [type, fbEventName, fbEventProperties] = mapFBEvent(name, properties);\n // The two branches are identical on purpose. `fbq` is overloaded per `type` — 'track' takes a\n // standard event name with its typed properties, 'trackCustom' an arbitrary string — and what\n // `mapFBEvent` returns is a union of both shapes. Narrowing `type` is what picks a single\n // overload; collapsing the branches leaves the call matching none of them.\n if (type === 'track') {\n window.fbq(type, fbEventName, fbEventProperties, options);\n } else {\n window.fbq(type, fbEventName, fbEventProperties, options);\n }\n}\n\nexport function setFBUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.fbq) {\n console.warn('fbq has not been initialized');\n return;\n }\n\n const address = getFirst(user_data?.address);\n\n window.fbq('init', pixelId, {\n em: getFirst(user_data?.email),\n fn: address?.first_name,\n ln: address?.last_name,\n ph: getFirst(user_data?.phone_number),\n external_id: user_id,\n ct: address?.city,\n st: address?.street,\n zp: address?.postal_code,\n country: address?.country,\n });\n };\n}\n"],"mappings":";;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,YACd,MACA,YACA,UACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,UAAU,EAAE,SAAS,SAAS;CACpC,MAAM,CAAC,MAAM,aAAa,qBAAqB,WAAW,MAAM,UAAU;CAK1E,IAAI,SAAS,SACX,OAAO,IAAI,MAAM,aAAa,mBAAmB,OAAO;MAExD,OAAO,IAAI,MAAM,aAAa,mBAAmB,OAAO;AAE5D;AAEA,SAAgB,UAAU,SAAkB;CAC1C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;GAChD,QAAQ,KAAK,8BAA8B;GAC3C;EACF;EAEA,MAAM,UAAU,SAAS,WAAW,OAAO;EAE3C,OAAO,IAAI,QAAQ,SAAS;GAC1B,IAAI,SAAS,WAAW,KAAK;GAC7B,IAAI,SAAS;GACb,IAAI,SAAS;GACb,IAAI,SAAS,WAAW,YAAY;GACpC,aAAa;GACb,IAAI,SAAS;GACb,IAAI,SAAS;GACb,IAAI,SAAS;GACb,SAAS,SAAS;EACpB,CAAC;CACH;AACF"}
|
|
@@ -11,6 +11,7 @@ const metrics = [
|
|
|
11
11
|
"TTFB"
|
|
12
12
|
];
|
|
13
13
|
function sendPosthogEvent(name, properties) {
|
|
14
|
+
if (typeof document === "undefined") return;
|
|
14
15
|
if (metrics.includes(name)) return;
|
|
15
16
|
if (window.location.host.includes("127.0.0.1")) return;
|
|
16
17
|
if (window.location.host.includes("localhost")) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog.cjs","names":["getFirst"],"sources":["../../src/third-parties/posthog.ts"],"sourcesContent":["import { posthog } from 'posthog-js';\nimport type { UpdateVisitorDTO } from '../schema/index';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\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 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\nexport function setPosthogUser({ user_id, distinct_id, user_data }: UpdateVisitorDTO) {\n if (!distinct_id && !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;
|
|
1
|
+
{"version":3,"file":"posthog.cjs","names":["getFirst"],"sources":["../../src/third-parties/posthog.ts"],"sourcesContent":["import { posthog } from 'posthog-js';\nimport type { UpdateVisitorDTO } from '../schema/index';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\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\nexport function setPosthogUser({ user_id, distinct_id, user_data }: UpdateVisitorDTO) {\n if (!distinct_id && !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;AAEA,SAAgB,eAAe,EAAE,SAAS,aAAa,aAA+B;CACpF,IAAI,CAAC,eAAe,CAAC,SAAS;CAC9B,WAAA,QAAQ,SAAS,eAAe,SAAS,EAAE,OAAOA,oBAAAA,SAAS,WAAW,KAAK,EAAE,CAAC;AAChF"}
|
|
@@ -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;iBAgBf,iBAAiB,SAAS,aAAa,aAAa"}
|
|
@@ -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;iBAgBf,iBAAiB,SAAS,aAAa,aAAa"}
|
|
@@ -10,6 +10,7 @@ const metrics = [
|
|
|
10
10
|
"TTFB"
|
|
11
11
|
];
|
|
12
12
|
function sendPosthogEvent(name, properties) {
|
|
13
|
+
if (typeof document === "undefined") return;
|
|
13
14
|
if (metrics.includes(name)) return;
|
|
14
15
|
if (window.location.host.includes("127.0.0.1")) return;
|
|
15
16
|
if (window.location.host.includes("localhost")) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog.mjs","names":[],"sources":["../../src/third-parties/posthog.ts"],"sourcesContent":["import { posthog } from 'posthog-js';\nimport type { UpdateVisitorDTO } from '../schema/index';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\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 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\nexport function setPosthogUser({ user_id, distinct_id, user_data }: UpdateVisitorDTO) {\n if (!distinct_id && !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;
|
|
1
|
+
{"version":3,"file":"posthog.mjs","names":[],"sources":["../../src/third-parties/posthog.ts"],"sourcesContent":["import { posthog } from 'posthog-js';\nimport type { UpdateVisitorDTO } from '../schema/index';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\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\nexport function setPosthogUser({ user_id, distinct_id, user_data }: UpdateVisitorDTO) {\n if (!distinct_id && !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,QAAQ,QAAQ,MAAM,UAAU;CAChC,IAAI,SAAS,UACX,QAAQ,MAAM;AAElB;AAEA,SAAgB,eAAe,EAAE,SAAS,aAAa,aAA+B;CACpF,IAAI,CAAC,eAAe,CAAC,SAAS;CAC9B,QAAQ,SAAS,eAAe,SAAS,EAAE,OAAO,SAAS,WAAW,KAAK,EAAE,CAAC;AAChF"}
|
|
@@ -24,7 +24,7 @@ function sendRedditEvent(name, properties, eventId) {
|
|
|
24
24
|
}
|
|
25
25
|
function setRedditUser(pixelId) {
|
|
26
26
|
return ({ user_id, user_data }) => {
|
|
27
|
-
if (!window.rdt) {
|
|
27
|
+
if (typeof window === "undefined" || !window.rdt) {
|
|
28
28
|
console.warn("rdt has not been initialized");
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.cjs","names":["mapRDTEvent","getFirst"],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Reddit Pixel script has loaded. */\n rdt?: RDT['rdt'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendRedditEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\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 const [type, params] = mapRDTEvent(name, properties, eventId);\n if (type === 'Custom') {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n } else {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n }\n}\n\nexport function setRedditUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (!window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n\n window.rdt('init', pixelId, {\n email: getFirst(user_data?.email),\n phoneNumber: getFirst(user_data?.phone_number),\n externalId: user_id,\n });\n };\n}\n"],"mappings":";;;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,CAAC,MAAM,UAAUA,kBAAAA,YAAY,MAAM,YAAY,OAAO;
|
|
1
|
+
{"version":3,"file":"reddit-pixel.cjs","names":["mapRDTEvent","getFirst"],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Reddit Pixel script has loaded. */\n rdt?: RDT['rdt'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendRedditEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\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 const [type, params] = mapRDTEvent(name, properties, eventId);\n // The two branches are identical on purpose: `rdt('track', ...)` is overloaded — a standard\n // event name carries its own params type, 'Custom' carries `CustomEventParams` — and what\n // `mapRDTEvent` returns is a union of both. Narrowing `type` is what picks a single overload.\n if (type === 'Custom') {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n } else {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n }\n}\n\nexport function setRedditUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n\n window.rdt('init', pixelId, {\n email: getFirst(user_data?.email),\n phoneNumber: getFirst(user_data?.phone_number),\n externalId: user_id,\n });\n };\n}\n"],"mappings":";;;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,CAAC,MAAM,UAAUA,kBAAAA,YAAY,MAAM,YAAY,OAAO;CAI5D,IAAI,SAAS,UACX,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;MAE5D,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;AAEhE;AAEA,SAAgB,cAAc,SAAkB;CAC9C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;GAChD,QAAQ,KAAK,8BAA8B;GAC3C;EACF;EAEA,OAAO,IAAI,QAAQ,SAAS;GAC1B,OAAOC,oBAAAA,SAAS,WAAW,KAAK;GAChC,aAAaA,oBAAAA,SAAS,WAAW,YAAY;GAC7C,YAAY;EACd,CAAC;CACH;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.d.cts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;
|
|
1
|
+
{"version":3,"file":"reddit-pixel.d.cts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAqBc,cAAc,SAAS,aAAO,SAAA,aACZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.d.mts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;
|
|
1
|
+
{"version":3,"file":"reddit-pixel.d.mts","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"mappings":";;;;QAKQ;YACI;;IAER,MAAM;;;iBAMM,gBAAgB,UAAU,WACxC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;iBAqBc,cAAc,SAAS,aAAO,SAAA,aACZ"}
|
|
@@ -23,7 +23,7 @@ function sendRedditEvent(name, properties, eventId) {
|
|
|
23
23
|
}
|
|
24
24
|
function setRedditUser(pixelId) {
|
|
25
25
|
return ({ user_id, user_data }) => {
|
|
26
|
-
if (!window.rdt) {
|
|
26
|
+
if (typeof window === "undefined" || !window.rdt) {
|
|
27
27
|
console.warn("rdt has not been initialized");
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reddit-pixel.mjs","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Reddit Pixel script has loaded. */\n rdt?: RDT['rdt'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendRedditEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\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 const [type, params] = mapRDTEvent(name, properties, eventId);\n if (type === 'Custom') {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n } else {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n }\n}\n\nexport function setRedditUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (!window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n\n window.rdt('init', pixelId, {\n email: getFirst(user_data?.email),\n phoneNumber: getFirst(user_data?.phone_number),\n externalId: user_id,\n });\n };\n}\n"],"mappings":";;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,CAAC,MAAM,UAAU,YAAY,MAAM,YAAY,OAAO;
|
|
1
|
+
{"version":3,"file":"reddit-pixel.mjs","names":[],"sources":["../../src/third-parties/reddit-pixel.ts"],"sourcesContent":["import type { UpdateVisitorDTO } from '../schema/index';\nimport { type PixelId, type RDT, mapRDTEvent } from '../track/rdt';\nimport type { EventName, TrackName, TrackProperties } from '../track/types';\nimport { getFirst } from '../utils/field';\n\ndeclare global {\n interface Window {\n /** Undefined until the Reddit Pixel script has loaded. */\n rdt?: RDT['rdt'];\n }\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport function sendRedditEvent<T extends EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n eventId?: string\n) {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\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 const [type, params] = mapRDTEvent(name, properties, eventId);\n // The two branches are identical on purpose: `rdt('track', ...)` is overloaded — a standard\n // event name carries its own params type, 'Custom' carries `CustomEventParams` — and what\n // `mapRDTEvent` returns is a union of both. Narrowing `type` is what picks a single overload.\n if (type === 'Custom') {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n } else {\n window.rdt('track', type, JSON.parse(JSON.stringify(params)));\n }\n}\n\nexport function setRedditUser(pixelId: PixelId) {\n return ({ user_id, user_data }: UpdateVisitorDTO) => {\n if (typeof window === 'undefined' || !window.rdt) {\n console.warn('rdt has not been initialized');\n return;\n }\n\n window.rdt('init', pixelId, {\n email: getFirst(user_data?.email),\n phoneNumber: getFirst(user_data?.phone_number),\n externalId: user_id,\n });\n };\n}\n"],"mappings":";;;AAYA,MAAM,UAAU;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM;AAE1D,SAAgB,gBACd,MACA,YACA,SACA;CACA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;EAChD,QAAQ,KAAK,8BAA8B;EAC3C;CACF;CACA,IAAI,QAAQ,SAAS,IAAI,GAAG;CAC5B,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAChD,IAAI,OAAO,SAAS,KAAK,SAAS,WAAW,GAAG;CAEhD,MAAM,CAAC,MAAM,UAAU,YAAY,MAAM,YAAY,OAAO;CAI5D,IAAI,SAAS,UACX,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;MAE5D,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,CAAC;AAEhE;AAEA,SAAgB,cAAc,SAAkB;CAC9C,QAAQ,EAAE,SAAS,gBAAkC;EACnD,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,KAAK;GAChD,QAAQ,KAAK,8BAA8B;GAC3C;EACF;EAEA,OAAO,IAAI,QAAQ,SAAS;GAC1B,OAAO,SAAS,WAAW,KAAK;GAChC,aAAa,SAAS,WAAW,YAAY;GAC7C,YAAY;EACd,CAAC;CACH;AACF"}
|
package/dist/track/index.cjs
CHANGED
|
@@ -83,7 +83,13 @@ async function sendEvents(events) {
|
|
|
83
83
|
options.onSucceed?.(eventId ? { id: eventId } : void 0);
|
|
84
84
|
index++;
|
|
85
85
|
if (!options.enableThirdPartyTracking || require_third_parties_ignored_events.IGNORED_EVENTS.includes(name)) continue;
|
|
86
|
-
require_setup_index.config.thirdPartyTrackers.forEach((tracker) =>
|
|
86
|
+
require_setup_index.config.thirdPartyTrackers.forEach((tracker) => {
|
|
87
|
+
try {
|
|
88
|
+
tracker(name, properties, eventId);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
if (e instanceof Error) console.log(e.message);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
87
93
|
}
|
|
88
94
|
} catch (e) {
|
|
89
95
|
if (e instanceof Error) console.log(e.message);
|
package/dist/track/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["TokenBucket","config","cache","getSession","getVisitor","IGNORED_EVENTS"],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { getSession } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties, TrackTags } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\n\nlet tokenBucket: TokenBucket | undefined;\n\n/**\n * The rate limiter, built on the first send rather than at module scope: its\n * constructor starts a refill `setInterval`, and Cloudflare Workers refuse to\n * set a timer outside a request handler for the same reason they refuse to\n * generate random values there — see `setup/session.ts`.\n */\nfunction getTokenBucket() {\n return (tokenBucket ??= new TokenBucket({ rate: 1, capacity: 20, requested: 2 }));\n}\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n tags: Promise<TrackTags>;\n timestamp: string;\n options: TrackOptions;\n};\n\n/**\n * Tags belong to the moment the event happened, not to the moment its batch goes out: a queued\n * event waits up to `delay` ms, and a single page app can navigate in that window, which would\n * stamp every pending event with the URL of the page the user has already left.\n *\n * The promise then sits in the queue with nothing awaiting it, so a failure has to be absorbed\n * here — an unhandled rejection would surface as a global error long before `sendEvents` could\n * catch it. Falling back to the last built tags keeps the event, minus whatever changed since.\n */\nasync function captureTags(): Promise<TrackTags> {\n try {\n return await config.getTags();\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n return cache.tags ?? {};\n }\n}\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n const session = getSession();\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await getTokenBucket().removeTokens();\n\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = await Promise.all(\n events.map(async (event) => ({\n name: event.name,\n properties: event.properties,\n tags: await event.tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }))\n );\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data.at(index)?.id;\n options.onSucceed?.(eventId ? { id: eventId } : undefined);\n index++;\n if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) {\n continue;\n }\n config.thirdPartyTrackers.forEach((tracker) => tracker(name, properties, eventId));\n }\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n events.forEach((event) => event.options.onError?.(e));\n }\n}\n\nconst batch = 10;\nconst delay = 2000;\nconst list: Item[] = [];\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Both paths into a send go through here, so a batch that fills up cancels the timer the\n * previous push armed rather than leaving it to wake up on its own with nothing to send.\n */\nfunction flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n if (list.length === 0) return;\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n}\n\nexport function track<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n list.push({\n name,\n properties,\n options,\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n if (list.length >= batch) {\n flush();\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(flush, delay);\n}\n\nexport async function trackAsync<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n await sendEvents([\n { name, properties, options, tags: captureTags(), timestamp: new Date().toISOString() },\n ]);\n}\n\nexport function sendBeacon<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!cache.tags || !cache.visitor) return;\n\n const session = getSession();\n session.updateLastActiveTime();\n\n const dto: CreateTrackEventDTO = [\n {\n name,\n properties,\n tags: cache.tags,\n visitor_id: cache.visitor.id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: new Date().toISOString(),\n },\n ];\n const blob = new Blob([JSON.stringify(dto)], { type: 'application/json' });\n const success = navigator.sendBeacon(`${config.endpoint}/events`, blob);\n if (success) return;\n console.warn('Failed to send beacon', name, properties);\n}\n"],"mappings":";;;;;;;AAcA,MAAM,iBAA+B,EAAE,0BAA0B,KAAK;AAEtE,IAAI;;;;;;;AAQJ,SAAS,iBAAiB;CACxB,OAAQ,gBAAgB,IAAIA,cAAAA,YAAY;EAAE,MAAM;EAAG,UAAU;EAAI,WAAW;CAAE,CAAC;AACjF;;;;;;;;;;AAqBA,eAAe,cAAkC;CAC/C,IAAI;EACF,OAAO,MAAMC,oBAAAA,OAAO,QAAQ;CAC9B,SAAS,GAAY;EACnB,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE,OAAO;EAC7C,OAAOC,oBAAAA,MAAM,QAAQ,CAAC;CACxB;AACF;AAEA,eAAe,WAAW,QAAgB;CACxC,IAAI;EACF,IAAI,OAAO,WAAW,GAAG;EAEzB,MAAM,UAAUC,sBAAAA,WAAW;EAC3B,IAAI,QAAQ,UAAU,GAAG;GACvB,QAAQ,QAAQ;GAChB,OAAO,QAAQ;IACb,MAAM;IACN,YAAY,CAAC;IACb,SAAS,EAAE,0BAA0B,MAAM;IAC3C,MAAM,YAAY;IAClB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GACpC,CAAC;EACH,OACE,QAAQ,qBAAqB;EAG/B,MAAM,eAAe,CAAC,CAAC,aAAa;EAEpC,MAAM,cAAc,MAAMC,sBAAAA,WAAW,EAAA,CAAG;EAExC,MAAM,MAA2B,MAAM,QAAQ,IAC7C,OAAO,IAAI,OAAO,WAAW;GAC3B,MAAM,MAAM;GACZ,YAAY,MAAM;GAClB,MAAM,MAAM,MAAM;GAClB;GACA,YAAY,QAAQ,MAAM;GAC1B,UAAUH,oBAAAA,OAAO;GACjB,aAAaA,oBAAAA,OAAO;GACpB,WAAW,MAAM;EACnB,EAAE,CACJ;EAEA,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,UAAU;GACxD,QAAQ;GACR,aAAa;GACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;GACjC,MAAM,KAAK,UAAU,GAAG;EAC1B,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,+BAA+B,SAAS,OAAO,GAAG,MAAM,SAAS,KAAK,GAAG;EAG3F,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,QAAQ;EACZ,OAAO,OAAO,SAAS,GAAG;GACxB,MAAM,QAAQ,OAAO,MAAM;GAC3B,IAAI,CAAC,OAAO;IACV;IACA;GACF;GACA,MAAM,EAAE,SAAS,MAAM,eAAe;GACtC,MAAM,UAAU,KAAK,GAAG,KAAK,CAAC,EAAE;GAChC,QAAQ,YAAY,UAAU,EAAE,IAAI,QAAQ,IAAI,KAAA,CAAS;GACzD;GACA,IAAI,CAAC,QAAQ,4BAA4BI,qCAAAA,eAAe,SAAS,IAAI,GACnE;GAEF,oBAAA,OAAO,mBAAmB,SAAS,YAAY,QAAQ,MAAM,YAAY,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["TokenBucket","config","cache","getSession","getVisitor","IGNORED_EVENTS"],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { getSession } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties, TrackTags } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\n\nlet tokenBucket: TokenBucket | undefined;\n\n/**\n * The rate limiter, built on the first send rather than at module scope: its\n * constructor starts a refill `setInterval`, and Cloudflare Workers refuse to\n * set a timer outside a request handler for the same reason they refuse to\n * generate random values there — see `setup/session.ts`.\n */\nfunction getTokenBucket() {\n return (tokenBucket ??= new TokenBucket({ rate: 1, capacity: 20, requested: 2 }));\n}\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n tags: Promise<TrackTags>;\n timestamp: string;\n options: TrackOptions;\n};\n\n/**\n * Tags belong to the moment the event happened, not to the moment its batch goes out: a queued\n * event waits up to `delay` ms, and a single page app can navigate in that window, which would\n * stamp every pending event with the URL of the page the user has already left.\n *\n * The promise then sits in the queue with nothing awaiting it, so a failure has to be absorbed\n * here — an unhandled rejection would surface as a global error long before `sendEvents` could\n * catch it. Falling back to the last built tags keeps the event, minus whatever changed since.\n */\nasync function captureTags(): Promise<TrackTags> {\n try {\n return await config.getTags();\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n return cache.tags ?? {};\n }\n}\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n const session = getSession();\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await getTokenBucket().removeTokens();\n\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = await Promise.all(\n events.map(async (event) => ({\n name: event.name,\n properties: event.properties,\n tags: await event.tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }))\n );\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data.at(index)?.id;\n options.onSucceed?.(eventId ? { id: eventId } : undefined);\n index++;\n if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) {\n continue;\n }\n config.thirdPartyTrackers.forEach((tracker) => {\n try {\n tracker(name, properties, eventId);\n } catch (e: unknown) {\n // A third-party script does not get to take the rest of the batch with it. This loop is\n // still draining `events` with `shift`, so a throw would escape to the catch below and\n // report failure to whatever is left in the queue — for events the server has already\n // accepted, and after the ones ahead of them were told they succeeded.\n if (e instanceof Error) console.log(e.message);\n }\n });\n }\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n events.forEach((event) => event.options.onError?.(e));\n }\n}\n\nconst batch = 10;\nconst delay = 2000;\nconst list: Item[] = [];\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Both paths into a send go through here, so a batch that fills up cancels the timer the\n * previous push armed rather than leaving it to wake up on its own with nothing to send.\n */\nfunction flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n if (list.length === 0) return;\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n}\n\nexport function track<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n list.push({\n name,\n properties,\n options,\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n if (list.length >= batch) {\n flush();\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(flush, delay);\n}\n\nexport async function trackAsync<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n await sendEvents([\n { name, properties, options, tags: captureTags(), timestamp: new Date().toISOString() },\n ]);\n}\n\nexport function sendBeacon<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!cache.tags || !cache.visitor) return;\n\n const session = getSession();\n session.updateLastActiveTime();\n\n const dto: CreateTrackEventDTO = [\n {\n name,\n properties,\n tags: cache.tags,\n visitor_id: cache.visitor.id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: new Date().toISOString(),\n },\n ];\n const blob = new Blob([JSON.stringify(dto)], { type: 'application/json' });\n const success = navigator.sendBeacon(`${config.endpoint}/events`, blob);\n if (success) return;\n console.warn('Failed to send beacon', name, properties);\n}\n"],"mappings":";;;;;;;AAcA,MAAM,iBAA+B,EAAE,0BAA0B,KAAK;AAEtE,IAAI;;;;;;;AAQJ,SAAS,iBAAiB;CACxB,OAAQ,gBAAgB,IAAIA,cAAAA,YAAY;EAAE,MAAM;EAAG,UAAU;EAAI,WAAW;CAAE,CAAC;AACjF;;;;;;;;;;AAqBA,eAAe,cAAkC;CAC/C,IAAI;EACF,OAAO,MAAMC,oBAAAA,OAAO,QAAQ;CAC9B,SAAS,GAAY;EACnB,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE,OAAO;EAC7C,OAAOC,oBAAAA,MAAM,QAAQ,CAAC;CACxB;AACF;AAEA,eAAe,WAAW,QAAgB;CACxC,IAAI;EACF,IAAI,OAAO,WAAW,GAAG;EAEzB,MAAM,UAAUC,sBAAAA,WAAW;EAC3B,IAAI,QAAQ,UAAU,GAAG;GACvB,QAAQ,QAAQ;GAChB,OAAO,QAAQ;IACb,MAAM;IACN,YAAY,CAAC;IACb,SAAS,EAAE,0BAA0B,MAAM;IAC3C,MAAM,YAAY;IAClB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GACpC,CAAC;EACH,OACE,QAAQ,qBAAqB;EAG/B,MAAM,eAAe,CAAC,CAAC,aAAa;EAEpC,MAAM,cAAc,MAAMC,sBAAAA,WAAW,EAAA,CAAG;EAExC,MAAM,MAA2B,MAAM,QAAQ,IAC7C,OAAO,IAAI,OAAO,WAAW;GAC3B,MAAM,MAAM;GACZ,YAAY,MAAM;GAClB,MAAM,MAAM,MAAM;GAClB;GACA,YAAY,QAAQ,MAAM;GAC1B,UAAUH,oBAAAA,OAAO;GACjB,aAAaA,oBAAAA,OAAO;GACpB,WAAW,MAAM;EACnB,EAAE,CACJ;EAEA,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,UAAU;GACxD,QAAQ;GACR,aAAa;GACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;GACjC,MAAM,KAAK,UAAU,GAAG;EAC1B,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,+BAA+B,SAAS,OAAO,GAAG,MAAM,SAAS,KAAK,GAAG;EAG3F,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,QAAQ;EACZ,OAAO,OAAO,SAAS,GAAG;GACxB,MAAM,QAAQ,OAAO,MAAM;GAC3B,IAAI,CAAC,OAAO;IACV;IACA;GACF;GACA,MAAM,EAAE,SAAS,MAAM,eAAe;GACtC,MAAM,UAAU,KAAK,GAAG,KAAK,CAAC,EAAE;GAChC,QAAQ,YAAY,UAAU,EAAE,IAAI,QAAQ,IAAI,KAAA,CAAS;GACzD;GACA,IAAI,CAAC,QAAQ,4BAA4BI,qCAAAA,eAAe,SAAS,IAAI,GACnE;GAEF,oBAAA,OAAO,mBAAmB,SAAS,YAAY;IAC7C,IAAI;KACF,QAAQ,MAAM,YAAY,OAAO;IACnC,SAAS,GAAY;KAKnB,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE,OAAO;IAC/C;GACF,CAAC;EACH;CACF,SAAS,GAAY;EACnB,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE,OAAO;EAC7C,OAAO,SAAS,UAAU,MAAM,QAAQ,UAAU,CAAC,CAAC;CACtD;AACF;AAEA,MAAM,QAAQ;AACd,MAAM,QAAQ;AACd,MAAM,OAAe,CAAC;AACtB,IAAI,QAA8C;;;;;AAMlD,SAAS,QAAQ;CACf,IAAI,OAAO;EACT,aAAa,KAAK;EAClB,QAAQ;CACV;CACA,IAAI,KAAK,WAAW,GAAG;CACvB,MAAM,OAAO,CAAC,GAAG,IAAI;CACrB,KAAK,SAAS;CACd,WAAgB,IAAI;AACtB;AAEA,SAAgB,MACd,MACA,YACA,UAAwB,gBACxB;CACA,KAAK,KAAK;EACR;EACA;EACA;EACA,MAAM,YAAY;EAClB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CACpC,CAAC;CACD,IAAI,KAAK,UAAU,OAAO;EACxB,MAAM;EACN;CACF;CACA,IAAI,OAAO,aAAa,KAAK;CAC7B,QAAQ,WAAW,OAAO,KAAK;AACjC;AAEA,eAAsB,WACpB,MACA,YACA,UAAwB,gBACxB;CACA,MAAM,WAAW,CACf;EAAE;EAAM;EAAY;EAAS,MAAM,YAAY;EAAG,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CAAE,CACxF,CAAC;AACH;AAEA,SAAgB,WACd,MACA,YACA;CACA,IAAI,CAACH,oBAAAA,MAAM,QAAQ,CAACA,oBAAAA,MAAM,SAAS;CAEnC,MAAM,UAAUC,sBAAAA,WAAW;CAC3B,QAAQ,qBAAqB;CAE7B,MAAM,MAA2B,CAC/B;EACE;EACA;EACA,MAAMD,oBAAAA,MAAM;EACZ,YAAYA,oBAAAA,MAAM,QAAQ;EAC1B,YAAY,QAAQ,MAAM;EAC1B,UAAUD,oBAAAA,OAAO;EACjB,aAAaA,oBAAAA,OAAO;EACpB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CACpC,CACF;CACA,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,MAAM,mBAAmB,CAAC;CAEzE,IADgB,UAAU,WAAW,GAAGA,oBAAAA,OAAO,SAAS,UAAU,IACxD,GAAG;CACb,QAAQ,KAAK,yBAAyB,MAAM,UAAU;AACxD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;iBAiJG,MAAM,UAAU,YAAY,WAC1C,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS;iBAiBW,WAAW,UAAU,YAAY,WACrD,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS,eAA6B;iBAOxB,WAAW,UAAU,YAAY,WAC/C,MAAM,UAAU,IAChB,aAAa,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/track/index.ts"],"mappings":";;UAQiB;EACf;EACA,aAAa,WAAW;EACxB,WAAW;;iBAiJG,MAAM,UAAU,YAAY,WAC1C,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS;iBAiBW,WAAW,UAAU,YAAY,WACrD,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B,UAAS,eAA6B;iBAOxB,WAAW,UAAU,YAAY,WAC/C,MAAM,UAAU,IAChB,aAAa,gBAAgB"}
|
package/dist/track/index.mjs
CHANGED
|
@@ -82,7 +82,13 @@ async function sendEvents(events) {
|
|
|
82
82
|
options.onSucceed?.(eventId ? { id: eventId } : void 0);
|
|
83
83
|
index++;
|
|
84
84
|
if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) continue;
|
|
85
|
-
config.thirdPartyTrackers.forEach((tracker) =>
|
|
85
|
+
config.thirdPartyTrackers.forEach((tracker) => {
|
|
86
|
+
try {
|
|
87
|
+
tracker(name, properties, eventId);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
if (e instanceof Error) console.log(e.message);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
86
92
|
}
|
|
87
93
|
} catch (e) {
|
|
88
94
|
if (e instanceof Error) console.log(e.message);
|
package/dist/track/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { getSession } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties, TrackTags } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\n\nlet tokenBucket: TokenBucket | undefined;\n\n/**\n * The rate limiter, built on the first send rather than at module scope: its\n * constructor starts a refill `setInterval`, and Cloudflare Workers refuse to\n * set a timer outside a request handler for the same reason they refuse to\n * generate random values there — see `setup/session.ts`.\n */\nfunction getTokenBucket() {\n return (tokenBucket ??= new TokenBucket({ rate: 1, capacity: 20, requested: 2 }));\n}\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n tags: Promise<TrackTags>;\n timestamp: string;\n options: TrackOptions;\n};\n\n/**\n * Tags belong to the moment the event happened, not to the moment its batch goes out: a queued\n * event waits up to `delay` ms, and a single page app can navigate in that window, which would\n * stamp every pending event with the URL of the page the user has already left.\n *\n * The promise then sits in the queue with nothing awaiting it, so a failure has to be absorbed\n * here — an unhandled rejection would surface as a global error long before `sendEvents` could\n * catch it. Falling back to the last built tags keeps the event, minus whatever changed since.\n */\nasync function captureTags(): Promise<TrackTags> {\n try {\n return await config.getTags();\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n return cache.tags ?? {};\n }\n}\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n const session = getSession();\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await getTokenBucket().removeTokens();\n\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = await Promise.all(\n events.map(async (event) => ({\n name: event.name,\n properties: event.properties,\n tags: await event.tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }))\n );\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data.at(index)?.id;\n options.onSucceed?.(eventId ? { id: eventId } : undefined);\n index++;\n if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) {\n continue;\n }\n config.thirdPartyTrackers.forEach((tracker) => tracker(name, properties, eventId));\n }\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n events.forEach((event) => event.options.onError?.(e));\n }\n}\n\nconst batch = 10;\nconst delay = 2000;\nconst list: Item[] = [];\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Both paths into a send go through here, so a batch that fills up cancels the timer the\n * previous push armed rather than leaving it to wake up on its own with nothing to send.\n */\nfunction flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n if (list.length === 0) return;\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n}\n\nexport function track<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n list.push({\n name,\n properties,\n options,\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n if (list.length >= batch) {\n flush();\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(flush, delay);\n}\n\nexport async function trackAsync<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n await sendEvents([\n { name, properties, options, tags: captureTags(), timestamp: new Date().toISOString() },\n ]);\n}\n\nexport function sendBeacon<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!cache.tags || !cache.visitor) return;\n\n const session = getSession();\n session.updateLastActiveTime();\n\n const dto: CreateTrackEventDTO = [\n {\n name,\n properties,\n tags: cache.tags,\n visitor_id: cache.visitor.id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: new Date().toISOString(),\n },\n ];\n const blob = new Blob([JSON.stringify(dto)], { type: 'application/json' });\n const success = navigator.sendBeacon(`${config.endpoint}/events`, blob);\n if (success) return;\n console.warn('Failed to send beacon', name, properties);\n}\n"],"mappings":";;;;;;AAcA,MAAM,iBAA+B,EAAE,0BAA0B,KAAK;AAEtE,IAAI;;;;;;;AAQJ,SAAS,iBAAiB;CACxB,OAAQ,gBAAgB,IAAI,YAAY;EAAE,MAAM;EAAG,UAAU;EAAI,WAAW;CAAE,CAAC;AACjF;;;;;;;;;;AAqBA,eAAe,cAAkC;CAC/C,IAAI;EACF,OAAO,MAAM,OAAO,QAAQ;CAC9B,SAAS,GAAY;EACnB,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE,OAAO;EAC7C,OAAO,MAAM,QAAQ,CAAC;CACxB;AACF;AAEA,eAAe,WAAW,QAAgB;CACxC,IAAI;EACF,IAAI,OAAO,WAAW,GAAG;EAEzB,MAAM,UAAU,WAAW;EAC3B,IAAI,QAAQ,UAAU,GAAG;GACvB,QAAQ,QAAQ;GAChB,OAAO,QAAQ;IACb,MAAM;IACN,YAAY,CAAC;IACb,SAAS,EAAE,0BAA0B,MAAM;IAC3C,MAAM,YAAY;IAClB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GACpC,CAAC;EACH,OACE,QAAQ,qBAAqB;EAG/B,MAAM,eAAe,CAAC,CAAC,aAAa;EAEpC,MAAM,cAAc,MAAM,WAAW,EAAA,CAAG;EAExC,MAAM,MAA2B,MAAM,QAAQ,IAC7C,OAAO,IAAI,OAAO,WAAW;GAC3B,MAAM,MAAM;GACZ,YAAY,MAAM;GAClB,MAAM,MAAM,MAAM;GAClB;GACA,YAAY,QAAQ,MAAM;GAC1B,UAAU,OAAO;GACjB,aAAa,OAAO;GACpB,WAAW,MAAM;EACnB,EAAE,CACJ;EAEA,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,SAAS,UAAU;GACxD,QAAQ;GACR,aAAa;GACb,SAAS,MAAM,OAAO,WAAW;GACjC,MAAM,KAAK,UAAU,GAAG;EAC1B,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,+BAA+B,SAAS,OAAO,GAAG,MAAM,SAAS,KAAK,GAAG;EAG3F,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,QAAQ;EACZ,OAAO,OAAO,SAAS,GAAG;GACxB,MAAM,QAAQ,OAAO,MAAM;GAC3B,IAAI,CAAC,OAAO;IACV;IACA;GACF;GACA,MAAM,EAAE,SAAS,MAAM,eAAe;GACtC,MAAM,UAAU,KAAK,GAAG,KAAK,CAAC,EAAE;GAChC,QAAQ,YAAY,UAAU,EAAE,IAAI,QAAQ,IAAI,KAAA,CAAS;GACzD;GACA,IAAI,CAAC,QAAQ,4BAA4B,eAAe,SAAS,IAAI,GACnE;GAEF,OAAO,mBAAmB,SAAS,YAAY,QAAQ,MAAM,YAAY,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/track/index.ts"],"sourcesContent":["import { TokenBucket, fetch } from '@shware/utils';\nimport type { CreateTrackEventDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport { getSession } from '../setup/session';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { getVisitor } from '../visitor/index';\nimport type { EventName, TrackEventResponse, TrackName, TrackProperties, TrackTags } from './types';\n\nexport interface TrackOptions {\n enableThirdPartyTracking?: boolean;\n onSucceed?: (response?: TrackEventResponse[number]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst defaultOptions: TrackOptions = { enableThirdPartyTracking: true };\n\nlet tokenBucket: TokenBucket | undefined;\n\n/**\n * The rate limiter, built on the first send rather than at module scope: its\n * constructor starts a refill `setInterval`, and Cloudflare Workers refuse to\n * set a timer outside a request handler for the same reason they refuse to\n * generate random values there — see `setup/session.ts`.\n */\nfunction getTokenBucket() {\n return (tokenBucket ??= new TokenBucket({ rate: 1, capacity: 20, requested: 2 }));\n}\n\ntype Item = {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n name: TrackName<any>;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n properties: TrackProperties<any>;\n tags: Promise<TrackTags>;\n timestamp: string;\n options: TrackOptions;\n};\n\n/**\n * Tags belong to the moment the event happened, not to the moment its batch goes out: a queued\n * event waits up to `delay` ms, and a single page app can navigate in that window, which would\n * stamp every pending event with the URL of the page the user has already left.\n *\n * The promise then sits in the queue with nothing awaiting it, so a failure has to be absorbed\n * here — an unhandled rejection would surface as a global error long before `sendEvents` could\n * catch it. Falling back to the last built tags keeps the event, minus whatever changed since.\n */\nasync function captureTags(): Promise<TrackTags> {\n try {\n return await config.getTags();\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n return cache.tags ?? {};\n }\n}\n\nasync function sendEvents(events: Item[]) {\n try {\n if (events.length === 0) return;\n\n const session = getSession();\n if (session.isExpired()) {\n session.refresh();\n events.unshift({\n name: 'session_start',\n properties: {},\n options: { enableThirdPartyTracking: false },\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n } else {\n session.updateLastActiveTime();\n }\n\n await getTokenBucket().removeTokens();\n\n const visitor_id = (await getVisitor()).id;\n\n const dto: CreateTrackEventDTO = await Promise.all(\n events.map(async (event) => ({\n name: event.name,\n properties: event.properties,\n tags: await event.tags,\n visitor_id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: event.timestamp,\n }))\n );\n\n const response = await fetch(`${config.endpoint}/events`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send track event: ${response.status} ${await response.text()}`);\n }\n\n const data = (await response.json()) as TrackEventResponse;\n\n let index = 0;\n while (events.length > 0) {\n const event = events.shift();\n if (!event) {\n index++;\n continue;\n }\n const { options, name, properties } = event;\n const eventId = data.at(index)?.id;\n options.onSucceed?.(eventId ? { id: eventId } : undefined);\n index++;\n if (!options.enableThirdPartyTracking || IGNORED_EVENTS.includes(name)) {\n continue;\n }\n config.thirdPartyTrackers.forEach((tracker) => {\n try {\n tracker(name, properties, eventId);\n } catch (e: unknown) {\n // A third-party script does not get to take the rest of the batch with it. This loop is\n // still draining `events` with `shift`, so a throw would escape to the catch below and\n // report failure to whatever is left in the queue — for events the server has already\n // accepted, and after the ones ahead of them were told they succeeded.\n if (e instanceof Error) console.log(e.message);\n }\n });\n }\n } catch (e: unknown) {\n if (e instanceof Error) console.log(e.message);\n events.forEach((event) => event.options.onError?.(e));\n }\n}\n\nconst batch = 10;\nconst delay = 2000;\nconst list: Item[] = [];\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Both paths into a send go through here, so a batch that fills up cancels the timer the\n * previous push armed rather than leaving it to wake up on its own with nothing to send.\n */\nfunction flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n if (list.length === 0) return;\n const copy = [...list];\n list.length = 0;\n void sendEvents(copy);\n}\n\nexport function track<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n list.push({\n name,\n properties,\n options,\n tags: captureTags(),\n timestamp: new Date().toISOString(),\n });\n if (list.length >= batch) {\n flush();\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(flush, delay);\n}\n\nexport async function trackAsync<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>,\n options: TrackOptions = defaultOptions\n) {\n await sendEvents([\n { name, properties, options, tags: captureTags(), timestamp: new Date().toISOString() },\n ]);\n}\n\nexport function sendBeacon<T extends EventName = EventName>(\n name: TrackName<T>,\n properties?: TrackProperties<T>\n) {\n if (!cache.tags || !cache.visitor) return;\n\n const session = getSession();\n session.updateLastActiveTime();\n\n const dto: CreateTrackEventDTO = [\n {\n name,\n properties,\n tags: cache.tags,\n visitor_id: cache.visitor.id,\n session_id: session.getId(),\n platform: config.platform,\n environment: config.environment,\n timestamp: new Date().toISOString(),\n },\n ];\n const blob = new Blob([JSON.stringify(dto)], { type: 'application/json' });\n const success = navigator.sendBeacon(`${config.endpoint}/events`, blob);\n if (success) return;\n console.warn('Failed to send beacon', name, properties);\n}\n"],"mappings":"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"}
|
package/dist/visitor/index.cjs
CHANGED
|
@@ -66,7 +66,13 @@ async function setVisitor(dto) {
|
|
|
66
66
|
});
|
|
67
67
|
if (!response.ok) throw new Error("Failed to set visitor");
|
|
68
68
|
const data = await response.json();
|
|
69
|
-
require_setup_index.config.thirdPartyUserSetters.forEach((setter) =>
|
|
69
|
+
require_setup_index.config.thirdPartyUserSetters.forEach((setter) => {
|
|
70
|
+
try {
|
|
71
|
+
setter(body);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (e instanceof Error) console.log(e.message);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
70
76
|
require_setup_index.cache.visitor = data;
|
|
71
77
|
return data;
|
|
72
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["config","keys","cache"],"sources":["../../src/visitor/index.ts"],"sourcesContent":["import { fetch } from '@shware/utils';\nimport { keys } from '../constants/storage';\nimport type { CreateVisitorDTO, UpdateVisitorDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport type { Visitor, VisitorProperties } from './types';\n\nasync function createVisitor(): Promise<Visitor> {\n const tags = await config.getTags();\n const dto: CreateVisitorDTO = {\n device_id: await config.getDeviceId(),\n platform: config.platform,\n environment: config.environment,\n tags,\n properties: tags as VisitorProperties,\n };\n\n const response = await fetch(`${config.endpoint}/visitors`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create visitor: ${response.status} ${await response.text()}`);\n }\n const data = (await response.json()) as Visitor;\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n}\n\nasync function getOrCreateVisitor(): Promise<Visitor> {\n const visitorId = config.storage.getItem(keys.visitor_id);\n if (visitorId && visitorId !== 'undefined') {\n // PATCH, not GET: `tags` is the last-touch counterpart to `initial_tags`,\n // and the only thing that ever refreshed it was `setVisitor`, which hosts\n // call when they identify a user. A visitor who never signs in therefore\n // kept the browser, screen, and release captured on their first ever page\n // load — for the rest of their life — leaving `tags` permanently equal to\n // `initial_tags` and the two columns pointless.\n //\n // Costs nothing extra: this replaces the request that was already here.\n const tags = await config.getTags();\n const response = await fetch(`${config.endpoint}/visitors/${visitorId}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify({ tags } satisfies UpdateVisitorDTO),\n });\n\n if (!response.ok) return createVisitor();\n const data = (await response.json()) as Visitor;\n\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n } else {\n return createVisitor();\n }\n}\n\nlet visitorFetcher: Promise<Visitor> | null = null;\n\nexport async function getVisitor(): Promise<Visitor> {\n if (cache.visitor) return cache.visitor;\n if (visitorFetcher) return visitorFetcher;\n visitorFetcher = getOrCreateVisitor();\n try {\n cache.visitor = await visitorFetcher;\n return cache.visitor;\n } finally {\n // In a `finally`, so a rejected attempt is not left in `visitorFetcher` for every later\n // caller to await again: `sendEvents` needs a visitor for every batch, and one failed\n // request would otherwise stop the page from reporting anything until it is reloaded.\n visitorFetcher = null;\n }\n}\n\nexport async function setVisitor(dto: Omit<UpdateVisitorDTO, 'tags'>) {\n const { id } = await getVisitor();\n const tags = await config.getTags();\n const body: UpdateVisitorDTO = { ...dto, tags };\n const response = await fetch(`${config.endpoint}/visitors/${id}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) throw new Error('Failed to set visitor');\n const data = (await response.json()) as Visitor;\n\n config.thirdPartyUserSetters.forEach((setter) => setter(body));\n cache.visitor = data;\n return data;\n}\n"],"mappings":";;;;;AAMA,eAAe,gBAAkC;CAC/C,MAAM,OAAO,MAAMA,oBAAAA,OAAO,QAAQ;CAClC,MAAM,MAAwB;EAC5B,WAAW,MAAMA,oBAAAA,OAAO,YAAY;EACpC,UAAUA,oBAAAA,OAAO;EACjB,aAAaA,oBAAAA,OAAO;EACpB;EACA,YAAY;CACd;CAEA,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,YAAY;EAC1D,QAAQ;EACR,aAAa;EACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,GAAG;CAC1B,CAAC;CAED,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,6BAA6B,SAAS,OAAO,GAAG,MAAM,SAAS,KAAK,GAAG;CAEzF,MAAM,OAAQ,MAAM,SAAS,KAAK;CAClC,IAAI,KAAK,IACP,oBAAA,OAAO,QAAQ,QAAQC,0BAAAA,KAAK,YAAY,KAAK,EAAE;CAEjD,OAAO;AACT;AAEA,eAAe,qBAAuC;CACpD,MAAM,YAAYD,oBAAAA,OAAO,QAAQ,QAAQC,0BAAAA,KAAK,UAAU;CACxD,IAAI,aAAa,cAAc,aAAa;EAS1C,MAAM,OAAO,MAAMD,oBAAAA,OAAO,QAAQ;EAClC,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,YAAY,aAAa;GACvE,QAAQ;GACR,aAAa;GACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;GACjC,MAAM,KAAK,UAAU,EAAE,KAAK,CAA4B;EAC1D,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO,cAAc;EACvC,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,KAAK,IACP,oBAAA,OAAO,QAAQ,QAAQC,0BAAAA,KAAK,YAAY,KAAK,EAAE;EAEjD,OAAO;CACT,OACE,OAAO,cAAc;AAEzB;AAEA,IAAI,iBAA0C;AAE9C,eAAsB,aAA+B;CACnD,IAAIC,oBAAAA,MAAM,SAAS,OAAOA,oBAAAA,MAAM;CAChC,IAAI,gBAAgB,OAAO;CAC3B,iBAAiB,mBAAmB;CACpC,IAAI;EACF,oBAAA,MAAM,UAAU,MAAM;EACtB,OAAOA,oBAAAA,MAAM;CACf,UAAU;EAIR,iBAAiB;CACnB;AACF;AAEA,eAAsB,WAAW,KAAqC;CACpE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,OAAO,MAAMF,oBAAAA,OAAO,QAAQ;CAClC,MAAM,OAAyB;EAAE,GAAG;EAAK;CAAK;CAC9C,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,YAAY,MAAM;EAChE,QAAQ;EACR,aAAa;EACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,IAAI;CAC3B,CAAC;CAED,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,uBAAuB;CACzD,MAAM,OAAQ,MAAM,SAAS,KAAK;CAElC,oBAAA,OAAO,sBAAsB,SAAS,WAAW,OAAO,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["config","keys","cache"],"sources":["../../src/visitor/index.ts"],"sourcesContent":["import { fetch } from '@shware/utils';\nimport { keys } from '../constants/storage';\nimport type { CreateVisitorDTO, UpdateVisitorDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport type { Visitor, VisitorProperties } from './types';\n\nasync function createVisitor(): Promise<Visitor> {\n const tags = await config.getTags();\n const dto: CreateVisitorDTO = {\n device_id: await config.getDeviceId(),\n platform: config.platform,\n environment: config.environment,\n tags,\n properties: tags as VisitorProperties,\n };\n\n const response = await fetch(`${config.endpoint}/visitors`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create visitor: ${response.status} ${await response.text()}`);\n }\n const data = (await response.json()) as Visitor;\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n}\n\nasync function getOrCreateVisitor(): Promise<Visitor> {\n const visitorId = config.storage.getItem(keys.visitor_id);\n if (visitorId && visitorId !== 'undefined') {\n // PATCH, not GET: `tags` is the last-touch counterpart to `initial_tags`,\n // and the only thing that ever refreshed it was `setVisitor`, which hosts\n // call when they identify a user. A visitor who never signs in therefore\n // kept the browser, screen, and release captured on their first ever page\n // load — for the rest of their life — leaving `tags` permanently equal to\n // `initial_tags` and the two columns pointless.\n //\n // Costs nothing extra: this replaces the request that was already here.\n const tags = await config.getTags();\n const response = await fetch(`${config.endpoint}/visitors/${visitorId}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify({ tags } satisfies UpdateVisitorDTO),\n });\n\n if (!response.ok) return createVisitor();\n const data = (await response.json()) as Visitor;\n\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n } else {\n return createVisitor();\n }\n}\n\nlet visitorFetcher: Promise<Visitor> | null = null;\n\nexport async function getVisitor(): Promise<Visitor> {\n if (cache.visitor) return cache.visitor;\n if (visitorFetcher) return visitorFetcher;\n visitorFetcher = getOrCreateVisitor();\n try {\n cache.visitor = await visitorFetcher;\n return cache.visitor;\n } finally {\n // In a `finally`, so a rejected attempt is not left in `visitorFetcher` for every later\n // caller to await again: `sendEvents` needs a visitor for every batch, and one failed\n // request would otherwise stop the page from reporting anything until it is reloaded.\n visitorFetcher = null;\n }\n}\n\nexport async function setVisitor(dto: Omit<UpdateVisitorDTO, 'tags'>) {\n const { id } = await getVisitor();\n const tags = await config.getTags();\n const body: UpdateVisitorDTO = { ...dto, tags };\n const response = await fetch(`${config.endpoint}/visitors/${id}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) throw new Error('Failed to set visitor');\n const data = (await response.json()) as Visitor;\n\n config.thirdPartyUserSetters.forEach((setter) => {\n try {\n setter(body);\n } catch (e: unknown) {\n // The visitor was updated before this ran, so a third-party setter throwing must not skip\n // the cache write below or reject a call that already succeeded.\n if (e instanceof Error) console.log(e.message);\n }\n });\n cache.visitor = data;\n return data;\n}\n"],"mappings":";;;;;AAMA,eAAe,gBAAkC;CAC/C,MAAM,OAAO,MAAMA,oBAAAA,OAAO,QAAQ;CAClC,MAAM,MAAwB;EAC5B,WAAW,MAAMA,oBAAAA,OAAO,YAAY;EACpC,UAAUA,oBAAAA,OAAO;EACjB,aAAaA,oBAAAA,OAAO;EACpB;EACA,YAAY;CACd;CAEA,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,YAAY;EAC1D,QAAQ;EACR,aAAa;EACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,GAAG;CAC1B,CAAC;CAED,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,6BAA6B,SAAS,OAAO,GAAG,MAAM,SAAS,KAAK,GAAG;CAEzF,MAAM,OAAQ,MAAM,SAAS,KAAK;CAClC,IAAI,KAAK,IACP,oBAAA,OAAO,QAAQ,QAAQC,0BAAAA,KAAK,YAAY,KAAK,EAAE;CAEjD,OAAO;AACT;AAEA,eAAe,qBAAuC;CACpD,MAAM,YAAYD,oBAAAA,OAAO,QAAQ,QAAQC,0BAAAA,KAAK,UAAU;CACxD,IAAI,aAAa,cAAc,aAAa;EAS1C,MAAM,OAAO,MAAMD,oBAAAA,OAAO,QAAQ;EAClC,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,YAAY,aAAa;GACvE,QAAQ;GACR,aAAa;GACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;GACjC,MAAM,KAAK,UAAU,EAAE,KAAK,CAA4B;EAC1D,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO,cAAc;EACvC,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,KAAK,IACP,oBAAA,OAAO,QAAQ,QAAQC,0BAAAA,KAAK,YAAY,KAAK,EAAE;EAEjD,OAAO;CACT,OACE,OAAO,cAAc;AAEzB;AAEA,IAAI,iBAA0C;AAE9C,eAAsB,aAA+B;CACnD,IAAIC,oBAAAA,MAAM,SAAS,OAAOA,oBAAAA,MAAM;CAChC,IAAI,gBAAgB,OAAO;CAC3B,iBAAiB,mBAAmB;CACpC,IAAI;EACF,oBAAA,MAAM,UAAU,MAAM;EACtB,OAAOA,oBAAAA,MAAM;CACf,UAAU;EAIR,iBAAiB;CACnB;AACF;AAEA,eAAsB,WAAW,KAAqC;CACpE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,OAAO,MAAMF,oBAAAA,OAAO,QAAQ;CAClC,MAAM,OAAyB;EAAE,GAAG;EAAK;CAAK;CAC9C,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAGA,oBAAAA,OAAO,SAAS,YAAY,MAAM;EAChE,QAAQ;EACR,aAAa;EACb,SAAS,MAAMA,oBAAAA,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,IAAI;CAC3B,CAAC;CAED,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,uBAAuB;CACzD,MAAM,OAAQ,MAAM,SAAS,KAAK;CAElC,oBAAA,OAAO,sBAAsB,SAAS,WAAW;EAC/C,IAAI;GACF,OAAO,IAAI;EACb,SAAS,GAAY;GAGnB,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE,OAAO;EAC/C;CACF,CAAC;CACD,oBAAA,MAAM,UAAU;CAChB,OAAO;AACT"}
|
package/dist/visitor/index.mjs
CHANGED
|
@@ -65,7 +65,13 @@ async function setVisitor(dto) {
|
|
|
65
65
|
});
|
|
66
66
|
if (!response.ok) throw new Error("Failed to set visitor");
|
|
67
67
|
const data = await response.json();
|
|
68
|
-
config.thirdPartyUserSetters.forEach((setter) =>
|
|
68
|
+
config.thirdPartyUserSetters.forEach((setter) => {
|
|
69
|
+
try {
|
|
70
|
+
setter(body);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
if (e instanceof Error) console.log(e.message);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
69
75
|
cache.visitor = data;
|
|
70
76
|
return data;
|
|
71
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/visitor/index.ts"],"sourcesContent":["import { fetch } from '@shware/utils';\nimport { keys } from '../constants/storage';\nimport type { CreateVisitorDTO, UpdateVisitorDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport type { Visitor, VisitorProperties } from './types';\n\nasync function createVisitor(): Promise<Visitor> {\n const tags = await config.getTags();\n const dto: CreateVisitorDTO = {\n device_id: await config.getDeviceId(),\n platform: config.platform,\n environment: config.environment,\n tags,\n properties: tags as VisitorProperties,\n };\n\n const response = await fetch(`${config.endpoint}/visitors`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create visitor: ${response.status} ${await response.text()}`);\n }\n const data = (await response.json()) as Visitor;\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n}\n\nasync function getOrCreateVisitor(): Promise<Visitor> {\n const visitorId = config.storage.getItem(keys.visitor_id);\n if (visitorId && visitorId !== 'undefined') {\n // PATCH, not GET: `tags` is the last-touch counterpart to `initial_tags`,\n // and the only thing that ever refreshed it was `setVisitor`, which hosts\n // call when they identify a user. A visitor who never signs in therefore\n // kept the browser, screen, and release captured on their first ever page\n // load — for the rest of their life — leaving `tags` permanently equal to\n // `initial_tags` and the two columns pointless.\n //\n // Costs nothing extra: this replaces the request that was already here.\n const tags = await config.getTags();\n const response = await fetch(`${config.endpoint}/visitors/${visitorId}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify({ tags } satisfies UpdateVisitorDTO),\n });\n\n if (!response.ok) return createVisitor();\n const data = (await response.json()) as Visitor;\n\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n } else {\n return createVisitor();\n }\n}\n\nlet visitorFetcher: Promise<Visitor> | null = null;\n\nexport async function getVisitor(): Promise<Visitor> {\n if (cache.visitor) return cache.visitor;\n if (visitorFetcher) return visitorFetcher;\n visitorFetcher = getOrCreateVisitor();\n try {\n cache.visitor = await visitorFetcher;\n return cache.visitor;\n } finally {\n // In a `finally`, so a rejected attempt is not left in `visitorFetcher` for every later\n // caller to await again: `sendEvents` needs a visitor for every batch, and one failed\n // request would otherwise stop the page from reporting anything until it is reloaded.\n visitorFetcher = null;\n }\n}\n\nexport async function setVisitor(dto: Omit<UpdateVisitorDTO, 'tags'>) {\n const { id } = await getVisitor();\n const tags = await config.getTags();\n const body: UpdateVisitorDTO = { ...dto, tags };\n const response = await fetch(`${config.endpoint}/visitors/${id}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) throw new Error('Failed to set visitor');\n const data = (await response.json()) as Visitor;\n\n config.thirdPartyUserSetters.forEach((setter) => setter(body));\n cache.visitor = data;\n return data;\n}\n"],"mappings":";;;;AAMA,eAAe,gBAAkC;CAC/C,MAAM,OAAO,MAAM,OAAO,QAAQ;CAClC,MAAM,MAAwB;EAC5B,WAAW,MAAM,OAAO,YAAY;EACpC,UAAU,OAAO;EACjB,aAAa,OAAO;EACpB;EACA,YAAY;CACd;CAEA,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,SAAS,YAAY;EAC1D,QAAQ;EACR,aAAa;EACb,SAAS,MAAM,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,GAAG;CAC1B,CAAC;CAED,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,6BAA6B,SAAS,OAAO,GAAG,MAAM,SAAS,KAAK,GAAG;CAEzF,MAAM,OAAQ,MAAM,SAAS,KAAK;CAClC,IAAI,KAAK,IACP,OAAO,QAAQ,QAAQ,KAAK,YAAY,KAAK,EAAE;CAEjD,OAAO;AACT;AAEA,eAAe,qBAAuC;CACpD,MAAM,YAAY,OAAO,QAAQ,QAAQ,KAAK,UAAU;CACxD,IAAI,aAAa,cAAc,aAAa;EAS1C,MAAM,OAAO,MAAM,OAAO,QAAQ;EAClC,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,SAAS,YAAY,aAAa;GACvE,QAAQ;GACR,aAAa;GACb,SAAS,MAAM,OAAO,WAAW;GACjC,MAAM,KAAK,UAAU,EAAE,KAAK,CAA4B;EAC1D,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO,cAAc;EACvC,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,KAAK,IACP,OAAO,QAAQ,QAAQ,KAAK,YAAY,KAAK,EAAE;EAEjD,OAAO;CACT,OACE,OAAO,cAAc;AAEzB;AAEA,IAAI,iBAA0C;AAE9C,eAAsB,aAA+B;CACnD,IAAI,MAAM,SAAS,OAAO,MAAM;CAChC,IAAI,gBAAgB,OAAO;CAC3B,iBAAiB,mBAAmB;CACpC,IAAI;EACF,MAAM,UAAU,MAAM;EACtB,OAAO,MAAM;CACf,UAAU;EAIR,iBAAiB;CACnB;AACF;AAEA,eAAsB,WAAW,KAAqC;CACpE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,OAAO,MAAM,OAAO,QAAQ;CAClC,MAAM,OAAyB;EAAE,GAAG;EAAK;CAAK;CAC9C,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,SAAS,YAAY,MAAM;EAChE,QAAQ;EACR,aAAa;EACb,SAAS,MAAM,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,IAAI;CAC3B,CAAC;CAED,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,uBAAuB;CACzD,MAAM,OAAQ,MAAM,SAAS,KAAK;CAElC,OAAO,sBAAsB,SAAS,WAAW,OAAO,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/visitor/index.ts"],"sourcesContent":["import { fetch } from '@shware/utils';\nimport { keys } from '../constants/storage';\nimport type { CreateVisitorDTO, UpdateVisitorDTO } from '../schema/index';\nimport { cache, config } from '../setup/index';\nimport type { Visitor, VisitorProperties } from './types';\n\nasync function createVisitor(): Promise<Visitor> {\n const tags = await config.getTags();\n const dto: CreateVisitorDTO = {\n device_id: await config.getDeviceId(),\n platform: config.platform,\n environment: config.environment,\n tags,\n properties: tags as VisitorProperties,\n };\n\n const response = await fetch(`${config.endpoint}/visitors`, {\n method: 'POST',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(dto),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create visitor: ${response.status} ${await response.text()}`);\n }\n const data = (await response.json()) as Visitor;\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n}\n\nasync function getOrCreateVisitor(): Promise<Visitor> {\n const visitorId = config.storage.getItem(keys.visitor_id);\n if (visitorId && visitorId !== 'undefined') {\n // PATCH, not GET: `tags` is the last-touch counterpart to `initial_tags`,\n // and the only thing that ever refreshed it was `setVisitor`, which hosts\n // call when they identify a user. A visitor who never signs in therefore\n // kept the browser, screen, and release captured on their first ever page\n // load — for the rest of their life — leaving `tags` permanently equal to\n // `initial_tags` and the two columns pointless.\n //\n // Costs nothing extra: this replaces the request that was already here.\n const tags = await config.getTags();\n const response = await fetch(`${config.endpoint}/visitors/${visitorId}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify({ tags } satisfies UpdateVisitorDTO),\n });\n\n if (!response.ok) return createVisitor();\n const data = (await response.json()) as Visitor;\n\n if (data.id) {\n config.storage.setItem(keys.visitor_id, data.id);\n }\n return data;\n } else {\n return createVisitor();\n }\n}\n\nlet visitorFetcher: Promise<Visitor> | null = null;\n\nexport async function getVisitor(): Promise<Visitor> {\n if (cache.visitor) return cache.visitor;\n if (visitorFetcher) return visitorFetcher;\n visitorFetcher = getOrCreateVisitor();\n try {\n cache.visitor = await visitorFetcher;\n return cache.visitor;\n } finally {\n // In a `finally`, so a rejected attempt is not left in `visitorFetcher` for every later\n // caller to await again: `sendEvents` needs a visitor for every batch, and one failed\n // request would otherwise stop the page from reporting anything until it is reloaded.\n visitorFetcher = null;\n }\n}\n\nexport async function setVisitor(dto: Omit<UpdateVisitorDTO, 'tags'>) {\n const { id } = await getVisitor();\n const tags = await config.getTags();\n const body: UpdateVisitorDTO = { ...dto, tags };\n const response = await fetch(`${config.endpoint}/visitors/${id}`, {\n method: 'PATCH',\n credentials: 'include',\n headers: await config.getHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) throw new Error('Failed to set visitor');\n const data = (await response.json()) as Visitor;\n\n config.thirdPartyUserSetters.forEach((setter) => {\n try {\n setter(body);\n } catch (e: unknown) {\n // The visitor was updated before this ran, so a third-party setter throwing must not skip\n // the cache write below or reject a call that already succeeded.\n if (e instanceof Error) console.log(e.message);\n }\n });\n cache.visitor = data;\n return data;\n}\n"],"mappings":";;;;AAMA,eAAe,gBAAkC;CAC/C,MAAM,OAAO,MAAM,OAAO,QAAQ;CAClC,MAAM,MAAwB;EAC5B,WAAW,MAAM,OAAO,YAAY;EACpC,UAAU,OAAO;EACjB,aAAa,OAAO;EACpB;EACA,YAAY;CACd;CAEA,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,SAAS,YAAY;EAC1D,QAAQ;EACR,aAAa;EACb,SAAS,MAAM,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,GAAG;CAC1B,CAAC;CAED,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,6BAA6B,SAAS,OAAO,GAAG,MAAM,SAAS,KAAK,GAAG;CAEzF,MAAM,OAAQ,MAAM,SAAS,KAAK;CAClC,IAAI,KAAK,IACP,OAAO,QAAQ,QAAQ,KAAK,YAAY,KAAK,EAAE;CAEjD,OAAO;AACT;AAEA,eAAe,qBAAuC;CACpD,MAAM,YAAY,OAAO,QAAQ,QAAQ,KAAK,UAAU;CACxD,IAAI,aAAa,cAAc,aAAa;EAS1C,MAAM,OAAO,MAAM,OAAO,QAAQ;EAClC,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,SAAS,YAAY,aAAa;GACvE,QAAQ;GACR,aAAa;GACb,SAAS,MAAM,OAAO,WAAW;GACjC,MAAM,KAAK,UAAU,EAAE,KAAK,CAA4B;EAC1D,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO,cAAc;EACvC,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,KAAK,IACP,OAAO,QAAQ,QAAQ,KAAK,YAAY,KAAK,EAAE;EAEjD,OAAO;CACT,OACE,OAAO,cAAc;AAEzB;AAEA,IAAI,iBAA0C;AAE9C,eAAsB,aAA+B;CACnD,IAAI,MAAM,SAAS,OAAO,MAAM;CAChC,IAAI,gBAAgB,OAAO;CAC3B,iBAAiB,mBAAmB;CACpC,IAAI;EACF,MAAM,UAAU,MAAM;EACtB,OAAO,MAAM;CACf,UAAU;EAIR,iBAAiB;CACnB;AACF;AAEA,eAAsB,WAAW,KAAqC;CACpE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,OAAO,MAAM,OAAO,QAAQ;CAClC,MAAM,OAAyB;EAAE,GAAG;EAAK;CAAK;CAC9C,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,SAAS,YAAY,MAAM;EAChE,QAAQ;EACR,aAAa;EACb,SAAS,MAAM,OAAO,WAAW;EACjC,MAAM,KAAK,UAAU,IAAI;CAC3B,CAAC;CAED,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,uBAAuB;CACzD,MAAM,OAAQ,MAAM,SAAS,KAAK;CAElC,OAAO,sBAAsB,SAAS,WAAW;EAC/C,IAAI;GACF,OAAO,IAAI;EACb,SAAS,GAAY;GAGnB,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE,OAAO;EAC/C;CACF,CAAC;CACD,MAAM,UAAU;CAChB,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shware/analytics",
|
|
3
|
-
"version": "7.1
|
|
3
|
+
"version": "7.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -126,35 +126,35 @@
|
|
|
126
126
|
"access": "public"
|
|
127
127
|
},
|
|
128
128
|
"dependencies": {
|
|
129
|
+
"@shware/utils": "^1.6.1",
|
|
129
130
|
"cookie": "^2.0.1",
|
|
130
|
-
"uuid": "^14.0.
|
|
131
|
-
"web-vitals": "^6.
|
|
132
|
-
"zod": "^4.4.3"
|
|
133
|
-
"@shware/utils": "^1.6.0"
|
|
131
|
+
"uuid": "^14.0.2",
|
|
132
|
+
"web-vitals": "^6.2.0",
|
|
133
|
+
"zod": "^4.4.3"
|
|
134
134
|
},
|
|
135
135
|
"devDependencies": {
|
|
136
|
+
"@repo/typescript-config": "0.0.0",
|
|
136
137
|
"@types/facebook-nodejs-business-sdk": "^24.0.0",
|
|
137
|
-
"@types/node": "^26.
|
|
138
|
+
"@types/node": "^26.3.0",
|
|
138
139
|
"@types/react": "^19.2.18",
|
|
139
140
|
"bowser": "^2.14.1",
|
|
140
141
|
"typescript": "^7.0.2",
|
|
141
|
-
"vitest": "^4.1.
|
|
142
|
-
"@repo/typescript-config": "0.0.0"
|
|
142
|
+
"vitest": "^4.1.11"
|
|
143
143
|
},
|
|
144
144
|
"peerDependencies": {
|
|
145
|
-
"@react-native-firebase/analytics": "^26.2
|
|
146
|
-
"@tanstack/react-router": "^1.170.
|
|
147
|
-
"@tanstack/react-start": "^1.168.
|
|
145
|
+
"@react-native-firebase/analytics": "^26.3.2",
|
|
146
|
+
"@tanstack/react-router": "^1.170.32",
|
|
147
|
+
"@tanstack/react-start": "^1.168.49",
|
|
148
148
|
"expo-application": "^57.0.2",
|
|
149
149
|
"expo-clipboard": "^57.0.1",
|
|
150
|
-
"expo-crypto": "^57.0.
|
|
150
|
+
"expo-crypto": "^57.0.2",
|
|
151
151
|
"expo-device": "^57.0.1",
|
|
152
152
|
"expo-localization": "^57.0.1",
|
|
153
153
|
"expo-sqlite": "^57.0.1",
|
|
154
154
|
"expo-tracking-transparency": "^57.0.1",
|
|
155
155
|
"facebook-nodejs-business-sdk": "^24.0.1",
|
|
156
|
-
"next": "^16.3.
|
|
157
|
-
"posthog-js": "^1.
|
|
156
|
+
"next": "^16.3.3",
|
|
157
|
+
"posthog-js": "^1.419.4",
|
|
158
158
|
"react": "^19.2.8",
|
|
159
159
|
"react-native": "^0.87.0",
|
|
160
160
|
"react-native-fbsdk-next": "^13.4.3",
|