@shware/analytics 8.0.0 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/_virtual/_rolldown/runtime.mjs +1 -1
  3. package/dist/click-id/index.cjs +64 -5
  4. package/dist/click-id/index.cjs.map +1 -1
  5. package/dist/click-id/index.d.cts +21 -1
  6. package/dist/click-id/index.d.cts.map +1 -1
  7. package/dist/click-id/index.d.mts +21 -1
  8. package/dist/click-id/index.d.mts.map +1 -1
  9. package/dist/click-id/index.mjs +60 -5
  10. package/dist/click-id/index.mjs.map +1 -1
  11. package/dist/feedback/index.cjs.map +1 -1
  12. package/dist/hooks/use-previous.cjs.map +1 -1
  13. package/dist/hooks/use-track-impression.cjs.map +1 -1
  14. package/dist/hooks/use-web-analytics.cjs.map +1 -1
  15. package/dist/link/index.cjs.map +1 -1
  16. package/dist/native/fingerprint.cjs.map +1 -1
  17. package/dist/native/firebase.cjs.map +1 -1
  18. package/dist/native/setup.cjs.map +1 -1
  19. package/dist/next/index.cjs +2 -1
  20. package/dist/next/index.cjs.map +1 -1
  21. package/dist/next/index.mjs +2 -1
  22. package/dist/next/index.mjs.map +1 -1
  23. package/dist/react-router/index.cjs.map +1 -1
  24. package/dist/schema/index.cjs.map +1 -1
  25. package/dist/server/google-data-manager.cjs +157 -0
  26. package/dist/server/google-data-manager.cjs.map +1 -0
  27. package/dist/server/google-data-manager.d.cts +75 -0
  28. package/dist/server/google-data-manager.d.cts.map +1 -0
  29. package/dist/server/google-data-manager.d.mts +75 -0
  30. package/dist/server/google-data-manager.d.mts.map +1 -0
  31. package/dist/server/google-data-manager.mjs +154 -0
  32. package/dist/server/google-data-manager.mjs.map +1 -0
  33. package/dist/server/index.cjs +8 -0
  34. package/dist/server/index.d.cts +7 -6
  35. package/dist/server/index.d.mts +7 -6
  36. package/dist/server/index.mjs +7 -6
  37. package/dist/server/linkedin-conversions-api.cjs.map +1 -1
  38. package/dist/server/meta-capi.cjs +18 -16
  39. package/dist/server/meta-capi.cjs.map +1 -1
  40. package/dist/server/meta-capi.mjs +18 -16
  41. package/dist/server/meta-capi.mjs.map +1 -1
  42. package/dist/server/meta-conversions-api.cjs +39 -35
  43. package/dist/server/meta-conversions-api.cjs.map +1 -1
  44. package/dist/server/meta-conversions-api.mjs +39 -35
  45. package/dist/server/meta-conversions-api.mjs.map +1 -1
  46. package/dist/server/openai-conversions-api.cjs.map +1 -1
  47. package/dist/server/reddit-conversions-api.cjs.map +1 -1
  48. package/dist/setup/session.cjs +1 -1
  49. package/dist/setup/session.cjs.map +1 -1
  50. package/dist/setup/session.mjs +1 -1
  51. package/dist/setup/session.mjs.map +1 -1
  52. package/dist/tanstack/analytics.cjs.map +1 -1
  53. package/dist/tanstack/middleware.cjs.map +1 -1
  54. package/dist/track/index.cjs.map +1 -1
  55. package/dist/visitor/index.cjs.map +1 -1
  56. package/dist/web/index.cjs +3 -2
  57. package/dist/web/index.cjs.map +1 -1
  58. package/dist/web/index.d.cts.map +1 -1
  59. package/dist/web/index.d.mts.map +1 -1
  60. package/dist/web/index.mjs +3 -2
  61. package/dist/web/index.mjs.map +1 -1
  62. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"setup.cjs","names":["Platform","deviceType","DeviceType","Dimensions","URLSearchParams","osName","osVersion","modelName","manufacturer","modelId","PixelRatio","config"],"sources":["../../src/native/setup.ts"],"sourcesContent":["import 'expo-sqlite/localStorage/install';\nimport { getAndroidId, getInstallReferrerAsync, getIosIdForVendorAsync } from 'expo-application';\nimport { randomUUID } from 'expo-crypto';\nimport {\n DeviceType,\n deviceType,\n manufacturer,\n modelId,\n modelName,\n osName,\n osVersion,\n} from 'expo-device';\nimport { getCalendars, getLocales } from 'expo-localization';\nimport { getAdvertisingId } from 'expo-tracking-transparency';\nimport { Dimensions, PixelRatio, Platform } from 'react-native';\nimport { URLSearchParams } from 'react-native-url-polyfill';\nimport { type Storage, cache, config } from '../setup/index';\nimport type { TrackTags } from '../track/types';\n\nconst map = new Map<string, string>();\n\nexport const storage: Storage = {\n getItem: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n console.error('localStorage is not available');\n return map.get(key) ?? null;\n }\n },\n setItem: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch {\n console.error('localStorage is not available');\n map.set(key, value);\n }\n },\n};\n\n/**\n * `getTags` runs once per event now, and both of these reach for a native module. Neither answer\n * can change while the app is running, so each is resolved once and the promise is reused. A\n * failed lookup is not cached, so the next event tries again.\n */\nlet deviceIdPromise: Promise<string> | undefined;\nlet installReferrerPromise: Promise<string | undefined> | undefined;\n\nexport function getDeviceId(): Promise<string> {\n deviceIdPromise ??= resolveDeviceId().catch((error: unknown) => {\n deviceIdPromise = undefined;\n throw error;\n });\n return deviceIdPromise;\n}\n\nfunction getInstallReferrer(): Promise<string | undefined> {\n if (Platform.OS !== 'android') return Promise.resolve(undefined);\n installReferrerPromise ??= getInstallReferrerAsync().catch((error: unknown) => {\n installReferrerPromise = undefined;\n throw error;\n });\n return installReferrerPromise;\n}\n\nasync function resolveDeviceId(): Promise<string> {\n let deviceId: string | null = null;\n if (Platform.OS === 'ios') {\n deviceId = await getIosIdForVendorAsync();\n } else if (Platform.OS === 'android') {\n deviceId = getAndroidId();\n }\n if (!deviceId) {\n deviceId = localStorage.getItem('device_id');\n if (!deviceId) {\n deviceId = randomUUID();\n localStorage.setItem('device_id', deviceId);\n }\n }\n return deviceId;\n}\n\nexport function getDeviceType(): string | undefined {\n switch (deviceType) {\n case DeviceType.PHONE:\n return 'mobile';\n case DeviceType.TABLET:\n return 'tablet';\n case DeviceType.DESKTOP:\n return 'desktop';\n case DeviceType.TV:\n return 'smarttv';\n default:\n return undefined;\n }\n}\n\nexport async function getTags(): Promise<TrackTags> {\n const screen = Dimensions.get('screen');\n const screen_width = Math.floor(screen.width);\n const screen_height = Math.floor(screen.height);\n\n const install_referrer = await getInstallReferrer();\n const params = new URLSearchParams(install_referrer);\n\n const tags: TrackTags = {\n os: `${osName} ${osVersion}`,\n os_name: osName ?? undefined,\n os_version: osVersion ?? undefined,\n device: modelName ?? undefined,\n device_id: await getDeviceId(),\n device_type: getDeviceType(),\n device_vendor: manufacturer ?? undefined,\n device_model_id: modelId ?? undefined,\n device_pixel_ratio: PixelRatio.get(),\n screen_width,\n screen_height,\n screen_resolution: `${screen_width}x${screen_height}`,\n release: config.release,\n language: getLocales().at(0)?.languageTag ?? 'en',\n time_zone: getCalendars().at(0)?.timeZone ?? 'UTC',\n // ads\n advertising_id: getAdvertisingId() ?? undefined,\n install_referrer,\n // utm params\n utm_source: params.get('utm_source') ?? undefined,\n utm_medium: params.get('utm_medium') ?? undefined,\n utm_campaign: params.get('utm_campaign') ?? undefined,\n utm_term: params.get('utm_term') ?? undefined,\n utm_content: params.get('utm_content') ?? undefined,\n utm_id: params.get('utm_id') ?? undefined,\n utm_source_platform: params.get('utm_source_platform') ?? undefined,\n utm_creative_format: params.get('utm_creative_format') ?? undefined,\n utm_marketing_tactic: params.get('utm_marketing_tactic') ?? undefined,\n };\n\n cache.tags = tags;\n return tags;\n}\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,sBAAM,IAAI,IAAoB;AAEpC,MAAa,UAAmB;CAC9B,UAAU,QAAQ;EAChB,IAAI;GACF,OAAO,aAAa,QAAQ,GAAG;EACjC,QAAQ;GACN,QAAQ,MAAM,+BAA+B;GAC7C,OAAO,IAAI,IAAI,GAAG,KAAK;EACzB;CACF;CACA,UAAU,KAAK,UAAU;EACvB,IAAI;GACF,aAAa,QAAQ,KAAK,KAAK;EACjC,QAAQ;GACN,QAAQ,MAAM,+BAA+B;GAC7C,IAAI,IAAI,KAAK,KAAK;EACpB;CACF;AACF;;;;;;AAOA,IAAI;AACJ,IAAI;AAEJ,SAAgB,cAA+B;CAC7C,oBAAoB,gBAAgB,CAAC,CAAC,OAAO,UAAmB;EAC9D,kBAAkB,KAAA;EAClB,MAAM;CACR,CAAC;CACD,OAAO;AACT;AAEA,SAAS,qBAAkD;CACzD,IAAIA,aAAAA,SAAS,OAAO,WAAW,OAAO,QAAQ,QAAQ,KAAA,CAAS;CAC/D,4BAAA,GAAA,iBAAA,wBAAA,CAAmD,CAAC,CAAC,OAAO,UAAmB;EAC7E,yBAAyB,KAAA;EACzB,MAAM;CACR,CAAC;CACD,OAAO;AACT;AAEA,eAAe,kBAAmC;CAChD,IAAI,WAA0B;CAC9B,IAAIA,aAAAA,SAAS,OAAO,OAClB,WAAW,OAAA,GAAA,iBAAA,uBAAA,CAA6B;MACnC,IAAIA,aAAAA,SAAS,OAAO,WACzB,YAAA,GAAA,iBAAA,aAAA,CAAwB;CAE1B,IAAI,CAAC,UAAU;EACb,WAAW,aAAa,QAAQ,WAAW;EAC3C,IAAI,CAAC,UAAU;GACb,YAAA,GAAA,YAAA,WAAA,CAAsB;GACtB,aAAa,QAAQ,aAAa,QAAQ;EAC5C;CACF;CACA,OAAO;AACT;AAEA,SAAgB,gBAAoC;CAClD,QAAQC,YAAAA,YAAR;EACE,KAAKC,YAAAA,WAAW,OACd,OAAO;EACT,KAAKA,YAAAA,WAAW,QACd,OAAO;EACT,KAAKA,YAAAA,WAAW,SACd,OAAO;EACT,KAAKA,YAAAA,WAAW,IACd,OAAO;EACT,SACE;CACJ;AACF;AAEA,eAAsB,UAA8B;CAClD,MAAM,SAASC,aAAAA,WAAW,IAAI,QAAQ;CACtC,MAAM,eAAe,KAAK,MAAM,OAAO,KAAK;CAC5C,MAAM,gBAAgB,KAAK,MAAM,OAAO,MAAM;CAE9C,MAAM,mBAAmB,MAAM,mBAAmB;CAClD,MAAM,SAAS,IAAIC,0BAAAA,gBAAgB,gBAAgB;CAEnD,MAAM,OAAkB;EACtB,IAAI,GAAGC,YAAAA,OAAO,GAAGC,YAAAA;EACjB,SAASD,YAAAA,UAAU,KAAA;EACnB,YAAYC,YAAAA,aAAa,KAAA;EACzB,QAAQC,YAAAA,aAAa,KAAA;EACrB,WAAW,MAAM,YAAY;EAC7B,aAAa,cAAc;EAC3B,eAAeC,YAAAA,gBAAgB,KAAA;EAC/B,iBAAiBC,YAAAA,WAAW,KAAA;EAC5B,oBAAoBC,aAAAA,WAAW,IAAI;EACnC;EACA;EACA,mBAAmB,GAAG,aAAa,GAAG;EACtC,SAASC,oBAAAA,OAAO;EAChB,WAAA,GAAA,kBAAA,WAAA,CAAqB,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe;EAC7C,YAAA,GAAA,kBAAA,aAAA,CAAwB,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY;EAE7C,iBAAA,GAAA,2BAAA,iBAAA,CAAiC,KAAK,KAAA;EACtC;EAEA,YAAY,OAAO,IAAI,YAAY,KAAK,KAAA;EACxC,YAAY,OAAO,IAAI,YAAY,KAAK,KAAA;EACxC,cAAc,OAAO,IAAI,cAAc,KAAK,KAAA;EAC5C,UAAU,OAAO,IAAI,UAAU,KAAK,KAAA;EACpC,aAAa,OAAO,IAAI,aAAa,KAAK,KAAA;EAC1C,QAAQ,OAAO,IAAI,QAAQ,KAAK,KAAA;EAChC,qBAAqB,OAAO,IAAI,qBAAqB,KAAK,KAAA;EAC1D,qBAAqB,OAAO,IAAI,qBAAqB,KAAK,KAAA;EAC1D,sBAAsB,OAAO,IAAI,sBAAsB,KAAK,KAAA;CAC9D;CAEA,oBAAA,MAAM,OAAO;CACb,OAAO;AACT"}
