@shware/analytics 2.13.4 → 2.14.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 (71) hide show
  1. package/README.md +4 -11
  2. package/dist/hooks/use-session-analytics.cjs +53 -0
  3. package/dist/hooks/use-session-analytics.cjs.map +1 -0
  4. package/dist/hooks/use-session-analytics.d.cts +3 -0
  5. package/dist/hooks/use-session-analytics.d.ts +3 -0
  6. package/dist/hooks/use-session-analytics.mjs +28 -0
  7. package/dist/hooks/use-session-analytics.mjs.map +1 -0
  8. package/dist/native/analytics.cjs +1 -0
  9. package/dist/native/analytics.cjs.map +1 -1
  10. package/dist/native/analytics.mjs +1 -0
  11. package/dist/native/analytics.mjs.map +1 -1
  12. package/dist/native/setup.cjs +6 -3
  13. package/dist/native/setup.cjs.map +1 -1
  14. package/dist/native/setup.d.cts +1 -1
  15. package/dist/native/setup.d.ts +1 -1
  16. package/dist/native/setup.mjs +6 -3
  17. package/dist/native/setup.mjs.map +1 -1
  18. package/dist/next/index.cjs +3 -1
  19. package/dist/next/index.cjs.map +1 -1
  20. package/dist/next/index.mjs +3 -1
  21. package/dist/next/index.mjs.map +1 -1
  22. package/dist/react-router/index.cjs +3 -1
  23. package/dist/react-router/index.cjs.map +1 -1
  24. package/dist/react-router/index.mjs +3 -1
  25. package/dist/react-router/index.mjs.map +1 -1
  26. package/dist/server/ignore-events.cjs +33 -0
  27. package/dist/server/ignore-events.cjs.map +1 -0
  28. package/dist/server/ignore-events.d.cts +3 -0
  29. package/dist/server/ignore-events.d.ts +3 -0
  30. package/dist/server/ignore-events.mjs +8 -0
  31. package/dist/server/ignore-events.mjs.map +1 -0
  32. package/dist/server/linkedin-conversions-api.cjs +2 -2
  33. package/dist/server/linkedin-conversions-api.cjs.map +1 -1
  34. package/dist/server/linkedin-conversions-api.mjs +2 -2
  35. package/dist/server/linkedin-conversions-api.mjs.map +1 -1
  36. package/dist/server/meta-conversions-api.cjs +3 -3
  37. package/dist/server/meta-conversions-api.cjs.map +1 -1
  38. package/dist/server/meta-conversions-api.mjs +3 -3
  39. package/dist/server/meta-conversions-api.mjs.map +1 -1
  40. package/dist/server/reddit-conversions-api.cjs +2 -2
  41. package/dist/server/reddit-conversions-api.cjs.map +1 -1
  42. package/dist/server/reddit-conversions-api.mjs +2 -2
  43. package/dist/server/reddit-conversions-api.mjs.map +1 -1
  44. package/dist/setup/index.cjs +8 -0
  45. package/dist/setup/index.cjs.map +1 -1
  46. package/dist/setup/index.d.cts +13 -4
  47. package/dist/setup/index.d.ts +13 -4
  48. package/dist/setup/index.mjs +7 -0
  49. package/dist/setup/index.mjs.map +1 -1
  50. package/dist/track/gtag.cjs.map +1 -1
  51. package/dist/track/gtag.d.cts +9 -0
  52. package/dist/track/gtag.d.ts +9 -0
  53. package/dist/track/gtag.mjs.map +1 -1
  54. package/dist/track/index.cjs +15 -0
  55. package/dist/track/index.cjs.map +1 -1
  56. package/dist/track/index.d.cts +2 -1
  57. package/dist/track/index.d.ts +2 -1
  58. package/dist/track/index.mjs +15 -1
  59. package/dist/track/index.mjs.map +1 -1
  60. package/dist/track/types.cjs.map +1 -1
  61. package/dist/visitor/index.cjs +6 -7
  62. package/dist/visitor/index.cjs.map +1 -1
  63. package/dist/visitor/index.mjs +7 -8
  64. package/dist/visitor/index.mjs.map +1 -1
  65. package/dist/web/index.cjs +4 -2
  66. package/dist/web/index.cjs.map +1 -1
  67. package/dist/web/index.d.cts +1 -1
  68. package/dist/web/index.d.ts +1 -1
  69. package/dist/web/index.mjs +4 -2
  70. package/dist/web/index.mjs.map +1 -1
  71. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react-router/index.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useLocation } from 'react-router';\nimport { type Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\nimport { useClickIdPersistence } from '../hooks/use-click-id-persistence';\nimport { usePageViewAnalytics } from '../hooks/use-page-view-analytics';\nimport { track } from '../track/index';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ntype HotjarId = `${number}`;\n\nfunction useReportWebVitals(reportWebVitalsFn: (metric: Metric) => void) {\n useEffect(() => {\n onCLS(reportWebVitalsFn);\n onLCP(reportWebVitalsFn);\n onINP(reportWebVitalsFn);\n onFCP(reportWebVitalsFn);\n onTTFB(reportWebVitalsFn);\n }, [reportWebVitalsFn]);\n}\n\ninterface Props {\n gaId?: GaId;\n gtmId?: GtmId;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n hotjarId?: HotjarId;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n nonce,\n debugMode,\n metaPixelId,\n redditPixelId,\n linkedInPartnerId,\n hotjarId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n const { pathname } = useLocation();\n usePageViewAnalytics(pathname);\n\n useClickIdPersistence();\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n id: metric.id,\n rating: metric.rating,\n value: metric.value,\n delta: metric.delta,\n 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={`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":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAsB,OAAO,OAAO,OAAO,OAAO,cAAc;AAChE,SAAS,6BAA6B;AACtC,SAAS,4BAA4B;AACrC,SAAS,aAAa;AA6DE,SAEhB,UAFgB,KAEhB,YAFgB;AAtDxB,SAAS,mBAAmB,mBAA6C;AACvE,YAAU,MAAM;AACd,UAAM,iBAAiB;AACvB,UAAM,iBAAiB;AACvB,UAAM,iBAAiB;AACvB,UAAM,iBAAiB;AACvB,WAAO,iBAAiB;AAAA,EAC1B,GAAG,CAAC,iBAAiB,CAAC;AACxB;AAeO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AACpB,GAAU;AACR,QAAM,EAAE,SAAS,IAAI,YAAY;AACjC,uBAAqB,QAAQ;AAE7B,wBAAsB;AAEtB,qBAAmB,CAAC,WAAW;AAC7B,QAAI,CAAC,gBAAiB;AACtB,UAAM,aAAa;AAAA,MACjB,IAAI,OAAO;AAAA,MACX,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MACd,iBAAiB,OAAO;AAAA,MACxB,iBAAiB;AAAA;AAAA,IACnB;AACA,UAAM,OAAO,MAAM,UAAU;AAAA,EAC/B,CAAC;AAED,SACE,iCACG;AAAA,qBAAiB,oBAAC,UAAK,UAAS,aAAY,SAAS,eAAe;AAAA,IACpE,QACC,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAK;AAAA,UACL,IAAG;AAAA,UACH;AAAA,UACA,KAAK,+CAA+C,IAAI;AAAA;AAAA,MAC1D;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAK;AAAA,UACL;AAAA,UACA,IAAG;AAAA,UACH,yBAAyB;AAAA,YACvB,QAAQ;AAAA;AAAA;AAAA;AAAA,gCAIU,IAAI,IAAI,YAAY,6BAA6B,EAAE;AAAA;AAAA,UAEvE;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IAED,eACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAK;AAAA,QACL,IAAG;AAAA,QACH,yBAAyB;AAAA,UACvB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAiBO,WAAW;AAAA;AAAA,QAE5B;AAAA;AAAA,IACF;AAAA,IAED,iBACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAK;AAAA,QACL,IAAG;AAAA,QACH,yBAAyB;AAAA,UACvB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAcO,aAAa;AAAA;AAAA,QAE9B;AAAA;AAAA,IACF;AAAA,IAED,qBACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAK;AAAA,QACL,IAAG;AAAA,QACH,yBAAyB;AAAA,UACvB,QAAQ;AAAA,sCACkB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAkB7C;AAAA;AAAA,IACF;AAAA,IAED,YACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAK;AAAA,QACL,IAAG;AAAA,QACH,yBAAyB;AAAA,UACvB,QAAQ;AAAA;AAAA;AAAA,oCAGgB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOlC;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/react-router/index.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useLocation } from 'react-router';\nimport { type Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';\nimport { useClickIdPersistence } from '../hooks/use-click-id-persistence';\nimport { usePageViewAnalytics } from '../hooks/use-page-view-analytics';\nimport { useSessionAnalytics } from '../hooks/use-session-analytics';\nimport { track } from '../track/index';\nimport type { PixelId as MetaPixelId } from '../track/fbq';\nimport type { GaId, GtmId } from '../track/gtag';\nimport type { PixelId as RedditPixelId } from '../track/rdt';\n\ntype HotjarId = `${number}`;\n\nfunction useReportWebVitals(reportWebVitalsFn: (metric: Metric) => void) {\n useEffect(() => {\n onCLS(reportWebVitalsFn);\n onLCP(reportWebVitalsFn);\n onINP(reportWebVitalsFn);\n onFCP(reportWebVitalsFn);\n onTTFB(reportWebVitalsFn);\n }, [reportWebVitalsFn]);\n}\n\ninterface Props {\n gaId?: GaId;\n gtmId?: GtmId;\n metaPixelId?: MetaPixelId;\n redditPixelId?: RedditPixelId;\n linkedInPartnerId?: `${number}`;\n hotjarId?: HotjarId;\n facebookAppId?: string;\n nonce?: string;\n debugMode?: boolean;\n reportWebVitals?: boolean;\n}\n\nexport function Analytics({\n gaId,\n nonce,\n debugMode,\n metaPixelId,\n redditPixelId,\n linkedInPartnerId,\n hotjarId,\n facebookAppId,\n reportWebVitals = true,\n}: Props) {\n useSessionAnalytics();\n useClickIdPersistence();\n\n const { pathname } = useLocation();\n usePageViewAnalytics(pathname);\n\n useReportWebVitals((metric) => {\n if (!reportWebVitals) return;\n const properties = {\n id: metric.id,\n rating: metric.rating,\n value: metric.value,\n delta: metric.delta,\n 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={`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":"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","names":[]}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/server/ignore-events.ts
21
+ var ignore_events_exports = {};
22
+ __export(ignore_events_exports, {
23
+ IGNORE_EVENTS: () => IGNORE_EVENTS
24
+ });
25
+ module.exports = __toCommonJS(ignore_events_exports);
26
+ var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
27
+ var session = ["session_start", "session_end", "page_view", "screen_view"];
28
+ var IGNORE_EVENTS = [...metrics, ...session];
29
+ // Annotate the CommonJS export names for ESM import in node:
30
+ 0 && (module.exports = {
31
+ IGNORE_EVENTS
32
+ });
33
+ //# sourceMappingURL=ignore-events.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/server/ignore-events.ts"],"sourcesContent":["const metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\nconst session = ['session_start', 'session_end', 'page_view', 'screen_view'];\n\nexport const IGNORE_EVENTS = [...metrics, ...session];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAM,UAAU,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAC1D,IAAM,UAAU,CAAC,iBAAiB,eAAe,aAAa,aAAa;AAEpE,IAAM,gBAAgB,CAAC,GAAG,SAAS,GAAG,OAAO;","names":[]}
@@ -0,0 +1,3 @@
1
+ declare const IGNORE_EVENTS: string[];
2
+
3
+ export { IGNORE_EVENTS };
@@ -0,0 +1,3 @@
1
+ declare const IGNORE_EVENTS: string[];
2
+
3
+ export { IGNORE_EVENTS };
@@ -0,0 +1,8 @@
1
+ // src/server/ignore-events.ts
2
+ var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
3
+ var session = ["session_start", "session_end", "page_view", "screen_view"];
4
+ var IGNORE_EVENTS = [...metrics, ...session];
5
+ export {
6
+ IGNORE_EVENTS
7
+ };
8
+ //# sourceMappingURL=ignore-events.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/server/ignore-events.ts"],"sourcesContent":["const metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\nconst session = ['session_start', 'session_end', 'page_view', 'screen_view'];\n\nexport const IGNORE_EVENTS = [...metrics, ...session];\n"],"mappings":";AAAA,IAAM,UAAU,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAC1D,IAAM,UAAU,CAAC,iBAAiB,eAAe,aAAa,aAAa;AAEpE,IAAM,gBAAgB,CAAC,GAAG,SAAS,GAAG,OAAO;","names":[]}
@@ -26,7 +26,7 @@ module.exports = __toCommonJS(linkedin_conversions_api_exports);
26
26
  var import_crypto = require("crypto");
27
27
  var import_fetch = require("../utils/fetch.cjs");
28
28
  var import_field = require("../utils/field.cjs");
29
- var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
29
+ var import_ignore_events = require("./ignore-events.cjs");
30
30
  async function sendEvents(accessToken, config, events, data = {}) {
31
31
  const eventNames = Object.keys(config);
32
32
  const address = (0, import_field.getFirst)(data.address);
@@ -46,7 +46,7 @@ async function sendEvents(accessToken, config, events, data = {}) {
46
46
  });
47
47
  }
48
48
  const dto = {
49
- elements: events.filter((event) => eventNames.includes(event.name) && !metrics.includes(event.name)).map((event) => {
49
+ elements: events.filter((event) => eventNames.includes(event.name) && !import_ignore_events.IGNORE_EVENTS.includes(event.name)).map((event) => {
50
50
  var _a, _b, _c, _d;
51
51
  return {
52
52
  eventId: event.id,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/linkedin-conversions-api.ts"],"sourcesContent":["/**\n * Conversions API Payload Builder: https://www.linkedin.com/developers/payload-builder\n * https://learn.microsoft.com/en-us/linkedin/marketing/conversions/conversions-overview?view=li-lms-2025-09\n */\nimport { createHash } from 'crypto';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\ntype UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface CreateLinkedinEventDTO {\n /**\n * For any conversion that you want to send through multiple methods, such as Insight Tag and\n * Conversions API, you must create a conversion rule for each data source (browser and server).\n * Then, you can implement a logic to pick up the eventId from the browser and send it with the\n * corresponding event from your server. If we receive an Insight Tag event and a Conversions API\n * event from the same account with the same eventId, we discard the Conversions API event and\n * count only the Insight Tag event in campaign reporting.\n */\n eventId?: string;\n\n /**\n * Replace <id> with the conversion ID extracted when creating the conversion rule\n * (e.g. urn:lla:llaPartnerConversion:<id>).\n */\n conversion: `urn:lla:llaPartnerConversion:${number}`;\n\n /** Epoch timestamp in milliseconds at which the conversion event happened. */\n conversionHappenedAt: number;\n conversionValue: { currencyCode: string; amount: string };\n user: {\n userIds: { idType: UserIdType; idValue: string }[];\n userInfo?: {\n firstName?: string;\n lastName?: string;\n companyName?: string;\n countryCode?: string;\n title?: string;\n };\n\n /**\n * The maximum supported size of the list is 1 at the moment. If the list contains multiple\n * values, only the first value will be used.\n */\n externalIds?: [string, ...string[]];\n\n /**\n * This is generated when users submit the Linkedin Lead-gen form\n * (e.g. urn:li:leadGenFormResponse:<id>).\n */\n lead?: `urn:li:leadGenFormResponse:${string}`;\n };\n}\n\nexport interface CreateMultipleLinkedinEventsDTO {\n elements: CreateLinkedinEventDTO[];\n}\n\nexport type LinkedinConversionConfig = Record<Lowercase<string>, number>;\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport async function sendEvents(\n accessToken: string,\n config: LinkedinConversionConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {}\n) {\n const eventNames = Object.keys(config);\n const address = getFirst(data.address);\n const userIds: { idType: UserIdType; idValue: string }[] = [];\n const externalIds: [string, ...string[]] | undefined = data.user_id ? [data.user_id] : undefined;\n const userInfo =\n address && address.first_name && address.last_name\n ? {\n firstName: address.first_name,\n lastName: address.last_name,\n countryCode: address.country,\n }\n : undefined;\n\n if (data.email) {\n const email = getFirst(data.email);\n if (email)\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue: createHash('sha256').update(email).digest('hex'),\n });\n }\n\n const dto: CreateMultipleLinkedinEventsDTO = {\n elements: events\n .filter((event) => eventNames.includes(event.name) && !metrics.includes(event.name))\n .map((event) => ({\n eventId: event.id,\n conversion: `urn:lla:llaPartnerConversion:${config[event.name]}`,\n conversionHappenedAt: Date.now(),\n conversionValue: {\n currencyCode: event.properties?.currency?.toUpperCase() ?? 'USD',\n amount: event.properties?.value?.toString() ?? '0',\n },\n user: {\n userIds: event.tags.li_fat_id\n ? [\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: event.tags.li_fat_id,\n },\n ...userIds,\n ]\n : userIds,\n userInfo,\n externalIds,\n },\n })),\n };\n\n if (dto.elements.length === 0) return;\n try {\n const response = await fetch('https://api.linkedin.com/rest/conversionEvents', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'LinkedIn-Version': '202509',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n },\n body: JSON.stringify(dto),\n });\n\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send LinkedIn conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send LinkedIn conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAA2B;AAC3B,mBAAsB;AACtB,mBAAyB;AA2DzB,IAAM,UAAU,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAE1D,eAAsB,WACpB,aACA,QAEA,QACA,OAAyB,CAAC,GAC1B;AACA,QAAM,aAAa,OAAO,KAAK,MAAM;AACrC,QAAM,cAAU,uBAAS,KAAK,OAAO;AACrC,QAAM,UAAqD,CAAC;AAC5D,QAAM,cAAiD,KAAK,UAAU,CAAC,KAAK,OAAO,IAAI;AACvF,QAAM,WACJ,WAAW,QAAQ,cAAc,QAAQ,YACrC;AAAA,IACE,WAAW,QAAQ;AAAA,IACnB,UAAU,QAAQ;AAAA,IAClB,aAAa,QAAQ;AAAA,EACvB,IACA;AAEN,MAAI,KAAK,OAAO;AACd,UAAM,YAAQ,uBAAS,KAAK,KAAK;AACjC,QAAI;AACF,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,aAAS,0BAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAAA,MAC1D,CAAC;AAAA,EACL;AAEA,QAAM,MAAuC;AAAA,IAC3C,UAAU,OACP,OAAO,CAAC,UAAU,WAAW,SAAS,MAAM,IAAI,KAAK,CAAC,QAAQ,SAAS,MAAM,IAAI,CAAC,EAClF,IAAI,CAAC,UAAO;AAnGnB;AAmGuB;AAAA,QACf,SAAS,MAAM;AAAA,QACf,YAAY,gCAAgC,OAAO,MAAM,IAAI,CAAC;AAAA,QAC9D,sBAAsB,KAAK,IAAI;AAAA,QAC/B,iBAAiB;AAAA,UACf,gBAAc,iBAAM,eAAN,mBAAkB,aAAlB,mBAA4B,kBAAiB;AAAA,UAC3D,UAAQ,iBAAM,eAAN,mBAAkB,UAAlB,mBAAyB,eAAc;AAAA,QACjD;AAAA,QACA,MAAM;AAAA,UACJ,SAAS,MAAM,KAAK,YAChB;AAAA,YACE;AAAA,cACE,QAAQ;AAAA,cACR,SAAS,MAAM,KAAK;AAAA,YACtB;AAAA,YACA,GAAG;AAAA,UACL,IACA;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,KAAE;AAAA,EACN;AAEA,MAAI,IAAI,SAAS,WAAW,EAAG;AAC/B,MAAI;AACF,UAAM,WAAW,UAAM,oBAAM,kDAAkD;AAAA,MAC7E,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,WAAW;AAAA,QACpC,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,6BAA6B;AAAA,QAC7B,mBAAmB;AAAA,MACrB;AAAA,MACA,MAAM,KAAK,UAAU,GAAG;AAAA,IAC1B,CAAC;AAED,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,+CAA+C,MAAM,WAAW,OAAO,EAAE;AAAA,EACzF,SAAS,OAAO;AACd,YAAQ,MAAM,sDAAsD,KAAK;AAAA,EAC3E;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/server/linkedin-conversions-api.ts"],"sourcesContent":["/**\n * Conversions API Payload Builder: https://www.linkedin.com/developers/payload-builder\n * https://learn.microsoft.com/en-us/linkedin/marketing/conversions/conversions-overview?view=li-lms-2025-09\n */\nimport { createHash } from 'crypto';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport { IGNORE_EVENTS } from './ignore-events';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\ntype UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface CreateLinkedinEventDTO {\n /**\n * For any conversion that you want to send through multiple methods, such as Insight Tag and\n * Conversions API, you must create a conversion rule for each data source (browser and server).\n * Then, you can implement a logic to pick up the eventId from the browser and send it with the\n * corresponding event from your server. If we receive an Insight Tag event and a Conversions API\n * event from the same account with the same eventId, we discard the Conversions API event and\n * count only the Insight Tag event in campaign reporting.\n */\n eventId?: string;\n\n /**\n * Replace <id> with the conversion ID extracted when creating the conversion rule\n * (e.g. urn:lla:llaPartnerConversion:<id>).\n */\n conversion: `urn:lla:llaPartnerConversion:${number}`;\n\n /** Epoch timestamp in milliseconds at which the conversion event happened. */\n conversionHappenedAt: number;\n conversionValue: { currencyCode: string; amount: string };\n user: {\n userIds: { idType: UserIdType; idValue: string }[];\n userInfo?: {\n firstName?: string;\n lastName?: string;\n companyName?: string;\n countryCode?: string;\n title?: string;\n };\n\n /**\n * The maximum supported size of the list is 1 at the moment. If the list contains multiple\n * values, only the first value will be used.\n */\n externalIds?: [string, ...string[]];\n\n /**\n * This is generated when users submit the Linkedin Lead-gen form\n * (e.g. urn:li:leadGenFormResponse:<id>).\n */\n lead?: `urn:li:leadGenFormResponse:${string}`;\n };\n}\n\nexport interface CreateMultipleLinkedinEventsDTO {\n elements: CreateLinkedinEventDTO[];\n}\n\nexport type LinkedinConversionConfig = Record<Lowercase<string>, number>;\n\nexport async function sendEvents(\n accessToken: string,\n config: LinkedinConversionConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {}\n) {\n const eventNames = Object.keys(config);\n const address = getFirst(data.address);\n const userIds: { idType: UserIdType; idValue: string }[] = [];\n const externalIds: [string, ...string[]] | undefined = data.user_id ? [data.user_id] : undefined;\n const userInfo =\n address && address.first_name && address.last_name\n ? {\n firstName: address.first_name,\n lastName: address.last_name,\n countryCode: address.country,\n }\n : undefined;\n\n if (data.email) {\n const email = getFirst(data.email);\n if (email)\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue: createHash('sha256').update(email).digest('hex'),\n });\n }\n\n const dto: CreateMultipleLinkedinEventsDTO = {\n elements: events\n .filter((event) => eventNames.includes(event.name) && !IGNORE_EVENTS.includes(event.name))\n .map((event) => ({\n eventId: event.id,\n conversion: `urn:lla:llaPartnerConversion:${config[event.name]}`,\n conversionHappenedAt: Date.now(),\n conversionValue: {\n currencyCode: event.properties?.currency?.toUpperCase() ?? 'USD',\n amount: event.properties?.value?.toString() ?? '0',\n },\n user: {\n userIds: event.tags.li_fat_id\n ? [\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: event.tags.li_fat_id,\n },\n ...userIds,\n ]\n : userIds,\n userInfo,\n externalIds,\n },\n })),\n };\n\n if (dto.elements.length === 0) return;\n try {\n const response = await fetch('https://api.linkedin.com/rest/conversionEvents', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'LinkedIn-Version': '202509',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n },\n body: JSON.stringify(dto),\n });\n\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send LinkedIn conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send LinkedIn conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAA2B;AAC3B,mBAAsB;AACtB,mBAAyB;AACzB,2BAA8B;AA2D9B,eAAsB,WACpB,aACA,QAEA,QACA,OAAyB,CAAC,GAC1B;AACA,QAAM,aAAa,OAAO,KAAK,MAAM;AACrC,QAAM,cAAU,uBAAS,KAAK,OAAO;AACrC,QAAM,UAAqD,CAAC;AAC5D,QAAM,cAAiD,KAAK,UAAU,CAAC,KAAK,OAAO,IAAI;AACvF,QAAM,WACJ,WAAW,QAAQ,cAAc,QAAQ,YACrC;AAAA,IACE,WAAW,QAAQ;AAAA,IACnB,UAAU,QAAQ;AAAA,IAClB,aAAa,QAAQ;AAAA,EACvB,IACA;AAEN,MAAI,KAAK,OAAO;AACd,UAAM,YAAQ,uBAAS,KAAK,KAAK;AACjC,QAAI;AACF,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,aAAS,0BAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAAA,MAC1D,CAAC;AAAA,EACL;AAEA,QAAM,MAAuC;AAAA,IAC3C,UAAU,OACP,OAAO,CAAC,UAAU,WAAW,SAAS,MAAM,IAAI,KAAK,CAAC,mCAAc,SAAS,MAAM,IAAI,CAAC,EACxF,IAAI,CAAC,UAAO;AAlGnB;AAkGuB;AAAA,QACf,SAAS,MAAM;AAAA,QACf,YAAY,gCAAgC,OAAO,MAAM,IAAI,CAAC;AAAA,QAC9D,sBAAsB,KAAK,IAAI;AAAA,QAC/B,iBAAiB;AAAA,UACf,gBAAc,iBAAM,eAAN,mBAAkB,aAAlB,mBAA4B,kBAAiB;AAAA,UAC3D,UAAQ,iBAAM,eAAN,mBAAkB,UAAlB,mBAAyB,eAAc;AAAA,QACjD;AAAA,QACA,MAAM;AAAA,UACJ,SAAS,MAAM,KAAK,YAChB;AAAA,YACE;AAAA,cACE,QAAQ;AAAA,cACR,SAAS,MAAM,KAAK;AAAA,YACtB;AAAA,YACA,GAAG;AAAA,UACL,IACA;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,KAAE;AAAA,EACN;AAEA,MAAI,IAAI,SAAS,WAAW,EAAG;AAC/B,MAAI;AACF,UAAM,WAAW,UAAM,oBAAM,kDAAkD;AAAA,MAC7E,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,WAAW;AAAA,QACpC,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,6BAA6B;AAAA,QAC7B,mBAAmB;AAAA,MACrB;AAAA,MACA,MAAM,KAAK,UAAU,GAAG;AAAA,IAC1B,CAAC;AAED,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,+CAA+C,MAAM,WAAW,OAAO,EAAE;AAAA,EACzF,SAAS,OAAO;AACd,YAAQ,MAAM,sDAAsD,KAAK;AAAA,EAC3E;AACF;","names":[]}
@@ -2,7 +2,7 @@
2
2
  import { createHash } from "crypto";
3
3
  import { fetch } from "../utils/fetch.mjs";
4
4
  import { getFirst } from "../utils/field.mjs";
5
- var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
5
+ import { IGNORE_EVENTS } from "./ignore-events.mjs";
6
6
  async function sendEvents(accessToken, config, events, data = {}) {
7
7
  const eventNames = Object.keys(config);
8
8
  const address = getFirst(data.address);
@@ -22,7 +22,7 @@ async function sendEvents(accessToken, config, events, data = {}) {
22
22
  });
23
23
  }
24
24
  const dto = {
25
- elements: events.filter((event) => eventNames.includes(event.name) && !metrics.includes(event.name)).map((event) => {
25
+ elements: events.filter((event) => eventNames.includes(event.name) && !IGNORE_EVENTS.includes(event.name)).map((event) => {
26
26
  var _a, _b, _c, _d;
27
27
  return {
28
28
  eventId: event.id,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/linkedin-conversions-api.ts"],"sourcesContent":["/**\n * Conversions API Payload Builder: https://www.linkedin.com/developers/payload-builder\n * https://learn.microsoft.com/en-us/linkedin/marketing/conversions/conversions-overview?view=li-lms-2025-09\n */\nimport { createHash } from 'crypto';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\ntype UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface CreateLinkedinEventDTO {\n /**\n * For any conversion that you want to send through multiple methods, such as Insight Tag and\n * Conversions API, you must create a conversion rule for each data source (browser and server).\n * Then, you can implement a logic to pick up the eventId from the browser and send it with the\n * corresponding event from your server. If we receive an Insight Tag event and a Conversions API\n * event from the same account with the same eventId, we discard the Conversions API event and\n * count only the Insight Tag event in campaign reporting.\n */\n eventId?: string;\n\n /**\n * Replace <id> with the conversion ID extracted when creating the conversion rule\n * (e.g. urn:lla:llaPartnerConversion:<id>).\n */\n conversion: `urn:lla:llaPartnerConversion:${number}`;\n\n /** Epoch timestamp in milliseconds at which the conversion event happened. */\n conversionHappenedAt: number;\n conversionValue: { currencyCode: string; amount: string };\n user: {\n userIds: { idType: UserIdType; idValue: string }[];\n userInfo?: {\n firstName?: string;\n lastName?: string;\n companyName?: string;\n countryCode?: string;\n title?: string;\n };\n\n /**\n * The maximum supported size of the list is 1 at the moment. If the list contains multiple\n * values, only the first value will be used.\n */\n externalIds?: [string, ...string[]];\n\n /**\n * This is generated when users submit the Linkedin Lead-gen form\n * (e.g. urn:li:leadGenFormResponse:<id>).\n */\n lead?: `urn:li:leadGenFormResponse:${string}`;\n };\n}\n\nexport interface CreateMultipleLinkedinEventsDTO {\n elements: CreateLinkedinEventDTO[];\n}\n\nexport type LinkedinConversionConfig = Record<Lowercase<string>, number>;\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport async function sendEvents(\n accessToken: string,\n config: LinkedinConversionConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {}\n) {\n const eventNames = Object.keys(config);\n const address = getFirst(data.address);\n const userIds: { idType: UserIdType; idValue: string }[] = [];\n const externalIds: [string, ...string[]] | undefined = data.user_id ? [data.user_id] : undefined;\n const userInfo =\n address && address.first_name && address.last_name\n ? {\n firstName: address.first_name,\n lastName: address.last_name,\n countryCode: address.country,\n }\n : undefined;\n\n if (data.email) {\n const email = getFirst(data.email);\n if (email)\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue: createHash('sha256').update(email).digest('hex'),\n });\n }\n\n const dto: CreateMultipleLinkedinEventsDTO = {\n elements: events\n .filter((event) => eventNames.includes(event.name) && !metrics.includes(event.name))\n .map((event) => ({\n eventId: event.id,\n conversion: `urn:lla:llaPartnerConversion:${config[event.name]}`,\n conversionHappenedAt: Date.now(),\n conversionValue: {\n currencyCode: event.properties?.currency?.toUpperCase() ?? 'USD',\n amount: event.properties?.value?.toString() ?? '0',\n },\n user: {\n userIds: event.tags.li_fat_id\n ? [\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: event.tags.li_fat_id,\n },\n ...userIds,\n ]\n : userIds,\n userInfo,\n externalIds,\n },\n })),\n };\n\n if (dto.elements.length === 0) return;\n try {\n const response = await fetch('https://api.linkedin.com/rest/conversionEvents', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'LinkedIn-Version': '202509',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n },\n body: JSON.stringify(dto),\n });\n\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send LinkedIn conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send LinkedIn conversion, network error:', error);\n }\n}\n"],"mappings":";AAIA,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,gBAAgB;AA2DzB,IAAM,UAAU,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAE1D,eAAsB,WACpB,aACA,QAEA,QACA,OAAyB,CAAC,GAC1B;AACA,QAAM,aAAa,OAAO,KAAK,MAAM;AACrC,QAAM,UAAU,SAAS,KAAK,OAAO;AACrC,QAAM,UAAqD,CAAC;AAC5D,QAAM,cAAiD,KAAK,UAAU,CAAC,KAAK,OAAO,IAAI;AACvF,QAAM,WACJ,WAAW,QAAQ,cAAc,QAAQ,YACrC;AAAA,IACE,WAAW,QAAQ;AAAA,IACnB,UAAU,QAAQ;AAAA,IAClB,aAAa,QAAQ;AAAA,EACvB,IACA;AAEN,MAAI,KAAK,OAAO;AACd,UAAM,QAAQ,SAAS,KAAK,KAAK;AACjC,QAAI;AACF,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAAA,MAC1D,CAAC;AAAA,EACL;AAEA,QAAM,MAAuC;AAAA,IAC3C,UAAU,OACP,OAAO,CAAC,UAAU,WAAW,SAAS,MAAM,IAAI,KAAK,CAAC,QAAQ,SAAS,MAAM,IAAI,CAAC,EAClF,IAAI,CAAC,UAAO;AAnGnB;AAmGuB;AAAA,QACf,SAAS,MAAM;AAAA,QACf,YAAY,gCAAgC,OAAO,MAAM,IAAI,CAAC;AAAA,QAC9D,sBAAsB,KAAK,IAAI;AAAA,QAC/B,iBAAiB;AAAA,UACf,gBAAc,iBAAM,eAAN,mBAAkB,aAAlB,mBAA4B,kBAAiB;AAAA,UAC3D,UAAQ,iBAAM,eAAN,mBAAkB,UAAlB,mBAAyB,eAAc;AAAA,QACjD;AAAA,QACA,MAAM;AAAA,UACJ,SAAS,MAAM,KAAK,YAChB;AAAA,YACE;AAAA,cACE,QAAQ;AAAA,cACR,SAAS,MAAM,KAAK;AAAA,YACtB;AAAA,YACA,GAAG;AAAA,UACL,IACA;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,KAAE;AAAA,EACN;AAEA,MAAI,IAAI,SAAS,WAAW,EAAG;AAC/B,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,kDAAkD;AAAA,MAC7E,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,WAAW;AAAA,QACpC,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,6BAA6B;AAAA,QAC7B,mBAAmB;AAAA,MACrB;AAAA,MACA,MAAM,KAAK,UAAU,GAAG;AAAA,IAC1B,CAAC;AAED,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,+CAA+C,MAAM,WAAW,OAAO,EAAE;AAAA,EACzF,SAAS,OAAO;AACd,YAAQ,MAAM,sDAAsD,KAAK;AAAA,EAC3E;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/server/linkedin-conversions-api.ts"],"sourcesContent":["/**\n * Conversions API Payload Builder: https://www.linkedin.com/developers/payload-builder\n * https://learn.microsoft.com/en-us/linkedin/marketing/conversions/conversions-overview?view=li-lms-2025-09\n */\nimport { createHash } from 'crypto';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport { IGNORE_EVENTS } from './ignore-events';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\ntype UserIdType =\n | 'SHA256_EMAIL'\n | 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID'\n | 'ACXIOM_ID'\n | 'ORACLE_MOAT_ID';\n\nexport interface CreateLinkedinEventDTO {\n /**\n * For any conversion that you want to send through multiple methods, such as Insight Tag and\n * Conversions API, you must create a conversion rule for each data source (browser and server).\n * Then, you can implement a logic to pick up the eventId from the browser and send it with the\n * corresponding event from your server. If we receive an Insight Tag event and a Conversions API\n * event from the same account with the same eventId, we discard the Conversions API event and\n * count only the Insight Tag event in campaign reporting.\n */\n eventId?: string;\n\n /**\n * Replace <id> with the conversion ID extracted when creating the conversion rule\n * (e.g. urn:lla:llaPartnerConversion:<id>).\n */\n conversion: `urn:lla:llaPartnerConversion:${number}`;\n\n /** Epoch timestamp in milliseconds at which the conversion event happened. */\n conversionHappenedAt: number;\n conversionValue: { currencyCode: string; amount: string };\n user: {\n userIds: { idType: UserIdType; idValue: string }[];\n userInfo?: {\n firstName?: string;\n lastName?: string;\n companyName?: string;\n countryCode?: string;\n title?: string;\n };\n\n /**\n * The maximum supported size of the list is 1 at the moment. If the list contains multiple\n * values, only the first value will be used.\n */\n externalIds?: [string, ...string[]];\n\n /**\n * This is generated when users submit the Linkedin Lead-gen form\n * (e.g. urn:li:leadGenFormResponse:<id>).\n */\n lead?: `urn:li:leadGenFormResponse:${string}`;\n };\n}\n\nexport interface CreateMultipleLinkedinEventsDTO {\n elements: CreateLinkedinEventDTO[];\n}\n\nexport type LinkedinConversionConfig = Record<Lowercase<string>, number>;\n\nexport async function sendEvents(\n accessToken: string,\n config: LinkedinConversionConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {}\n) {\n const eventNames = Object.keys(config);\n const address = getFirst(data.address);\n const userIds: { idType: UserIdType; idValue: string }[] = [];\n const externalIds: [string, ...string[]] | undefined = data.user_id ? [data.user_id] : undefined;\n const userInfo =\n address && address.first_name && address.last_name\n ? {\n firstName: address.first_name,\n lastName: address.last_name,\n countryCode: address.country,\n }\n : undefined;\n\n if (data.email) {\n const email = getFirst(data.email);\n if (email)\n userIds.push({\n idType: 'SHA256_EMAIL',\n idValue: createHash('sha256').update(email).digest('hex'),\n });\n }\n\n const dto: CreateMultipleLinkedinEventsDTO = {\n elements: events\n .filter((event) => eventNames.includes(event.name) && !IGNORE_EVENTS.includes(event.name))\n .map((event) => ({\n eventId: event.id,\n conversion: `urn:lla:llaPartnerConversion:${config[event.name]}`,\n conversionHappenedAt: Date.now(),\n conversionValue: {\n currencyCode: event.properties?.currency?.toUpperCase() ?? 'USD',\n amount: event.properties?.value?.toString() ?? '0',\n },\n user: {\n userIds: event.tags.li_fat_id\n ? [\n {\n idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',\n idValue: event.tags.li_fat_id,\n },\n ...userIds,\n ]\n : userIds,\n userInfo,\n externalIds,\n },\n })),\n };\n\n if (dto.elements.length === 0) return;\n try {\n const response = await fetch('https://api.linkedin.com/rest/conversionEvents', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n 'LinkedIn-Version': '202509',\n 'X-Restli-Protocol-Version': '2.0.0',\n 'X-RestLi-Method': 'BATCH_CREATE',\n },\n body: JSON.stringify(dto),\n });\n\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send LinkedIn conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send LinkedIn conversion, network error:', error);\n }\n}\n"],"mappings":";AAIA,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AA2D9B,eAAsB,WACpB,aACA,QAEA,QACA,OAAyB,CAAC,GAC1B;AACA,QAAM,aAAa,OAAO,KAAK,MAAM;AACrC,QAAM,UAAU,SAAS,KAAK,OAAO;AACrC,QAAM,UAAqD,CAAC;AAC5D,QAAM,cAAiD,KAAK,UAAU,CAAC,KAAK,OAAO,IAAI;AACvF,QAAM,WACJ,WAAW,QAAQ,cAAc,QAAQ,YACrC;AAAA,IACE,WAAW,QAAQ;AAAA,IACnB,UAAU,QAAQ;AAAA,IAClB,aAAa,QAAQ;AAAA,EACvB,IACA;AAEN,MAAI,KAAK,OAAO;AACd,UAAM,QAAQ,SAAS,KAAK,KAAK;AACjC,QAAI;AACF,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAAA,MAC1D,CAAC;AAAA,EACL;AAEA,QAAM,MAAuC;AAAA,IAC3C,UAAU,OACP,OAAO,CAAC,UAAU,WAAW,SAAS,MAAM,IAAI,KAAK,CAAC,cAAc,SAAS,MAAM,IAAI,CAAC,EACxF,IAAI,CAAC,UAAO;AAlGnB;AAkGuB;AAAA,QACf,SAAS,MAAM;AAAA,QACf,YAAY,gCAAgC,OAAO,MAAM,IAAI,CAAC;AAAA,QAC9D,sBAAsB,KAAK,IAAI;AAAA,QAC/B,iBAAiB;AAAA,UACf,gBAAc,iBAAM,eAAN,mBAAkB,aAAlB,mBAA4B,kBAAiB;AAAA,UAC3D,UAAQ,iBAAM,eAAN,mBAAkB,UAAlB,mBAAyB,eAAc;AAAA,QACjD;AAAA,QACA,MAAM;AAAA,UACJ,SAAS,MAAM,KAAK,YAChB;AAAA,YACE;AAAA,cACE,QAAQ;AAAA,cACR,SAAS,MAAM,KAAK;AAAA,YACtB;AAAA,YACA,GAAG;AAAA,UACL,IACA;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,KAAE;AAAA,EACN;AAEA,MAAI,IAAI,SAAS,WAAW,EAAG;AAC/B,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,kDAAkD;AAAA,MAC7E,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,WAAW;AAAA,QACpC,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,6BAA6B;AAAA,QAC7B,mBAAmB;AAAA,MACrB;AAAA,MACA,MAAM,KAAK,UAAU,GAAG;AAAA,IAC1B,CAAC;AAED,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,+CAA+C,MAAM,WAAW,OAAO,EAAE;AAAA,EACzF,SAAS,OAAO;AACd,YAAQ,MAAM,sDAAsD,KAAK;AAAA,EAC3E;AACF;","names":[]}
@@ -28,6 +28,7 @@ __export(meta_conversions_api_exports, {
28
28
  module.exports = __toCommonJS(meta_conversions_api_exports);
29
29
  var import_facebook_nodejs_business_sdk = require("facebook-nodejs-business-sdk");
30
30
  var import_fbq = require("../track/fbq.cjs");
31
+ var import_ignore_events = require("./ignore-events.cjs");
31
32
  var USER_ASSIGNED_COUNTRIES = ["xk"];
32
33
  function normalizeCountry(input) {
33
34
  const country = input == null ? void 0 : input.split(/[-_]/).at(0);
@@ -246,16 +247,15 @@ function getServerEvent(event, data, appPackageName) {
246
247
  }
247
248
  return serverEvent;
248
249
  }
249
- var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
250
250
  async function sendEvent(accessToken, pixelId, event, data = {}, appPackageName) {
251
- if (metrics.includes(event.name)) return;
251
+ if (import_ignore_events.IGNORE_EVENTS.includes(event.name)) return;
252
252
  const request = new import_facebook_nodejs_business_sdk.EventRequest(accessToken, pixelId);
253
253
  const fbEvent = getServerEvent(event, data, appPackageName);
254
254
  request.setEvents([fbEvent]);
255
255
  return request.execute();
256
256
  }
257
257
  async function sendEvents(accessToken, pixelId, events, data = {}, appPackageName) {
258
- const fbEvents = events.filter((event) => !metrics.includes(event.name)).map((event) => getServerEvent(event, data, appPackageName));
258
+ const fbEvents = events.filter((event) => !import_ignore_events.IGNORE_EVENTS.includes(event.name)).map((event) => getServerEvent(event, data, appPackageName));
259
259
  if (fbEvents.length === 0) return;
260
260
  const request = new import_facebook_nodejs_business_sdk.EventRequest(accessToken, pixelId);
261
261
  request.setEvents(fbEvents);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/meta-conversions-api.ts"],"sourcesContent":["import {\n AppData,\n Content,\n CustomData,\n EventRequest,\n ExtendedDeviceInfo,\n ServerEvent,\n UserData,\n} from 'facebook-nodejs-business-sdk';\nimport { mapFBEvent } from '../track/fbq';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0);\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData) {\n const userData = new UserData();\n\n // set user provided data\n if (data.email) {\n if (Array.isArray(data.email)) {\n userData.setEmails(data.email);\n } else {\n userData.setEmail(data.email);\n }\n }\n if (data.phone_number) {\n if (Array.isArray(data.phone_number)) {\n userData.setPhones(data.phone_number);\n } else {\n userData.setPhone(data.phone_number);\n }\n }\n if (data.gender) {\n if (data.gender === 'female') {\n userData.setGender('f');\n } else if (data.gender === 'male') {\n userData.setGender('m');\n }\n }\n if (data.address) {\n if (Array.isArray(data.address)) {\n const firstNames = data.address.map((a) => a.first_name).filter(Boolean);\n const lastNames = data.address.map((a) => a.last_name).filter(Boolean);\n const cities = data.address.map((a) => a.city).filter(Boolean);\n const states = data.address.map((a) => a.region).filter(Boolean);\n const postalCodes = data.address.map((a) => a.postal_code).filter(Boolean);\n const countries = data.address.map((a) => normalizeCountry(a.country)).filter(Boolean);\n\n userData.setFirstNames(firstNames as string[]);\n userData.setLastNames(lastNames as string[]);\n userData.setCities(cities as string[]);\n userData.setStates(states as string[]);\n userData.setZips(postalCodes as string[]);\n userData.setCountries(countries as string[]);\n } else {\n if (data.address.first_name) {\n userData.setFirstName(data.address.first_name);\n userData.setF5First(data.address.first_name.slice(0, 5));\n }\n if (data.address.last_name) {\n userData.setLastName(data.address.last_name);\n userData.setF5Last(data.address.last_name.slice(0, 5));\n }\n if (data.address.city) userData.setCity(data.address.city);\n if (data.address.region) userData.setState(data.address.region);\n if (data.address.postal_code) userData.setZip(data.address.postal_code);\n if (data.address.country) {\n const country = normalizeCountry(data.address.country);\n if (country) userData.setCountry(country);\n }\n }\n }\n if (data.birthday) {\n userData.setDoby(data.birthday.year.toString());\n userData.setDobm(data.birthday.month.toString());\n userData.setDobd(data.birthday.day.toString());\n }\n if (data.user_id && data.user_id.length !== 0) {\n userData.setExternalId(data.user_id);\n }\n if (data.ip_address) {\n userData.setClientIpAddress(data.ip_address);\n }\n if (data.user_agent) {\n userData.setClientUserAgent(data.user_agent);\n }\n if (data.fb_login_id) {\n userData.setFbLoginId(data.fb_login_id);\n }\n if (data.fb_page_id) {\n userData.setPageId(data.fb_page_id);\n }\n\n // set tags info\n if (tags.fbc) {\n userData.setFbc(tags.fbc);\n } else if (tags.fbclid) {\n // ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc#2--format-clickid\n // The formatted ClickID value must be of the form `version.subdomainIndex.creationTime.<fbclid>`, where:\n // - version is always this prefix: fb\n // - subdomainIndex is which domain the cookie is defined on ('com' = 0, 'example.com' = 1, 'www.example.com' = 2)\n // - creationTime is the UNIX time since epoch in milliseconds when the _fbc was stored. If you don't save the _fbc cookie, use the timestamp when you first observed or received this fbclid value\n // - <fbclid> is the value for the fbclid query parameter in the page URL.\n\n const fbc = `fb.1.${Date.now()}.${tags.fbclid}`;\n userData.setFbc(fbc);\n }\n\n if (tags.fbp) {\n userData.setFbp(tags.fbp);\n }\n if (tags.advertising_id) {\n userData.setMadid(tags.advertising_id);\n }\n if (tags.ip_address && typeof tags.ip_address === 'string') {\n userData.setClientIpAddress(tags.ip_address);\n }\n\n return userData;\n}\n\nfunction getAppData(tags: TrackTags, appPackageName: string) {\n const extinfo = new ExtendedDeviceInfo();\n if (tags.os_name) {\n if (tags.os_name === 'iOS' || tags.os_name === 'iPadOS') {\n extinfo.setExtInfoVersion('i2');\n } else if (tags.os_name === 'Android') {\n extinfo.setExtInfoVersion('a2');\n }\n }\n extinfo.setAppPackageName(appPackageName);\n const shortVersion = tags.release?.split('.').at(0);\n if (shortVersion) {\n extinfo.setShortVersion(shortVersion);\n }\n if (tags.release) {\n extinfo.setLongVersion(tags.release);\n }\n if (tags.os_version) {\n extinfo.setOsVersion(tags.os_version);\n }\n if (tags.device_model_id) {\n extinfo.setDeviceModelName(tags.device_model_id);\n }\n if (tags.language) {\n extinfo.setLocale(tags.language);\n }\n if (tags.screen_width) {\n extinfo.setScreenWidth(tags.screen_width);\n }\n if (tags.screen_height) {\n extinfo.setScreenHeight(tags.screen_height);\n }\n if (tags.device_pixel_ratio) {\n extinfo.setScreenDensity(tags.device_pixel_ratio.toString());\n }\n\n const appData = new AppData();\n appData.setExtinfo(extinfo);\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n if (tags.advertising_id) {\n appData.setAdvertiserTrackingEnabled(true);\n }\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n\n return appData;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getCustomData({ name, properties }: TrackEvent<any>) {\n const data = new CustomData();\n const [_, _name, fbEventProperties] = mapFBEvent(name, properties);\n const {\n value,\n currency,\n content_name,\n content_category,\n content_ids,\n contents,\n content_type,\n // order_id,\n predicted_ltv,\n num_items,\n search_string,\n status,\n // item_number,\n delivery_category,\n ...custom_properties\n } = fbEventProperties;\n if (value) data.setValue(value);\n if (currency) data.setCurrency(currency);\n if (content_name) data.setContentName(content_name);\n if (content_category) data.setContentCategory(content_category);\n if (content_ids) data.setContentIds(content_ids);\n if (contents)\n data.setContents(\n contents.map((c) => {\n const result = new Content().setId(c.id).setQuantity(c.quantity);\n if (c.item_price) result.setItemPrice(c.item_price);\n if (c.title) result.setTitle(c.title);\n if (c.description) result.setDescription(c.description);\n if (c.brand) result.setBrand(c.brand);\n if (c.category) result.setCategory(c.category);\n if (c.delivery_category) result.setDeliveryCategory(c.delivery_category);\n return result;\n })\n );\n if (content_type) data.setContentType(content_type);\n // if (order_id) data.setOrderId(order_id);\n if (predicted_ltv) data.setPredictedLtv(predicted_ltv);\n if (num_items) data.setNumItems(num_items);\n if (search_string) data.setSearchString(search_string);\n if (status) data.setStatus(status.toString());\n // if (item_number) data.setItemNumber(item_number);\n if (delivery_category) data.setDeliveryCategory(delivery_category);\n if (custom_properties) data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string\n) {\n const userData = getUserData(event.tags, data);\n const customData = getCustomData(event);\n const [_, eventName] = mapFBEvent(event.name, event.properties);\n const serverEvent = new ServerEvent()\n .setEventId(event.tags.idempotency_key ?? event.id.toString())\n .setEventName(eventName)\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n if (event.tags.source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n if (event.tags.source_url) {\n serverEvent.setEventSourceUrl(event.tags.source_url);\n }\n switch (event.tags.source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n break;\n }\n return serverEvent;\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n if (metrics.includes(event.name)) return;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName);\n request.setEvents([fbEvent]);\n return request.execute();\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n const fbEvents = events\n .filter((event) => !metrics.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName));\n if (fbEvents.length === 0) return;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n return request.execute();\n}\n\nexport async function sendTestEvent(accessToken: string, pixelId: string, testEventCode: string) {\n const extinfo = new ExtendedDeviceInfo()\n .setExtInfoVersion('a2')\n .setAppPackageName('com.some.app')\n .setShortVersion('771')\n .setLongVersion('Version 7.7.1')\n .setOsVersion('10.1.1')\n .setDeviceModelName('OnePlus6')\n .setLocale('en_US')\n .setTimezoneAbbreviation('GMT-1')\n .setCarrier('TMobile')\n .setScreenWidth(1920)\n .setScreenHeight(1080)\n .setScreenDensity('2.00')\n .setCpuCoreCount(2)\n .setTotalDiskSpaceGb(128)\n .setFreeDiskSpaceGb(8)\n .setDeviceTimeZone('USA/New York');\n\n const userData = new UserData().setEmail('test@example.com');\n const appData = new AppData().setExtinfo(extinfo);\n const event = new ServerEvent()\n .setEventId(Math.round(Math.random() * 1000_000).toString())\n .setEventName('TestEvent')\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setAppData(appData)\n .setActionSource('app');\n\n const request = new EventRequest(accessToken, pixelId);\n request.setTestEventCode(testEventCode);\n request.setEvents([event]);\n return request.execute();\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/server/meta-conversions-api.ts"],"sourcesContent":["import {\n AppData,\n Content,\n CustomData,\n EventRequest,\n ExtendedDeviceInfo,\n ServerEvent,\n UserData,\n} from 'facebook-nodejs-business-sdk';\nimport { mapFBEvent } from '../track/fbq';\nimport { IGNORE_EVENTS } from './ignore-events';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0);\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData) {\n const userData = new UserData();\n\n // set user provided data\n if (data.email) {\n if (Array.isArray(data.email)) {\n userData.setEmails(data.email);\n } else {\n userData.setEmail(data.email);\n }\n }\n if (data.phone_number) {\n if (Array.isArray(data.phone_number)) {\n userData.setPhones(data.phone_number);\n } else {\n userData.setPhone(data.phone_number);\n }\n }\n if (data.gender) {\n if (data.gender === 'female') {\n userData.setGender('f');\n } else if (data.gender === 'male') {\n userData.setGender('m');\n }\n }\n if (data.address) {\n if (Array.isArray(data.address)) {\n const firstNames = data.address.map((a) => a.first_name).filter(Boolean);\n const lastNames = data.address.map((a) => a.last_name).filter(Boolean);\n const cities = data.address.map((a) => a.city).filter(Boolean);\n const states = data.address.map((a) => a.region).filter(Boolean);\n const postalCodes = data.address.map((a) => a.postal_code).filter(Boolean);\n const countries = data.address.map((a) => normalizeCountry(a.country)).filter(Boolean);\n\n userData.setFirstNames(firstNames as string[]);\n userData.setLastNames(lastNames as string[]);\n userData.setCities(cities as string[]);\n userData.setStates(states as string[]);\n userData.setZips(postalCodes as string[]);\n userData.setCountries(countries as string[]);\n } else {\n if (data.address.first_name) {\n userData.setFirstName(data.address.first_name);\n userData.setF5First(data.address.first_name.slice(0, 5));\n }\n if (data.address.last_name) {\n userData.setLastName(data.address.last_name);\n userData.setF5Last(data.address.last_name.slice(0, 5));\n }\n if (data.address.city) userData.setCity(data.address.city);\n if (data.address.region) userData.setState(data.address.region);\n if (data.address.postal_code) userData.setZip(data.address.postal_code);\n if (data.address.country) {\n const country = normalizeCountry(data.address.country);\n if (country) userData.setCountry(country);\n }\n }\n }\n if (data.birthday) {\n userData.setDoby(data.birthday.year.toString());\n userData.setDobm(data.birthday.month.toString());\n userData.setDobd(data.birthday.day.toString());\n }\n if (data.user_id && data.user_id.length !== 0) {\n userData.setExternalId(data.user_id);\n }\n if (data.ip_address) {\n userData.setClientIpAddress(data.ip_address);\n }\n if (data.user_agent) {\n userData.setClientUserAgent(data.user_agent);\n }\n if (data.fb_login_id) {\n userData.setFbLoginId(data.fb_login_id);\n }\n if (data.fb_page_id) {\n userData.setPageId(data.fb_page_id);\n }\n\n // set tags info\n if (tags.fbc) {\n userData.setFbc(tags.fbc);\n } else if (tags.fbclid) {\n // ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc#2--format-clickid\n // The formatted ClickID value must be of the form `version.subdomainIndex.creationTime.<fbclid>`, where:\n // - version is always this prefix: fb\n // - subdomainIndex is which domain the cookie is defined on ('com' = 0, 'example.com' = 1, 'www.example.com' = 2)\n // - creationTime is the UNIX time since epoch in milliseconds when the _fbc was stored. If you don't save the _fbc cookie, use the timestamp when you first observed or received this fbclid value\n // - <fbclid> is the value for the fbclid query parameter in the page URL.\n\n const fbc = `fb.1.${Date.now()}.${tags.fbclid}`;\n userData.setFbc(fbc);\n }\n\n if (tags.fbp) {\n userData.setFbp(tags.fbp);\n }\n if (tags.advertising_id) {\n userData.setMadid(tags.advertising_id);\n }\n if (tags.ip_address && typeof tags.ip_address === 'string') {\n userData.setClientIpAddress(tags.ip_address);\n }\n\n return userData;\n}\n\nfunction getAppData(tags: TrackTags, appPackageName: string) {\n const extinfo = new ExtendedDeviceInfo();\n if (tags.os_name) {\n if (tags.os_name === 'iOS' || tags.os_name === 'iPadOS') {\n extinfo.setExtInfoVersion('i2');\n } else if (tags.os_name === 'Android') {\n extinfo.setExtInfoVersion('a2');\n }\n }\n extinfo.setAppPackageName(appPackageName);\n const shortVersion = tags.release?.split('.').at(0);\n if (shortVersion) {\n extinfo.setShortVersion(shortVersion);\n }\n if (tags.release) {\n extinfo.setLongVersion(tags.release);\n }\n if (tags.os_version) {\n extinfo.setOsVersion(tags.os_version);\n }\n if (tags.device_model_id) {\n extinfo.setDeviceModelName(tags.device_model_id);\n }\n if (tags.language) {\n extinfo.setLocale(tags.language);\n }\n if (tags.screen_width) {\n extinfo.setScreenWidth(tags.screen_width);\n }\n if (tags.screen_height) {\n extinfo.setScreenHeight(tags.screen_height);\n }\n if (tags.device_pixel_ratio) {\n extinfo.setScreenDensity(tags.device_pixel_ratio.toString());\n }\n\n const appData = new AppData();\n appData.setExtinfo(extinfo);\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n if (tags.advertising_id) {\n appData.setAdvertiserTrackingEnabled(true);\n }\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n\n return appData;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getCustomData({ name, properties }: TrackEvent<any>) {\n const data = new CustomData();\n const [_, _name, fbEventProperties] = mapFBEvent(name, properties);\n const {\n value,\n currency,\n content_name,\n content_category,\n content_ids,\n contents,\n content_type,\n // order_id,\n predicted_ltv,\n num_items,\n search_string,\n status,\n // item_number,\n delivery_category,\n ...custom_properties\n } = fbEventProperties;\n if (value) data.setValue(value);\n if (currency) data.setCurrency(currency);\n if (content_name) data.setContentName(content_name);\n if (content_category) data.setContentCategory(content_category);\n if (content_ids) data.setContentIds(content_ids);\n if (contents)\n data.setContents(\n contents.map((c) => {\n const result = new Content().setId(c.id).setQuantity(c.quantity);\n if (c.item_price) result.setItemPrice(c.item_price);\n if (c.title) result.setTitle(c.title);\n if (c.description) result.setDescription(c.description);\n if (c.brand) result.setBrand(c.brand);\n if (c.category) result.setCategory(c.category);\n if (c.delivery_category) result.setDeliveryCategory(c.delivery_category);\n return result;\n })\n );\n if (content_type) data.setContentType(content_type);\n // if (order_id) data.setOrderId(order_id);\n if (predicted_ltv) data.setPredictedLtv(predicted_ltv);\n if (num_items) data.setNumItems(num_items);\n if (search_string) data.setSearchString(search_string);\n if (status) data.setStatus(status.toString());\n // if (item_number) data.setItemNumber(item_number);\n if (delivery_category) data.setDeliveryCategory(delivery_category);\n if (custom_properties) data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string\n) {\n const userData = getUserData(event.tags, data);\n const customData = getCustomData(event);\n const [_, eventName] = mapFBEvent(event.name, event.properties);\n const serverEvent = new ServerEvent()\n .setEventId(event.tags.idempotency_key ?? event.id.toString())\n .setEventName(eventName)\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n if (event.tags.source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n if (event.tags.source_url) {\n serverEvent.setEventSourceUrl(event.tags.source_url);\n }\n switch (event.tags.source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n break;\n }\n return serverEvent;\n}\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n if (IGNORE_EVENTS.includes(event.name)) return;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName);\n request.setEvents([fbEvent]);\n return request.execute();\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n const fbEvents = events\n .filter((event) => !IGNORE_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName));\n if (fbEvents.length === 0) return;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n return request.execute();\n}\n\nexport async function sendTestEvent(accessToken: string, pixelId: string, testEventCode: string) {\n const extinfo = new ExtendedDeviceInfo()\n .setExtInfoVersion('a2')\n .setAppPackageName('com.some.app')\n .setShortVersion('771')\n .setLongVersion('Version 7.7.1')\n .setOsVersion('10.1.1')\n .setDeviceModelName('OnePlus6')\n .setLocale('en_US')\n .setTimezoneAbbreviation('GMT-1')\n .setCarrier('TMobile')\n .setScreenWidth(1920)\n .setScreenHeight(1080)\n .setScreenDensity('2.00')\n .setCpuCoreCount(2)\n .setTotalDiskSpaceGb(128)\n .setFreeDiskSpaceGb(8)\n .setDeviceTimeZone('USA/New York');\n\n const userData = new UserData().setEmail('test@example.com');\n const appData = new AppData().setExtinfo(extinfo);\n const event = new ServerEvent()\n .setEventId(Math.round(Math.random() * 1000_000).toString())\n .setEventName('TestEvent')\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setAppData(appData)\n .setActionSource('app');\n\n const request = new EventRequest(accessToken, pixelId);\n request.setTestEventCode(testEventCode);\n request.setEvents([event]);\n return request.execute();\n}\n"],"mappings":"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","names":[]}
@@ -9,6 +9,7 @@ import {
9
9
  UserData
10
10
  } from "facebook-nodejs-business-sdk";
11
11
  import { mapFBEvent } from "../track/fbq.mjs";
12
+ import { IGNORE_EVENTS } from "./ignore-events.mjs";
12
13
  var USER_ASSIGNED_COUNTRIES = ["xk"];
13
14
  function normalizeCountry(input) {
14
15
  const country = input == null ? void 0 : input.split(/[-_]/).at(0);
@@ -227,16 +228,15 @@ function getServerEvent(event, data, appPackageName) {
227
228
  }
228
229
  return serverEvent;
229
230
  }
230
- var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
231
231
  async function sendEvent(accessToken, pixelId, event, data = {}, appPackageName) {
232
- if (metrics.includes(event.name)) return;
232
+ if (IGNORE_EVENTS.includes(event.name)) return;
233
233
  const request = new EventRequest(accessToken, pixelId);
234
234
  const fbEvent = getServerEvent(event, data, appPackageName);
235
235
  request.setEvents([fbEvent]);
236
236
  return request.execute();
237
237
  }
238
238
  async function sendEvents(accessToken, pixelId, events, data = {}, appPackageName) {
239
- const fbEvents = events.filter((event) => !metrics.includes(event.name)).map((event) => getServerEvent(event, data, appPackageName));
239
+ const fbEvents = events.filter((event) => !IGNORE_EVENTS.includes(event.name)).map((event) => getServerEvent(event, data, appPackageName));
240
240
  if (fbEvents.length === 0) return;
241
241
  const request = new EventRequest(accessToken, pixelId);
242
242
  request.setEvents(fbEvents);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/meta-conversions-api.ts"],"sourcesContent":["import {\n AppData,\n Content,\n CustomData,\n EventRequest,\n ExtendedDeviceInfo,\n ServerEvent,\n UserData,\n} from 'facebook-nodejs-business-sdk';\nimport { mapFBEvent } from '../track/fbq';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0);\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData) {\n const userData = new UserData();\n\n // set user provided data\n if (data.email) {\n if (Array.isArray(data.email)) {\n userData.setEmails(data.email);\n } else {\n userData.setEmail(data.email);\n }\n }\n if (data.phone_number) {\n if (Array.isArray(data.phone_number)) {\n userData.setPhones(data.phone_number);\n } else {\n userData.setPhone(data.phone_number);\n }\n }\n if (data.gender) {\n if (data.gender === 'female') {\n userData.setGender('f');\n } else if (data.gender === 'male') {\n userData.setGender('m');\n }\n }\n if (data.address) {\n if (Array.isArray(data.address)) {\n const firstNames = data.address.map((a) => a.first_name).filter(Boolean);\n const lastNames = data.address.map((a) => a.last_name).filter(Boolean);\n const cities = data.address.map((a) => a.city).filter(Boolean);\n const states = data.address.map((a) => a.region).filter(Boolean);\n const postalCodes = data.address.map((a) => a.postal_code).filter(Boolean);\n const countries = data.address.map((a) => normalizeCountry(a.country)).filter(Boolean);\n\n userData.setFirstNames(firstNames as string[]);\n userData.setLastNames(lastNames as string[]);\n userData.setCities(cities as string[]);\n userData.setStates(states as string[]);\n userData.setZips(postalCodes as string[]);\n userData.setCountries(countries as string[]);\n } else {\n if (data.address.first_name) {\n userData.setFirstName(data.address.first_name);\n userData.setF5First(data.address.first_name.slice(0, 5));\n }\n if (data.address.last_name) {\n userData.setLastName(data.address.last_name);\n userData.setF5Last(data.address.last_name.slice(0, 5));\n }\n if (data.address.city) userData.setCity(data.address.city);\n if (data.address.region) userData.setState(data.address.region);\n if (data.address.postal_code) userData.setZip(data.address.postal_code);\n if (data.address.country) {\n const country = normalizeCountry(data.address.country);\n if (country) userData.setCountry(country);\n }\n }\n }\n if (data.birthday) {\n userData.setDoby(data.birthday.year.toString());\n userData.setDobm(data.birthday.month.toString());\n userData.setDobd(data.birthday.day.toString());\n }\n if (data.user_id && data.user_id.length !== 0) {\n userData.setExternalId(data.user_id);\n }\n if (data.ip_address) {\n userData.setClientIpAddress(data.ip_address);\n }\n if (data.user_agent) {\n userData.setClientUserAgent(data.user_agent);\n }\n if (data.fb_login_id) {\n userData.setFbLoginId(data.fb_login_id);\n }\n if (data.fb_page_id) {\n userData.setPageId(data.fb_page_id);\n }\n\n // set tags info\n if (tags.fbc) {\n userData.setFbc(tags.fbc);\n } else if (tags.fbclid) {\n // ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc#2--format-clickid\n // The formatted ClickID value must be of the form `version.subdomainIndex.creationTime.<fbclid>`, where:\n // - version is always this prefix: fb\n // - subdomainIndex is which domain the cookie is defined on ('com' = 0, 'example.com' = 1, 'www.example.com' = 2)\n // - creationTime is the UNIX time since epoch in milliseconds when the _fbc was stored. If you don't save the _fbc cookie, use the timestamp when you first observed or received this fbclid value\n // - <fbclid> is the value for the fbclid query parameter in the page URL.\n\n const fbc = `fb.1.${Date.now()}.${tags.fbclid}`;\n userData.setFbc(fbc);\n }\n\n if (tags.fbp) {\n userData.setFbp(tags.fbp);\n }\n if (tags.advertising_id) {\n userData.setMadid(tags.advertising_id);\n }\n if (tags.ip_address && typeof tags.ip_address === 'string') {\n userData.setClientIpAddress(tags.ip_address);\n }\n\n return userData;\n}\n\nfunction getAppData(tags: TrackTags, appPackageName: string) {\n const extinfo = new ExtendedDeviceInfo();\n if (tags.os_name) {\n if (tags.os_name === 'iOS' || tags.os_name === 'iPadOS') {\n extinfo.setExtInfoVersion('i2');\n } else if (tags.os_name === 'Android') {\n extinfo.setExtInfoVersion('a2');\n }\n }\n extinfo.setAppPackageName(appPackageName);\n const shortVersion = tags.release?.split('.').at(0);\n if (shortVersion) {\n extinfo.setShortVersion(shortVersion);\n }\n if (tags.release) {\n extinfo.setLongVersion(tags.release);\n }\n if (tags.os_version) {\n extinfo.setOsVersion(tags.os_version);\n }\n if (tags.device_model_id) {\n extinfo.setDeviceModelName(tags.device_model_id);\n }\n if (tags.language) {\n extinfo.setLocale(tags.language);\n }\n if (tags.screen_width) {\n extinfo.setScreenWidth(tags.screen_width);\n }\n if (tags.screen_height) {\n extinfo.setScreenHeight(tags.screen_height);\n }\n if (tags.device_pixel_ratio) {\n extinfo.setScreenDensity(tags.device_pixel_ratio.toString());\n }\n\n const appData = new AppData();\n appData.setExtinfo(extinfo);\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n if (tags.advertising_id) {\n appData.setAdvertiserTrackingEnabled(true);\n }\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n\n return appData;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getCustomData({ name, properties }: TrackEvent<any>) {\n const data = new CustomData();\n const [_, _name, fbEventProperties] = mapFBEvent(name, properties);\n const {\n value,\n currency,\n content_name,\n content_category,\n content_ids,\n contents,\n content_type,\n // order_id,\n predicted_ltv,\n num_items,\n search_string,\n status,\n // item_number,\n delivery_category,\n ...custom_properties\n } = fbEventProperties;\n if (value) data.setValue(value);\n if (currency) data.setCurrency(currency);\n if (content_name) data.setContentName(content_name);\n if (content_category) data.setContentCategory(content_category);\n if (content_ids) data.setContentIds(content_ids);\n if (contents)\n data.setContents(\n contents.map((c) => {\n const result = new Content().setId(c.id).setQuantity(c.quantity);\n if (c.item_price) result.setItemPrice(c.item_price);\n if (c.title) result.setTitle(c.title);\n if (c.description) result.setDescription(c.description);\n if (c.brand) result.setBrand(c.brand);\n if (c.category) result.setCategory(c.category);\n if (c.delivery_category) result.setDeliveryCategory(c.delivery_category);\n return result;\n })\n );\n if (content_type) data.setContentType(content_type);\n // if (order_id) data.setOrderId(order_id);\n if (predicted_ltv) data.setPredictedLtv(predicted_ltv);\n if (num_items) data.setNumItems(num_items);\n if (search_string) data.setSearchString(search_string);\n if (status) data.setStatus(status.toString());\n // if (item_number) data.setItemNumber(item_number);\n if (delivery_category) data.setDeliveryCategory(delivery_category);\n if (custom_properties) data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string\n) {\n const userData = getUserData(event.tags, data);\n const customData = getCustomData(event);\n const [_, eventName] = mapFBEvent(event.name, event.properties);\n const serverEvent = new ServerEvent()\n .setEventId(event.tags.idempotency_key ?? event.id.toString())\n .setEventName(eventName)\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n if (event.tags.source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n if (event.tags.source_url) {\n serverEvent.setEventSourceUrl(event.tags.source_url);\n }\n switch (event.tags.source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n break;\n }\n return serverEvent;\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n if (metrics.includes(event.name)) return;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName);\n request.setEvents([fbEvent]);\n return request.execute();\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n const fbEvents = events\n .filter((event) => !metrics.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName));\n if (fbEvents.length === 0) return;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n return request.execute();\n}\n\nexport async function sendTestEvent(accessToken: string, pixelId: string, testEventCode: string) {\n const extinfo = new ExtendedDeviceInfo()\n .setExtInfoVersion('a2')\n .setAppPackageName('com.some.app')\n .setShortVersion('771')\n .setLongVersion('Version 7.7.1')\n .setOsVersion('10.1.1')\n .setDeviceModelName('OnePlus6')\n .setLocale('en_US')\n .setTimezoneAbbreviation('GMT-1')\n .setCarrier('TMobile')\n .setScreenWidth(1920)\n .setScreenHeight(1080)\n .setScreenDensity('2.00')\n .setCpuCoreCount(2)\n .setTotalDiskSpaceGb(128)\n .setFreeDiskSpaceGb(8)\n .setDeviceTimeZone('USA/New York');\n\n const userData = new UserData().setEmail('test@example.com');\n const appData = new AppData().setExtinfo(extinfo);\n const event = new ServerEvent()\n .setEventId(Math.round(Math.random() * 1000_000).toString())\n .setEventName('TestEvent')\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setAppData(appData)\n .setActionSource('app');\n\n const request = new EventRequest(accessToken, pixelId);\n request.setTestEventCode(testEventCode);\n request.setEvents([event]);\n return request.execute();\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/server/meta-conversions-api.ts"],"sourcesContent":["import {\n AppData,\n Content,\n CustomData,\n EventRequest,\n ExtendedDeviceInfo,\n ServerEvent,\n UserData,\n} from 'facebook-nodejs-business-sdk';\nimport { mapFBEvent } from '../track/fbq';\nimport { IGNORE_EVENTS } from './ignore-events';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0);\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData) {\n const userData = new UserData();\n\n // set user provided data\n if (data.email) {\n if (Array.isArray(data.email)) {\n userData.setEmails(data.email);\n } else {\n userData.setEmail(data.email);\n }\n }\n if (data.phone_number) {\n if (Array.isArray(data.phone_number)) {\n userData.setPhones(data.phone_number);\n } else {\n userData.setPhone(data.phone_number);\n }\n }\n if (data.gender) {\n if (data.gender === 'female') {\n userData.setGender('f');\n } else if (data.gender === 'male') {\n userData.setGender('m');\n }\n }\n if (data.address) {\n if (Array.isArray(data.address)) {\n const firstNames = data.address.map((a) => a.first_name).filter(Boolean);\n const lastNames = data.address.map((a) => a.last_name).filter(Boolean);\n const cities = data.address.map((a) => a.city).filter(Boolean);\n const states = data.address.map((a) => a.region).filter(Boolean);\n const postalCodes = data.address.map((a) => a.postal_code).filter(Boolean);\n const countries = data.address.map((a) => normalizeCountry(a.country)).filter(Boolean);\n\n userData.setFirstNames(firstNames as string[]);\n userData.setLastNames(lastNames as string[]);\n userData.setCities(cities as string[]);\n userData.setStates(states as string[]);\n userData.setZips(postalCodes as string[]);\n userData.setCountries(countries as string[]);\n } else {\n if (data.address.first_name) {\n userData.setFirstName(data.address.first_name);\n userData.setF5First(data.address.first_name.slice(0, 5));\n }\n if (data.address.last_name) {\n userData.setLastName(data.address.last_name);\n userData.setF5Last(data.address.last_name.slice(0, 5));\n }\n if (data.address.city) userData.setCity(data.address.city);\n if (data.address.region) userData.setState(data.address.region);\n if (data.address.postal_code) userData.setZip(data.address.postal_code);\n if (data.address.country) {\n const country = normalizeCountry(data.address.country);\n if (country) userData.setCountry(country);\n }\n }\n }\n if (data.birthday) {\n userData.setDoby(data.birthday.year.toString());\n userData.setDobm(data.birthday.month.toString());\n userData.setDobd(data.birthday.day.toString());\n }\n if (data.user_id && data.user_id.length !== 0) {\n userData.setExternalId(data.user_id);\n }\n if (data.ip_address) {\n userData.setClientIpAddress(data.ip_address);\n }\n if (data.user_agent) {\n userData.setClientUserAgent(data.user_agent);\n }\n if (data.fb_login_id) {\n userData.setFbLoginId(data.fb_login_id);\n }\n if (data.fb_page_id) {\n userData.setPageId(data.fb_page_id);\n }\n\n // set tags info\n if (tags.fbc) {\n userData.setFbc(tags.fbc);\n } else if (tags.fbclid) {\n // ref: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc#2--format-clickid\n // The formatted ClickID value must be of the form `version.subdomainIndex.creationTime.<fbclid>`, where:\n // - version is always this prefix: fb\n // - subdomainIndex is which domain the cookie is defined on ('com' = 0, 'example.com' = 1, 'www.example.com' = 2)\n // - creationTime is the UNIX time since epoch in milliseconds when the _fbc was stored. If you don't save the _fbc cookie, use the timestamp when you first observed or received this fbclid value\n // - <fbclid> is the value for the fbclid query parameter in the page URL.\n\n const fbc = `fb.1.${Date.now()}.${tags.fbclid}`;\n userData.setFbc(fbc);\n }\n\n if (tags.fbp) {\n userData.setFbp(tags.fbp);\n }\n if (tags.advertising_id) {\n userData.setMadid(tags.advertising_id);\n }\n if (tags.ip_address && typeof tags.ip_address === 'string') {\n userData.setClientIpAddress(tags.ip_address);\n }\n\n return userData;\n}\n\nfunction getAppData(tags: TrackTags, appPackageName: string) {\n const extinfo = new ExtendedDeviceInfo();\n if (tags.os_name) {\n if (tags.os_name === 'iOS' || tags.os_name === 'iPadOS') {\n extinfo.setExtInfoVersion('i2');\n } else if (tags.os_name === 'Android') {\n extinfo.setExtInfoVersion('a2');\n }\n }\n extinfo.setAppPackageName(appPackageName);\n const shortVersion = tags.release?.split('.').at(0);\n if (shortVersion) {\n extinfo.setShortVersion(shortVersion);\n }\n if (tags.release) {\n extinfo.setLongVersion(tags.release);\n }\n if (tags.os_version) {\n extinfo.setOsVersion(tags.os_version);\n }\n if (tags.device_model_id) {\n extinfo.setDeviceModelName(tags.device_model_id);\n }\n if (tags.language) {\n extinfo.setLocale(tags.language);\n }\n if (tags.screen_width) {\n extinfo.setScreenWidth(tags.screen_width);\n }\n if (tags.screen_height) {\n extinfo.setScreenHeight(tags.screen_height);\n }\n if (tags.device_pixel_ratio) {\n extinfo.setScreenDensity(tags.device_pixel_ratio.toString());\n }\n\n const appData = new AppData();\n appData.setExtinfo(extinfo);\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n if (tags.advertising_id) {\n appData.setAdvertiserTrackingEnabled(true);\n }\n if (tags.install_referrer) {\n appData.setInstallReferrer(tags.install_referrer);\n }\n\n return appData;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getCustomData({ name, properties }: TrackEvent<any>) {\n const data = new CustomData();\n const [_, _name, fbEventProperties] = mapFBEvent(name, properties);\n const {\n value,\n currency,\n content_name,\n content_category,\n content_ids,\n contents,\n content_type,\n // order_id,\n predicted_ltv,\n num_items,\n search_string,\n status,\n // item_number,\n delivery_category,\n ...custom_properties\n } = fbEventProperties;\n if (value) data.setValue(value);\n if (currency) data.setCurrency(currency);\n if (content_name) data.setContentName(content_name);\n if (content_category) data.setContentCategory(content_category);\n if (content_ids) data.setContentIds(content_ids);\n if (contents)\n data.setContents(\n contents.map((c) => {\n const result = new Content().setId(c.id).setQuantity(c.quantity);\n if (c.item_price) result.setItemPrice(c.item_price);\n if (c.title) result.setTitle(c.title);\n if (c.description) result.setDescription(c.description);\n if (c.brand) result.setBrand(c.brand);\n if (c.category) result.setCategory(c.category);\n if (c.delivery_category) result.setDeliveryCategory(c.delivery_category);\n return result;\n })\n );\n if (content_type) data.setContentType(content_type);\n // if (order_id) data.setOrderId(order_id);\n if (predicted_ltv) data.setPredictedLtv(predicted_ltv);\n if (num_items) data.setNumItems(num_items);\n if (search_string) data.setSearchString(search_string);\n if (status) data.setStatus(status.toString());\n // if (item_number) data.setItemNumber(item_number);\n if (delivery_category) data.setDeliveryCategory(delivery_category);\n if (custom_properties) data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string\n) {\n const userData = getUserData(event.tags, data);\n const customData = getCustomData(event);\n const [_, eventName] = mapFBEvent(event.name, event.properties);\n const serverEvent = new ServerEvent()\n .setEventId(event.tags.idempotency_key ?? event.id.toString())\n .setEventName(eventName)\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n if (event.tags.source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n if (event.tags.source_url) {\n serverEvent.setEventSourceUrl(event.tags.source_url);\n }\n switch (event.tags.source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n break;\n }\n return serverEvent;\n}\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n if (IGNORE_EVENTS.includes(event.name)) return;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName);\n request.setEvents([fbEvent]);\n return request.execute();\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string\n) {\n const fbEvents = events\n .filter((event) => !IGNORE_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName));\n if (fbEvents.length === 0) return;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n return request.execute();\n}\n\nexport async function sendTestEvent(accessToken: string, pixelId: string, testEventCode: string) {\n const extinfo = new ExtendedDeviceInfo()\n .setExtInfoVersion('a2')\n .setAppPackageName('com.some.app')\n .setShortVersion('771')\n .setLongVersion('Version 7.7.1')\n .setOsVersion('10.1.1')\n .setDeviceModelName('OnePlus6')\n .setLocale('en_US')\n .setTimezoneAbbreviation('GMT-1')\n .setCarrier('TMobile')\n .setScreenWidth(1920)\n .setScreenHeight(1080)\n .setScreenDensity('2.00')\n .setCpuCoreCount(2)\n .setTotalDiskSpaceGb(128)\n .setFreeDiskSpaceGb(8)\n .setDeviceTimeZone('USA/New York');\n\n const userData = new UserData().setEmail('test@example.com');\n const appData = new AppData().setExtinfo(extinfo);\n const event = new ServerEvent()\n .setEventId(Math.round(Math.random() * 1000_000).toString())\n .setEventName('TestEvent')\n .setEventTime(Math.round(Date.now() / 1000))\n .setUserData(userData)\n .setAppData(appData)\n .setActionSource('app');\n\n const request = new EventRequest(accessToken, pixelId);\n request.setTestEventCode(testEventCode);\n request.setEvents([event]);\n return request.execute();\n}\n"],"mappings":"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","names":[]}
@@ -27,6 +27,7 @@ module.exports = __toCommonJS(reddit_conversions_api_exports);
27
27
  var import_rdt = require("../track/rdt.cjs");
28
28
  var import_fetch = require("../utils/fetch.cjs");
29
29
  var import_field = require("../utils/field.cjs");
30
+ var import_ignore_events = require("./ignore-events.cjs");
30
31
  function getServerEvent(event, data) {
31
32
  const { id, name, properties, tags } = event;
32
33
  const [type, params] = (0, import_rdt.mapRDTEvent)(name, properties, id);
@@ -58,12 +59,11 @@ function getServerEvent(event, data) {
58
59
  }
59
60
  };
60
61
  }
61
- var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
62
62
  async function sendEvents(accessToken, pixelId, events, data = {}, testId) {
63
63
  const dto = {
64
64
  data: {
65
65
  test_id: testId,
66
- events: events.filter((event) => !metrics.includes(event.name)).map((event) => getServerEvent(event, data))
66
+ events: events.filter((event) => !import_ignore_events.IGNORE_EVENTS.includes(event.name)).map((event) => getServerEvent(event, data))
67
67
  }
68
68
  };
69
69
  if (dto.data.events.length === 0) return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/reddit-conversions-api.ts"],"sourcesContent":["import { mapRDTEvent, mapServerStandardEvent } from '../track/rdt';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport type { ServerStandardEvent } from '../track/rdt';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\n/**\n * https://ads-api.reddit.com/docs/v3/operations/Post%20Conversion%20Events\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport interface RedditEvent {\n /** Match keys: Share user identifiers to match conversions to a Reddit ad engagement. */\n click_id?: string;\n\n /** Unix epoch timestamp in milliseconds, event_at can't be older than seven days. */\n event_at: number;\n\n action_source: 'WEBSITE' | 'APP' | string;\n\n type: {\n tracking_type: ServerStandardEvent | 'CUSTOM';\n custom_event_name?: string;\n };\n\n /**\n * Event metadata\n * Share as much additional information about your conversion event as you'd like. If you're\n * using the Conversions API with the pixel, conversion_id is required for deduplication.\n */\n metadata?: {\n conversion_id?: string;\n currency?: string; // ISO 4217 3-letter currency code\n item_count?: number;\n value?: number;\n products?: { id: string; name?: string; category?: string }[];\n };\n\n user?: {\n email?: string;\n external_id?: string;\n ip_address?: string;\n phone_number?: string;\n user_agent?: string;\n\n /** The Identifier for Advertisers (IDFA) of the user's Apple device. */\n idfa?: string;\n\n /** The Android Advertising ID (AAID) of the user's Android device. */\n aaid?: string;\n /**\n * The value from the first-party Pixel _rdt_uuid cookie on your domain. Note that it is in\n * the {timestamp}.{uuid} format. You may use the full value or just the UUID portion.\n * Example: 1684189007728.7c73f2ae-a433-4d7b-9838-f467da98f48e\n */\n uuid?: string;\n\n screen_dimensions?: { width: number; height: number };\n\n /**\n * A structure of data processing options to specify the processing type for the event\n * https://business.reddithelp.com/s/article/Limited-Data-Use\n */\n data_processing_options?: {\n country: string;\n region: string;\n modes: string[] | ['LDU'];\n };\n };\n}\n\nexport interface CreateRedditEventDTO {\n data: { test_id?: string; events: RedditEvent[] };\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData\n): RedditEvent {\n const { id, name, properties, tags } = event;\n const [type, params] = mapRDTEvent(name, properties, id);\n\n return {\n click_id: tags.rdt_cid,\n event_at: Date.now(),\n action_source: tags.source === 'web' ? 'WEBSITE' : tags.source === 'app' ? 'APP' : 'UNKNOWN',\n type: {\n tracking_type: type === 'Custom' ? 'CUSTOM' : mapServerStandardEvent(type),\n custom_event_name: type === 'Custom' ? params.customEventName : undefined,\n },\n metadata: {\n conversion_id: id,\n currency:\n 'currency' in params && typeof params.currency === 'string'\n ? params.currency.toUpperCase()\n : undefined,\n item_count:\n 'itemCount' in params && typeof params.itemCount === 'number'\n ? params.itemCount\n : undefined,\n value: 'value' in params && typeof params.value === 'number' ? params.value : undefined,\n products:\n 'products' in params && Array.isArray(params.products) && params.products.length > 0\n ? params.products\n : undefined,\n },\n user: {\n email: getFirst(data.email),\n external_id: data.user_id,\n ip_address: data.ip_address,\n phone_number: getFirst(data.phone_number),\n user_agent: data.user_agent,\n idfa: tags.platform === 'ios' ? tags.advertising_id : undefined,\n aaid: tags.platform === 'android' ? tags.advertising_id : undefined,\n uuid: tags.rdt_uuid,\n screen_dimensions:\n tags.screen_width && tags.screen_height\n ? { width: tags.screen_width, height: tags.screen_height }\n : undefined,\n },\n };\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n testId?: string\n) {\n const dto: CreateRedditEventDTO = {\n data: {\n test_id: testId,\n events: events\n .filter((event) => !metrics.includes(event.name))\n .map((event) => getServerEvent(event, data)),\n },\n };\n\n if (dto.data.events.length === 0) return;\n\n try {\n const response = await fetch(\n `https://ads-api.reddit.com/api/v3/pixels/${pixelId}/conversion_events`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: JSON.stringify(dto),\n }\n );\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send Reddit conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send Reddit conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoD;AACpD,mBAAsB;AACtB,mBAAyB;AAwElB,SAAS,eAEd,OACA,MACa;AACb,QAAM,EAAE,IAAI,MAAM,YAAY,KAAK,IAAI;AACvC,QAAM,CAAC,MAAM,MAAM,QAAI,wBAAY,MAAM,YAAY,EAAE;AAEvD,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,UAAU,KAAK,IAAI;AAAA,IACnB,eAAe,KAAK,WAAW,QAAQ,YAAY,KAAK,WAAW,QAAQ,QAAQ;AAAA,IACnF,MAAM;AAAA,MACJ,eAAe,SAAS,WAAW,eAAW,mCAAuB,IAAI;AAAA,MACzE,mBAAmB,SAAS,WAAW,OAAO,kBAAkB;AAAA,IAClE;AAAA,IACA,UAAU;AAAA,MACR,eAAe;AAAA,MACf,UACE,cAAc,UAAU,OAAO,OAAO,aAAa,WAC/C,OAAO,SAAS,YAAY,IAC5B;AAAA,MACN,YACE,eAAe,UAAU,OAAO,OAAO,cAAc,WACjD,OAAO,YACP;AAAA,MACN,OAAO,WAAW,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;AAAA,MAC9E,UACE,cAAc,UAAU,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IAC/E,OAAO,WACP;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACJ,WAAO,uBAAS,KAAK,KAAK;AAAA,MAC1B,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,kBAAc,uBAAS,KAAK,YAAY;AAAA,MACxC,YAAY,KAAK;AAAA,MACjB,MAAM,KAAK,aAAa,QAAQ,KAAK,iBAAiB;AAAA,MACtD,MAAM,KAAK,aAAa,YAAY,KAAK,iBAAiB;AAAA,MAC1D,MAAM,KAAK;AAAA,MACX,mBACE,KAAK,gBAAgB,KAAK,gBACtB,EAAE,OAAO,KAAK,cAAc,QAAQ,KAAK,cAAc,IACvD;AAAA,IACR;AAAA,EACF;AACF;AAEA,IAAM,UAAU,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAE1D,eAAsB,WACpB,aACA,SAEA,QACA,OAAyB,CAAC,GAC1B,QACA;AACA,QAAM,MAA4B;AAAA,IAChC,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,OACL,OAAO,CAAC,UAAU,CAAC,QAAQ,SAAS,MAAM,IAAI,CAAC,EAC/C,IAAI,CAAC,UAAU,eAAe,OAAO,IAAI,CAAC;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,IAAI,KAAK,OAAO,WAAW,EAAG;AAElC,MAAI;AACF,UAAM,WAAW,UAAM;AAAA,MACrB,4CAA4C,OAAO;AAAA,MACnD;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,eAAe,UAAU,WAAW;AAAA,QACtC;AAAA,QACA,MAAM,KAAK,UAAU,GAAG;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,6CAA6C,MAAM,WAAW,OAAO,EAAE;AAAA,EACvF,SAAS,OAAO;AACd,YAAQ,MAAM,oDAAoD,KAAK;AAAA,EACzE;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/server/reddit-conversions-api.ts"],"sourcesContent":["import { mapRDTEvent, mapServerStandardEvent } from '../track/rdt';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport { IGNORE_EVENTS } from './ignore-events';\nimport type { ServerStandardEvent } from '../track/rdt';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\n/**\n * https://ads-api.reddit.com/docs/v3/operations/Post%20Conversion%20Events\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport interface RedditEvent {\n /** Match keys: Share user identifiers to match conversions to a Reddit ad engagement. */\n click_id?: string;\n\n /** Unix epoch timestamp in milliseconds, event_at can't be older than seven days. */\n event_at: number;\n\n action_source: 'WEBSITE' | 'APP' | string;\n\n type: {\n tracking_type: ServerStandardEvent | 'CUSTOM';\n custom_event_name?: string;\n };\n\n /**\n * Event metadata\n * Share as much additional information about your conversion event as you'd like. If you're\n * using the Conversions API with the pixel, conversion_id is required for deduplication.\n */\n metadata?: {\n conversion_id?: string;\n currency?: string; // ISO 4217 3-letter currency code\n item_count?: number;\n value?: number;\n products?: { id: string; name?: string; category?: string }[];\n };\n\n user?: {\n email?: string;\n external_id?: string;\n ip_address?: string;\n phone_number?: string;\n user_agent?: string;\n\n /** The Identifier for Advertisers (IDFA) of the user's Apple device. */\n idfa?: string;\n\n /** The Android Advertising ID (AAID) of the user's Android device. */\n aaid?: string;\n /**\n * The value from the first-party Pixel _rdt_uuid cookie on your domain. Note that it is in\n * the {timestamp}.{uuid} format. You may use the full value or just the UUID portion.\n * Example: 1684189007728.7c73f2ae-a433-4d7b-9838-f467da98f48e\n */\n uuid?: string;\n\n screen_dimensions?: { width: number; height: number };\n\n /**\n * A structure of data processing options to specify the processing type for the event\n * https://business.reddithelp.com/s/article/Limited-Data-Use\n */\n data_processing_options?: {\n country: string;\n region: string;\n modes: string[] | ['LDU'];\n };\n };\n}\n\nexport interface CreateRedditEventDTO {\n data: { test_id?: string; events: RedditEvent[] };\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData\n): RedditEvent {\n const { id, name, properties, tags } = event;\n const [type, params] = mapRDTEvent(name, properties, id);\n\n return {\n click_id: tags.rdt_cid,\n event_at: Date.now(),\n action_source: tags.source === 'web' ? 'WEBSITE' : tags.source === 'app' ? 'APP' : 'UNKNOWN',\n type: {\n tracking_type: type === 'Custom' ? 'CUSTOM' : mapServerStandardEvent(type),\n custom_event_name: type === 'Custom' ? params.customEventName : undefined,\n },\n metadata: {\n conversion_id: id,\n currency:\n 'currency' in params && typeof params.currency === 'string'\n ? params.currency.toUpperCase()\n : undefined,\n item_count:\n 'itemCount' in params && typeof params.itemCount === 'number'\n ? params.itemCount\n : undefined,\n value: 'value' in params && typeof params.value === 'number' ? params.value : undefined,\n products:\n 'products' in params && Array.isArray(params.products) && params.products.length > 0\n ? params.products\n : undefined,\n },\n user: {\n email: getFirst(data.email),\n external_id: data.user_id,\n ip_address: data.ip_address,\n phone_number: getFirst(data.phone_number),\n user_agent: data.user_agent,\n idfa: tags.platform === 'ios' ? tags.advertising_id : undefined,\n aaid: tags.platform === 'android' ? tags.advertising_id : undefined,\n uuid: tags.rdt_uuid,\n screen_dimensions:\n tags.screen_width && tags.screen_height\n ? { width: tags.screen_width, height: tags.screen_height }\n : undefined,\n },\n };\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n testId?: string\n) {\n const dto: CreateRedditEventDTO = {\n data: {\n test_id: testId,\n events: events\n .filter((event) => !IGNORE_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data)),\n },\n };\n\n if (dto.data.events.length === 0) return;\n\n try {\n const response = await fetch(\n `https://ads-api.reddit.com/api/v3/pixels/${pixelId}/conversion_events`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: JSON.stringify(dto),\n }\n );\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send Reddit conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send Reddit conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoD;AACpD,mBAAsB;AACtB,mBAAyB;AACzB,2BAA8B;AAwEvB,SAAS,eAEd,OACA,MACa;AACb,QAAM,EAAE,IAAI,MAAM,YAAY,KAAK,IAAI;AACvC,QAAM,CAAC,MAAM,MAAM,QAAI,wBAAY,MAAM,YAAY,EAAE;AAEvD,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,UAAU,KAAK,IAAI;AAAA,IACnB,eAAe,KAAK,WAAW,QAAQ,YAAY,KAAK,WAAW,QAAQ,QAAQ;AAAA,IACnF,MAAM;AAAA,MACJ,eAAe,SAAS,WAAW,eAAW,mCAAuB,IAAI;AAAA,MACzE,mBAAmB,SAAS,WAAW,OAAO,kBAAkB;AAAA,IAClE;AAAA,IACA,UAAU;AAAA,MACR,eAAe;AAAA,MACf,UACE,cAAc,UAAU,OAAO,OAAO,aAAa,WAC/C,OAAO,SAAS,YAAY,IAC5B;AAAA,MACN,YACE,eAAe,UAAU,OAAO,OAAO,cAAc,WACjD,OAAO,YACP;AAAA,MACN,OAAO,WAAW,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;AAAA,MAC9E,UACE,cAAc,UAAU,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IAC/E,OAAO,WACP;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACJ,WAAO,uBAAS,KAAK,KAAK;AAAA,MAC1B,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,kBAAc,uBAAS,KAAK,YAAY;AAAA,MACxC,YAAY,KAAK;AAAA,MACjB,MAAM,KAAK,aAAa,QAAQ,KAAK,iBAAiB;AAAA,MACtD,MAAM,KAAK,aAAa,YAAY,KAAK,iBAAiB;AAAA,MAC1D,MAAM,KAAK;AAAA,MACX,mBACE,KAAK,gBAAgB,KAAK,gBACtB,EAAE,OAAO,KAAK,cAAc,QAAQ,KAAK,cAAc,IACvD;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAsB,WACpB,aACA,SAEA,QACA,OAAyB,CAAC,GAC1B,QACA;AACA,QAAM,MAA4B;AAAA,IAChC,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,OACL,OAAO,CAAC,UAAU,CAAC,mCAAc,SAAS,MAAM,IAAI,CAAC,EACrD,IAAI,CAAC,UAAU,eAAe,OAAO,IAAI,CAAC;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,IAAI,KAAK,OAAO,WAAW,EAAG;AAElC,MAAI;AACF,UAAM,WAAW,UAAM;AAAA,MACrB,4CAA4C,OAAO;AAAA,MACnD;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,eAAe,UAAU,WAAW;AAAA,QACtC;AAAA,QACA,MAAM,KAAK,UAAU,GAAG;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,6CAA6C,MAAM,WAAW,OAAO,EAAE;AAAA,EACvF,SAAS,OAAO;AACd,YAAQ,MAAM,oDAAoD,KAAK;AAAA,EACzE;AACF;","names":[]}
@@ -2,6 +2,7 @@
2
2
  import { mapRDTEvent, mapServerStandardEvent } from "../track/rdt.mjs";
3
3
  import { fetch } from "../utils/fetch.mjs";
4
4
  import { getFirst } from "../utils/field.mjs";
5
+ import { IGNORE_EVENTS } from "./ignore-events.mjs";
5
6
  function getServerEvent(event, data) {
6
7
  const { id, name, properties, tags } = event;
7
8
  const [type, params] = mapRDTEvent(name, properties, id);
@@ -33,12 +34,11 @@ function getServerEvent(event, data) {
33
34
  }
34
35
  };
35
36
  }
36
- var metrics = ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"];
37
37
  async function sendEvents(accessToken, pixelId, events, data = {}, testId) {
38
38
  const dto = {
39
39
  data: {
40
40
  test_id: testId,
41
- events: events.filter((event) => !metrics.includes(event.name)).map((event) => getServerEvent(event, data))
41
+ events: events.filter((event) => !IGNORE_EVENTS.includes(event.name)).map((event) => getServerEvent(event, data))
42
42
  }
43
43
  };
44
44
  if (dto.data.events.length === 0) return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/reddit-conversions-api.ts"],"sourcesContent":["import { mapRDTEvent, mapServerStandardEvent } from '../track/rdt';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport type { ServerStandardEvent } from '../track/rdt';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\n/**\n * https://ads-api.reddit.com/docs/v3/operations/Post%20Conversion%20Events\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport interface RedditEvent {\n /** Match keys: Share user identifiers to match conversions to a Reddit ad engagement. */\n click_id?: string;\n\n /** Unix epoch timestamp in milliseconds, event_at can't be older than seven days. */\n event_at: number;\n\n action_source: 'WEBSITE' | 'APP' | string;\n\n type: {\n tracking_type: ServerStandardEvent | 'CUSTOM';\n custom_event_name?: string;\n };\n\n /**\n * Event metadata\n * Share as much additional information about your conversion event as you'd like. If you're\n * using the Conversions API with the pixel, conversion_id is required for deduplication.\n */\n metadata?: {\n conversion_id?: string;\n currency?: string; // ISO 4217 3-letter currency code\n item_count?: number;\n value?: number;\n products?: { id: string; name?: string; category?: string }[];\n };\n\n user?: {\n email?: string;\n external_id?: string;\n ip_address?: string;\n phone_number?: string;\n user_agent?: string;\n\n /** The Identifier for Advertisers (IDFA) of the user's Apple device. */\n idfa?: string;\n\n /** The Android Advertising ID (AAID) of the user's Android device. */\n aaid?: string;\n /**\n * The value from the first-party Pixel _rdt_uuid cookie on your domain. Note that it is in\n * the {timestamp}.{uuid} format. You may use the full value or just the UUID portion.\n * Example: 1684189007728.7c73f2ae-a433-4d7b-9838-f467da98f48e\n */\n uuid?: string;\n\n screen_dimensions?: { width: number; height: number };\n\n /**\n * A structure of data processing options to specify the processing type for the event\n * https://business.reddithelp.com/s/article/Limited-Data-Use\n */\n data_processing_options?: {\n country: string;\n region: string;\n modes: string[] | ['LDU'];\n };\n };\n}\n\nexport interface CreateRedditEventDTO {\n data: { test_id?: string; events: RedditEvent[] };\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData\n): RedditEvent {\n const { id, name, properties, tags } = event;\n const [type, params] = mapRDTEvent(name, properties, id);\n\n return {\n click_id: tags.rdt_cid,\n event_at: Date.now(),\n action_source: tags.source === 'web' ? 'WEBSITE' : tags.source === 'app' ? 'APP' : 'UNKNOWN',\n type: {\n tracking_type: type === 'Custom' ? 'CUSTOM' : mapServerStandardEvent(type),\n custom_event_name: type === 'Custom' ? params.customEventName : undefined,\n },\n metadata: {\n conversion_id: id,\n currency:\n 'currency' in params && typeof params.currency === 'string'\n ? params.currency.toUpperCase()\n : undefined,\n item_count:\n 'itemCount' in params && typeof params.itemCount === 'number'\n ? params.itemCount\n : undefined,\n value: 'value' in params && typeof params.value === 'number' ? params.value : undefined,\n products:\n 'products' in params && Array.isArray(params.products) && params.products.length > 0\n ? params.products\n : undefined,\n },\n user: {\n email: getFirst(data.email),\n external_id: data.user_id,\n ip_address: data.ip_address,\n phone_number: getFirst(data.phone_number),\n user_agent: data.user_agent,\n idfa: tags.platform === 'ios' ? tags.advertising_id : undefined,\n aaid: tags.platform === 'android' ? tags.advertising_id : undefined,\n uuid: tags.rdt_uuid,\n screen_dimensions:\n tags.screen_width && tags.screen_height\n ? { width: tags.screen_width, height: tags.screen_height }\n : undefined,\n },\n };\n}\n\nconst metrics = ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'];\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n testId?: string\n) {\n const dto: CreateRedditEventDTO = {\n data: {\n test_id: testId,\n events: events\n .filter((event) => !metrics.includes(event.name))\n .map((event) => getServerEvent(event, data)),\n },\n };\n\n if (dto.data.events.length === 0) return;\n\n try {\n const response = await fetch(\n `https://ads-api.reddit.com/api/v3/pixels/${pixelId}/conversion_events`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: JSON.stringify(dto),\n }\n );\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send Reddit conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send Reddit conversion, network error:', error);\n }\n}\n"],"mappings":";AAAA,SAAS,aAAa,8BAA8B;AACpD,SAAS,aAAa;AACtB,SAAS,gBAAgB;AAwElB,SAAS,eAEd,OACA,MACa;AACb,QAAM,EAAE,IAAI,MAAM,YAAY,KAAK,IAAI;AACvC,QAAM,CAAC,MAAM,MAAM,IAAI,YAAY,MAAM,YAAY,EAAE;AAEvD,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,UAAU,KAAK,IAAI;AAAA,IACnB,eAAe,KAAK,WAAW,QAAQ,YAAY,KAAK,WAAW,QAAQ,QAAQ;AAAA,IACnF,MAAM;AAAA,MACJ,eAAe,SAAS,WAAW,WAAW,uBAAuB,IAAI;AAAA,MACzE,mBAAmB,SAAS,WAAW,OAAO,kBAAkB;AAAA,IAClE;AAAA,IACA,UAAU;AAAA,MACR,eAAe;AAAA,MACf,UACE,cAAc,UAAU,OAAO,OAAO,aAAa,WAC/C,OAAO,SAAS,YAAY,IAC5B;AAAA,MACN,YACE,eAAe,UAAU,OAAO,OAAO,cAAc,WACjD,OAAO,YACP;AAAA,MACN,OAAO,WAAW,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;AAAA,MAC9E,UACE,cAAc,UAAU,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IAC/E,OAAO,WACP;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACJ,OAAO,SAAS,KAAK,KAAK;AAAA,MAC1B,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,cAAc,SAAS,KAAK,YAAY;AAAA,MACxC,YAAY,KAAK;AAAA,MACjB,MAAM,KAAK,aAAa,QAAQ,KAAK,iBAAiB;AAAA,MACtD,MAAM,KAAK,aAAa,YAAY,KAAK,iBAAiB;AAAA,MAC1D,MAAM,KAAK;AAAA,MACX,mBACE,KAAK,gBAAgB,KAAK,gBACtB,EAAE,OAAO,KAAK,cAAc,QAAQ,KAAK,cAAc,IACvD;AAAA,IACR;AAAA,EACF;AACF;AAEA,IAAM,UAAU,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAE1D,eAAsB,WACpB,aACA,SAEA,QACA,OAAyB,CAAC,GAC1B,QACA;AACA,QAAM,MAA4B;AAAA,IAChC,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,OACL,OAAO,CAAC,UAAU,CAAC,QAAQ,SAAS,MAAM,IAAI,CAAC,EAC/C,IAAI,CAAC,UAAU,eAAe,OAAO,IAAI,CAAC;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,IAAI,KAAK,OAAO,WAAW,EAAG;AAElC,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,4CAA4C,OAAO;AAAA,MACnD;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,eAAe,UAAU,WAAW;AAAA,QACtC;AAAA,QACA,MAAM,KAAK,UAAU,GAAG;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,6CAA6C,MAAM,WAAW,OAAO,EAAE;AAAA,EACvF,SAAS,OAAO;AACd,YAAQ,MAAM,oDAAoD,KAAK;AAAA,EACzE;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/server/reddit-conversions-api.ts"],"sourcesContent":["import { mapRDTEvent, mapServerStandardEvent } from '../track/rdt';\nimport { fetch } from '../utils/fetch';\nimport { getFirst } from '../utils/field';\nimport { IGNORE_EVENTS } from './ignore-events';\nimport type { ServerStandardEvent } from '../track/rdt';\nimport type { TrackEvent, UserProvidedData } from '../track/types';\n\n/**\n * https://ads-api.reddit.com/docs/v3/operations/Post%20Conversion%20Events\n * https://business.reddithelp.com/s/article/map-a-catalog-to-a-signal-source\n */\nexport interface RedditEvent {\n /** Match keys: Share user identifiers to match conversions to a Reddit ad engagement. */\n click_id?: string;\n\n /** Unix epoch timestamp in milliseconds, event_at can't be older than seven days. */\n event_at: number;\n\n action_source: 'WEBSITE' | 'APP' | string;\n\n type: {\n tracking_type: ServerStandardEvent | 'CUSTOM';\n custom_event_name?: string;\n };\n\n /**\n * Event metadata\n * Share as much additional information about your conversion event as you'd like. If you're\n * using the Conversions API with the pixel, conversion_id is required for deduplication.\n */\n metadata?: {\n conversion_id?: string;\n currency?: string; // ISO 4217 3-letter currency code\n item_count?: number;\n value?: number;\n products?: { id: string; name?: string; category?: string }[];\n };\n\n user?: {\n email?: string;\n external_id?: string;\n ip_address?: string;\n phone_number?: string;\n user_agent?: string;\n\n /** The Identifier for Advertisers (IDFA) of the user's Apple device. */\n idfa?: string;\n\n /** The Android Advertising ID (AAID) of the user's Android device. */\n aaid?: string;\n /**\n * The value from the first-party Pixel _rdt_uuid cookie on your domain. Note that it is in\n * the {timestamp}.{uuid} format. You may use the full value or just the UUID portion.\n * Example: 1684189007728.7c73f2ae-a433-4d7b-9838-f467da98f48e\n */\n uuid?: string;\n\n screen_dimensions?: { width: number; height: number };\n\n /**\n * A structure of data processing options to specify the processing type for the event\n * https://business.reddithelp.com/s/article/Limited-Data-Use\n */\n data_processing_options?: {\n country: string;\n region: string;\n modes: string[] | ['LDU'];\n };\n };\n}\n\nexport interface CreateRedditEventDTO {\n data: { test_id?: string; events: RedditEvent[] };\n}\n\nexport function getServerEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData\n): RedditEvent {\n const { id, name, properties, tags } = event;\n const [type, params] = mapRDTEvent(name, properties, id);\n\n return {\n click_id: tags.rdt_cid,\n event_at: Date.now(),\n action_source: tags.source === 'web' ? 'WEBSITE' : tags.source === 'app' ? 'APP' : 'UNKNOWN',\n type: {\n tracking_type: type === 'Custom' ? 'CUSTOM' : mapServerStandardEvent(type),\n custom_event_name: type === 'Custom' ? params.customEventName : undefined,\n },\n metadata: {\n conversion_id: id,\n currency:\n 'currency' in params && typeof params.currency === 'string'\n ? params.currency.toUpperCase()\n : undefined,\n item_count:\n 'itemCount' in params && typeof params.itemCount === 'number'\n ? params.itemCount\n : undefined,\n value: 'value' in params && typeof params.value === 'number' ? params.value : undefined,\n products:\n 'products' in params && Array.isArray(params.products) && params.products.length > 0\n ? params.products\n : undefined,\n },\n user: {\n email: getFirst(data.email),\n external_id: data.user_id,\n ip_address: data.ip_address,\n phone_number: getFirst(data.phone_number),\n user_agent: data.user_agent,\n idfa: tags.platform === 'ios' ? tags.advertising_id : undefined,\n aaid: tags.platform === 'android' ? tags.advertising_id : undefined,\n uuid: tags.rdt_uuid,\n screen_dimensions:\n tags.screen_width && tags.screen_height\n ? { width: tags.screen_width, height: tags.screen_height }\n : undefined,\n },\n };\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n testId?: string\n) {\n const dto: CreateRedditEventDTO = {\n data: {\n test_id: testId,\n events: events\n .filter((event) => !IGNORE_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data)),\n },\n };\n\n if (dto.data.events.length === 0) return;\n\n try {\n const response = await fetch(\n `https://ads-api.reddit.com/api/v3/pixels/${pixelId}/conversion_events`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: JSON.stringify(dto),\n }\n );\n if (response.ok) return;\n const { status } = response;\n const message = await response.text();\n console.error(`Failed to send Reddit conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send Reddit conversion, network error:', error);\n }\n}\n"],"mappings":";AAAA,SAAS,aAAa,8BAA8B;AACpD,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAwEvB,SAAS,eAEd,OACA,MACa;AACb,QAAM,EAAE,IAAI,MAAM,YAAY,KAAK,IAAI;AACvC,QAAM,CAAC,MAAM,MAAM,IAAI,YAAY,MAAM,YAAY,EAAE;AAEvD,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,UAAU,KAAK,IAAI;AAAA,IACnB,eAAe,KAAK,WAAW,QAAQ,YAAY,KAAK,WAAW,QAAQ,QAAQ;AAAA,IACnF,MAAM;AAAA,MACJ,eAAe,SAAS,WAAW,WAAW,uBAAuB,IAAI;AAAA,MACzE,mBAAmB,SAAS,WAAW,OAAO,kBAAkB;AAAA,IAClE;AAAA,IACA,UAAU;AAAA,MACR,eAAe;AAAA,MACf,UACE,cAAc,UAAU,OAAO,OAAO,aAAa,WAC/C,OAAO,SAAS,YAAY,IAC5B;AAAA,MACN,YACE,eAAe,UAAU,OAAO,OAAO,cAAc,WACjD,OAAO,YACP;AAAA,MACN,OAAO,WAAW,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;AAAA,MAC9E,UACE,cAAc,UAAU,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IAC/E,OAAO,WACP;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACJ,OAAO,SAAS,KAAK,KAAK;AAAA,MAC1B,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,cAAc,SAAS,KAAK,YAAY;AAAA,MACxC,YAAY,KAAK;AAAA,MACjB,MAAM,KAAK,aAAa,QAAQ,KAAK,iBAAiB;AAAA,MACtD,MAAM,KAAK,aAAa,YAAY,KAAK,iBAAiB;AAAA,MAC1D,MAAM,KAAK;AAAA,MACX,mBACE,KAAK,gBAAgB,KAAK,gBACtB,EAAE,OAAO,KAAK,cAAc,QAAQ,KAAK,cAAc,IACvD;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAsB,WACpB,aACA,SAEA,QACA,OAAyB,CAAC,GAC1B,QACA;AACA,QAAM,MAA4B;AAAA,IAChC,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,OACL,OAAO,CAAC,UAAU,CAAC,cAAc,SAAS,MAAM,IAAI,CAAC,EACrD,IAAI,CAAC,UAAU,eAAe,OAAO,IAAI,CAAC;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,IAAI,KAAK,OAAO,WAAW,EAAG;AAElC,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,4CAA4C,OAAO;AAAA,MACnD;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,eAAe,UAAU,WAAW;AAAA,QACtC;AAAA,QACA,MAAM,KAAK,UAAU,GAAG;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,SAAS,GAAI;AACjB,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAQ,MAAM,6CAA6C,MAAM,WAAW,OAAO,EAAE;AAAA,EACvF,SAAS,OAAO;AACd,YAAQ,MAAM,oDAAoD,KAAK;AAAA,EACzE;AACF;","names":[]}