@shware/analytics 7.5.0 → 7.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/schema/index.cjs +7 -0
  2. package/dist/schema/index.cjs.map +1 -1
  3. package/dist/schema/index.d.cts +4 -0
  4. package/dist/schema/index.d.cts.map +1 -1
  5. package/dist/schema/index.d.mts +4 -0
  6. package/dist/schema/index.d.mts.map +1 -1
  7. package/dist/schema/index.mjs +7 -0
  8. package/dist/schema/index.mjs.map +1 -1
  9. package/dist/server/meta-conversions-api.cjs +3 -1
  10. package/dist/server/meta-conversions-api.cjs.map +1 -1
  11. package/dist/server/meta-conversions-api.d.cts.map +1 -1
  12. package/dist/server/meta-conversions-api.d.mts.map +1 -1
  13. package/dist/server/meta-conversions-api.mjs +3 -1
  14. package/dist/server/meta-conversions-api.mjs.map +1 -1
  15. package/dist/server/openai-conversions-api.cjs +2 -1
  16. package/dist/server/openai-conversions-api.cjs.map +1 -1
  17. package/dist/server/openai-conversions-api.d.cts.map +1 -1
  18. package/dist/server/openai-conversions-api.d.mts.map +1 -1
  19. package/dist/server/openai-conversions-api.mjs +2 -1
  20. package/dist/server/openai-conversions-api.mjs.map +1 -1
  21. package/dist/server/page-location.cjs +22 -0
  22. package/dist/server/page-location.cjs.map +1 -0
  23. package/dist/server/page-location.d.cts +19 -0
  24. package/dist/server/page-location.d.cts.map +1 -0
  25. package/dist/server/page-location.d.mts +19 -0
  26. package/dist/server/page-location.d.mts.map +1 -0
  27. package/dist/server/page-location.mjs +21 -0
  28. package/dist/server/page-location.mjs.map +1 -0
  29. package/dist/track/types.d.cts +6 -0
  30. package/dist/track/types.d.cts.map +1 -1
  31. package/dist/track/types.d.mts +6 -0
  32. package/dist/track/types.d.mts.map +1 -1
  33. package/package.json +1 -1