1
+ {"version":3,"file":"setup.cjs","names":["Platform","getInstallReferrerAsync","getIosIdForVendorAsync","getAndroidId","randomUUID","deviceType","DeviceType","Dimensions","URLSearchParams","osName","osVersion","modelName","manufacturer","modelId","PixelRatio","config","getLocales","getCalendars","getAdvertisingId"],"sources":["../../src/native/setup.ts"],"sourcesContent":["import 'expo-sqlite/localStorage/install';\nimport { getAndroidId, getInstallReferrerAsync, getIosIdForVendorAsync } from 'expo-application';\nimport { randomUUID } from 'expo-crypto';\nimport {\n DeviceType,\n deviceType,\n manufacturer,\n modelId,\n modelName,\n osName,\n osVersion,\n} from 'expo-device';\nimport { getCalendars, getLocales } from 'expo-localization';\nimport { getAdvertisingId } from 'expo-tracking-transparency';\nimport { Dimensions, PixelRatio, Platform } from 'react-native';\nimport { URLSearchParams } from 'react-native-url-polyfill';\nimport { type Storage, cache, config } from '../setup/index';\nimport type { TrackTags } from '../track/types';\n\nconst map = new Map<string, string>();\n\nexport const storage: Storage = {\n getItem: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n console.error('localStorage is not available');\n return map.get(key) ?? null;\n }\n },\n setItem: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch {\n console.error('localStorage is not available');\n map.set(key, value);\n }\n },\n};\n\n/**\n * `getTags` runs once per event now, and both of these reach for a native module. Neither answer\n * can change while the app is running, so each is resolved once and the promise is reused. A\n * failed lookup is not cached, so the next event tries again.\n */\nlet deviceIdPromise: Promise<string> | undefined;\nlet installReferrerPromise: Promise<string | undefined> | undefined;\n\nexport function getDeviceId(): Promise<string> {\n deviceIdPromise ??= resolveDeviceId().catch((error: unknown) => {\n deviceIdPromise = undefined;\n throw error;\n });\n return deviceIdPromise;\n}\n\nfunction getInstallReferrer(): Promise<string | undefined> {\n if (Platform.OS !== 'android') return Promise.resolve(undefined);\n installReferrerPromise ??= getInstallReferrerAsync().catch((error: unknown) => {\n installReferrerPromise = undefined;\n throw error;\n });\n return installReferrerPromise;\n}\n\nasync function resolveDeviceId(): Promise<string> {\n let deviceId: string | null = null;\n if (Platform.OS === 'ios') {\n deviceId = await getIosIdForVendorAsync();\n } else if (Platform.OS === 'android') {\n deviceId = getAndroidId();\n }\n if (!deviceId) {\n deviceId = localStorage.getItem('device_id');\n if (!deviceId) {\n deviceId = randomUUID();\n localStorage.setItem('device_id', deviceId);\n }\n }\n return deviceId;\n}\n\nexport function getDeviceType(): string | undefined {\n switch (deviceType) {\n case DeviceType.PHONE:\n return 'mobile';\n case DeviceType.TABLET:\n return 'tablet';\n case DeviceType.DESKTOP:\n return 'desktop';\n case DeviceType.TV:\n return 'smarttv';\n default:\n return undefined;\n }\n}\n\nexport async function getTags(): Promise<TrackTags> {\n const screen = Dimensions.get('screen');\n const screen_width = Math.floor(screen.width);\n const screen_height = Math.floor(screen.height);\n\n const install_referrer = await getInstallReferrer();\n const params = new URLSearchParams(install_referrer);\n\n const tags: TrackTags = {\n os: `${osName} ${osVersion}`,\n os_name: osName ?? undefined,\n os_version: osVersion ?? undefined,\n device: modelName ?? undefined,\n device_id: await getDeviceId(),\n device_type: getDeviceType(),\n device_vendor: manufacturer ?? undefined,\n device_model_id: modelId ?? undefined,\n device_pixel_ratio: PixelRatio.get(),\n screen_width,\n screen_height,\n screen_resolution: `${screen_width}x${screen_height}`,\n release: config.release,\n language: getLocales().at(0)?.languageTag ?? 'en',\n time_zone: getCalendars().at(0)?.timeZone ?? 'UTC',\n // ads\n advertising_id: getAdvertisingId() ?? undefined,\n install_referrer,\n // utm params\n utm_source: params.get('utm_source') ?? undefined,\n utm_medium: params.get('utm_medium') ?? undefined,\n utm_campaign: params.get('utm_campaign') ?? undefined,\n utm_term: params.get('utm_term') ?? undefined,\n utm_content: params.get('utm_content') ?? undefined,\n utm_id: params.get('utm_id') ?? undefined,\n utm_source_platform: params.get('utm_source_platform') ?? undefined,\n utm_creative_format: params.get('utm_creative_format') ?? undefined,\n utm_marketing_tactic: params.get('utm_marketing_tactic') ?? undefined,\n };\n\n cache.tags = tags;\n return tags;\n}\n"],"mappings":"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"}
@@ -11,7 +11,8 @@ let next_web_vitals_js = require("next/web-vitals.js");
11
11
  let react_jsx_runtime = require("react/jsx-runtime");
12
12
  //#region src/next/index.tsx
