{"version":3,"sources":["../../src/track/oaiq.ts"],"sourcesContent":["import type { Item } from './gtag';\nimport type { EventName, TrackName, TrackProperties } from './types';\n\nexport const NON_AD_EVENTS = [\n  // metrics\n  'CLS',\n  'FCP',\n  'FID',\n  'INP',\n  'LCP',\n  'TTFB',\n  // promotions\n  'view_promotion',\n  'select_promotion',\n];\n\n/**\n * Content item shared by `contents` and `plan_enrollment` events.\n * https://developers.openai.com/ads/supported-events\n */\nexport type ContentItem = {\n  id?: string;\n  name?: string;\n  content_type?: string;\n  quantity?: number;\n  /** Per-item monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n  amount?: number;\n  currency?: string;\n};\n\nexport type ContentsData = {\n  type: 'contents';\n  /** Monetary value in ISO 4217 minor units (e.g., 12,999 = $129.99 USD). */\n  amount?: number;\n  currency?: string;\n  contents?: ContentItem[];\n};\n\nexport type CustomerActionData = {\n  type: 'customer_action';\n  amount?: number;\n  currency?: string;\n};\n\nexport type PlanEnrollmentData = {\n  type: 'plan_enrollment';\n  plan_id?: string;\n  amount?: number;\n  currency?: string;\n  contents?: ContentItem[];\n};\n\nexport type CustomEventData = {\n  type: 'custom';\n  amount?: number;\n  currency?: string;\n  contents?: ContentItem[];\n};\n\nexport type EventData = ContentsData | CustomerActionData | PlanEnrollmentData | CustomEventData;\n\n/**\n * Standard event names and the `data` shape each one expects.\n * https://developers.openai.com/ads/supported-events\n */\nexport type StandardEvents = {\n  appointment_scheduled: CustomerActionData;\n  checkout_started: ContentsData;\n  contents_viewed: ContentsData;\n  items_added: ContentsData;\n  lead_created: CustomerActionData;\n  order_created: ContentsData;\n  page_viewed: ContentsData;\n  registration_completed: CustomerActionData;\n  subscription_created: PlanEnrollmentData;\n  trial_started: PlanEnrollmentData;\n};\n\nexport type StandardEvent = keyof StandardEvents;\n\n/**\n * Identity fields passed to `oaiq(\"init\", ...)` for conversion matching. Email and external id\n * must be pre-hashed as lowercase 64-char SHA-256 hex strings; the rest are sent as raw values.\n * https://developers.openai.com/ads/measurement-pixel\n */\nexport type OAIQUser = {\n  email_sha256?: string;\n  external_id_sha256?: string;\n  /** Two-letter ISO 3166-1 country code (e.g. \"US\"). */\n  country?: string;\n  /** Lowercased, max 128 characters. */\n  city?: string;\n  /** Max 32 characters. */\n  zip_code?: string;\n};\n\nexport type InitConfig = {\n  pixelId: string;\n  /** Log SDK activity to the browser console. */\n  debug?: boolean;\n  user?: OAIQUser;\n};\n\n/**\n * Fourth argument of `oaiq(\"measure\", ...)`. Required for custom events (carries\n * `custom_event_name`); optional for standard events.\n */\nexport type MeasureOptions = {\n  /** Shared with the Conversions API to deduplicate the same conversion across browser and server. */\n  event_id?: string;\n  /** Required for custom events; 1-64 chars of letters, numbers, underscores, or dashes. */\n  custom_event_name?: string;\n  /** When true, opts the event out of user-level personalization. */\n  opt_out?: boolean;\n};\n\nexport interface OAIQ {\n  oaiq(command: 'init', config: InitConfig): void;\n  oaiq<T extends StandardEvent>(\n    command: 'measure',\n    event: T,\n    data: StandardEvents[T],\n    options?: MeasureOptions\n  ): void;\n  oaiq(\n    command: 'measure',\n    event: 'custom',\n    data: CustomEventData,\n    options: MeasureOptions & { custom_event_name: string }\n  ): void;\n}\n\n/**\n * Currencies whose minor unit has 0 or 3 decimal places; everything else uses 2.\n * Follows Stripe's zero-decimal convention (e.g., MGA is treated as 0, ISK is included),\n * which can differ from strict ISO 4217 exponents.\n * https://docs.stripe.com/currencies#zero-decimal\n */\nconst ZERO_DECIMAL_CURRENCIES = new Set([\n  'BIF',\n  'CLP',\n  'DJF',\n  'GNF',\n  'ISK',\n  'JPY',\n  'KMF',\n  'KRW',\n  'MGA',\n  'PYG',\n  'RWF',\n  'UGX',\n  'VND',\n  'VUV',\n  'XAF',\n  'XOF',\n  'XPF',\n]);\nconst THREE_DECIMAL_CURRENCIES = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']);\n\n/** Convert a major-unit amount (e.g., 129.99) into ISO 4217 minor units (e.g., 12,999). */\nexport function toMinorUnits(value?: number, currency?: string): number | undefined {\n  if (value === undefined || value === null || Number.isNaN(value)) return undefined;\n  const code = currency?.toUpperCase();\n  const exponent =\n    code && ZERO_DECIMAL_CURRENCIES.has(code)\n      ? 0\n      : code && THREE_DECIMAL_CURRENCIES.has(code)\n        ? 3\n        : 2;\n  return Math.round(value * 10 ** exponent);\n}\n\nexport function mapContents(items?: Item[], currency?: string): ContentItem[] | undefined {\n  if (!items || items.length === 0) return undefined;\n  const code = currency?.toUpperCase();\n  return items.map((item) => ({\n    id: item.item_id,\n    name: item.item_name,\n    content_type: item.item_category,\n    quantity: item.quantity,\n    amount: toMinorUnits(item.price, currency),\n    currency: item.price !== undefined ? code : undefined,\n  }));\n}\n\n/** Safely read a property off loosely typed track properties without widening to `any`. */\nfunction prop(properties: unknown, key: string): unknown {\n  return typeof properties === 'object' && properties !== null\n    ? (properties as Record<string, unknown>)[key]\n    : undefined;\n}\n\nfunction readValue(properties: unknown): number | undefined {\n  const value = prop(properties, 'value');\n  return typeof value === 'number' ? value : undefined;\n}\n\nfunction readCurrency(properties: unknown): string | undefined {\n  const currency = prop(properties, 'currency');\n  return typeof currency === 'string' ? currency : undefined;\n}\n\nfunction readItems(properties: unknown): Item[] | undefined {\n  const items = prop(properties, 'items');\n  return Array.isArray(items) ? (items as Item[]) : undefined;\n}\n\nfunction contentsData(properties: unknown): ContentsData {\n  const currency = readCurrency(properties);\n  return {\n    type: 'contents',\n    amount: toMinorUnits(readValue(properties), currency),\n    currency: currency?.toUpperCase(),\n    contents: mapContents(readItems(properties), currency),\n  };\n}\n\nfunction customerActionData(properties: unknown): CustomerActionData {\n  const currency = readCurrency(properties);\n  return {\n    type: 'customer_action',\n    amount: toMinorUnits(readValue(properties), currency),\n    currency: currency?.toUpperCase(),\n  };\n}\n\nfunction planEnrollmentData(properties: unknown): PlanEnrollmentData {\n  const currency = readCurrency(properties);\n  const items = readItems(properties);\n  return {\n    type: 'plan_enrollment',\n    plan_id: items?.[0]?.item_id,\n    amount: toMinorUnits(readValue(properties), currency),\n    currency: currency?.toUpperCase(),\n    contents: mapContents(items, currency),\n  };\n}\n\nexport type MappedOAIEvent = {\n  type: StandardEvent | 'custom';\n  data: EventData;\n};\n\n/** Map an internal track event onto an OpenAI standard (or custom) conversion event. */\nexport function mapOAIEvent<T extends EventName>(\n  name: TrackName<T>,\n  properties?: TrackProperties<T>\n): MappedOAIEvent {\n  switch (name) {\n    case 'page_view':\n      return { type: 'page_viewed', data: contentsData(properties) };\n    case 'view_item':\n    case 'view_item_list':\n      return { type: 'contents_viewed', data: contentsData(properties) };\n    case 'begin_checkout':\n      return { type: 'checkout_started', data: contentsData(properties) };\n    case 'add_to_cart':\n      return { type: 'items_added', data: contentsData(properties) };\n    case 'purchase':\n      return { type: 'order_created', data: contentsData(properties) };\n    case 'generate_lead':\n    case 'qualify_lead':\n      return { type: 'lead_created', data: customerActionData(properties) };\n    case 'sign_up':\n    case 'login':\n      return { type: 'registration_completed', data: customerActionData(properties) };\n    case 'schedule':\n      return { type: 'appointment_scheduled', data: customerActionData(properties) };\n    case 'subscribe':\n      return { type: 'subscription_created', data: planEnrollmentData(properties) };\n    case 'trial_begin':\n      return { type: 'trial_started', data: planEnrollmentData(properties) };\n    default: {\n      const currency = readCurrency(properties);\n      return {\n        type: 'custom',\n        data: {\n          type: 'custom',\n          amount: toMinorUnits(readValue(properties), currency),\n          currency: currency?.toUpperCase(),\n          contents: mapContents(readItems(properties), currency),\n        },\n      };\n    }\n  }\n}\n"],"mappings":"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","names":[]}