@@ -76,6 +76,13 @@ const tagsSchema = (0, zod_mini.object)({
76
76
  page_location: (0, zod_mini.optional)((0, zod_mini.string)()),
77
77
  page_referrer: (0, zod_mini.optional)((0, zod_mini.string)()),
78
78
  page_title: (0, zod_mini.optional)((0, zod_mini.string)()),
79
+ /**
80
+ * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients
81
+ * still on an older SDK are not stripped of their page URL at this boundary — a browser
82
+ * bundle stays cached long after a backend deploys. Remove once those clients are gone;
83
+ * `pageLocation` in `server/page-location.ts` is the only reader.
84
+ */
85
+ source_url: (0, zod_mini.optional)((0, zod_mini.string)()),
79
86
  advertising_id: (0, zod_mini.optional)((0, zod_mini.string)()),
80
87
  install_referrer: (0, zod_mini.optional)((0, zod_mini.string)()),
81
88
  fbc: (0, zod_mini.optional)((0, zod_mini.string)()),
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["iso"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n site_source_name: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["iso"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n site_source_name: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
@@ -23,6 +23,7 @@ declare const tagsSchema: z.ZodMiniObject<{
23
23
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
24
24
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
25
25
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
26
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
26
27
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
27
28
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
28
29
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -102,6 +103,7 @@ declare const createTrackEventSchema: z.ZodMiniArray<z.ZodMiniObject<{
102
103
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
103
104
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
104
105
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
106
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
105
107
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
106
108
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
107
109
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -179,6 +181,7 @@ declare const createVisitorSchema: z.ZodMiniObject<{
179
181
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
180
182
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
181
183
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
184
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
182
185
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
183
186
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
184
187
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -296,6 +299,7 @@ declare const updateVisitorSchema: z.ZodMiniObject<{
296
299
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
297
300
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
298
301
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
302
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
299
303
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
300
304
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
301
305
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;cAEW,sBAAoB,EAAA;;;;GAI/B,EAAA,KAAA;;;;;cAWW,kBAAgB,EAAA;;;;;;;;;;;GA+C3B,EAAA,KAAA;KAEU,sBAAsB,EAAE,cAAc;KACtC,oBAAoB,EAAE,cAAc;KACpC,gBAAgB,EAAE,cAAc;KAChC,mBAAmB,EAAE,cAAc;KACnC,sBAAsB,EAAE,cAAc;KACtC,mBAAmB,EAAE,cAAc"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6ErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;cAEW,sBAAoB,EAAA;;;;GAI/B,EAAA,KAAA;;;;;cAWW,kBAAgB,EAAA;;;;;;;;;;;GA+C3B,EAAA,KAAA;KAEU,sBAAsB,EAAE,cAAc;KACtC,oBAAoB,EAAE,cAAc;KACpC,gBAAgB,EAAE,cAAc;KAChC,mBAAmB,EAAE,cAAc;KACnC,sBAAsB,EAAE,cAAc;KACtC,mBAAmB,EAAE,cAAc"}
@@ -23,6 +23,7 @@ declare const tagsSchema: z.ZodMiniObject<{
23
23
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
24
24
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
25
25
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
26
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
26
27
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
27
28
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
28
29
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -102,6 +103,7 @@ declare const createTrackEventSchema: z.ZodMiniArray<z.ZodMiniObject<{
102
103
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
103
104
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
104
105
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
106
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
105
107
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
106
108
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
107
109
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -179,6 +181,7 @@ declare const createVisitorSchema: z.ZodMiniObject<{
179
181
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
180
182
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
181
183
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
184
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
182
185
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
183
186
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
184
187
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -296,6 +299,7 @@ declare const updateVisitorSchema: z.ZodMiniObject<{
296
299
  page_location: z.ZodMiniOptional<z.ZodMiniString<string>>;
297
300
  page_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
298
301
  page_title: z.ZodMiniOptional<z.ZodMiniString<string>>;
302
+ source_url: z.ZodMiniOptional<z.ZodMiniString<string>>;
299
303
  advertising_id: z.ZodMiniOptional<z.ZodMiniString<string>>;
300
304
  install_referrer: z.ZodMiniOptional<z.ZodMiniString<string>>;
301
305
  fbc: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;cAEW,sBAAoB,EAAA;;;;GAI/B,EAAA,KAAA;;;;;cAWW,kBAAgB,EAAA;;;;;;;;;;;GA+C3B,EAAA,KAAA;KAEU,sBAAsB,EAAE,cAAc;KACtC,oBAAoB,EAAE,cAAc;KACpC,gBAAgB,EAAE,cAAc;KAChC,mBAAmB,EAAE,cAAc;KACnC,sBAAsB,EAAE,cAAc;KACtC,mBAAmB,EAAE,cAAc"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schema/index.ts"],"mappings":";;cAmFa;cAUA;cAEA,YAAU,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6ErB,EAAA,KAAA;cAEW,kBAAgB,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,uBAAA,EAAA,YAAA,EAAA,uBAAA,EAAA,mCAAA,EAAA,uBAAA,EAAA,yBAAA,EAAA,gBAAA,EAAA,iBAAA,kDAAA,qDAAA,EAAA,iBAAA,oDAAA,yDAAA,EAAA,iBAAA,2CAAA,4DAAA,2CAAA;cAehB,wBAAsB,EAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWE,EAAA,KAAA;cAExB,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;;;;;;;;;;;cA6BW,wBAAsB,EAAA;;;;;;;;;;;;;;;;;;;;GAIjC,EAAA,KAAA;cAEW,qBAAmB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAM9B,EAAA,KAAA;cAEW,sBAAoB,EAAA;;;;GAI/B,EAAA,KAAA;;;;;cAWW,kBAAgB,EAAA;;;;;;;;;;;GA+C3B,EAAA,KAAA;KAEU,sBAAsB,EAAE,cAAc;KACtC,oBAAoB,EAAE,cAAc;KACpC,gBAAgB,EAAE,cAAc;KAChC,mBAAmB,EAAE,cAAc;KACnC,sBAAsB,EAAE,cAAc;KACtC,mBAAmB,EAAE,cAAc"}
@@ -75,6 +75,13 @@ const tagsSchema = object({
75
75
  page_location: optional(string()),
76
76
  page_referrer: optional(string()),
77
77
  page_title: optional(string()),
78
+ /**
79
+ * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients
80
+ * still on an older SDK are not stripped of their page URL at this boundary — a browser
81
+ * bundle stays cached long after a backend deploys. Remove once those clients are gone;
82
+ * `pageLocation` in `server/page-location.ts` is the only reader.
83
+ */
84
+ source_url: optional(string()),
78
85
  advertising_id: optional(string()),
79
86
  install_referrer: optional(string()),
80
87
  fbc: optional(string()),
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["_null","_enum"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n site_source_name: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["_null","_enum"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n site_source_name: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\nexport const createTrackEventSchema = array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n).check(minLength(1), maxLength(100));\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n distinct_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ const require_third_parties_ignored_events = require("../third-parties/ignored-e
3
3
  const require_click_id_index = require("../click-id/index.cjs");
4
4
  const require_track_fbq = require("../track/fbq.cjs");
5
5
  const require_server_action_source = require("./action-source.cjs");
6
+ const require_server_page_location = require("./page-location.cjs");
6
7
  let facebook_nodejs_business_sdk = require("facebook-nodejs-business-sdk");
7
8
  //#region src/server/meta-conversions-api.ts
8
9
  const USER_ASSIGNED_COUNTRIES = ["xk"];
@@ -130,7 +131,8 @@ function getServerEvent(event, data, appPackageName, actionSource) {
130
131
  const appData = getAppData(event.tags, appPackageName);
131
132
  serverEvent.setAppData(appData);
132
133
  }
133
- if (event.tags.page_location) serverEvent.setEventSourceUrl(event.tags.page_location);
134
+ const eventSourceUrl = require_server_page_location.pageLocation(event.tags);
135
+ if (eventSourceUrl) serverEvent.setEventSourceUrl(eventSourceUrl);
134
136
  switch (source) {
135
137
  case "app":
136
138
  serverEvent.setActionSource("app");
@@ -1 +1 @@
1
- {"version":3,"file":"meta-conversions-api.cjs","names":["UserData","formatFbc","ExtendedDeviceInfo","AppData","CustomData","mapFBEvent","Content","ServerEvent","resolveActionSource","IGNORED_EVENTS","EventRequest"],"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 { formatFbc } from '../click-id/index';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { mapFBEvent } from '../track/fbq';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\nimport { type EventActionSource, resolveActionSource } from './action-source';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0)?.toLowerCase();\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData, eventTimeMs: number) {\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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- user-provided data may carry values outside the declared union at runtime\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 // \"the timestamp when you first observed or received this fbclid value\" — the event's own\n // time is the closest thing the server has to that, and it does not move when a queued or\n // retried batch finally goes out.\n userData.setFbc(formatFbc(tags.fbclid, eventTimeMs));\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// oxlint-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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- custom event properties may carry `value: null` at runtime despite the declared type\n if (value !== undefined && value !== null) 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 data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const eventTimeMs = new Date(event.created_at).getTime();\n const userData = getUserData(event.tags, data, eventTimeMs);\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)\n .setEventName(eventName)\n .setEventTime(Math.round(eventTimeMs / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n const source = resolveActionSource(event.platform, actionSource);\n if (source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n if (event.tags.page_location) {\n serverEvent.setEventSourceUrl(event.tags.page_location);\n }\n switch (source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n // `action_source` is required on a server event, so both an offline conversion and an\n // undeterminable platform still have to send something. Meta has no generic offline\n // value: 'physical_store' and 'system_generated' are narrower claims only the caller can\n // make, so everything left lands in Meta's own catch-all.\n serverEvent.setActionSource('other');\n break;\n }\n return serverEvent;\n}\n\n/**\n * The shape `FacebookRequestError` exposes: `status` and `response` are the HTTP status and the\n * parsed error body, and both are null when the request never received a response.\n */\ntype MetaRequestError = { status?: number | null; message?: string; response?: unknown };\n\n/**\n * Meta's SDK rejects on API errors, where every other conversion sender here logs and resolves.\n * Keep the failure inside this module, so one rejected batch cannot fail the caller's request.\n * Never log the error itself: it also carries the access token, in both `url` and `data`.\n */\nfunction logError(error: unknown) {\n const { status, message, response } = (error ?? {}) as MetaRequestError;\n if (typeof status !== 'number') {\n console.error(`Failed to send Meta conversion, network error: ${message ?? String(error)}`);\n return;\n }\n console.error(\n `Failed to send Meta conversion, status: ${status}, body: ${JSON.stringify(response)}`\n );\n}\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n if (IGNORED_EVENTS.includes(event.name)) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName, actionSource);\n request.setEvents([fbEvent]);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const fbEvents = events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName, actionSource));\n if (fbEvents.length === 0) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\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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"}
1
+ {"version":3,"file":"meta-conversions-api.cjs","names":["UserData","formatFbc","ExtendedDeviceInfo","AppData","CustomData","mapFBEvent","Content","ServerEvent","resolveActionSource","pageLocation","IGNORED_EVENTS","EventRequest"],"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 { formatFbc } from '../click-id/index';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { mapFBEvent } from '../track/fbq';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\nimport { type EventActionSource, resolveActionSource } from './action-source';\nimport { pageLocation } from './page-location';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0)?.toLowerCase();\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData, eventTimeMs: number) {\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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- user-provided data may carry values outside the declared union at runtime\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 // \"the timestamp when you first observed or received this fbclid value\" — the event's own\n // time is the closest thing the server has to that, and it does not move when a queued or\n // retried batch finally goes out.\n userData.setFbc(formatFbc(tags.fbclid, eventTimeMs));\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// oxlint-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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- custom event properties may carry `value: null` at runtime despite the declared type\n if (value !== undefined && value !== null) 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 data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const eventTimeMs = new Date(event.created_at).getTime();\n const userData = getUserData(event.tags, data, eventTimeMs);\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)\n .setEventName(eventName)\n .setEventTime(Math.round(eventTimeMs / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n const source = resolveActionSource(event.platform, actionSource);\n if (source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n const eventSourceUrl = pageLocation(event.tags);\n if (eventSourceUrl) {\n serverEvent.setEventSourceUrl(eventSourceUrl);\n }\n switch (source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n // `action_source` is required on a server event, so both an offline conversion and an\n // undeterminable platform still have to send something. Meta has no generic offline\n // value: 'physical_store' and 'system_generated' are narrower claims only the caller can\n // make, so everything left lands in Meta's own catch-all.\n serverEvent.setActionSource('other');\n break;\n }\n return serverEvent;\n}\n\n/**\n * The shape `FacebookRequestError` exposes: `status` and `response` are the HTTP status and the\n * parsed error body, and both are null when the request never received a response.\n */\ntype MetaRequestError = { status?: number | null; message?: string; response?: unknown };\n\n/**\n * Meta's SDK rejects on API errors, where every other conversion sender here logs and resolves.\n * Keep the failure inside this module, so one rejected batch cannot fail the caller's request.\n * Never log the error itself: it also carries the access token, in both `url` and `data`.\n */\nfunction logError(error: unknown) {\n const { status, message, response } = (error ?? {}) as MetaRequestError;\n if (typeof status !== 'number') {\n console.error(`Failed to send Meta conversion, network error: ${message ?? String(error)}`);\n return;\n }\n console.error(\n `Failed to send Meta conversion, status: ${status}, body: ${JSON.stringify(response)}`\n );\n}\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n if (IGNORED_EVENTS.includes(event.name)) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName, actionSource);\n request.setEvents([fbEvent]);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const fbEvents = events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName, actionSource));\n if (fbEvents.length === 0) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"meta-conversions-api.d.cts","names":[],"sources":["../../src/server/meta-conversions-api.ts"],"mappings":";;;;iBA2OgB,eAEd,OAAO,iBACP,MAAM,kBACN,yBACA,eAAe,oBAAiB;iBA6DZ,UACpB,qBACA,iBAEA,OAAO,iBACP,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAcZ,WACpB,qBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAgBZ,cAAc,qBAAqB,iBAAiB,wBAAqB,+CAAA"}
1
+ {"version":3,"file":"meta-conversions-api.d.cts","names":[],"sources":["../../src/server/meta-conversions-api.ts"],"mappings":";;;;iBA4OgB,eAEd,OAAO,iBACP,MAAM,kBACN,yBACA,eAAe,oBAAiB;iBA8DZ,UACpB,qBACA,iBAEA,OAAO,iBACP,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAcZ,WACpB,qBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAgBZ,cAAc,qBAAqB,iBAAiB,wBAAqB,+CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"meta-conversions-api.d.mts","names":[],"sources":["../../src/server/meta-conversions-api.ts"],"mappings":";;;;iBA2OgB,eAEd,OAAO,iBACP,MAAM,kBACN,yBACA,eAAe,oBAAiB;iBA6DZ,UACpB,qBACA,iBAEA,OAAO,iBACP,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAcZ,WACpB,qBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAgBZ,cAAc,qBAAqB,iBAAiB,wBAAqB,+CAAA"}
1
+ {"version":3,"file":"meta-conversions-api.d.mts","names":[],"sources":["../../src/server/meta-conversions-api.ts"],"mappings":";;;;iBA4OgB,eAEd,OAAO,iBACP,MAAM,kBACN,yBACA,eAAe,oBAAiB;iBA8DZ,UACpB,qBACA,iBAEA,OAAO,iBACP,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAcZ,WACpB,qBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,yBACA,eAAe,oBAAiB,+CAAA;iBAgBZ,cAAc,qBAAqB,iBAAiB,wBAAqB,+CAAA"}
@@ -2,6 +2,7 @@ import { IGNORED_EVENTS } from "../third-parties/ignored-events.mjs";
2
2
  import { formatFbc } from "../click-id/index.mjs";
3
3
  import { mapFBEvent } from "../track/fbq.mjs";
4
4
  import { resolveActionSource } from "./action-source.mjs";
5
+ import { pageLocation } from "./page-location.mjs";
5
6
  import { AppData, Content, CustomData, EventRequest, ExtendedDeviceInfo, ServerEvent, UserData } from "facebook-nodejs-business-sdk";
6
7
  //#region src/server/meta-conversions-api.ts
7
8
  const USER_ASSIGNED_COUNTRIES = ["xk"];
@@ -129,7 +130,8 @@ function getServerEvent(event, data, appPackageName, actionSource) {
129
130
  const appData = getAppData(event.tags, appPackageName);
130
131
  serverEvent.setAppData(appData);
131
132
  }
132
- if (event.tags.page_location) serverEvent.setEventSourceUrl(event.tags.page_location);
133
+ const eventSourceUrl = pageLocation(event.tags);
134
+ if (eventSourceUrl) serverEvent.setEventSourceUrl(eventSourceUrl);
133
135
  switch (source) {
134
136
  case "app":
135
137
  serverEvent.setActionSource("app");
@@ -1 +1 @@
1
- {"version":3,"file":"meta-conversions-api.mjs","names":[],"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 { formatFbc } from '../click-id/index';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { mapFBEvent } from '../track/fbq';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\nimport { type EventActionSource, resolveActionSource } from './action-source';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0)?.toLowerCase();\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData, eventTimeMs: number) {\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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- user-provided data may carry values outside the declared union at runtime\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 // \"the timestamp when you first observed or received this fbclid value\" — the event's own\n // time is the closest thing the server has to that, and it does not move when a queued or\n // retried batch finally goes out.\n userData.setFbc(formatFbc(tags.fbclid, eventTimeMs));\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// oxlint-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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- custom event properties may carry `value: null` at runtime despite the declared type\n if (value !== undefined && value !== null) 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 data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const eventTimeMs = new Date(event.created_at).getTime();\n const userData = getUserData(event.tags, data, eventTimeMs);\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)\n .setEventName(eventName)\n .setEventTime(Math.round(eventTimeMs / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n const source = resolveActionSource(event.platform, actionSource);\n if (source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n if (event.tags.page_location) {\n serverEvent.setEventSourceUrl(event.tags.page_location);\n }\n switch (source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n // `action_source` is required on a server event, so both an offline conversion and an\n // undeterminable platform still have to send something. Meta has no generic offline\n // value: 'physical_store' and 'system_generated' are narrower claims only the caller can\n // make, so everything left lands in Meta's own catch-all.\n serverEvent.setActionSource('other');\n break;\n }\n return serverEvent;\n}\n\n/**\n * The shape `FacebookRequestError` exposes: `status` and `response` are the HTTP status and the\n * parsed error body, and both are null when the request never received a response.\n */\ntype MetaRequestError = { status?: number | null; message?: string; response?: unknown };\n\n/**\n * Meta's SDK rejects on API errors, where every other conversion sender here logs and resolves.\n * Keep the failure inside this module, so one rejected batch cannot fail the caller's request.\n * Never log the error itself: it also carries the access token, in both `url` and `data`.\n */\nfunction logError(error: unknown) {\n const { status, message, response } = (error ?? {}) as MetaRequestError;\n if (typeof status !== 'number') {\n console.error(`Failed to send Meta conversion, network error: ${message ?? String(error)}`);\n return;\n }\n console.error(\n `Failed to send Meta conversion, status: ${status}, body: ${JSON.stringify(response)}`\n );\n}\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n if (IGNORED_EVENTS.includes(event.name)) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName, actionSource);\n request.setEvents([fbEvent]);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const fbEvents = events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName, actionSource));\n if (fbEvents.length === 0) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\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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"}
1
+ {"version":3,"file":"meta-conversions-api.mjs","names":[],"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 { formatFbc } from '../click-id/index';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { mapFBEvent } from '../track/fbq';\nimport type { TrackEvent, TrackTags, UserProvidedData } from '../track/types';\nimport { type EventActionSource, resolveActionSource } from './action-source';\nimport { pageLocation } from './page-location';\n\nconst USER_ASSIGNED_COUNTRIES: string[] = ['xk'];\nfunction normalizeCountry(input: string | undefined): string | undefined {\n const country = input?.split(/[-_]/).at(0)?.toLowerCase();\n if (!country) return undefined;\n return USER_ASSIGNED_COUNTRIES.includes(country) ? undefined : country;\n}\n\nfunction getUserData(tags: TrackTags, data: UserProvidedData, eventTimeMs: number) {\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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- user-provided data may carry values outside the declared union at runtime\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 // \"the timestamp when you first observed or received this fbclid value\" — the event's own\n // time is the closest thing the server has to that, and it does not move when a queued or\n // retried batch finally goes out.\n userData.setFbc(formatFbc(tags.fbclid, eventTimeMs));\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// oxlint-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 // oxlint-disable-next-line typescript/no-unnecessary-condition -- custom event properties may carry `value: null` at runtime despite the declared type\n if (value !== undefined && value !== null) 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 data.setCustomProperties(custom_properties);\n return data;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const eventTimeMs = new Date(event.created_at).getTime();\n const userData = getUserData(event.tags, data, eventTimeMs);\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)\n .setEventName(eventName)\n .setEventTime(Math.round(eventTimeMs / 1000))\n .setUserData(userData)\n .setCustomData(customData);\n\n const source = resolveActionSource(event.platform, actionSource);\n if (source === 'app' && appPackageName) {\n const appData = getAppData(event.tags, appPackageName);\n serverEvent.setAppData(appData);\n }\n const eventSourceUrl = pageLocation(event.tags);\n if (eventSourceUrl) {\n serverEvent.setEventSourceUrl(eventSourceUrl);\n }\n switch (source) {\n case 'app':\n serverEvent.setActionSource('app');\n break;\n case 'web':\n serverEvent.setActionSource('website');\n break;\n default:\n // `action_source` is required on a server event, so both an offline conversion and an\n // undeterminable platform still have to send something. Meta has no generic offline\n // value: 'physical_store' and 'system_generated' are narrower claims only the caller can\n // make, so everything left lands in Meta's own catch-all.\n serverEvent.setActionSource('other');\n break;\n }\n return serverEvent;\n}\n\n/**\n * The shape `FacebookRequestError` exposes: `status` and `response` are the HTTP status and the\n * parsed error body, and both are null when the request never received a response.\n */\ntype MetaRequestError = { status?: number | null; message?: string; response?: unknown };\n\n/**\n * Meta's SDK rejects on API errors, where every other conversion sender here logs and resolves.\n * Keep the failure inside this module, so one rejected batch cannot fail the caller's request.\n * Never log the error itself: it also carries the access token, in both `url` and `data`.\n */\nfunction logError(error: unknown) {\n const { status, message, response } = (error ?? {}) as MetaRequestError;\n if (typeof status !== 'number') {\n console.error(`Failed to send Meta conversion, network error: ${message ?? String(error)}`);\n return;\n }\n console.error(\n `Failed to send Meta conversion, status: ${status}, body: ${JSON.stringify(response)}`\n );\n}\n\nexport async function sendEvent(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n if (IGNORED_EVENTS.includes(event.name)) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n const fbEvent = getServerEvent(event, data, appPackageName, actionSource);\n request.setEvents([fbEvent]);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\n}\n\nexport async function sendEvents(\n accessToken: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n appPackageName?: string,\n actionSource?: EventActionSource\n) {\n const fbEvents = events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, appPackageName, actionSource));\n if (fbEvents.length === 0) return undefined;\n const request = new EventRequest(accessToken, pixelId);\n request.setEvents(fbEvents);\n try {\n return await request.execute();\n } catch (error) {\n logError(error);\n return undefined;\n }\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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"}
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_third_parties_ignored_events = require("../third-parties/ignored-events.cjs");
3
3
  const require_server_action_source = require("./action-source.cjs");
4
+ const require_server_page_location = require("./page-location.cjs");
4
5
  const require_utils_field = require("../utils/field.cjs");
5
6
  const require_track_oaiq = require("../track/oaiq.cjs");
6
7
  let _shware_utils = require("@shware/utils");
@@ -44,7 +45,7 @@ function getServerEvent(event, data, actionSource) {
44
45
  type,
45
46
  custom_event_name: type === "custom" ? event.name : void 0,
46
47
  timestamp_ms: new Date(event.created_at).getTime(),
47
- source_url: event.tags.page_location,
48
+ source_url: require_server_page_location.pageLocation(event.tags),
48
49
  action_source: mapActionSource(event.platform, actionSource),
49
50
  user: getUser(data),
50
51
  data: eventData
@@ -1 +1 @@
1
- {"version":3,"file":"openai-conversions-api.cjs","names":["resolveActionSource","getFirst","mapOAIEvent","IGNORED_EVENTS","NON_AD_EVENTS"],"sources":["../../src/server/openai-conversions-api.ts"],"sourcesContent":["/**\n * OpenAI Conversions API\n * https://developers.openai.com/ads/conversions-api\n * https://developers.openai.com/ads/supported-events\n */\nimport { createHash } from 'node:crypto';\nimport { fetch } from '@shware/utils';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { type EventData, NON_AD_EVENTS, mapOAIEvent } from '../track/oaiq';\nimport type { Platform, TrackEvent, UserProvidedData } from '../track/types';\nimport { getFirst } from '../utils/field';\nimport { type EventActionSource, resolveActionSource } from './action-source';\n\nconst ENDPOINT = 'https://bzr.openai.com/v1/events';\n\ntype ActionSource =\n | 'web'\n | 'mobile_app'\n | 'offline'\n | 'physical_store'\n | 'phone_call'\n | 'email'\n | 'other';\n\n/**\n * User/identity fields. Email and external id must be sent as lowercase 64-char SHA-256 hex\n * strings; geographic, IP, and user-agent fields are sent as raw values.\n */\nexport interface OpenAIUser {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n city?: string;\n zip_code?: string;\n ip_address?: string;\n user_agent?: string;\n}\n\nexport interface OpenAIEvent {\n /** Unique event id; combined with `type` for deduplication against pixel events. */\n id: string;\n /** Standard event name or `custom`. */\n type: string;\n /** Required when `type` is `custom`. */\n custom_event_name?: string;\n /** Event timestamp in ms; must be within 7 days and no more than 10 minutes in the future. */\n timestamp_ms: number;\n /** Required for `action_source: \"web\"`. */\n source_url?: string;\n action_source?: ActionSource;\n /** OpenAI-provided privacy-preserving identifier. */\n oppref?: string;\n /** When true, opts the event out of personalization. */\n opt_out?: boolean;\n user?: OpenAIUser;\n data: EventData;\n}\n\nexport interface CreateOpenAIEventsDTO {\n /** When true, validates the events without persisting them. */\n validate_only?: boolean;\n events: OpenAIEvent[];\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction mapActionSource(\n platform: Platform,\n actionSource?: EventActionSource\n): ActionSource | undefined {\n switch (resolveActionSource(platform, actionSource)) {\n case 'web':\n return 'web';\n case 'app':\n return 'mobile_app';\n case 'offline':\n return 'offline';\n default:\n return undefined;\n }\n}\n\nfunction getUser(data: UserProvidedData): OpenAIUser | undefined {\n const email = getFirst(data.email)?.trim().toLowerCase();\n const address = getFirst(data.address);\n\n const user: OpenAIUser = {\n email_sha256: email ? sha256(email) : undefined,\n external_id_sha256: data.user_id ? sha256(data.user_id) : undefined,\n country: address?.country?.trim().toUpperCase(),\n city: address?.city?.trim().toLowerCase(),\n zip_code: address?.postal_code,\n ip_address: data.ip_address,\n user_agent: data.user_agent,\n };\n\n return Object.values(user).some((value) => value !== undefined) ? user : undefined;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n actionSource?: EventActionSource\n): OpenAIEvent {\n const { type, data: eventData } = mapOAIEvent(event.name, event.properties);\n\n return {\n id: event.tags.idempotency_key ?? event.id,\n type,\n // For custom events the original track name is the OpenAI custom_event_name; this matches\n // the browser pixel so the two deduplicate. Standard events omit it.\n custom_event_name: type === 'custom' ? event.name : undefined,\n timestamp_ms: new Date(event.created_at).getTime(),\n source_url: event.tags.page_location,\n action_source: mapActionSource(event.platform, actionSource),\n user: getUser(data),\n data: eventData,\n };\n}\n\nexport async function sendEvents(\n apiKey: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n validateOnly = false,\n actionSource?: EventActionSource\n) {\n const dto: CreateOpenAIEventsDTO = {\n validate_only: validateOnly,\n events: events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .filter((event) => !NON_AD_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, actionSource)),\n };\n\n if (dto.events.length === 0) return;\n\n try {\n const response = await fetch(`${ENDPOINT}?pid=${pixelId}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${apiKey}`,\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 OpenAI conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send OpenAI conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,WAAW;AAoDjB,SAAS,OAAO,OAAuB;CACrC,QAAA,GAAA,YAAA,WAAA,CAAkB,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;AACxD;AAEA,SAAS,gBACP,UACA,cAC0B;CAC1B,QAAQA,6BAAAA,oBAAoB,UAAU,YAAY,GAAlD;EACE,KAAK,OACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,SACE;CACJ;AACF;AAEA,SAAS,QAAQ,MAAgD;CAC/D,MAAM,QAAQC,oBAAAA,SAAS,KAAK,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY;CACvD,MAAM,UAAUA,oBAAAA,SAAS,KAAK,OAAO;CAErC,MAAM,OAAmB;EACvB,cAAc,QAAQ,OAAO,KAAK,IAAI,KAAA;EACtC,oBAAoB,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI,KAAA;EAC1D,SAAS,SAAS,SAAS,KAAK,CAAC,CAAC,YAAY;EAC9C,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;EACxC,UAAU,SAAS;EACnB,YAAY,KAAK;EACjB,YAAY,KAAK;CACnB;CAEA,OAAO,OAAO,OAAO,IAAI,CAAC,CAAC,MAAM,UAAU,UAAU,KAAA,CAAS,IAAI,OAAO,KAAA;AAC3E;AAEA,SAAgB,eAEd,OACA,MACA,cACa;CACb,MAAM,EAAE,MAAM,MAAM,cAAcC,mBAAAA,YAAY,MAAM,MAAM,MAAM,UAAU;CAE1E,OAAO;EACL,IAAI,MAAM,KAAK,mBAAmB,MAAM;EACxC;EAGA,mBAAmB,SAAS,WAAW,MAAM,OAAO,KAAA;EACpD,cAAc,IAAI,KAAK,MAAM,UAAU,CAAC,CAAC,QAAQ;EACjD,YAAY,MAAM,KAAK;EACvB,eAAe,gBAAgB,MAAM,UAAU,YAAY;EAC3D,MAAM,QAAQ,IAAI;EAClB,MAAM;CACR;AACF;AAEA,eAAsB,WACpB,QACA,SAEA,QACA,OAAyB,CAAC,GAC1B,eAAe,OACf,cACA;CACA,MAAM,MAA6B;EACjC,eAAe;EACf,QAAQ,OACL,QAAQ,UAAU,CAACC,qCAAAA,eAAe,SAAS,MAAM,IAAI,CAAC,CAAC,CACvD,QAAQ,UAAU,CAACC,mBAAAA,cAAc,SAAS,MAAM,IAAI,CAAC,CAAC,CACtD,KAAK,UAAU,eAAe,OAAO,MAAM,YAAY,CAAC;CAC7D;CAEA,IAAI,IAAI,OAAO,WAAW,GAAG;CAE7B,IAAI;EACF,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAG,SAAS,OAAO,WAAW;GACzD,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,QAAQ;IACR,eAAe,UAAU;GAC3B;GACA,MAAM,KAAK,UAAU,GAAG;EAC1B,CAAC;EAED,IAAI,SAAS,IAAI;EACjB,MAAM,EAAE,WAAW;EACnB,MAAM,UAAU,MAAM,SAAS,KAAK;EACpC,QAAQ,MAAM,6CAA6C,OAAO,UAAU,SAAS;CACvF,SAAS,OAAO;EACd,QAAQ,MAAM,oDAAoD,KAAK;CACzE;AACF"}
1
+ {"version":3,"file":"openai-conversions-api.cjs","names":["resolveActionSource","getFirst","mapOAIEvent","pageLocation","IGNORED_EVENTS","NON_AD_EVENTS"],"sources":["../../src/server/openai-conversions-api.ts"],"sourcesContent":["/**\n * OpenAI Conversions API\n * https://developers.openai.com/ads/conversions-api\n * https://developers.openai.com/ads/supported-events\n */\nimport { createHash } from 'node:crypto';\nimport { fetch } from '@shware/utils';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { type EventData, NON_AD_EVENTS, mapOAIEvent } from '../track/oaiq';\nimport type { Platform, TrackEvent, UserProvidedData } from '../track/types';\nimport { getFirst } from '../utils/field';\nimport { type EventActionSource, resolveActionSource } from './action-source';\nimport { pageLocation } from './page-location';\n\nconst ENDPOINT = 'https://bzr.openai.com/v1/events';\n\ntype ActionSource =\n | 'web'\n | 'mobile_app'\n | 'offline'\n | 'physical_store'\n | 'phone_call'\n | 'email'\n | 'other';\n\n/**\n * User/identity fields. Email and external id must be sent as lowercase 64-char SHA-256 hex\n * strings; geographic, IP, and user-agent fields are sent as raw values.\n */\nexport interface OpenAIUser {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n city?: string;\n zip_code?: string;\n ip_address?: string;\n user_agent?: string;\n}\n\nexport interface OpenAIEvent {\n /** Unique event id; combined with `type` for deduplication against pixel events. */\n id: string;\n /** Standard event name or `custom`. */\n type: string;\n /** Required when `type` is `custom`. */\n custom_event_name?: string;\n /** Event timestamp in ms; must be within 7 days and no more than 10 minutes in the future. */\n timestamp_ms: number;\n /** Required for `action_source: \"web\"`. */\n source_url?: string;\n action_source?: ActionSource;\n /** OpenAI-provided privacy-preserving identifier. */\n oppref?: string;\n /** When true, opts the event out of personalization. */\n opt_out?: boolean;\n user?: OpenAIUser;\n data: EventData;\n}\n\nexport interface CreateOpenAIEventsDTO {\n /** When true, validates the events without persisting them. */\n validate_only?: boolean;\n events: OpenAIEvent[];\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction mapActionSource(\n platform: Platform,\n actionSource?: EventActionSource\n): ActionSource | undefined {\n switch (resolveActionSource(platform, actionSource)) {\n case 'web':\n return 'web';\n case 'app':\n return 'mobile_app';\n case 'offline':\n return 'offline';\n default:\n return undefined;\n }\n}\n\nfunction getUser(data: UserProvidedData): OpenAIUser | undefined {\n const email = getFirst(data.email)?.trim().toLowerCase();\n const address = getFirst(data.address);\n\n const user: OpenAIUser = {\n email_sha256: email ? sha256(email) : undefined,\n external_id_sha256: data.user_id ? sha256(data.user_id) : undefined,\n country: address?.country?.trim().toUpperCase(),\n city: address?.city?.trim().toLowerCase(),\n zip_code: address?.postal_code,\n ip_address: data.ip_address,\n user_agent: data.user_agent,\n };\n\n return Object.values(user).some((value) => value !== undefined) ? user : undefined;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n actionSource?: EventActionSource\n): OpenAIEvent {\n const { type, data: eventData } = mapOAIEvent(event.name, event.properties);\n\n return {\n id: event.tags.idempotency_key ?? event.id,\n type,\n // For custom events the original track name is the OpenAI custom_event_name; this matches\n // the browser pixel so the two deduplicate. Standard events omit it.\n custom_event_name: type === 'custom' ? event.name : undefined,\n timestamp_ms: new Date(event.created_at).getTime(),\n source_url: pageLocation(event.tags),\n action_source: mapActionSource(event.platform, actionSource),\n user: getUser(data),\n data: eventData,\n };\n}\n\nexport async function sendEvents(\n apiKey: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n validateOnly = false,\n actionSource?: EventActionSource\n) {\n const dto: CreateOpenAIEventsDTO = {\n validate_only: validateOnly,\n events: events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .filter((event) => !NON_AD_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, actionSource)),\n };\n\n if (dto.events.length === 0) return;\n\n try {\n const response = await fetch(`${ENDPOINT}?pid=${pixelId}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${apiKey}`,\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 OpenAI conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send OpenAI conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,MAAM,WAAW;AAoDjB,SAAS,OAAO,OAAuB;CACrC,QAAA,GAAA,YAAA,WAAA,CAAkB,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;AACxD;AAEA,SAAS,gBACP,UACA,cAC0B;CAC1B,QAAQA,6BAAAA,oBAAoB,UAAU,YAAY,GAAlD;EACE,KAAK,OACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,SACE;CACJ;AACF;AAEA,SAAS,QAAQ,MAAgD;CAC/D,MAAM,QAAQC,oBAAAA,SAAS,KAAK,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY;CACvD,MAAM,UAAUA,oBAAAA,SAAS,KAAK,OAAO;CAErC,MAAM,OAAmB;EACvB,cAAc,QAAQ,OAAO,KAAK,IAAI,KAAA;EACtC,oBAAoB,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI,KAAA;EAC1D,SAAS,SAAS,SAAS,KAAK,CAAC,CAAC,YAAY;EAC9C,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;EACxC,UAAU,SAAS;EACnB,YAAY,KAAK;EACjB,YAAY,KAAK;CACnB;CAEA,OAAO,OAAO,OAAO,IAAI,CAAC,CAAC,MAAM,UAAU,UAAU,KAAA,CAAS,IAAI,OAAO,KAAA;AAC3E;AAEA,SAAgB,eAEd,OACA,MACA,cACa;CACb,MAAM,EAAE,MAAM,MAAM,cAAcC,mBAAAA,YAAY,MAAM,MAAM,MAAM,UAAU;CAE1E,OAAO;EACL,IAAI,MAAM,KAAK,mBAAmB,MAAM;EACxC;EAGA,mBAAmB,SAAS,WAAW,MAAM,OAAO,KAAA;EACpD,cAAc,IAAI,KAAK,MAAM,UAAU,CAAC,CAAC,QAAQ;EACjD,YAAYC,6BAAAA,aAAa,MAAM,IAAI;EACnC,eAAe,gBAAgB,MAAM,UAAU,YAAY;EAC3D,MAAM,QAAQ,IAAI;EAClB,MAAM;CACR;AACF;AAEA,eAAsB,WACpB,QACA,SAEA,QACA,OAAyB,CAAC,GAC1B,eAAe,OACf,cACA;CACA,MAAM,MAA6B;EACjC,eAAe;EACf,QAAQ,OACL,QAAQ,UAAU,CAACC,qCAAAA,eAAe,SAAS,MAAM,IAAI,CAAC,CAAC,CACvD,QAAQ,UAAU,CAACC,mBAAAA,cAAc,SAAS,MAAM,IAAI,CAAC,CAAC,CACtD,KAAK,UAAU,eAAe,OAAO,MAAM,YAAY,CAAC;CAC7D;CAEA,IAAI,IAAI,OAAO,WAAW,GAAG;CAE7B,IAAI;EACF,MAAM,WAAW,OAAA,GAAA,cAAA,MAAA,CAAY,GAAG,SAAS,OAAO,WAAW;GACzD,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,QAAQ;IACR,eAAe,UAAU;GAC3B;GACA,MAAM,KAAK,UAAU,GAAG;EAC1B,CAAC;EAED,IAAI,SAAS,IAAI;EACjB,MAAM,EAAE,WAAW;EACnB,MAAM,UAAU,MAAM,SAAS,KAAK;EACpC,QAAQ,MAAM,6CAA6C,OAAO,UAAU,SAAS;CACvF,SAAS,OAAO;EACd,QAAQ,MAAM,oDAAoD,KAAK;CACzE;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"openai-conversions-api.d.cts","names":[],"sources":["../../src/server/openai-conversions-api.ts"],"mappings":";;;;KAeK;;;;;UAaY;EACf;EACA;;EAEA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;EACA,gBAAgB;;EAEhB;;EAEA;EACA,OAAO;EACP,MAAM;;UAGS;;EAEf;EACA,QAAQ;;iBAwCM,eAEd,OAAO,iBACP,MAAM,kBACN,eAAe,oBACd;iBAiBmB,WACpB,gBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,wBACA,eAAe,oBAAiB"}
1
+ {"version":3,"file":"openai-conversions-api.d.cts","names":[],"sources":["../../src/server/openai-conversions-api.ts"],"mappings":";;;;KAgBK;;;;;UAaY;EACf;EACA;;EAEA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;EACA,gBAAgB;;EAEhB;;EAEA;EACA,OAAO;EACP,MAAM;;UAGS;;EAEf;EACA,QAAQ;;iBAwCM,eAEd,OAAO,iBACP,MAAM,kBACN,eAAe,oBACd;iBAiBmB,WACpB,gBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,wBACA,eAAe,oBAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"openai-conversions-api.d.mts","names":[],"sources":["../../src/server/openai-conversions-api.ts"],"mappings":";;;;KAeK;;;;;UAaY;EACf;EACA;;EAEA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;EACA,gBAAgB;;EAEhB;;EAEA;EACA,OAAO;EACP,MAAM;;UAGS;;EAEf;EACA,QAAQ;;iBAwCM,eAEd,OAAO,iBACP,MAAM,kBACN,eAAe,oBACd;iBAiBmB,WACpB,gBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,wBACA,eAAe,oBAAiB"}
1
+ {"version":3,"file":"openai-conversions-api.d.mts","names":[],"sources":["../../src/server/openai-conversions-api.ts"],"mappings":";;;;KAgBK;;;;;UAaY;EACf;EACA;;EAEA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;EACA,gBAAgB;;EAEhB;;EAEA;EACA,OAAO;EACP,MAAM;;UAGS;;EAEf;EACA,QAAQ;;iBAwCM,eAEd,OAAO,iBACP,MAAM,kBACN,eAAe,oBACd;iBAiBmB,WACpB,gBACA,iBAEA,QAAQ,mBACR,OAAM,kBACN,wBACA,eAAe,oBAAiB"}
@@ -1,5 +1,6 @@
1
1
  import { IGNORED_EVENTS } from "../third-parties/ignored-events.mjs";
2
2
  import { resolveActionSource } from "./action-source.mjs";
3
+ import { pageLocation } from "./page-location.mjs";
3
4
  import { getFirst } from "../utils/field.mjs";
4
5
  import { NON_AD_EVENTS, mapOAIEvent } from "../track/oaiq.mjs";
5
6
  import { fetch } from "@shware/utils";
@@ -43,7 +44,7 @@ function getServerEvent(event, data, actionSource) {
43
44
  type,
44
45
  custom_event_name: type === "custom" ? event.name : void 0,
45
46
  timestamp_ms: new Date(event.created_at).getTime(),
46
- source_url: event.tags.page_location,
47
+ source_url: pageLocation(event.tags),
47
48
  action_source: mapActionSource(event.platform, actionSource),
48
49
  user: getUser(data),
49
50
  data: eventData
@@ -1 +1 @@
1
- {"version":3,"file":"openai-conversions-api.mjs","names":[],"sources":["../../src/server/openai-conversions-api.ts"],"sourcesContent":["/**\n * OpenAI Conversions API\n * https://developers.openai.com/ads/conversions-api\n * https://developers.openai.com/ads/supported-events\n */\nimport { createHash } from 'node:crypto';\nimport { fetch } from '@shware/utils';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { type EventData, NON_AD_EVENTS, mapOAIEvent } from '../track/oaiq';\nimport type { Platform, TrackEvent, UserProvidedData } from '../track/types';\nimport { getFirst } from '../utils/field';\nimport { type EventActionSource, resolveActionSource } from './action-source';\n\nconst ENDPOINT = 'https://bzr.openai.com/v1/events';\n\ntype ActionSource =\n | 'web'\n | 'mobile_app'\n | 'offline'\n | 'physical_store'\n | 'phone_call'\n | 'email'\n | 'other';\n\n/**\n * User/identity fields. Email and external id must be sent as lowercase 64-char SHA-256 hex\n * strings; geographic, IP, and user-agent fields are sent as raw values.\n */\nexport interface OpenAIUser {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n city?: string;\n zip_code?: string;\n ip_address?: string;\n user_agent?: string;\n}\n\nexport interface OpenAIEvent {\n /** Unique event id; combined with `type` for deduplication against pixel events. */\n id: string;\n /** Standard event name or `custom`. */\n type: string;\n /** Required when `type` is `custom`. */\n custom_event_name?: string;\n /** Event timestamp in ms; must be within 7 days and no more than 10 minutes in the future. */\n timestamp_ms: number;\n /** Required for `action_source: \"web\"`. */\n source_url?: string;\n action_source?: ActionSource;\n /** OpenAI-provided privacy-preserving identifier. */\n oppref?: string;\n /** When true, opts the event out of personalization. */\n opt_out?: boolean;\n user?: OpenAIUser;\n data: EventData;\n}\n\nexport interface CreateOpenAIEventsDTO {\n /** When true, validates the events without persisting them. */\n validate_only?: boolean;\n events: OpenAIEvent[];\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction mapActionSource(\n platform: Platform,\n actionSource?: EventActionSource\n): ActionSource | undefined {\n switch (resolveActionSource(platform, actionSource)) {\n case 'web':\n return 'web';\n case 'app':\n return 'mobile_app';\n case 'offline':\n return 'offline';\n default:\n return undefined;\n }\n}\n\nfunction getUser(data: UserProvidedData): OpenAIUser | undefined {\n const email = getFirst(data.email)?.trim().toLowerCase();\n const address = getFirst(data.address);\n\n const user: OpenAIUser = {\n email_sha256: email ? sha256(email) : undefined,\n external_id_sha256: data.user_id ? sha256(data.user_id) : undefined,\n country: address?.country?.trim().toUpperCase(),\n city: address?.city?.trim().toLowerCase(),\n zip_code: address?.postal_code,\n ip_address: data.ip_address,\n user_agent: data.user_agent,\n };\n\n return Object.values(user).some((value) => value !== undefined) ? user : undefined;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n actionSource?: EventActionSource\n): OpenAIEvent {\n const { type, data: eventData } = mapOAIEvent(event.name, event.properties);\n\n return {\n id: event.tags.idempotency_key ?? event.id,\n type,\n // For custom events the original track name is the OpenAI custom_event_name; this matches\n // the browser pixel so the two deduplicate. Standard events omit it.\n custom_event_name: type === 'custom' ? event.name : undefined,\n timestamp_ms: new Date(event.created_at).getTime(),\n source_url: event.tags.page_location,\n action_source: mapActionSource(event.platform, actionSource),\n user: getUser(data),\n data: eventData,\n };\n}\n\nexport async function sendEvents(\n apiKey: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n validateOnly = false,\n actionSource?: EventActionSource\n) {\n const dto: CreateOpenAIEventsDTO = {\n validate_only: validateOnly,\n events: events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .filter((event) => !NON_AD_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, actionSource)),\n };\n\n if (dto.events.length === 0) return;\n\n try {\n const response = await fetch(`${ENDPOINT}?pid=${pixelId}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${apiKey}`,\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 OpenAI conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send OpenAI conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,WAAW;AAoDjB,SAAS,OAAO,OAAuB;CACrC,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;AACxD;AAEA,SAAS,gBACP,UACA,cAC0B;CAC1B,QAAQ,oBAAoB,UAAU,YAAY,GAAlD;EACE,KAAK,OACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,SACE;CACJ;AACF;AAEA,SAAS,QAAQ,MAAgD;CAC/D,MAAM,QAAQ,SAAS,KAAK,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY;CACvD,MAAM,UAAU,SAAS,KAAK,OAAO;CAErC,MAAM,OAAmB;EACvB,cAAc,QAAQ,OAAO,KAAK,IAAI,KAAA;EACtC,oBAAoB,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI,KAAA;EAC1D,SAAS,SAAS,SAAS,KAAK,CAAC,CAAC,YAAY;EAC9C,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;EACxC,UAAU,SAAS;EACnB,YAAY,KAAK;EACjB,YAAY,KAAK;CACnB;CAEA,OAAO,OAAO,OAAO,IAAI,CAAC,CAAC,MAAM,UAAU,UAAU,KAAA,CAAS,IAAI,OAAO,KAAA;AAC3E;AAEA,SAAgB,eAEd,OACA,MACA,cACa;CACb,MAAM,EAAE,MAAM,MAAM,cAAc,YAAY,MAAM,MAAM,MAAM,UAAU;CAE1E,OAAO;EACL,IAAI,MAAM,KAAK,mBAAmB,MAAM;EACxC;EAGA,mBAAmB,SAAS,WAAW,MAAM,OAAO,KAAA;EACpD,cAAc,IAAI,KAAK,MAAM,UAAU,CAAC,CAAC,QAAQ;EACjD,YAAY,MAAM,KAAK;EACvB,eAAe,gBAAgB,MAAM,UAAU,YAAY;EAC3D,MAAM,QAAQ,IAAI;EAClB,MAAM;CACR;AACF;AAEA,eAAsB,WACpB,QACA,SAEA,QACA,OAAyB,CAAC,GAC1B,eAAe,OACf,cACA;CACA,MAAM,MAA6B;EACjC,eAAe;EACf,QAAQ,OACL,QAAQ,UAAU,CAAC,eAAe,SAAS,MAAM,IAAI,CAAC,CAAC,CACvD,QAAQ,UAAU,CAAC,cAAc,SAAS,MAAM,IAAI,CAAC,CAAC,CACtD,KAAK,UAAU,eAAe,OAAO,MAAM,YAAY,CAAC;CAC7D;CAEA,IAAI,IAAI,OAAO,WAAW,GAAG;CAE7B,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,SAAS,OAAO,WAAW;GACzD,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,QAAQ;IACR,eAAe,UAAU;GAC3B;GACA,MAAM,KAAK,UAAU,GAAG;EAC1B,CAAC;EAED,IAAI,SAAS,IAAI;EACjB,MAAM,EAAE,WAAW;EACnB,MAAM,UAAU,MAAM,SAAS,KAAK;EACpC,QAAQ,MAAM,6CAA6C,OAAO,UAAU,SAAS;CACvF,SAAS,OAAO;EACd,QAAQ,MAAM,oDAAoD,KAAK;CACzE;AACF"}
1
+ {"version":3,"file":"openai-conversions-api.mjs","names":[],"sources":["../../src/server/openai-conversions-api.ts"],"sourcesContent":["/**\n * OpenAI Conversions API\n * https://developers.openai.com/ads/conversions-api\n * https://developers.openai.com/ads/supported-events\n */\nimport { createHash } from 'node:crypto';\nimport { fetch } from '@shware/utils';\nimport { IGNORED_EVENTS } from '../third-parties/ignored-events';\nimport { type EventData, NON_AD_EVENTS, mapOAIEvent } from '../track/oaiq';\nimport type { Platform, TrackEvent, UserProvidedData } from '../track/types';\nimport { getFirst } from '../utils/field';\nimport { type EventActionSource, resolveActionSource } from './action-source';\nimport { pageLocation } from './page-location';\n\nconst ENDPOINT = 'https://bzr.openai.com/v1/events';\n\ntype ActionSource =\n | 'web'\n | 'mobile_app'\n | 'offline'\n | 'physical_store'\n | 'phone_call'\n | 'email'\n | 'other';\n\n/**\n * User/identity fields. Email and external id must be sent as lowercase 64-char SHA-256 hex\n * strings; geographic, IP, and user-agent fields are sent as raw values.\n */\nexport interface OpenAIUser {\n email_sha256?: string;\n external_id_sha256?: string;\n /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n country?: string;\n city?: string;\n zip_code?: string;\n ip_address?: string;\n user_agent?: string;\n}\n\nexport interface OpenAIEvent {\n /** Unique event id; combined with `type` for deduplication against pixel events. */\n id: string;\n /** Standard event name or `custom`. */\n type: string;\n /** Required when `type` is `custom`. */\n custom_event_name?: string;\n /** Event timestamp in ms; must be within 7 days and no more than 10 minutes in the future. */\n timestamp_ms: number;\n /** Required for `action_source: \"web\"`. */\n source_url?: string;\n action_source?: ActionSource;\n /** OpenAI-provided privacy-preserving identifier. */\n oppref?: string;\n /** When true, opts the event out of personalization. */\n opt_out?: boolean;\n user?: OpenAIUser;\n data: EventData;\n}\n\nexport interface CreateOpenAIEventsDTO {\n /** When true, validates the events without persisting them. */\n validate_only?: boolean;\n events: OpenAIEvent[];\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction mapActionSource(\n platform: Platform,\n actionSource?: EventActionSource\n): ActionSource | undefined {\n switch (resolveActionSource(platform, actionSource)) {\n case 'web':\n return 'web';\n case 'app':\n return 'mobile_app';\n case 'offline':\n return 'offline';\n default:\n return undefined;\n }\n}\n\nfunction getUser(data: UserProvidedData): OpenAIUser | undefined {\n const email = getFirst(data.email)?.trim().toLowerCase();\n const address = getFirst(data.address);\n\n const user: OpenAIUser = {\n email_sha256: email ? sha256(email) : undefined,\n external_id_sha256: data.user_id ? sha256(data.user_id) : undefined,\n country: address?.country?.trim().toUpperCase(),\n city: address?.city?.trim().toLowerCase(),\n zip_code: address?.postal_code,\n ip_address: data.ip_address,\n user_agent: data.user_agent,\n };\n\n return Object.values(user).some((value) => value !== undefined) ? user : undefined;\n}\n\nexport function getServerEvent(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n event: TrackEvent<any>,\n data: UserProvidedData,\n actionSource?: EventActionSource\n): OpenAIEvent {\n const { type, data: eventData } = mapOAIEvent(event.name, event.properties);\n\n return {\n id: event.tags.idempotency_key ?? event.id,\n type,\n // For custom events the original track name is the OpenAI custom_event_name; this matches\n // the browser pixel so the two deduplicate. Standard events omit it.\n custom_event_name: type === 'custom' ? event.name : undefined,\n timestamp_ms: new Date(event.created_at).getTime(),\n source_url: pageLocation(event.tags),\n action_source: mapActionSource(event.platform, actionSource),\n user: getUser(data),\n data: eventData,\n };\n}\n\nexport async function sendEvents(\n apiKey: string,\n pixelId: string,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n events: TrackEvent<any>[],\n data: UserProvidedData = {},\n validateOnly = false,\n actionSource?: EventActionSource\n) {\n const dto: CreateOpenAIEventsDTO = {\n validate_only: validateOnly,\n events: events\n .filter((event) => !IGNORED_EVENTS.includes(event.name))\n .filter((event) => !NON_AD_EVENTS.includes(event.name))\n .map((event) => getServerEvent(event, data, actionSource)),\n };\n\n if (dto.events.length === 0) return;\n\n try {\n const response = await fetch(`${ENDPOINT}?pid=${pixelId}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${apiKey}`,\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 OpenAI conversion, status: ${status}, body: ${message}`);\n } catch (error) {\n console.error('Failed to send OpenAI conversion, network error:', error);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,MAAM,WAAW;AAoDjB,SAAS,OAAO,OAAuB;CACrC,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;AACxD;AAEA,SAAS,gBACP,UACA,cAC0B;CAC1B,QAAQ,oBAAoB,UAAU,YAAY,GAAlD;EACE,KAAK,OACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,SACE;CACJ;AACF;AAEA,SAAS,QAAQ,MAAgD;CAC/D,MAAM,QAAQ,SAAS,KAAK,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY;CACvD,MAAM,UAAU,SAAS,KAAK,OAAO;CAErC,MAAM,OAAmB;EACvB,cAAc,QAAQ,OAAO,KAAK,IAAI,KAAA;EACtC,oBAAoB,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI,KAAA;EAC1D,SAAS,SAAS,SAAS,KAAK,CAAC,CAAC,YAAY;EAC9C,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;EACxC,UAAU,SAAS;EACnB,YAAY,KAAK;EACjB,YAAY,KAAK;CACnB;CAEA,OAAO,OAAO,OAAO,IAAI,CAAC,CAAC,MAAM,UAAU,UAAU,KAAA,CAAS,IAAI,OAAO,KAAA;AAC3E;AAEA,SAAgB,eAEd,OACA,MACA,cACa;CACb,MAAM,EAAE,MAAM,MAAM,cAAc,YAAY,MAAM,MAAM,MAAM,UAAU;CAE1E,OAAO;EACL,IAAI,MAAM,KAAK,mBAAmB,MAAM;EACxC;EAGA,mBAAmB,SAAS,WAAW,MAAM,OAAO,KAAA;EACpD,cAAc,IAAI,KAAK,MAAM,UAAU,CAAC,CAAC,QAAQ;EACjD,YAAY,aAAa,MAAM,IAAI;EACnC,eAAe,gBAAgB,MAAM,UAAU,YAAY;EAC3D,MAAM,QAAQ,IAAI;EAClB,MAAM;CACR;AACF;AAEA,eAAsB,WACpB,QACA,SAEA,QACA,OAAyB,CAAC,GAC1B,eAAe,OACf,cACA;CACA,MAAM,MAA6B;EACjC,eAAe;EACf,QAAQ,OACL,QAAQ,UAAU,CAAC,eAAe,SAAS,MAAM,IAAI,CAAC,CAAC,CACvD,QAAQ,UAAU,CAAC,cAAc,SAAS,MAAM,IAAI,CAAC,CAAC,CACtD,KAAK,UAAU,eAAe,OAAO,MAAM,YAAY,CAAC;CAC7D;CAEA,IAAI,IAAI,OAAO,WAAW,GAAG;CAE7B,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,SAAS,OAAO,WAAW;GACzD,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,QAAQ;IACR,eAAe,UAAU;GAC3B;GACA,MAAM,KAAK,UAAU,GAAG;EAC1B,CAAC;EAED,IAAI,SAAS,IAAI;EACjB,MAAM,EAAE,WAAW;EACnB,MAAM,UAAU,MAAM,SAAS,KAAK;EACpC,QAAQ,MAAM,6CAA6C,OAAO,UAAU,SAAS;CACvF,SAAS,OAAO;EACd,QAAQ,MAAM,oDAAoD,KAAK;CACzE;AACF"}
@@ -0,0 +1,22 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/server/page-location.ts
3
+ /**
4
+ * The URL an event happened on, whichever name the client that sent it used.
5
+ *
6
+ * `source_url` became `page_location` in 7.0.0. A backend upgrades in one deploy; the browser
7
+ * bundles that talk to it do not — a tab opened before the deploy keeps sending the old name
8
+ * until someone reloads it. Reading only the new one would leave every such event without an
9
+ * `event_source_url` for Meta and a `source_url` for OpenAI, which is a measurable hit to
10
+ * match rates for as long as the old bundles are alive.
11
+ *
12
+ * Transitional. Delete this, the `source_url` entries in `tagsSchema` and `PageInfo`, and
13
+ * inline `tags.page_location` at both call sites once no client is sending the old name —
14
+ * a month of cache lifetime is the usual bound, and stored rows can be checked for it.
15
+ */
16
+ function pageLocation(tags) {
17
+ return tags.page_location ?? tags.source_url;
18
+ }
19
+ //#endregion
20
+ exports.pageLocation = pageLocation;
21
+
22
+ //# sourceMappingURL=page-location.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-location.cjs","names":[],"sources":["../../src/server/page-location.ts"],"sourcesContent":["import type { TrackTags } from '../track/types';\n\n/**\n * The URL an event happened on, whichever name the client that sent it used.\n *\n * `source_url` became `page_location` in 7.0.0. A backend upgrades in one deploy; the browser\n * bundles that talk to it do not — a tab opened before the deploy keeps sending the old name\n * until someone reloads it. Reading only the new one would leave every such event without an\n * `event_source_url` for Meta and a `source_url` for OpenAI, which is a measurable hit to\n * match rates for as long as the old bundles are alive.\n *\n * Transitional. Delete this, the `source_url` entries in `tagsSchema` and `PageInfo`, and\n * inline `tags.page_location` at both call sites once no client is sending the old name —\n * a month of cache lifetime is the usual bound, and stored rows can be checked for it.\n */\nexport function pageLocation(tags: TrackTags): string | undefined {\n return tags.page_location ?? tags.source_url;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAgB,aAAa,MAAqC;CAChE,OAAO,KAAK,iBAAiB,KAAK;AACpC"}
@@ -0,0 +1,19 @@
1
+ import { TrackTags } from "../track/types.cjs";
2
+ //#region src/server/page-location.d.ts
3
+ /**
4
+ * The URL an event happened on, whichever name the client that sent it used.
5
+ *
6
+ * `source_url` became `page_location` in 7.0.0. A backend upgrades in one deploy; the browser
7
+ * bundles that talk to it do not — a tab opened before the deploy keeps sending the old name
8
+ * until someone reloads it. Reading only the new one would leave every such event without an
9
+ * `event_source_url` for Meta and a `source_url` for OpenAI, which is a measurable hit to
10
+ * match rates for as long as the old bundles are alive.
11
+ *
12
+ * Transitional. Delete this, the `source_url` entries in `tagsSchema` and `PageInfo`, and
13
+ * inline `tags.page_location` at both call sites once no client is sending the old name —
14
+ * a month of cache lifetime is the usual bound, and stored rows can be checked for it.
15
+ */
16
+ declare function pageLocation(tags: TrackTags): string | undefined;
17
+ //#endregion
18
+ export { pageLocation };
19
+ //# sourceMappingURL=page-location.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-location.d.cts","names":[],"sources":["../../src/server/page-location.ts"],"mappings":";;;;;;;;;;;;;;;iBAegB,aAAa,MAAM"}
@@ -0,0 +1,19 @@
1
+ import { TrackTags } from "../track/types.mjs";
2
+ //#region src/server/page-location.d.ts
3
+ /**
4
+ * The URL an event happened on, whichever name the client that sent it used.
5
+ *
6
+ * `source_url` became `page_location` in 7.0.0. A backend upgrades in one deploy; the browser
7
+ * bundles that talk to it do not — a tab opened before the deploy keeps sending the old name
8
+ * until someone reloads it. Reading only the new one would leave every such event without an
9
+ * `event_source_url` for Meta and a `source_url` for OpenAI, which is a measurable hit to
10
+ * match rates for as long as the old bundles are alive.
11
+ *
12
+ * Transitional. Delete this, the `source_url` entries in `tagsSchema` and `PageInfo`, and
13
+ * inline `tags.page_location` at both call sites once no client is sending the old name —
14
+ * a month of cache lifetime is the usual bound, and stored rows can be checked for it.
15
+ */
16
+ declare function pageLocation(tags: TrackTags): string | undefined;
17
+ //#endregion
18
+ export { pageLocation };
19
+ //# sourceMappingURL=page-location.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-location.d.mts","names":[],"sources":["../../src/server/page-location.ts"],"mappings":";;;;;;;;;;;;;;;iBAegB,aAAa,MAAM"}
@@ -0,0 +1,21 @@
1
+ //#region src/server/page-location.ts
2
+ /**
3
+ * The URL an event happened on, whichever name the client that sent it used.
4
+ *
5
+ * `source_url` became `page_location` in 7.0.0. A backend upgrades in one deploy; the browser
6
+ * bundles that talk to it do not — a tab opened before the deploy keeps sending the old name
7
+ * until someone reloads it. Reading only the new one would leave every such event without an
8
+ * `event_source_url` for Meta and a `source_url` for OpenAI, which is a measurable hit to
9
+ * match rates for as long as the old bundles are alive.
10
+ *
11
+ * Transitional. Delete this, the `source_url` entries in `tagsSchema` and `PageInfo`, and
12
+ * inline `tags.page_location` at both call sites once no client is sending the old name —
13
+ * a month of cache lifetime is the usual bound, and stored rows can be checked for it.
14
+ */
15
+ function pageLocation(tags) {
16
+ return tags.page_location ?? tags.source_url;
17
+ }
18
+ //#endregion
19
+ export { pageLocation };
20
+
21
+ //# sourceMappingURL=page-location.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-location.mjs","names":[],"sources":["../../src/server/page-location.ts"],"sourcesContent":["import type { TrackTags } from '../track/types';\n\n/**\n * The URL an event happened on, whichever name the client that sent it used.\n *\n * `source_url` became `page_location` in 7.0.0. A backend upgrades in one deploy; the browser\n * bundles that talk to it do not — a tab opened before the deploy keeps sending the old name\n * until someone reloads it. Reading only the new one would leave every such event without an\n * `event_source_url` for Meta and a `source_url` for OpenAI, which is a measurable hit to\n * match rates for as long as the old bundles are alive.\n *\n * Transitional. Delete this, the `source_url` entries in `tagsSchema` and `PageInfo`, and\n * inline `tags.page_location` at both call sites once no client is sending the old name —\n * a month of cache lifetime is the usual bound, and stored rows can be checked for it.\n */\nexport function pageLocation(tags: TrackTags): string | undefined {\n return tags.page_location ?? tags.source_url;\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,aAAa,MAAqC;CAChE,OAAO,KAAK,iBAAiB,KAAK;AACpC"}
@@ -108,6 +108,12 @@ interface PageInfo {
108
108
  page_location?: string;
109
109
  page_referrer?: string;
110
110
  page_title?: string;
111
+ /**
112
+ * @deprecated Renamed to `page_location` in 7.0.0, and never set by this SDK any more.
113
+ * Declared so events from clients still on an older version keep their page URL through
114
+ * validation; read it through `pageLocation` rather than directly.
115
+ */
116
+ source_url?: string;
111
117
  }
112
118
  interface AdvertisingInfo {
113
119
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/track/types.ts"],"mappings":";;KAEY;KACA,YAAY;KAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;UA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;KAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;KAEpB;KACA;UAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe,yBAAyB;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;KAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;EACA;;UAGe;EACf;EACA;EACA;;;;;;;;;;UAWe;EACf;EACA;EACA;;UAGe;;;;;;;EAOf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;;EAEA;EACA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;UAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;UAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;UAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;KAGU;;EAEV"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/track/types.ts"],"mappings":";;KAEY;KACA,YAAY;KAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;UA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;KAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;KAEpB;KACA;UAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe,yBAAyB;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;KAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;EACA;;UAGe;EACf;EACA;EACA;;;;;;;;;;UAWe;EACf;EACA;EACA;;;;;;EAMA;;UAGe;;;;;;;EAOf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;;EAEA;EACA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;UAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;UAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;UAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;KAGU;;EAEV"}
@@ -108,6 +108,12 @@ interface PageInfo {
108
108
  page_location?: string;
109
109
  page_referrer?: string;
110
110
  page_title?: string;
111
+ /**
112
+ * @deprecated Renamed to `page_location` in 7.0.0, and never set by this SDK any more.
113
+ * Declared so events from clients still on an older version keep their page URL through
114
+ * validation; read it through `pageLocation` rather than directly.
115
+ */
116
+ source_url?: string;
111
117
  }
112
118
  interface AdvertisingInfo {
113
119
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/track/types.ts"],"mappings":";;KAEY;KACA,YAAY;KAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;UA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;KAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;KAEpB;KACA;UAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe,yBAAyB;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;KAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;EACA;;UAGe;EACf;EACA;EACA;;;;;;;;;;UAWe;EACf;EACA;EACA;;UAGe;;;;;;;EAOf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;;EAEA;EACA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;UAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;UAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;UAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;KAGU;;EAEV"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/track/types.ts"],"mappings":";;KAEY;KACA,YAAY;KAEZ,UAAU,UAAU,YAAY,aAAa,gBAAgB,iBACrE,IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;UA+Ba;;;;;;;KAQZ,oBAAoB,KAAK,gBAAgB,wBAC1C,sBAAsB;KAGd,gBAAgB,UAAU,YAAY,aAAa,gBAAgB,iBAC3E,eAAe,KAAK,oBAAoB,KACxC,gBAAgB,wBACd,sBAAsB,KACtB,OAAO,mBAAmB;KAEpB;KACA;UAEK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe,yBAAyB;EACxC;EACA;EACA;EACA;EACA;IAAa;IAAc;IAAe;;EAE1C;EACA;;KAGU,qBAAqB,UAAU,WACzC,MAAM,UAAU,IAChB,aAAa,gBAAgB,IAC7B;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;;EAEf;EACA;;UAGe;EACf;EACA;EACA;;;;;;;;;;UAWe;EACf;EACA;EACA;;;;;;EAMA;;UAGe;;;;;;;EAOf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;;EAEA;EACA;;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;UAQe;;EAEf;;;;;;;;;;;;EAqCA;;;;;;EAuDA;;EAMA;;EAEA;;EAEA;;EAEA;;EAUA;;EAEA;;UAGe,kBACP,cAAc,YAAY,SAAS,iBAAiB,UAAU,iBAAiB;EACvF;GACC;;UAGc,WAAW,UAAU,YAAY;EAChD;EACA,MAAM,UAAU;EAChB,MAAM;EACN;EACA;EACA,UAAU;EACV,aAAa;EACb,aAAa,gBAAgB;EAC7B;;KAGU;;EAEV"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shware/analytics",
3
- "version": "7.5.0",
3
+ "version": "7.5.1",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",