13
13
  function Analytics({ gaId, gaSrc, nonce, debugMode, metaPixelId, hotjarId, redditPixelId, linkedInPartnerId, facebookAppId, reportWebVitals = true }) {
14
- require_hooks_use_web_analytics.useWebAnalytics((0, next_navigation_js.usePathname)());
14
+ const pathname = (0, next_navigation_js.usePathname)();
15
+ require_hooks_use_web_analytics.useWebAnalytics(pathname);
15
16
  require_hooks_use_outbound_click_analytics.useOutboundClickAnalytics();
16
17
  (0, next_web_vitals_js.useReportWebVitals)((metric) => {
17
18
  if (!reportWebVitals) return;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["Script"],"sources":["../../src/next/index.tsx"],"sourcesContent":["'use client';\n\nimport { usePathname } from 'next/navigation';\nimport Script from 'next/script';\nimport { useReportWebVitals } from 'next/web-vitals';\nimport { useOutboundClickAnalytics } from '../hooks/use-outbound-click-analytics';\nimport { useWebAnalytics } from '../hooks/use-web-analytics';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport { track } from '../track/index';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ninterface Props {\n gaId?: GaId;\n gaSrc?: string;\n gtmId?: GtmId;\n hotjarId?: `${number}`;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n gaSrc,\n nonce,\n debugMode,\n metaPixelId,\n hotjarId,\n redditPixelId,\n linkedInPartnerId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n const pathname = usePathname();\n useWebAnalytics(pathname);\n useOutboundClickAnalytics();\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n value: metric.delta,\n metric_id: metric.id,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n metric_navigation_type: metric.navigationType,\n non_interaction: true, // avoids affecting bounce rate.\n };\n track(metric.name, properties);\n });\n\n return (\n <>\n {facebookAppId && <meta property=\"fb:app_id\" content={facebookAppId} />}\n {gaId && (\n <>\n <Script\n id=\"gtag\"\n nonce={nonce}\n src={gaSrc ?? `https://www.googletagmanager.com/gtag/js?id=${gaId}`}\n />\n <Script\n nonce={nonce}\n id=\"gtag-init\"\n dangerouslySetInnerHTML={{\n __html: `\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '${gaId}'${debugMode ? \" ,{ 'debug_mode': true }\" : ''});\n `,\n }}\n />\n </>\n )}\n {metaPixelId && (\n <Script\n id=\"meta-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !(function (f, b, e, v, n, t, s) {\n if (f.fbq) return;\n n = f.fbq = function () {\n n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);\n };\n if (!f._fbq) f._fbq = n;\n n.push = n;\n n.loaded = !0;\n n.version = '2.0';\n n.queue = [];\n t = b.createElement(e);\n t.async = !0;\n t.src = v;\n s = b.getElementsByTagName(e)[0];\n s.parentNode.insertBefore(t, s);\n })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');\n fbq('init', '${metaPixelId}');\n fbq('track', 'PageView');`,\n }}\n />\n )}\n {redditPixelId && (\n <Script\n id=\"reddit-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !function(w,d) {\n if(!w.rdt) {\n var p = w.rdt = function() {\n p.sendEvent ? p.sendEvent.apply(p,arguments) : p.callQueue.push(arguments)\n };\n p.callQueue = [];\n var t = d.createElement(\"script\");\n t.src = \"https://www.redditstatic.com/ads/pixel.js\";\n t.async = !0;\n var s = d.getElementsByTagName(\"script\")[0];\n s.parentNode.insertBefore(t,s)\n }\n }(window, document);\n rdt('init', '${redditPixelId}');\n rdt('track', 'PageVisit');`,\n }}\n />\n )}\n {linkedInPartnerId && (\n <Script\n id=\"linkedin-insight-tag\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n _linkedin_partner_id = \"${linkedInPartnerId}\";\n window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];\n window._linkedin_data_partner_ids.push(_linkedin_partner_id);\n\n (function(l) {\n if (!l){\n window.lintrk = function(a,b){ \n window.lintrk.q.push([a,b])\n };\n window.lintrk.q=[]\n }\n var s = document.getElementsByTagName(\"script\")[0];\n var b = document.createElement(\"script\");\n b.type = \"text/javascript\";b.async = true;\n b.src = \"https://snap.licdn.com/li.lms-analytics/insight.min.js\";\n s.parentNode.insertBefore(b, s);\n })(window.lintrk);\n `,\n }}\n />\n )}\n {hotjarId && (\n <Script\n id=\"hotjar\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:${hotjarId},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n `,\n }}\n />\n )}\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,UAAU,EACxB,MACA,OACA,OACA,WACA,aACA,UACA,eACA,mBACA,eACA,kBAAkB,QACV;CAER,gCAAA,iBAAA,GAAA,mBAAA,YAAA,CAAuB,CAAC;CACxB,2CAAA,0BAA0B;CAE1B,CAAA,GAAA,mBAAA,mBAAA,EAAoB,WAAW;EAC7B,IAAI,CAAC,iBAAiB;EACtB,MAAM,aAAa;GACjB,OAAO,OAAO;GACd,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,cAAc,OAAO;GACrB,eAAe,OAAO;GACtB,wBAAwB,OAAO;GAC/B,iBAAiB;EACnB;EACA,oBAAA,MAAM,OAAO,MAAM,UAAU;CAC/B,CAAC;CAED,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;EACG,iBAAiB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,UAAS;GAAY,SAAS;EAAgB,CAAA;EACrE,QACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACI;GACP,KAAK,SAAS,+CAA+C;EAC9D,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACS;GACP,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;gCAIU,KAAK,GAAG,YAAY,6BAA6B,GAAG;cAExE;EACD,CAAA,CACD,EAAA,CAAA;EAEH,eACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;;;;2BAiBO,YAAY;uCAE7B;EACD,CAAA;EAEF,iBACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;2BAcO,cAAc;wCAE/B;EACD,CAAA;EAEF,qBACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;wCACoB,kBAAkB;;;;;;;;;;;;;;;;;gBAkBhD;EACD,CAAA;EAEF,YACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;oCAGgB,SAAS;;;;;;cAOnC;EACD,CAAA;CAEH,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"index.cjs","names":["usePathname","Script"],"sources":["../../src/next/index.tsx"],"sourcesContent":["'use client';\n\nimport { usePathname } from 'next/navigation';\nimport Script from 'next/script';\nimport { useReportWebVitals } from 'next/web-vitals';\nimport { useOutboundClickAnalytics } from '../hooks/use-outbound-click-analytics';\nimport { useWebAnalytics } from '../hooks/use-web-analytics';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport { track } from '../track/index';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ninterface Props {\n gaId?: GaId;\n gaSrc?: string;\n gtmId?: GtmId;\n hotjarId?: `${number}`;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n gaSrc,\n nonce,\n debugMode,\n metaPixelId,\n hotjarId,\n redditPixelId,\n linkedInPartnerId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n const pathname = usePathname();\n useWebAnalytics(pathname);\n useOutboundClickAnalytics();\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n value: metric.delta,\n metric_id: metric.id,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n metric_navigation_type: metric.navigationType,\n non_interaction: true, // avoids affecting bounce rate.\n };\n track(metric.name, properties);\n });\n\n return (\n <>\n {facebookAppId && <meta property=\"fb:app_id\" content={facebookAppId} />}\n {gaId && (\n <>\n <Script\n id=\"gtag\"\n nonce={nonce}\n src={gaSrc ?? `https://www.googletagmanager.com/gtag/js?id=${gaId}`}\n />\n <Script\n nonce={nonce}\n id=\"gtag-init\"\n dangerouslySetInnerHTML={{\n __html: `\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '${gaId}'${debugMode ? \" ,{ 'debug_mode': true }\" : ''});\n `,\n }}\n />\n </>\n )}\n {metaPixelId && (\n <Script\n id=\"meta-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !(function (f, b, e, v, n, t, s) {\n if (f.fbq) return;\n n = f.fbq = function () {\n n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);\n };\n if (!f._fbq) f._fbq = n;\n n.push = n;\n n.loaded = !0;\n n.version = '2.0';\n n.queue = [];\n t = b.createElement(e);\n t.async = !0;\n t.src = v;\n s = b.getElementsByTagName(e)[0];\n s.parentNode.insertBefore(t, s);\n })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');\n fbq('init', '${metaPixelId}');\n fbq('track', 'PageView');`,\n }}\n />\n )}\n {redditPixelId && (\n <Script\n id=\"reddit-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !function(w,d) {\n if(!w.rdt) {\n var p = w.rdt = function() {\n p.sendEvent ? p.sendEvent.apply(p,arguments) : p.callQueue.push(arguments)\n };\n p.callQueue = [];\n var t = d.createElement(\"script\");\n t.src = \"https://www.redditstatic.com/ads/pixel.js\";\n t.async = !0;\n var s = d.getElementsByTagName(\"script\")[0];\n s.parentNode.insertBefore(t,s)\n }\n }(window, document);\n rdt('init', '${redditPixelId}');\n rdt('track', 'PageVisit');`,\n }}\n />\n )}\n {linkedInPartnerId && (\n <Script\n id=\"linkedin-insight-tag\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n _linkedin_partner_id = \"${linkedInPartnerId}\";\n window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];\n window._linkedin_data_partner_ids.push(_linkedin_partner_id);\n\n (function(l) {\n if (!l){\n window.lintrk = function(a,b){ \n window.lintrk.q.push([a,b])\n };\n window.lintrk.q=[]\n }\n var s = document.getElementsByTagName(\"script\")[0];\n var b = document.createElement(\"script\");\n b.type = \"text/javascript\";b.async = true;\n b.src = \"https://snap.licdn.com/li.lms-analytics/insight.min.js\";\n s.parentNode.insertBefore(b, s);\n })(window.lintrk);\n `,\n }}\n />\n )}\n {hotjarId && (\n <Script\n id=\"hotjar\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:${hotjarId},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n `,\n }}\n />\n )}\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,UAAU,EACxB,MACA,OACA,OACA,WACA,aACA,UACA,eACA,mBACA,eACA,kBAAkB,QACV;CACR,MAAM,YAAA,GAAWA,mBAAAA,YAAAA,CAAY;CAC7B,gCAAA,gBAAgB,QAAQ;CACxB,2CAAA,0BAA0B;CAE1B,CAAA,GAAA,mBAAA,mBAAA,EAAoB,WAAW;EAC7B,IAAI,CAAC,iBAAiB;EACtB,MAAM,aAAa;GACjB,OAAO,OAAO;GACd,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,cAAc,OAAO;GACrB,eAAe,OAAO;GACtB,wBAAwB,OAAO;GAC/B,iBAAiB;EACnB;EACA,oBAAA,MAAM,OAAO,MAAM,UAAU;CAC/B,CAAC;CAED,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;EACG,iBAAiB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,UAAS;GAAY,SAAS;EAAgB,CAAA;EACrE,QACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,SAAD;GACE,IAAG;GACI;GACP,KAAK,SAAS,+CAA+C;EAC9D,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACS;GACP,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;gCAIU,KAAK,GAAG,YAAY,6BAA6B,GAAG;cAExE;EACD,CAAA,CACD,EAAA,CAAA;EAEH,eACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;;;;2BAiBO,YAAY;uCAE7B;EACD,CAAA;EAEF,iBACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;2BAcO,cAAc;wCAE/B;EACD,CAAA;EAEF,qBACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;wCACoB,kBAAkB;;;;;;;;;;;;;;;;;gBAkBhD;EACD,CAAA;EAEF,YACC,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,SAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;oCAGgB,SAAS;;;;;;cAOnC;EACD,CAAA;CAEH,EAAA,CAAA;AAEN"}
@@ -8,7 +8,8 @@ import { useReportWebVitals } from "next/web-vitals.js";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/next/index.tsx
10
10
  function Analytics({ gaId, gaSrc, nonce, debugMode, metaPixelId, hotjarId, redditPixelId, linkedInPartnerId, facebookAppId, reportWebVitals = true }) {
11
- useWebAnalytics(usePathname());
11
+ const pathname = usePathname();
12
+ useWebAnalytics(pathname);
12
13
  useOutboundClickAnalytics();
13
14
  useReportWebVitals((metric) => {
14
15
  if (!reportWebVitals) return;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/next/index.tsx"],"sourcesContent":["'use client';\n\nimport { usePathname } from 'next/navigation';\nimport Script from 'next/script';\nimport { useReportWebVitals } from 'next/web-vitals';\nimport { useOutboundClickAnalytics } from '../hooks/use-outbound-click-analytics';\nimport { useWebAnalytics } from '../hooks/use-web-analytics';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport { track } from '../track/index';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ninterface Props {\n gaId?: GaId;\n gaSrc?: string;\n gtmId?: GtmId;\n hotjarId?: `${number}`;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n gaSrc,\n nonce,\n debugMode,\n metaPixelId,\n hotjarId,\n redditPixelId,\n linkedInPartnerId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n const pathname = usePathname();\n useWebAnalytics(pathname);\n useOutboundClickAnalytics();\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n value: metric.delta,\n metric_id: metric.id,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n metric_navigation_type: metric.navigationType,\n non_interaction: true, // avoids affecting bounce rate.\n };\n track(metric.name, properties);\n });\n\n return (\n <>\n {facebookAppId && <meta property=\"fb:app_id\" content={facebookAppId} />}\n {gaId && (\n <>\n <Script\n id=\"gtag\"\n nonce={nonce}\n src={gaSrc ?? `https://www.googletagmanager.com/gtag/js?id=${gaId}`}\n />\n <Script\n nonce={nonce}\n id=\"gtag-init\"\n dangerouslySetInnerHTML={{\n __html: `\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '${gaId}'${debugMode ? \" ,{ 'debug_mode': true }\" : ''});\n `,\n }}\n />\n </>\n )}\n {metaPixelId && (\n <Script\n id=\"meta-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !(function (f, b, e, v, n, t, s) {\n if (f.fbq) return;\n n = f.fbq = function () {\n n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);\n };\n if (!f._fbq) f._fbq = n;\n n.push = n;\n n.loaded = !0;\n n.version = '2.0';\n n.queue = [];\n t = b.createElement(e);\n t.async = !0;\n t.src = v;\n s = b.getElementsByTagName(e)[0];\n s.parentNode.insertBefore(t, s);\n })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');\n fbq('init', '${metaPixelId}');\n fbq('track', 'PageView');`,\n }}\n />\n )}\n {redditPixelId && (\n <Script\n id=\"reddit-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !function(w,d) {\n if(!w.rdt) {\n var p = w.rdt = function() {\n p.sendEvent ? p.sendEvent.apply(p,arguments) : p.callQueue.push(arguments)\n };\n p.callQueue = [];\n var t = d.createElement(\"script\");\n t.src = \"https://www.redditstatic.com/ads/pixel.js\";\n t.async = !0;\n var s = d.getElementsByTagName(\"script\")[0];\n s.parentNode.insertBefore(t,s)\n }\n }(window, document);\n rdt('init', '${redditPixelId}');\n rdt('track', 'PageVisit');`,\n }}\n />\n )}\n {linkedInPartnerId && (\n <Script\n id=\"linkedin-insight-tag\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n _linkedin_partner_id = \"${linkedInPartnerId}\";\n window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];\n window._linkedin_data_partner_ids.push(_linkedin_partner_id);\n\n (function(l) {\n if (!l){\n window.lintrk = function(a,b){ \n window.lintrk.q.push([a,b])\n };\n window.lintrk.q=[]\n }\n var s = document.getElementsByTagName(\"script\")[0];\n var b = document.createElement(\"script\");\n b.type = \"text/javascript\";b.async = true;\n b.src = \"https://snap.licdn.com/li.lms-analytics/insight.min.js\";\n s.parentNode.insertBefore(b, s);\n })(window.lintrk);\n `,\n }}\n />\n )}\n {hotjarId && (\n <Script\n id=\"hotjar\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:${hotjarId},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n `,\n }}\n />\n )}\n </>\n );\n}\n"],"mappings":";;;;;;;;;AA0BA,SAAgB,UAAU,EACxB,MACA,OACA,OACA,WACA,aACA,UACA,eACA,mBACA,eACA,kBAAkB,QACV;CAER,gBADiB,YACM,CAAC;CACxB,0BAA0B;CAE1B,oBAAoB,WAAW;EAC7B,IAAI,CAAC,iBAAiB;EACtB,MAAM,aAAa;GACjB,OAAO,OAAO;GACd,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,cAAc,OAAO;GACrB,eAAe,OAAO;GACtB,wBAAwB,OAAO;GAC/B,iBAAiB;EACnB;EACA,MAAM,OAAO,MAAM,UAAU;CAC/B,CAAC;CAED,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,iBAAiB,oBAAC,QAAD;GAAM,UAAS;GAAY,SAAS;EAAgB,CAAA;EACrE,QACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;GACE,IAAG;GACI;GACP,KAAK,SAAS,+CAA+C;EAC9D,CAAA,GACD,oBAAC,QAAD;GACS;GACP,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;gCAIU,KAAK,GAAG,YAAY,6BAA6B,GAAG;cAExE;EACD,CAAA,CACD,EAAA,CAAA;EAEH,eACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;;;;2BAiBO,YAAY;uCAE7B;EACD,CAAA;EAEF,iBACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;2BAcO,cAAc;wCAE/B;EACD,CAAA;EAEF,qBACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;wCACoB,kBAAkB;;;;;;;;;;;;;;;;;gBAkBhD;EACD,CAAA;EAEF,YACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;oCAGgB,SAAS;;;;;;cAOnC;EACD,CAAA;CAEH,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/next/index.tsx"],"sourcesContent":["'use client';\n\nimport { usePathname } from 'next/navigation';\nimport Script from 'next/script';\nimport { useReportWebVitals } from 'next/web-vitals';\nimport { useOutboundClickAnalytics } from '../hooks/use-outbound-click-analytics';\nimport { useWebAnalytics } from '../hooks/use-web-analytics';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport { track } from '../track/index';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ninterface Props {\n gaId?: GaId;\n gaSrc?: string;\n gtmId?: GtmId;\n hotjarId?: `${number}`;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n gaSrc,\n nonce,\n debugMode,\n metaPixelId,\n hotjarId,\n redditPixelId,\n linkedInPartnerId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n const pathname = usePathname();\n useWebAnalytics(pathname);\n useOutboundClickAnalytics();\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n value: metric.delta,\n metric_id: metric.id,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n metric_navigation_type: metric.navigationType,\n non_interaction: true, // avoids affecting bounce rate.\n };\n track(metric.name, properties);\n });\n\n return (\n <>\n {facebookAppId && <meta property=\"fb:app_id\" content={facebookAppId} />}\n {gaId && (\n <>\n <Script\n id=\"gtag\"\n nonce={nonce}\n src={gaSrc ?? `https://www.googletagmanager.com/gtag/js?id=${gaId}`}\n />\n <Script\n nonce={nonce}\n id=\"gtag-init\"\n dangerouslySetInnerHTML={{\n __html: `\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '${gaId}'${debugMode ? \" ,{ 'debug_mode': true }\" : ''});\n `,\n }}\n />\n </>\n )}\n {metaPixelId && (\n <Script\n id=\"meta-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !(function (f, b, e, v, n, t, s) {\n if (f.fbq) return;\n n = f.fbq = function () {\n n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);\n };\n if (!f._fbq) f._fbq = n;\n n.push = n;\n n.loaded = !0;\n n.version = '2.0';\n n.queue = [];\n t = b.createElement(e);\n t.async = !0;\n t.src = v;\n s = b.getElementsByTagName(e)[0];\n s.parentNode.insertBefore(t, s);\n })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');\n fbq('init', '${metaPixelId}');\n fbq('track', 'PageView');`,\n }}\n />\n )}\n {redditPixelId && (\n <Script\n id=\"reddit-pixel\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n !function(w,d) {\n if(!w.rdt) {\n var p = w.rdt = function() {\n p.sendEvent ? p.sendEvent.apply(p,arguments) : p.callQueue.push(arguments)\n };\n p.callQueue = [];\n var t = d.createElement(\"script\");\n t.src = \"https://www.redditstatic.com/ads/pixel.js\";\n t.async = !0;\n var s = d.getElementsByTagName(\"script\")[0];\n s.parentNode.insertBefore(t,s)\n }\n }(window, document);\n rdt('init', '${redditPixelId}');\n rdt('track', 'PageVisit');`,\n }}\n />\n )}\n {linkedInPartnerId && (\n <Script\n id=\"linkedin-insight-tag\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n _linkedin_partner_id = \"${linkedInPartnerId}\";\n window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];\n window._linkedin_data_partner_ids.push(_linkedin_partner_id);\n\n (function(l) {\n if (!l){\n window.lintrk = function(a,b){ \n window.lintrk.q.push([a,b])\n };\n window.lintrk.q=[]\n }\n var s = document.getElementsByTagName(\"script\")[0];\n var b = document.createElement(\"script\");\n b.type = \"text/javascript\";b.async = true;\n b.src = \"https://snap.licdn.com/li.lms-analytics/insight.min.js\";\n s.parentNode.insertBefore(b, s);\n })(window.lintrk);\n `,\n }}\n />\n )}\n {hotjarId && (\n <Script\n id=\"hotjar\"\n strategy=\"afterInteractive\"\n dangerouslySetInnerHTML={{\n __html: `\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:${hotjarId},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n `,\n }}\n />\n )}\n </>\n );\n}\n"],"mappings":";;;;;;;;;AA0BA,SAAgB,UAAU,EACxB,MACA,OACA,OACA,WACA,aACA,UACA,eACA,mBACA,eACA,kBAAkB,QACV;CACR,MAAM,WAAW,YAAY;CAC7B,gBAAgB,QAAQ;CACxB,0BAA0B;CAE1B,oBAAoB,WAAW;EAC7B,IAAI,CAAC,iBAAiB;EACtB,MAAM,aAAa;GACjB,OAAO,OAAO;GACd,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,cAAc,OAAO;GACrB,eAAe,OAAO;GACtB,wBAAwB,OAAO;GAC/B,iBAAiB;EACnB;EACA,MAAM,OAAO,MAAM,UAAU;CAC/B,CAAC;CAED,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,iBAAiB,oBAAC,QAAD;GAAM,UAAS;GAAY,SAAS;EAAgB,CAAA;EACrE,QACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;GACE,IAAG;GACI;GACP,KAAK,SAAS,+CAA+C;EAC9D,CAAA,GACD,oBAAC,QAAD;GACS;GACP,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;gCAIU,KAAK,GAAG,YAAY,6BAA6B,GAAG;cAExE;EACD,CAAA,CACD,EAAA,CAAA;EAEH,eACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;;;;2BAiBO,YAAY;uCAE7B;EACD,CAAA;EAEF,iBACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;2BAcO,cAAc;wCAE/B;EACD,CAAA;EAEF,qBACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;wCACoB,kBAAkB;;;;;;;;;;;;;;;;;gBAkBhD;EACD,CAAA;EAEF,YACC,oBAAC,QAAD;GACE,IAAG;GACH,UAAS;GACT,yBAAyB,EACvB,QAAQ;;;oCAGgB,SAAS;;;;;;cAOnC;EACD,CAAA;CAEH,EAAA,CAAA;AAEN"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/react-router/index.tsx"],"sourcesContent":["import { useLocation } from 'react-router';\nimport { useOutboundClickAnalytics } from '../hooks/use-outbound-click-analytics';\nimport { useReportWebVitals } from '../hooks/use-report-web-vitals';\nimport { useWebAnalytics } from '../hooks/use-web-analytics';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport { track } from '../track/index';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ninterface Props {\n gaId?: GaId;\n gaSrc?: string;\n gtmId?: GtmId;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n hotjarId?: `${number}`;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n gaSrc,\n nonce,\n debugMode,\n metaPixelId,\n redditPixelId,\n linkedInPartnerId,\n hotjarId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n const { pathname } = useLocation();\n useWebAnalytics(pathname);\n useOutboundClickAnalytics();\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n value: metric.delta,\n metric_id: metric.id,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n metric_navigation_type: metric.navigationType,\n non_interaction: true, // avoids affecting bounce rate.\n };\n track(metric.name, properties);\n });\n\n return (\n <>\n {facebookAppId && <meta property=\"fb:app_id\" content={facebookAppId} />}\n {gaId && (\n <>\n <script\n async\n id=\"gtag\"\n nonce={nonce}\n src={gaSrc ?? `https://www.googletagmanager.com/gtag/js?id=${gaId}`}\n />\n <script\n async\n nonce={nonce}\n id=\"gtag-init\"\n dangerouslySetInnerHTML={{\n __html: `\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '${gaId}'${debugMode ? \" ,{ 'debug_mode': true }\" : ''});\n `,\n }}\n />\n </>\n )}\n {metaPixelId && (\n <script\n async\n id=\"meta-pixel\"\n dangerouslySetInnerHTML={{\n __html: `\n !(function (f, b, e, v, n, t, s) {\n if (f.fbq) return;\n n = f.fbq = function () {\n n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);\n };\n if (!f._fbq) f._fbq = n;\n n.push = n;\n n.loaded = !0;\n n.version = '2.0';\n n.queue = [];\n t = b.createElement(e);\n t.async = !0;\n t.src = v;\n s = b.getElementsByTagName(e)[0];\n s.parentNode.insertBefore(t, s);\n })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');\n fbq('init', '${metaPixelId}');\n fbq('track', 'PageView');`,\n }}\n />\n )}\n {redditPixelId && (\n <script\n async\n id=\"reddit-pixel\"\n dangerouslySetInnerHTML={{\n __html: `\n !function(w,d) {\n if(!w.rdt) {\n var p = w.rdt = function() {\n p.sendEvent ? p.sendEvent.apply(p,arguments) : p.callQueue.push(arguments)\n };\n p.callQueue = [];\n var t = d.createElement(\"script\");\n t.src = \"https://www.redditstatic.com/ads/pixel.js\";\n t.async = !0;\n var s = d.getElementsByTagName(\"script\")[0];\n s.parentNode.insertBefore(t,s)\n }\n }(window, document);\n rdt('init', '${redditPixelId}');\n rdt('track', 'PageVisit');`,\n }}\n />\n )}\n {linkedInPartnerId && (\n <script\n async\n id=\"linkedin-insight-tag\"\n dangerouslySetInnerHTML={{\n __html: `\n _linkedin_partner_id = \"${linkedInPartnerId}\";\n window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];\n window._linkedin_data_partner_ids.push(_linkedin_partner_id);\n\n (function(l) {\n if (!l){\n window.lintrk = function(a,b){\n window.lintrk.q.push([a,b])\n };\n window.lintrk.q=[]\n }\n var s = document.getElementsByTagName(\"script\")[0];\n var b = document.createElement(\"script\");\n b.type = \"text/javascript\";b.async = true;\n b.src = \"https://snap.licdn.com/li.lms-analytics/insight.min.js\";\n s.parentNode.insertBefore(b, s);\n })(window.lintrk);\n `,\n }}\n />\n )}\n {hotjarId && (\n <script\n async\n id=\"hotjar\"\n dangerouslySetInnerHTML={{\n __html: `\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:${hotjarId},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n `,\n }}\n />\n )}\n </>\n );\n}\n"],"mappings":";;;;;;;;AAuBA,SAAgB,UAAU,EACxB,MACA,OACA,OACA,WACA,aACA,eACA,mBACA,UACA,eACA,kBAAkB,QACV;CACR,MAAM,EAAE,cAAA,GAAA,aAAA,YAAA,CAAyB;CACjC,gCAAA,gBAAgB,QAAQ;CACxB,2CAAA,0BAA0B;CAE1B,oCAAA,oBAAoB,WAAW;EAC7B,IAAI,CAAC,iBAAiB;EACtB,MAAM,aAAa;GACjB,OAAO,OAAO;GACd,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,cAAc,OAAO;GACrB,eAAe,OAAO;GACtB,wBAAwB,OAAO;GAC/B,iBAAiB;EACnB;EACA,oBAAA,MAAM,OAAO,MAAM,UAAU;CAC/B,CAAC;CAED,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;EACG,iBAAiB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,UAAS;GAAY,SAAS;EAAgB,CAAA;EACrE,QACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACI;GACP,KAAK,SAAS,+CAA+C;EAC9D,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACO;GACP,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;gCAIU,KAAK,GAAG,YAAY,6BAA6B,GAAG;cAExE;EACD,CAAA,CACD,EAAA,CAAA;EAEH,eACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;;;;2BAiBO,YAAY;uCAE7B;EACD,CAAA;EAEF,iBACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;2BAcO,cAAc;wCAE/B;EACD,CAAA;EAEF,qBACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;sCACkB,kBAAkB;;;;;;;;;;;;;;;;;cAkB9C;EACD,CAAA;EAEF,YACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;oCAGgB,SAAS;;;;;;cAOnC;EACD,CAAA;CAEH,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"index.cjs","names":["useLocation"],"sources":["../../src/react-router/index.tsx"],"sourcesContent":["import { useLocation } from 'react-router';\nimport { useOutboundClickAnalytics } from '../hooks/use-outbound-click-analytics';\nimport { useReportWebVitals } from '../hooks/use-report-web-vitals';\nimport { useWebAnalytics } from '../hooks/use-web-analytics';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport { track } from '../track/index';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ninterface Props {\n gaId?: GaId;\n gaSrc?: string;\n gtmId?: GtmId;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n hotjarId?: `${number}`;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n gaSrc,\n nonce,\n debugMode,\n metaPixelId,\n redditPixelId,\n linkedInPartnerId,\n hotjarId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n const { pathname } = useLocation();\n useWebAnalytics(pathname);\n useOutboundClickAnalytics();\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n value: metric.delta,\n metric_id: metric.id,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n metric_navigation_type: metric.navigationType,\n non_interaction: true, // avoids affecting bounce rate.\n };\n track(metric.name, properties);\n });\n\n return (\n <>\n {facebookAppId && <meta property=\"fb:app_id\" content={facebookAppId} />}\n {gaId && (\n <>\n <script\n async\n id=\"gtag\"\n nonce={nonce}\n src={gaSrc ?? `https://www.googletagmanager.com/gtag/js?id=${gaId}`}\n />\n <script\n async\n nonce={nonce}\n id=\"gtag-init\"\n dangerouslySetInnerHTML={{\n __html: `\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '${gaId}'${debugMode ? \" ,{ 'debug_mode': true }\" : ''});\n `,\n }}\n />\n </>\n )}\n {metaPixelId && (\n <script\n async\n id=\"meta-pixel\"\n dangerouslySetInnerHTML={{\n __html: `\n !(function (f, b, e, v, n, t, s) {\n if (f.fbq) return;\n n = f.fbq = function () {\n n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);\n };\n if (!f._fbq) f._fbq = n;\n n.push = n;\n n.loaded = !0;\n n.version = '2.0';\n n.queue = [];\n t = b.createElement(e);\n t.async = !0;\n t.src = v;\n s = b.getElementsByTagName(e)[0];\n s.parentNode.insertBefore(t, s);\n })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');\n fbq('init', '${metaPixelId}');\n fbq('track', 'PageView');`,\n }}\n />\n )}\n {redditPixelId && (\n <script\n async\n id=\"reddit-pixel\"\n dangerouslySetInnerHTML={{\n __html: `\n !function(w,d) {\n if(!w.rdt) {\n var p = w.rdt = function() {\n p.sendEvent ? p.sendEvent.apply(p,arguments) : p.callQueue.push(arguments)\n };\n p.callQueue = [];\n var t = d.createElement(\"script\");\n t.src = \"https://www.redditstatic.com/ads/pixel.js\";\n t.async = !0;\n var s = d.getElementsByTagName(\"script\")[0];\n s.parentNode.insertBefore(t,s)\n }\n }(window, document);\n rdt('init', '${redditPixelId}');\n rdt('track', 'PageVisit');`,\n }}\n />\n )}\n {linkedInPartnerId && (\n <script\n async\n id=\"linkedin-insight-tag\"\n dangerouslySetInnerHTML={{\n __html: `\n _linkedin_partner_id = \"${linkedInPartnerId}\";\n window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];\n window._linkedin_data_partner_ids.push(_linkedin_partner_id);\n\n (function(l) {\n if (!l){\n window.lintrk = function(a,b){\n window.lintrk.q.push([a,b])\n };\n window.lintrk.q=[]\n }\n var s = document.getElementsByTagName(\"script\")[0];\n var b = document.createElement(\"script\");\n b.type = \"text/javascript\";b.async = true;\n b.src = \"https://snap.licdn.com/li.lms-analytics/insight.min.js\";\n s.parentNode.insertBefore(b, s);\n })(window.lintrk);\n `,\n }}\n />\n )}\n {hotjarId && (\n <script\n async\n id=\"hotjar\"\n dangerouslySetInnerHTML={{\n __html: `\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:${hotjarId},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n `,\n }}\n />\n )}\n </>\n );\n}\n"],"mappings":";;;;;;;;AAuBA,SAAgB,UAAU,EACxB,MACA,OACA,OACA,WACA,aACA,eACA,mBACA,UACA,eACA,kBAAkB,QACV;CACR,MAAM,EAAE,cAAA,GAAaA,aAAAA,YAAAA,CAAY;CACjC,gCAAA,gBAAgB,QAAQ;CACxB,2CAAA,0BAA0B;CAE1B,oCAAA,oBAAoB,WAAW;EAC7B,IAAI,CAAC,iBAAiB;EACtB,MAAM,aAAa;GACjB,OAAO,OAAO;GACd,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,cAAc,OAAO;GACrB,eAAe,OAAO;GACtB,wBAAwB,OAAO;GAC/B,iBAAiB;EACnB;EACA,oBAAA,MAAM,OAAO,MAAM,UAAU;CAC/B,CAAC;CAED,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;EACG,iBAAiB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,UAAS;GAAY,SAAS;EAAgB,CAAA;EACrE,QACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACI;GACP,KAAK,SAAS,+CAA+C;EAC9D,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACO;GACP,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;gCAIU,KAAK,GAAG,YAAY,6BAA6B,GAAG;cAExE;EACD,CAAA,CACD,EAAA,CAAA;EAEH,eACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;;;;2BAiBO,YAAY;uCAE7B;EACD,CAAA;EAEF,iBACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;;;;;;;;;;;;2BAcO,cAAc;wCAE/B;EACD,CAAA;EAEF,qBACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;sCACkB,kBAAkB;;;;;;;;;;;;;;;;;cAkB9C;EACD,CAAA;EAEF,YACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,OAAA;GACA,IAAG;GACH,yBAAyB,EACvB,QAAQ;;;oCAGgB,SAAS;;;;;;cAOnC;EACD,CAAA;CAEH,EAAA,CAAA;AAEN"}
@@ -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 regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n 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 gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["pipe","string","transform","array","record","union","number","boolean","_null","object","optional","trim","minLength","maxLength","regex","uuid","_enum","iso","toLowerCase","email","e164","toUpperCase","url"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n 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 gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_third_parties_ignored_events = require("../third-parties/ignored-events.cjs");
3
+ const require_server_action_source = require("./action-source.cjs");
4
+ let _shware_utils = require("@shware/utils");
5
+ let node_crypto = require("node:crypto");
6
+ //#region src/server/google-data-manager.ts
7
+ /**
8
+ * Google Ads conversion sender over the Data Manager API (`events:ingest`) — Google's
9
+ * counterpart to Meta's Conversions API, and the mandated successor to the Google Ads API's
10
+ * `UploadClickConversions`, which stopped accepting new adopters on 2026-06-15. Same shape as
11
+ * the other senders here: a pure per-event builder, a never-throws `sendEvents`, credentials
12
+ * in headers and never in a URL or a log line.
13
+ *
14
+ * Google's recommended deployment is *hybrid* ("boost your tag with additional data sources"):
15
+ * this upload attaches to the SAME conversion action the gtag tag reports to, matched by
16
+ * `transactionId` — a matched pair collapses into one conversion with the server data winning,
17
+ * an unmatched upload is a recovered conversion. Both channels here are fed from the same
18
+ * `track()` call, so the ids agree by construction. `transactionId` is therefore required in
19
+ * that mode; this sender always sends one (the event id when there is no natural order id).
20
+ *
21
+ * Auth is a plain OAuth2 access token with the `datamanager` scope — no Google Ads developer
22
+ * token, no API Center approval. The caller exchanges its stored refresh token for the access
23
+ * token (one POST to oauth2.googleapis.com) and refreshes it however it likes; this module
24
+ * stays out of the OAuth business, exactly as it stays out of Meta's.
25
+ *
26
+ * https://developers.google.com/data-manager/api/reference/rest/v1/events/ingest
27
+ * https://developers.google.com/data-manager/api/devguides/events/google-ads/offline/upgrade/field-mappings
28
+ */
29
+ const ENDPOINT = "https://datamanager.googleapis.com/v1/events:ingest";
30
+ /**
31
+ * Google's email normalization is Meta's minus one wrinkle: for @gmail.com/@googlemail.com the
32
+ * username's dots and everything from '+' on are removed; for every other domain they are kept.
33
+ * https://developers.google.com/data-manager/api/devguides/format-data
34
+ */
35
+ function normalizeEmail(input) {
36
+ const email = input.trim().toLowerCase();
37
+ const at = email.lastIndexOf("@");
38
+ if (at === -1) return email;
39
+ let username = email.slice(0, at);
40
+ const domain = email.slice(at + 1);
41
+ if (domain === "gmail.com" || domain === "googlemail.com") username = username.replace(/\./g, "").split("+", 1)[0] ?? "";
42
+ return `${username}@${domain}`;
43
+ }
44
+ const sha256 = (value) => (0, node_crypto.createHash)("sha256").update(value).digest("hex");
45
+ function normalizeCurrency(input) {
46
+ if (typeof input !== "string") return "USD";
47
+ const currency = input.trim().toUpperCase();
48
+ return /^[A-Z]{3}$/.test(currency) ? currency : "USD";
49
+ }
50
+ /** At most 10 userIdentifiers per event, per the API's hard limit. */
51
+ const MAX_USER_IDENTIFIERS = 10;
52
+ /** Hashes are hex strings, declared by `encoding: 'HEX'` on the request. */
53
+ function getUserIdentifiers(data) {
54
+ const identifiers = [];
55
+ const emails = Array.isArray(data.email) ? data.email : data.email ? [data.email] : [];
56
+ for (const email of emails) identifiers.push({ emailAddress: sha256(normalizeEmail(email)) });
57
+ const phones = Array.isArray(data.phone_number) ? data.phone_number : data.phone_number ? [data.phone_number] : [];
58
+ for (const phone of phones) identifiers.push({ phoneNumber: sha256(phone.trim()) });
59
+ return identifiers.slice(0, MAX_USER_IDENTIFIERS);
60
+ }
61
+ /**
62
+ * Builds one Event, or undefined when no conversion action is configured for the event's name.
63
+ * At most one click identifier is sent, gclid first: it is the deterministic per-click id,
64
+ * where gbraid/wbraid are the aggregate iOS ones, and Google documents preferring it. Unlike
65
+ * the legacy upload, an event with no click id at all is still worth sending when it carries
66
+ * user identifiers — that is the enhanced-conversions match path.
67
+ */
68
+ function getDataManagerEvent(event, config, data = {}) {
69
+ const action = config[event.name];
70
+ if (!action) return void 0;
71
+ const source = require_server_action_source.resolveActionSource(event.platform);
72
+ const dmEvent = {
73
+ destinationReferences: [String(action)],
74
+ transactionId: typeof event.properties?.transaction_id === "string" ? event.properties.transaction_id : event.id,
75
+ eventTimestamp: new Date(event.created_at).toISOString(),
76
+ eventSource: source === "app" ? "APP" : source === "web" ? "WEB" : "OTHER",
77
+ conversionValue: typeof event.properties?.value === "number" ? event.properties.value : 0,
78
+ currency: normalizeCurrency(event.properties?.currency)
79
+ };
80
+ const { gclid, gbraid, wbraid } = event.tags;
81
+ if (gclid) dmEvent.adIdentifiers = { gclid };
82
+ else if (gbraid) dmEvent.adIdentifiers = { gbraid };
83
+ else if (wbraid) dmEvent.adIdentifiers = { wbraid };
84
+ const userIdentifiers = getUserIdentifiers(data);
85
+ if (userIdentifiers.length > 0) dmEvent.userData = { userIdentifiers };
86
+ if (!dmEvent.adIdentifiers && !dmEvent.userData) return void 0;
87
+ return dmEvent;
88
+ }
89
+ /** The API takes at most 2000 events per request. */
90
+ const MAX_EVENTS_PER_REQUEST = 2e3;
91
+ /**
92
+ * Uploads the configured conversions from a batch of events. Never throws: an unusable event
93
+ * is skipped and a failed request is logged and swallowed, like every other sender here. The
94
+ * Data Manager API has no partial-failure mode — a rejected request costs the whole batch, so
95
+ * the builder is strict about only emitting events the API can accept. A batch beyond the
96
+ * 2000-event request cap goes out as sequential requests; the first response is returned.
97
+ */
98
+ async function sendEvents(auth, config, events, data = {}, options = {}) {
99
+ const dmEvents = events.filter((event) => !require_third_parties_ignored_events.IGNORED_EVENTS.includes(event.name)).map((event) => getDataManagerEvent(event, config, data)).filter((dmEvent) => dmEvent !== void 0);
100
+ if (dmEvents.length === 0) return void 0;
101
+ const operatingAccount = {
102
+ accountType: "GOOGLE_ADS",
103
+ accountId: auth.operatingAccountId.replace(/-/g, "")
104
+ };
105
+ const loginAccount = auth.loginAccountId ? {
106
+ accountType: "GOOGLE_ADS",
107
+ accountId: auth.loginAccountId.replace(/-/g, "")
108
+ } : void 0;
109
+ const destinations = Array.from(new Set(dmEvents.flatMap((dmEvent) => dmEvent.destinationReferences))).map((action) => {
110
+ const destination = {
111
+ reference: action,
112
+ operatingAccount,
113
+ productDestinationId: action
114
+ };
115
+ if (loginAccount) destination.loginAccount = loginAccount;
116
+ return destination;
117
+ });
118
+ let firstResponse;
119
+ for (let offset = 0; offset < dmEvents.length; offset += MAX_EVENTS_PER_REQUEST) {
120
+ const chunk = dmEvents.slice(offset, offset + MAX_EVENTS_PER_REQUEST);
121
+ const body = {
122
+ destinations,
123
+ events: chunk,
124
+ validateOnly: options.validateOnly ?? false
125
+ };
126
+ if (chunk.some((dmEvent) => dmEvent.userData)) body.encoding = "HEX";
127
+ if (options.consent) body.consent = options.consent;
128
+ try {
129
+ const response = await (0, _shware_utils.fetch)(ENDPOINT, {
130
+ method: "POST",
131
+ headers: {
132
+ "Content-Type": "application/json",
133
+ Accept: "application/json",
134
+ Authorization: `Bearer ${auth.accessToken}`
135
+ },
136
+ body: JSON.stringify(body)
137
+ });
138
+ if (response.ok) {
139
+ firstResponse ??= await response.json();
140
+ continue;
141
+ }
142
+ const { status } = response;
143
+ const message = await response.text();
144
+ console.error(`Failed to send Google Ads conversions, status: ${status}, body: ${message}`);
145
+ } catch (error) {
146
+ const message = error instanceof Error ? error.message : String(error);
147
+ console.error(`Failed to send Google Ads conversions, network error: ${message}`);
148
+ }
149
+ }
150
+ return firstResponse;
151
+ }
152
+ //#endregion
153
+ exports.getDataManagerEvent = getDataManagerEvent;
154
+ exports.normalizeEmail = normalizeEmail;
155
+ exports.sendEvents = sendEvents;
156
+
157
+ //# sourceMappingURL=google-data-manager.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-data-manager.cjs","names":["createHash","resolveActionSource","IGNORED_EVENTS","fetch"],"sources":["../../src/server/google-data-manager.ts"],"sourcesContent":["/**\n * Google Ads conversion sender over the Data Manager API (`events:ingest`) — Google's\n * counterpart to Meta's Conversions API, and the mandated successor to the Google Ads API's\n * `UploadClickConversions`, which stopped accepting new adopters on 2026-06-15. Same shape as\n * the other senders here: a pure per-event builder, a never-throws `sendEvents`, credentials\n * in headers and never in a URL or a log line.\n *\n * Google's recommended deployment is *hybrid* (\"boost your tag with additional data sources\"):\n * this upload attaches to the SAME conversion action the gtag tag reports to, matched by\n * `transactionId` — a matched pair collapses into one conversion with the server data winning,\n * an unmatched upload is a recovered conversion. Both channels here are fed from the same\n * `track()` call, so the ids agree by construction. `transactionId` is therefore required in\n * that mode; this sender always sends one (the event id when there is no natural order id).\n *\n * Auth is a plain OAuth2 access token with the `datamanager` scope — no Google Ads developer\n * token, no API Center approval. The caller exchanges its stored refresh token for the access\n * token (one POST to oauth2.googleapis.com) and refreshes it however it likes; this module\n * stays out of the OAuth business, exactly as it stays out of Meta's.\n *\n * https://developers.google.com/data-manager/api/reference/rest/v1/events/ingest\n * https://developers.google.com/data-manager/api/devguides/events/google-ads/offline/upgrade/field-mappings\n */\nimport { createHash } from 'node:crypto';\nimport { fetch } from '@shware/utils';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\nimport { resolveActionSource } from './action-source';\n\nconst ENDPOINT = 'https://datamanager.googleapis.com/v1/events:ingest';\n\n/**\n * Event name → conversion action id, mirroring `LinkedinConversionConfig`: only configured\n * events upload, everything else is skipped silently. In the hybrid setup this is the id of\n * the SAME conversion action the gtag tag reports to.\n */\nexport type GoogleAdsConversionConfig = Record<Lowercase<string>, number | string>;\n\nexport interface GoogleAdsAuth {\n /** OAuth2 access token with the `datamanager` scope. Short-lived; the caller refreshes it. */\n accessToken: string;\n /** The Google Ads account the conversion actions live in. Dashes are tolerated: '123-456-7890'. */\n operatingAccountId: string;\n /** The manager account the OAuth user accesses through, when access is delegated. */\n loginAccountId?: string;\n}\n\n/**\n * EEA/UK/CH consent, applied request-wide. Google drops EEA conversions without granted\n * `adUserData` from bidding, so a host with consent signals should pass them.\n */\nexport interface GoogleAdsConsent {\n adUserData?: 'CONSENT_GRANTED' | 'CONSENT_DENIED' | 'CONSENT_STATUS_UNSPECIFIED';\n adPersonalization?: 'CONSENT_GRANTED' | 'CONSENT_DENIED' | 'CONSENT_STATUS_UNSPECIFIED';\n}\n\nexport interface GoogleAdsConversionsOptions {\n /** Validates the payload server-side without recording conversions. */\n validateOnly?: boolean;\n consent?: GoogleAdsConsent;\n}\n\n/**\n * Google's email normalization is Meta's minus one wrinkle: for @gmail.com/@googlemail.com the\n * username's dots and everything from '+' on are removed; for every other domain they are kept.\n * https://developers.google.com/data-manager/api/devguides/format-data\n */\nexport function normalizeEmail(input: string): string {\n const email = input.trim().toLowerCase();\n const at = email.lastIndexOf('@');\n if (at === -1) return email;\n let username = email.slice(0, at);\n const domain = email.slice(at + 1);\n if (domain === 'gmail.com' || domain === 'googlemail.com') {\n username = username.replace(/\\./g, '').split('+', 1)[0] ?? '';\n }\n return `${username}@${domain}`;\n}\n\nconst sha256 = (value: string) => createHash('sha256').update(value).digest('hex');\n\nfunction normalizeCurrency(input: unknown): string {\n if (typeof input !== 'string') return 'USD';\n const currency = input.trim().toUpperCase();\n return /^[A-Z]{3}$/.test(currency) ? currency : 'USD';\n}\n\n/** At most 10 userIdentifiers per event, per the API's hard limit. */\nconst MAX_USER_IDENTIFIERS = 10;\n\n/** Hashes are hex strings, declared by `encoding: 'HEX'` on the request. */\nfunction getUserIdentifiers(data: UserProvidedData): Record<string, string>[] {\n const identifiers: Record<string, string>[] = [];\n const emails = Array.isArray(data.email) ? data.email : data.email ? [data.email] : [];\n for (const email of emails) {\n identifiers.push({ emailAddress: sha256(normalizeEmail(email)) });\n }\n const phones = Array.isArray(data.phone_number)\n ? data.phone_number\n : data.phone_number\n ? [data.phone_number]\n : [];\n for (const phone of phones) {\n // Phones are already E.164 by the schema ('+' then digits); hash after a defensive trim.\n identifiers.push({ phoneNumber: sha256(phone.trim()) });\n }\n return identifiers.slice(0, MAX_USER_IDENTIFIERS);\n}\n\n/** One entry of the `events` array. Field names are the REST (camelCase) spellings. */\nexport interface DataManagerEvent {\n destinationReferences: string[];\n transactionId: string;\n /** RFC 3339 — `created_at` as stored, unlike the legacy API's bespoke format. */\n eventTimestamp: string;\n eventSource: 'WEB' | 'APP' | 'OTHER';\n conversionValue: number;\n currency: string;\n adIdentifiers?: { gclid?: string; gbraid?: string; wbraid?: string };\n userData?: { userIdentifiers: Record<string, string>[] };\n}\n\n/**\n * Builds one Event, or undefined when no conversion action is configured for the event's name.\n * At most one click identifier is sent, gclid first: it is the deterministic per-click id,\n * where gbraid/wbraid are the aggregate iOS ones, and Google documents preferring it. Unlike\n * the legacy upload, an event with no click id at all is still worth sending when it carries\n * user identifiers — that is the enhanced-conversions match path.\n */\nexport function getDataManagerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n config: GoogleAdsConversionConfig,\n data: UserProvidedData = {}\n): DataManagerEvent | undefined {\n const action = config[event.name as Lowercase<string>];\n if (!action) return undefined;\n\n const source = resolveActionSource(event.platform);\n const dmEvent: DataManagerEvent = {\n destinationReferences: [String(action)],\n // The hybrid-mode match key against the gtag tag's transaction_id: same track() call feeds\n // both channels, so they agree by construction for purchase-shaped events. The event id\n // covers conversions with no natural order id — but the gtag tracker only sends a\n // transaction_id when the properties carry one, so on a HYBRID action a non-purchase event\n // reported by both channels never matches and counts twice. Attach such events to a\n // standalone (API-only) conversion action instead.\n transactionId:\n typeof event.properties?.transaction_id === 'string'\n ? event.properties.transaction_id\n : event.id,\n eventTimestamp: new Date(event.created_at).toISOString(),\n eventSource: source === 'app' ? 'APP' : source === 'web' ? 'WEB' : 'OTHER',\n // Both mandatory, like the LinkedIn sender's defaults: 0 USD is Google's own convention\n // for value-less goals. The API has no partial-failure mode, so a malformed currency would\n // cost the whole batch — anything that isn't a 3-letter code falls back instead.\n conversionValue: typeof event.properties?.value === 'number' ? event.properties.value : 0,\n currency: normalizeCurrency(event.properties?.currency),\n };\n\n const { gclid, gbraid, wbraid } = event.tags;\n if (gclid) dmEvent.adIdentifiers = { gclid };\n else if (gbraid) dmEvent.adIdentifiers = { gbraid };\n else if (wbraid) dmEvent.adIdentifiers = { wbraid };\n\n const userIdentifiers = getUserIdentifiers(data);\n if (userIdentifiers.length > 0) dmEvent.userData = { userIdentifiers };\n\n // With neither a click id nor an identifier Google has nothing to match on; skip.\n if (!dmEvent.adIdentifiers && !dmEvent.userData) return undefined;\n\n return dmEvent;\n}\n\nexport interface DataManagerResponse {\n requestId?: string;\n}\n\n/** The API takes at most 2000 events per request. */\nconst MAX_EVENTS_PER_REQUEST = 2000;\n\n/**\n * Uploads the configured conversions from a batch of events. Never throws: an unusable event\n * is skipped and a failed request is logged and swallowed, like every other sender here. The\n * Data Manager API has no partial-failure mode — a rejected request costs the whole batch, so\n * the builder is strict about only emitting events the API can accept. A batch beyond the\n * 2000-event request cap goes out as sequential requests; the first response is returned.\n */\nexport async function sendEvents(\n auth: GoogleAdsAuth,\n config: GoogleAdsConversionConfig,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n options: GoogleAdsConversionsOptions = {}\n): Promise<DataManagerResponse | undefined> {\n const dmEvents = events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .map((event) => getDataManagerEvent(event, config, data))\n .filter((dmEvent): dmEvent is DataManagerEvent => dmEvent !== undefined);\n if (dmEvents.length === 0) return undefined;\n\n const operatingAccount = {\n accountType: 'GOOGLE_ADS',\n accountId: auth.operatingAccountId.replace(/-/g, ''),\n };\n // One destination per conversion action present in the batch; each event points at its own\n // through destinationReferences, so mixed-action batches go out as one request.\n const loginAccount = auth.loginAccountId\n ? { accountType: 'GOOGLE_ADS', accountId: auth.loginAccountId.replace(/-/g, '') }\n : undefined;\n const actions = Array.from(new Set(dmEvents.flatMap((dmEvent) => dmEvent.destinationReferences)));\n const destinations = actions.map((action) => {\n const destination: Record<string, unknown> = {\n reference: action,\n operatingAccount,\n productDestinationId: action,\n };\n if (loginAccount) destination.loginAccount = loginAccount;\n return destination;\n });\n\n let firstResponse: DataManagerResponse | undefined;\n for (let offset = 0; offset < dmEvents.length; offset += MAX_EVENTS_PER_REQUEST) {\n const chunk = dmEvents.slice(offset, offset + MAX_EVENTS_PER_REQUEST);\n const body: Record<string, unknown> = {\n destinations,\n events: chunk,\n validateOnly: options.validateOnly ?? false,\n };\n if (chunk.some((dmEvent) => dmEvent.userData)) {\n body.encoding = 'HEX';\n }\n if (options.consent) {\n body.consent = options.consent;\n }\n\n try {\n const response = await fetch(ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${auth.accessToken}`,\n },\n body: JSON.stringify(body),\n });\n if (response.ok) {\n firstResponse ??= (await response.json()) as DataManagerResponse;\n continue;\n }\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send Google Ads conversions, status: ${status}, body: ${message}`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Failed to send Google Ads conversions, network error: ${message}`);\n }\n }\n return firstResponse;\n}\n"],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { TrackEvent, UserProvidedData } from "../track/types.cjs";
2
+ //#region src/server/google-data-manager.d.ts
3
+ /**
4
+ * Event name → conversion action id, mirroring `LinkedinConversionConfig`: only configured
5
+ * events upload, everything else is skipped silently. In the hybrid setup this is the id of
6
+ * the SAME conversion action the gtag tag reports to.
7
+ */
8
+ type GoogleAdsConversionConfig = Record<Lowercase<string>, number | string>;
9
+ interface GoogleAdsAuth {
10
+ /** OAuth2 access token with the `datamanager` scope. Short-lived; the caller refreshes it. */
11
+ accessToken: string;
12
+ /** The Google Ads account the conversion actions live in. Dashes are tolerated: '123-456-7890'. */
13
+ operatingAccountId: string;
14
+ /** The manager account the OAuth user accesses through, when access is delegated. */
15
+ loginAccountId?: string;
16
+ }
17
+ /**
18
+ * EEA/UK/CH consent, applied request-wide. Google drops EEA conversions without granted
19
+ * `adUserData` from bidding, so a host with consent signals should pass them.
20
+ */
21
+ interface GoogleAdsConsent {
22
+ adUserData?: 'CONSENT_GRANTED' | 'CONSENT_DENIED' | 'CONSENT_STATUS_UNSPECIFIED';
23
+ adPersonalization?: 'CONSENT_GRANTED' | 'CONSENT_DENIED' | 'CONSENT_STATUS_UNSPECIFIED';
24
+ }
25
+ interface GoogleAdsConversionsOptions {
26
+ /** Validates the payload server-side without recording conversions. */
27
+ validateOnly?: boolean;
28
+ consent?: GoogleAdsConsent;
29
+ }
30
+ /**
31
+ * Google's email normalization is Meta's minus one wrinkle: for @gmail.com/@googlemail.com the
32
+ * username's dots and everything from '+' on are removed; for every other domain they are kept.
33
+ * https://developers.google.com/data-manager/api/devguides/format-data
34
+ */
35
+ declare function normalizeEmail(input: string): string;
36
+ /** One entry of the `events` array. Field names are the REST (camelCase) spellings. */
37
+ interface DataManagerEvent {
38
+ destinationReferences: string[];
39
+ transactionId: string;
40
+ /** RFC 3339 — `created_at` as stored, unlike the legacy API's bespoke format. */
41
+ eventTimestamp: string;
42
+ eventSource: 'WEB' | 'APP' | 'OTHER';
43
+ conversionValue: number;
44
+ currency: string;
45
+ adIdentifiers?: {
46
+ gclid?: string;
47
+ gbraid?: string;
48
+ wbraid?: string;
49
+ };
50
+ userData?: {
51
+ userIdentifiers: Record<string, string>[];
52
+ };
53
+ }
54
+ /**
55
+ * Builds one Event, or undefined when no conversion action is configured for the event's name.
56
+ * At most one click identifier is sent, gclid first: it is the deterministic per-click id,
57
+ * where gbraid/wbraid are the aggregate iOS ones, and Google documents preferring it. Unlike
58
+ * the legacy upload, an event with no click id at all is still worth sending when it carries
59
+ * user identifiers — that is the enhanced-conversions match path.
60
+ */
61
+ declare function getDataManagerEvent(event: TrackEvent<any>, config: GoogleAdsConversionConfig, data?: UserProvidedData): DataManagerEvent | undefined;
62
+ interface DataManagerResponse {
63
+ requestId?: string;
64
+ }
65
+ /**
66
+ * Uploads the configured conversions from a batch of events. Never throws: an unusable event
67
+ * is skipped and a failed request is logged and swallowed, like every other sender here. The
68
+ * Data Manager API has no partial-failure mode — a rejected request costs the whole batch, so
69
+ * the builder is strict about only emitting events the API can accept. A batch beyond the
70
+ * 2000-event request cap goes out as sequential requests; the first response is returned.
71
+ */
72
+ declare function sendEvents(auth: GoogleAdsAuth, config: GoogleAdsConversionConfig, events: TrackEvent<any>[], data?: UserProvidedData, options?: GoogleAdsConversionsOptions): Promise<DataManagerResponse | undefined>;
73
+ //#endregion
74
+ export { DataManagerEvent, DataManagerResponse, GoogleAdsAuth, GoogleAdsConsent, GoogleAdsConversionConfig, GoogleAdsConversionsOptions, getDataManagerEvent, normalizeEmail, sendEvents };
75
+ //# sourceMappingURL=google-data-manager.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-data-manager.d.cts","names":[],"sources":["../../src/server/google-data-manager.ts"],"mappings":";;;;;;;KAmCY,4BAA4B,OAAO;UAE9B;;EAEf;;EAEA;;EAEA;;;;;;UAOe;EACf;EACA;;UAGe;;EAEf;EACA,UAAU;;;;;;;iBAQI,eAAe;;UA2Cd;EACf;EACA;;EAEA;EACA;EACA;EACA;EACA;IAAkB;IAAgB;IAAiB;;EACnD;IAAa,iBAAiB;;;;;;;;;;iBAUhB,oBAEd,OAAO,iBACP,QAAQ,2BACR,OAAM,mBACL;UAwCc;EACf;;;;;;;;;iBAaoB,WACpB,MAAM,eACN,QAAQ,2BAER,QAAQ,mBACR,OAAM,kBACN,UAAS,8BACR,QAAQ"}