@aranova/tracking-react 0.12.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ AdPlatformTracking: () => AdPlatformTracking,
23
24
  AranovaApiError: () => AranovaApiError,
24
25
  ConsentBanner: () => ConsentBanner,
25
26
  DEFAULT_PHONE_COUNTRY: () => DEFAULT_PHONE_COUNTRY,
@@ -45,6 +46,7 @@ __export(src_exports, {
45
46
  parsePhone: () => parsePhone,
46
47
  phoneField: () => phoneField,
47
48
  resetConsent: () => resetConsent,
49
+ resolveConversionConfig: () => resolveConversionConfig,
48
50
  saleCreateSchema: () => saleCreateSchema,
49
51
  saleItemSchema: () => saleItemSchema,
50
52
  saleServiceSchema: () => saleServiceSchema,
@@ -71,6 +73,13 @@ var import_react = require("react");
71
73
  // ../tracking-core/src/consent.ts
72
74
  var CONSENT_STATE_KEY = "consent_state";
73
75
  var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
76
+ var grantedListeners = /* @__PURE__ */ new Set();
77
+ function onConsentGranted(listener) {
78
+ grantedListeners.add(listener);
79
+ return () => {
80
+ grantedListeners.delete(listener);
81
+ };
82
+ }
74
83
  function buildConsentPayload(state) {
75
84
  return {
76
85
  ad_storage: state,
@@ -81,21 +90,40 @@ function buildConsentPayload(state) {
81
90
  }
82
91
  function getConsentState() {
83
92
  if (typeof window === "undefined") return "pending";
84
- const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);
85
- if (storedState === "granted" || storedState === "denied") return storedState;
93
+ try {
94
+ const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);
95
+ if (storedState === "granted" || storedState === "denied") return storedState;
96
+ } catch {
97
+ }
86
98
  return "pending";
87
99
  }
88
100
  function setConsentState(state) {
89
101
  if (typeof window === "undefined") return;
90
- window.localStorage.setItem(CONSENT_STATE_KEY, state);
91
- window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, (/* @__PURE__ */ new Date()).toISOString());
102
+ try {
103
+ window.localStorage.setItem(CONSENT_STATE_KEY, state);
104
+ window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, (/* @__PURE__ */ new Date()).toISOString());
105
+ } catch {
106
+ }
92
107
  if (typeof window.gtag === "function")
93
108
  window.gtag("consent", "update", buildConsentPayload(state));
109
+ if (typeof window.fbq === "function")
110
+ window.fbq("consent", state === "granted" ? "grant" : "revoke");
111
+ if (state === "granted") {
112
+ for (const listener of grantedListeners) {
113
+ try {
114
+ listener();
115
+ } catch {
116
+ }
117
+ }
118
+ }
94
119
  }
95
120
  function resetConsent() {
96
121
  if (typeof window === "undefined") return;
97
- window.localStorage.removeItem(CONSENT_STATE_KEY);
98
- window.localStorage.removeItem(CONSENT_TIMESTAMP_KEY);
122
+ try {
123
+ window.localStorage.removeItem(CONSENT_STATE_KEY);
124
+ window.localStorage.removeItem(CONSENT_TIMESTAMP_KEY);
125
+ } catch {
126
+ }
99
127
  }
100
128
  function restoreStoredConsent() {
101
129
  const consentState = getConsentState();
@@ -103,45 +131,106 @@ function restoreStoredConsent() {
103
131
  return consentState;
104
132
  }
105
133
 
106
- // ../tracking-core/src/payloads.ts
107
- function createTrackingClientContext(surface, input = {}) {
134
+ // ../tracking-core/src/tracking.ts
135
+ var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
136
+ var TRACKING_PARAM_KEYS = [
137
+ "gclid",
138
+ "fbclid",
139
+ "utm_source",
140
+ "utm_medium",
141
+ "utm_campaign",
142
+ "utm_term",
143
+ "utm_content"
144
+ ];
145
+ function createEmptyTrackingParams() {
108
146
  return {
109
- surface,
110
- sdk_version: input.sdkVersion ?? null,
111
- package_name: input.packageName ?? null,
112
- site_origin: input.siteOrigin ?? (typeof window === "undefined" ? null : window.location.origin),
113
- page_title: input.pageTitle ?? (typeof document === "undefined" ? null : document.title || null),
114
- referrer: input.referrer ?? (typeof document === "undefined" ? null : document.referrer || null),
115
- environment: input.environment ?? "production",
116
- active_gtag_ids: input.activeGtagIds ?? null
147
+ gclid: null,
148
+ fbclid: null,
149
+ utm_source: null,
150
+ utm_medium: null,
151
+ utm_campaign: null,
152
+ utm_term: null,
153
+ utm_content: null
117
154
  };
118
155
  }
119
- function createTrackingSessionUpsertPayload(trackingParams, input, context) {
120
- return {
121
- session_id: input.sessionId,
122
- visitor_id: input.visitorId ?? null,
123
- gclid: trackingParams.gclid,
124
- fbclid: trackingParams.fbclid,
125
- utm_source: trackingParams.utm_source,
126
- utm_medium: trackingParams.utm_medium,
127
- utm_campaign: trackingParams.utm_campaign,
128
- utm_term: trackingParams.utm_term,
129
- utm_content: trackingParams.utm_content,
130
- first_page: input.firstPage ?? null,
131
- consent_state: input.consentState ?? null,
132
- context
133
- };
156
+ function normalizeTrackingCookieValue(value) {
157
+ return typeof value === "string" && value.length > 0 ? value : null;
134
158
  }
135
- function createTrackingEventCreatePayload(trackingParams, input, context) {
136
- return {
137
- session_id: input.sessionId,
138
- event_type: input.eventType,
139
- gclid: trackingParams.gclid,
140
- fbclid: trackingParams.fbclid,
141
- page_url: input.pageUrl ?? (typeof window === "undefined" ? null : window.location.href),
142
- metadata: input.metadata ?? null,
143
- context
144
- };
159
+ function getTrackingParamsFromCookieReader(readCookie) {
160
+ return TRACKING_PARAM_KEYS.reduce((params, key) => {
161
+ params[key] = normalizeTrackingCookieValue(readCookie(key));
162
+ return params;
163
+ }, createEmptyTrackingParams());
164
+ }
165
+ function getTrackingQueryValues(searchParams) {
166
+ return TRACKING_PARAM_KEYS.reduce((params, key) => {
167
+ const value = searchParams.get(key);
168
+ if (typeof value === "string" && value.trim().length > 0) {
169
+ params[key] = value;
170
+ }
171
+ return params;
172
+ }, {});
173
+ }
174
+ var FALLBACK_STORAGE_PREFIX = "_aranova_track_";
175
+ function fallbackKey(name) {
176
+ return `${FALLBACK_STORAGE_PREFIX}${name}`;
177
+ }
178
+ function persistCookieValue(name, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
179
+ const encoded = encodeURIComponent(value);
180
+ if (typeof document !== "undefined") {
181
+ try {
182
+ document.cookie = `${name}=${encoded}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;
183
+ } catch {
184
+ }
185
+ }
186
+ if (typeof window !== "undefined") {
187
+ try {
188
+ window.localStorage.setItem(fallbackKey(name), encoded);
189
+ } catch {
190
+ }
191
+ }
192
+ }
193
+ function readCookieValue(name) {
194
+ if (typeof document !== "undefined") {
195
+ const cookies = document.cookie ? document.cookie.split("; ") : [];
196
+ const match = cookies.find((cookie) => cookie.startsWith(`${name}=`));
197
+ if (match) {
198
+ const [, rawValue = ""] = match.split("=");
199
+ return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
200
+ }
201
+ }
202
+ if (typeof window !== "undefined") {
203
+ try {
204
+ const stored = window.localStorage.getItem(fallbackKey(name));
205
+ if (stored) return normalizeTrackingCookieValue(decodeURIComponent(stored));
206
+ } catch {
207
+ }
208
+ }
209
+ return null;
210
+ }
211
+ function getCookieValueFromDocument(key) {
212
+ return readCookieValue(key);
213
+ }
214
+ function setTrackingCookie(key, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
215
+ persistCookieValue(key, value, maxAgeSeconds);
216
+ }
217
+ function mergeTrackingParams(primary, fallback) {
218
+ return TRACKING_PARAM_KEYS.reduce((merged, key) => {
219
+ merged[key] = primary[key] ?? fallback[key];
220
+ return merged;
221
+ }, createEmptyTrackingParams());
222
+ }
223
+ function persistTrackingParamsFromSearchParams(searchParams, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
224
+ const trackingValues = getTrackingQueryValues(searchParams);
225
+ Object.entries(trackingValues).forEach(([key, value]) => {
226
+ setTrackingCookie(key, value, maxAgeSeconds);
227
+ });
228
+ return trackingValues;
229
+ }
230
+ function captureTrackingParamsFromLocation(url = typeof window === "undefined" ? "" : window.location.href, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
231
+ const resolvedUrl = typeof window === "undefined" ? new URL(url || "https://example.invalid") : new URL(url, window.location.origin);
232
+ persistTrackingParamsFromSearchParams(resolvedUrl.searchParams, maxAgeSeconds);
233
+ return getTrackingParamsFromCookieReader(getCookieValueFromDocument);
145
234
  }
146
235
 
147
236
  // ../tracking-core/src/gtag.ts
@@ -162,6 +251,24 @@ function ensureGtagFunction() {
162
251
  };
163
252
  return window.gtag;
164
253
  }
254
+ var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
255
+ function isValidSendTo(sendTo) {
256
+ return SEND_TO_RE.test(sendTo);
257
+ }
258
+ function fireGtagConversion(input) {
259
+ if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
260
+ if (!isValidSendTo(input.sendTo)) return false;
261
+ const params = { send_to: input.sendTo };
262
+ if (input.value != null) params.value = input.value;
263
+ if (input.currency) params.currency = input.currency;
264
+ if (input.transactionId) params.transaction_id = input.transactionId;
265
+ try {
266
+ window.gtag("event", "conversion", params);
267
+ return true;
268
+ } catch {
269
+ return false;
270
+ }
271
+ }
165
272
  function applyDefaultConsentState() {
166
273
  const gtag = ensureGtagFunction();
167
274
  gtag("consent", "default", {
@@ -214,70 +321,441 @@ function bootstrapMultipleGtags(gtagIds) {
214
321
  restoreStoredConsent();
215
322
  }
216
323
 
217
- // ../tracking-core/src/tracking.ts
218
- var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
219
- var TRACKING_PARAM_KEYS = [
220
- "gclid",
221
- "fbclid",
222
- "utm_source",
223
- "utm_medium",
224
- "utm_campaign",
225
- "utm_term",
226
- "utm_content"
227
- ];
228
- function createEmptyTrackingParams() {
324
+ // ../tracking-core/src/fbq.ts
325
+ var FB_EVENTS_SCRIPT_HOST = "https://connect.facebook.net/en_US/fbevents.js";
326
+ var FBC_COOKIE = "_fbc";
327
+ var FBP_COOKIE = "_fbp";
328
+ var META_PIXEL_ID_PATTERN = /^\d{15,16}$/;
329
+ function isValidMetaPixelId(id) {
330
+ return META_PIXEL_ID_PATTERN.test(id);
331
+ }
332
+ function computeFbSubdomainIndex(hostname) {
333
+ const labels = hostname.split(".").filter(Boolean);
334
+ return Math.max(0, labels.length - 1);
335
+ }
336
+ function buildFbc(fbclid, now, hostname) {
337
+ const host = hostname ?? (typeof window === "undefined" ? "" : window.location.hostname);
338
+ return `fb.${computeFbSubdomainIndex(host)}.${now}.${fbclid}`;
339
+ }
340
+ function getFbcCookie() {
341
+ return readCookieValue(FBC_COOKIE);
342
+ }
343
+ function getFbpCookie() {
344
+ return readCookieValue(FBP_COOKIE);
345
+ }
346
+ function readFbclidFromUrl() {
347
+ if (typeof window === "undefined") return null;
348
+ try {
349
+ const value = new URL(window.location.href).searchParams.get("fbclid");
350
+ return value && value.trim().length > 0 ? value : null;
351
+ } catch {
352
+ return null;
353
+ }
354
+ }
355
+ function captureFbc(now = typeof Date === "undefined" ? 0 : Date.now()) {
356
+ if (typeof window === "undefined") return;
357
+ if (getFbcCookie()) return;
358
+ const fbclid = readFbclidFromUrl() ?? readCookieValue("fbclid");
359
+ if (!fbclid) return;
360
+ persistCookieValue(FBC_COOKIE, buildFbc(fbclid, now), TRACKING_COOKIE_MAX_AGE_SECONDS);
361
+ }
362
+ function getScriptMarker2(id) {
363
+ return `aranova-${id}`;
364
+ }
365
+ function ensureFbqFunction() {
366
+ const w = window;
367
+ if (typeof w.fbq === "function") return w.fbq;
368
+ const fbq = function(...args) {
369
+ if (fbq.callMethod) fbq.callMethod.apply(fbq, args);
370
+ else fbq.queue.push(args);
371
+ };
372
+ fbq.push = fbq;
373
+ fbq.loaded = true;
374
+ fbq.version = "2.0";
375
+ fbq.queue = [];
376
+ w.fbq = fbq;
377
+ if (!w._fbq) w._fbq = fbq;
378
+ return fbq;
379
+ }
380
+ function applyDefaultMetaConsentState() {
381
+ ensureFbqFunction()("consent", "revoke");
382
+ }
383
+ function loadFbeventsScript() {
384
+ if (typeof document === "undefined") return;
385
+ const marker = getScriptMarker2("fbq-loader");
386
+ const existing = document.querySelector(
387
+ `script[${TRACKING_SCRIPT_ATTRIBUTE}="${marker}"]`
388
+ );
389
+ if (existing) return;
390
+ const script = document.createElement("script");
391
+ script.async = true;
392
+ script.src = FB_EVENTS_SCRIPT_HOST;
393
+ script.setAttribute(TRACKING_SCRIPT_ATTRIBUTE, marker);
394
+ document.head.append(script);
395
+ }
396
+ function initializeMetaPixel(pixelId) {
397
+ const fbq = ensureFbqFunction();
398
+ fbq("init", pixelId);
399
+ fbq("track", "PageView");
400
+ }
401
+ function restoreMetaConsentState() {
402
+ if (typeof window === "undefined") return;
403
+ const state = getConsentState();
404
+ if (state === "granted") window.fbq?.("consent", "grant");
405
+ else if (state === "denied") window.fbq?.("consent", "revoke");
406
+ }
407
+ function bootstrapMetaPixel(pixelId) {
408
+ if (typeof window === "undefined" || typeof document === "undefined") return;
409
+ if (!isValidMetaPixelId(pixelId)) return;
410
+ applyDefaultMetaConsentState();
411
+ loadFbeventsScript();
412
+ initializeMetaPixel(pixelId);
413
+ restoreMetaConsentState();
414
+ captureFbc();
415
+ }
416
+ function bootstrapMultiplePixels(pixelIds) {
417
+ if (typeof window === "undefined" || typeof document === "undefined") return;
418
+ const ids = Object.values(pixelIds).filter(
419
+ (id) => typeof id === "string" && isValidMetaPixelId(id)
420
+ );
421
+ if (ids.length === 0) return;
422
+ applyDefaultMetaConsentState();
423
+ loadFbeventsScript();
424
+ const fbq = ensureFbqFunction();
425
+ for (const id of ids) {
426
+ fbq("init", id);
427
+ }
428
+ fbq("track", "PageView");
429
+ restoreMetaConsentState();
430
+ captureFbc();
431
+ }
432
+
433
+ // ../tracking-core/src/payloads.ts
434
+ function createTrackingClientContext(surface, input = {}) {
229
435
  return {
230
- gclid: null,
231
- fbclid: null,
232
- utm_source: null,
233
- utm_medium: null,
234
- utm_campaign: null,
235
- utm_term: null,
236
- utm_content: null
436
+ surface,
437
+ sdk_version: input.sdkVersion ?? null,
438
+ package_name: input.packageName ?? null,
439
+ site_origin: input.siteOrigin ?? (typeof window === "undefined" ? null : window.location.origin),
440
+ page_title: input.pageTitle ?? (typeof document === "undefined" ? null : document.title || null),
441
+ referrer: input.referrer ?? (typeof document === "undefined" ? null : document.referrer || null),
442
+ environment: input.environment ?? "production",
443
+ active_gtag_ids: input.activeGtagIds ?? null
237
444
  };
238
445
  }
239
- function normalizeTrackingCookieValue(value) {
240
- return typeof value === "string" && value.length > 0 ? value : null;
446
+ function createTrackingSessionUpsertPayload(trackingParams, input, context) {
447
+ return {
448
+ session_id: input.sessionId,
449
+ visitor_id: input.visitorId ?? null,
450
+ gclid: trackingParams.gclid,
451
+ fbclid: trackingParams.fbclid,
452
+ fbc: getFbcCookie(),
453
+ fbp: getFbpCookie(),
454
+ utm_source: trackingParams.utm_source,
455
+ utm_medium: trackingParams.utm_medium,
456
+ utm_campaign: trackingParams.utm_campaign,
457
+ utm_term: trackingParams.utm_term,
458
+ utm_content: trackingParams.utm_content,
459
+ first_page: input.firstPage ?? null,
460
+ consent_state: input.consentState ?? null,
461
+ context
462
+ };
241
463
  }
242
- function getTrackingParamsFromCookieReader(readCookie) {
243
- return TRACKING_PARAM_KEYS.reduce((params, key) => {
244
- params[key] = normalizeTrackingCookieValue(readCookie(key));
245
- return params;
246
- }, createEmptyTrackingParams());
464
+ function createTrackingEventCreatePayload(trackingParams, input, context) {
465
+ return {
466
+ session_id: input.sessionId,
467
+ event_type: input.eventType,
468
+ gclid: trackingParams.gclid,
469
+ fbclid: trackingParams.fbclid,
470
+ fbc: getFbcCookie(),
471
+ fbp: getFbpCookie(),
472
+ page_url: input.pageUrl ?? (typeof window === "undefined" ? null : window.location.href),
473
+ metadata: input.metadata ?? null,
474
+ context
475
+ };
247
476
  }
248
- function getTrackingQueryValues(searchParams) {
249
- return TRACKING_PARAM_KEYS.reduce((params, key) => {
250
- const value = searchParams.get(key);
251
- if (typeof value === "string" && value.trim().length > 0) {
252
- params[key] = value;
253
- }
254
- return params;
255
- }, {});
477
+
478
+ // ../tracking-core/src/resources/conversion-firing.ts
479
+ var DEDUP_PREFIX = "_aranova_conv_";
480
+ var MAX_PENDING = 100;
481
+ var pendingQueue = [];
482
+ function dedupKey(input) {
483
+ return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
484
+ }
485
+ function alreadyFired(input) {
486
+ if (!input.transactionId || typeof window === "undefined") return false;
487
+ try {
488
+ return window.sessionStorage.getItem(dedupKey(input)) !== null;
489
+ } catch {
490
+ return false;
491
+ }
256
492
  }
257
- function getCookieValueFromDocument(key) {
258
- if (typeof document === "undefined") return null;
259
- const cookies = document.cookie ? document.cookie.split("; ") : [];
260
- const match = cookies.find((cookie) => cookie.startsWith(`${key}=`));
261
- if (!match) return null;
262
- const [, rawValue = ""] = match.split("=");
263
- return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
493
+ function markFired(input) {
494
+ if (!input.transactionId || typeof window === "undefined") return;
495
+ try {
496
+ window.sessionStorage.setItem(dedupKey(input), "1");
497
+ } catch {
498
+ }
264
499
  }
265
- function setTrackingCookie(key, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
266
- if (typeof document === "undefined") return;
267
- const encodedValue = encodeURIComponent(value);
268
- document.cookie = `${key}=${encodedValue}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;
500
+ function fireOnce(input) {
501
+ if (alreadyFired(input)) return;
502
+ if (fireGtagConversion(input)) markFired(input);
269
503
  }
270
- function persistTrackingParamsFromSearchParams(searchParams, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
271
- const trackingValues = getTrackingQueryValues(searchParams);
272
- Object.entries(trackingValues).forEach(([key, value]) => {
273
- setTrackingCookie(key, value, maxAgeSeconds);
504
+ function fireConversionWithConsent(input) {
505
+ const state = getConsentState();
506
+ if (state === "denied") return;
507
+ if (state === "pending") {
508
+ if (pendingQueue.length >= MAX_PENDING) pendingQueue.shift();
509
+ pendingQueue.push(input);
510
+ return;
511
+ }
512
+ fireOnce(input);
513
+ }
514
+ function flushPendingConversions() {
515
+ if (getConsentState() !== "granted") return;
516
+ while (pendingQueue.length > 0) {
517
+ const input = pendingQueue.shift();
518
+ if (input) fireOnce(input);
519
+ }
520
+ }
521
+ if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
522
+
523
+ // ../tracking-core/src/resources/conversion-config.ts
524
+ function isStringMap(value) {
525
+ return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
526
+ }
527
+ function parseFiring(value) {
528
+ if (!value || typeof value !== "object") return null;
529
+ const f = value;
530
+ if (typeof f.send_to !== "string") return null;
531
+ return {
532
+ send_to: f.send_to,
533
+ value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
534
+ currency: typeof f.currency === "string" ? f.currency : null
535
+ };
536
+ }
537
+ function parseTrigger(value) {
538
+ if (!value || typeof value !== "object") return null;
539
+ const t = value;
540
+ if (typeof t.event_type !== "string") return null;
541
+ const spec = { event_type: t.event_type };
542
+ if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
543
+ if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
544
+ if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
545
+ if (typeof t.page_name === "string") spec.page_name = t.page_name;
546
+ return spec;
547
+ }
548
+ function parseConversionConfig(raw) {
549
+ if (!raw || typeof raw !== "object") return null;
550
+ const obj = raw;
551
+ const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
552
+ const services = servicesRaw.flatMap((entry) => {
553
+ if (!entry || typeof entry !== "object") return [];
554
+ const s = entry;
555
+ if (typeof s.key !== "string") return [];
556
+ return [
557
+ {
558
+ key: s.key,
559
+ label: typeof s.label === "string" ? s.label : void 0,
560
+ firing: parseFiring(s.firing)
561
+ }
562
+ ];
274
563
  });
275
- return trackingValues;
564
+ const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
565
+ const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
566
+ if (!entry || typeof entry !== "object") return [];
567
+ const g = entry;
568
+ if (typeof g.key !== "string") return [];
569
+ return [
570
+ {
571
+ key: g.key,
572
+ label: typeof g.label === "string" ? g.label : void 0,
573
+ kind: g.kind === "event" ? "event" : "sale",
574
+ trigger: parseTrigger(g.trigger),
575
+ firing: parseFiring(g.firing)
576
+ }
577
+ ];
578
+ }) : services.map((s) => ({
579
+ key: s.key,
580
+ label: s.label,
581
+ kind: "sale",
582
+ trigger: null,
583
+ firing: s.firing
584
+ }));
585
+ return {
586
+ schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
587
+ config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
588
+ business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
589
+ customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
590
+ environment: typeof obj.environment === "string" ? obj.environment : void 0,
591
+ gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
592
+ meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
593
+ services,
594
+ goals
595
+ };
276
596
  }
277
- function captureTrackingParamsFromLocation(url = typeof window === "undefined" ? "" : window.location.href, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
278
- const resolvedUrl = typeof window === "undefined" ? new URL(url || "https://example.invalid") : new URL(url, window.location.origin);
279
- persistTrackingParamsFromSearchParams(resolvedUrl.searchParams, maxAgeSeconds);
280
- return getTrackingParamsFromCookieReader(getCookieValueFromDocument);
597
+ var CACHE_PREFIX = "_aranova_cfg_";
598
+ function cacheKey(url) {
599
+ return `${CACHE_PREFIX}${url}`;
600
+ }
601
+ function readCache(url) {
602
+ if (typeof window === "undefined") return null;
603
+ try {
604
+ const raw = window.sessionStorage.getItem(cacheKey(url));
605
+ if (!raw) return null;
606
+ const parsed = JSON.parse(raw);
607
+ const config = parseConversionConfig(parsed.config);
608
+ if (!config) return null;
609
+ return {
610
+ etag: typeof parsed.etag === "string" ? parsed.etag : null,
611
+ config
612
+ };
613
+ } catch {
614
+ return null;
615
+ }
616
+ }
617
+ function writeCache(url, entry) {
618
+ if (typeof window === "undefined") return;
619
+ try {
620
+ window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
621
+ } catch {
622
+ }
623
+ }
624
+ function resolveConversionConfig(options) {
625
+ const cached = readCache(options.cdnUrl);
626
+ let current = cached?.config ?? options.baked ?? null;
627
+ let etag = cached?.etag ?? null;
628
+ const goalsByKey = /* @__PURE__ */ new Map();
629
+ function rebuildIndex() {
630
+ goalsByKey.clear();
631
+ for (const goal of current?.goals ?? []) {
632
+ goalsByKey.set(goal.key, goal);
633
+ }
634
+ }
635
+ function adopt(next, nextEtag) {
636
+ if (!next) return;
637
+ if (current && next.config_version <= current.config_version) return;
638
+ current = next;
639
+ etag = nextEtag;
640
+ rebuildIndex();
641
+ writeCache(options.cdnUrl, { etag, config: next });
642
+ }
643
+ async function revalidate() {
644
+ if (typeof window === "undefined") return;
645
+ try {
646
+ const doFetch = options.fetchImpl ?? globalThis.fetch;
647
+ if (!doFetch) return;
648
+ const headers = {};
649
+ if (etag) headers["If-None-Match"] = etag;
650
+ const response = await doFetch(options.cdnUrl, {
651
+ method: "GET",
652
+ headers
653
+ });
654
+ if (response.status === 304 || !response.ok) return;
655
+ adopt(parseConversionConfig(await response.json()), response.headers.get("ETag"));
656
+ } catch {
657
+ }
658
+ }
659
+ rebuildIndex();
660
+ void revalidate();
661
+ return {
662
+ getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
663
+ getGoal: (key) => goalsByKey.get(key) ?? null,
664
+ listGoals: () => [...goalsByKey.values()],
665
+ current: () => current,
666
+ revalidate
667
+ };
668
+ }
669
+
670
+ // ../tracking-core/src/resources/sales/money.ts
671
+ var MINOR_UNIT_EXPONENT = {
672
+ USD: 2,
673
+ CAD: 2
674
+ };
675
+ function exponentFor(currency) {
676
+ return MINOR_UNIT_EXPONENT[currency] ?? 2;
677
+ }
678
+ function toMinor(amount, currency) {
679
+ return Math.round(amount * 10 ** exponentFor(currency));
680
+ }
681
+ function fromMinor(cents, currency) {
682
+ return cents / 10 ** exponentFor(currency);
683
+ }
684
+ function formatMoney(cents, currency, locale) {
685
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
686
+ fromMinor(cents, currency)
687
+ );
688
+ }
689
+ function formatDateInTz(iso, timeZone, opts, locale) {
690
+ const date = new Date(iso);
691
+ if (Number.isNaN(date.getTime())) return iso;
692
+ return new Intl.DateTimeFormat(locale, {
693
+ year: "numeric",
694
+ month: "short",
695
+ day: "2-digit",
696
+ hour: "2-digit",
697
+ minute: "2-digit",
698
+ ...opts,
699
+ timeZone
700
+ }).format(date);
701
+ }
702
+
703
+ // ../tracking-core/src/resources/conversion-autofire.ts
704
+ function thresholdMet(goal, eventType, metadata) {
705
+ const t = goal.trigger;
706
+ if (!t || t.event_type !== eventType) return false;
707
+ switch (eventType) {
708
+ case "scroll_depth":
709
+ return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
710
+ case "time_on_site":
711
+ return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
712
+ case "multi_page_session":
713
+ return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
714
+ case "specific_page_visit":
715
+ return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
716
+ case "page_view":
717
+ case "form_start":
718
+ return true;
719
+ // no threshold — fire whenever the detector emits
720
+ default:
721
+ return false;
722
+ }
723
+ }
724
+ function currentPath() {
725
+ return typeof window === "undefined" ? "" : window.location.pathname;
726
+ }
727
+ function createConversionAutoFire(store) {
728
+ return {
729
+ onAutomaticEvent(eventType, metadata) {
730
+ for (const goal of store.listGoals()) {
731
+ if (goal.kind !== "event" || !goal.firing) continue;
732
+ if (!thresholdMet(goal, eventType, metadata)) continue;
733
+ const firing = goal.firing;
734
+ const cents = firing.value_cents ?? null;
735
+ const currency = firing.currency ?? null;
736
+ fireConversionWithConsent({
737
+ sendTo: firing.send_to,
738
+ value: cents != null && currency ? fromMinor(cents, currency) : null,
739
+ currency,
740
+ // Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
741
+ // shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
742
+ transactionId: `auto:${goal.key}:${currentPath()}`
743
+ });
744
+ }
745
+ }
746
+ };
747
+ }
748
+ function withConversionAutoFire(client, autoFire) {
749
+ return {
750
+ ...client,
751
+ trackEvent: (input) => {
752
+ client.trackEvent(input);
753
+ try {
754
+ autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
755
+ } catch {
756
+ }
757
+ }
758
+ };
281
759
  }
282
760
 
283
761
  // ../tracking-core/src/session.ts
@@ -608,11 +1086,22 @@ function createTrackingClient(config) {
608
1086
  let queue = [];
609
1087
  let flushTimer = null;
610
1088
  let firstPage = null;
1089
+ let initialParams = createEmptyTrackingParams();
611
1090
  let destroyed = false;
612
1091
  const visitorId = getVisitorId();
613
1092
  const initialSession = getOrRotateSessionId();
614
1093
  let sessionId = initialSession.id;
615
- if (typeof window !== "undefined") firstPage = window.location.href;
1094
+ if (typeof window !== "undefined") {
1095
+ firstPage = window.location.href;
1096
+ try {
1097
+ initialParams = captureTrackingParamsFromLocation();
1098
+ } catch {
1099
+ }
1100
+ try {
1101
+ captureFbc();
1102
+ } catch {
1103
+ }
1104
+ }
616
1105
  function enqueueHeartbeat() {
617
1106
  const metadata = buildHeartbeatMetadata(
618
1107
  config.surface,
@@ -637,7 +1126,7 @@ function createTrackingClient(config) {
637
1126
  enqueueHeartbeat();
638
1127
  }
639
1128
  sessionId = rotated.id;
640
- const params = readTrackingParams();
1129
+ const params = mergeTrackingParams(readTrackingParams(), initialParams);
641
1130
  const context = buildContext(
642
1131
  config.surface,
643
1132
  sdkVersion,
@@ -650,6 +1139,8 @@ function createTrackingClient(config) {
650
1139
  visitor_id: visitorId,
651
1140
  gclid: params.gclid,
652
1141
  fbclid: params.fbclid,
1142
+ fbc: getFbcCookie(),
1143
+ fbp: getFbpCookie(),
653
1144
  utm_source: params.utm_source,
654
1145
  utm_medium: params.utm_medium,
655
1146
  utm_campaign: params.utm_campaign,
@@ -1086,7 +1577,7 @@ function attachScrollDepth(client, config) {
1086
1577
  }
1087
1578
  const thresholds = new Set(config.thresholds);
1088
1579
  let firedForPath = /* @__PURE__ */ new Set();
1089
- let currentPath = window.location.pathname;
1580
+ let currentPath2 = window.location.pathname;
1090
1581
  let rafId = null;
1091
1582
  function getScrollPercent() {
1092
1583
  const doc = document.documentElement;
@@ -1105,7 +1596,7 @@ function attachScrollDepth(client, config) {
1105
1596
  eventType: "scroll_depth",
1106
1597
  metadata: {
1107
1598
  depth_percent: threshold,
1108
- page: { path: currentPath }
1599
+ page: { path: currentPath2 }
1109
1600
  },
1110
1601
  pageUrl: window.location.href,
1111
1602
  occurredAt: null
@@ -1122,8 +1613,8 @@ function attachScrollDepth(client, config) {
1122
1613
  }
1123
1614
  function resetIfPathChanged() {
1124
1615
  const newPath = window.location.pathname;
1125
- if (newPath === currentPath) return;
1126
- currentPath = newPath;
1616
+ if (newPath === currentPath2) return;
1617
+ currentPath2 = newPath;
1127
1618
  firedForPath = /* @__PURE__ */ new Set();
1128
1619
  setTimeout(checkThresholds, 0);
1129
1620
  }
@@ -1199,13 +1690,13 @@ function attachMultiPageSession(client, config) {
1199
1690
  return storage.getItem(FIRED_KEY) === "1";
1200
1691
  }
1201
1692
  function check() {
1202
- const currentPath = window.location.pathname;
1203
- if (currentPath === lastCheckedPath) return;
1204
- lastCheckedPath = currentPath;
1693
+ const currentPath2 = window.location.pathname;
1694
+ if (currentPath2 === lastCheckedPath) return;
1695
+ lastCheckedPath = currentPath2;
1205
1696
  resetIfSessionChanged();
1206
1697
  if (hasFired()) return;
1207
1698
  const paths = getDistinctPaths();
1208
- paths.add(currentPath);
1699
+ paths.add(currentPath2);
1209
1700
  saveDistinctPaths(paths);
1210
1701
  if (paths.size >= pageThreshold) {
1211
1702
  storage.setItem(FIRED_KEY, "1");
@@ -1249,7 +1740,7 @@ function attachFormStart(client, config) {
1249
1740
  }
1250
1741
  const selector = config.selector ?? "form";
1251
1742
  let firedForms = /* @__PURE__ */ new Set();
1252
- let currentPath = window.location.pathname;
1743
+ let currentPath2 = window.location.pathname;
1253
1744
  function getFormKey(form) {
1254
1745
  if (form.id) return `id:${form.id}`;
1255
1746
  const explicitAction = form.getAttribute("action");
@@ -1280,8 +1771,8 @@ function attachFormStart(client, config) {
1280
1771
  }
1281
1772
  function resetIfPathChanged() {
1282
1773
  const newPath = window.location.pathname;
1283
- if (newPath === currentPath) return;
1284
- currentPath = newPath;
1774
+ if (newPath === currentPath2) return;
1775
+ currentPath2 = newPath;
1285
1776
  firedForms = /* @__PURE__ */ new Set();
1286
1777
  }
1287
1778
  const originalPushState = history.pushState.bind(history);
@@ -1360,21 +1851,64 @@ async function salesRequest(config, method, path, body) {
1360
1851
  }
1361
1852
 
1362
1853
  // ../tracking-core/src/resources/sales/client.ts
1854
+ function fireRecordedConversions(firing, input, recorded, sale, currency) {
1855
+ if (!firing) return;
1856
+ const txnBase = input.external_id ?? sale.id;
1857
+ for (const item of recorded) {
1858
+ if (!item.service) continue;
1859
+ const config = firing.getFiring(item.service);
1860
+ if (!config) continue;
1861
+ const cents = item.amount_cents ?? config.value_cents ?? null;
1862
+ fireConversionWithConsent({
1863
+ sendTo: config.send_to,
1864
+ value: cents != null ? fromMinor(cents, currency) : null,
1865
+ currency: config.currency ?? currency,
1866
+ transactionId: `${txnBase}:${item.service}`
1867
+ });
1868
+ }
1869
+ }
1363
1870
  function createSalesClient(config) {
1364
- return {
1365
- async record(input) {
1366
- const currency = input.currency ?? config.defaultCurrency;
1367
- if (!currency) {
1368
- throw new Error(
1369
- "record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
1370
- );
1871
+ async function record(input) {
1872
+ const currency = input.currency ?? config.defaultCurrency;
1873
+ if (!currency) {
1874
+ throw new Error(
1875
+ "record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
1876
+ );
1877
+ }
1878
+ const body = {
1879
+ ...input,
1880
+ currency,
1881
+ occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
1882
+ };
1883
+ const sale = await salesRequest(config, "POST", "/sales", body);
1884
+ const recorded = input.services?.length ? input.services.map((s) => ({
1885
+ service: s.service,
1886
+ amount_cents: s.amount_cents
1887
+ })) : [
1888
+ {
1889
+ service: input.service,
1890
+ amount_cents: input.amount_total_cents ?? null
1371
1891
  }
1372
- const body = {
1373
- ...input,
1892
+ ];
1893
+ fireRecordedConversions(config.firing, input, recorded, sale, currency);
1894
+ return sale;
1895
+ }
1896
+ return {
1897
+ record,
1898
+ // recordSale is the intent-revealing alias — same behavior, clearer call site.
1899
+ recordSale: record,
1900
+ trackConversion(key, options) {
1901
+ const firing = config.firing?.getFiring(key);
1902
+ if (!firing) return;
1903
+ const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
1904
+ const cents = firing.value_cents ?? null;
1905
+ const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
1906
+ fireConversionWithConsent({
1907
+ sendTo: firing.send_to,
1908
+ value,
1374
1909
  currency,
1375
- occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
1376
- };
1377
- return salesRequest(config, "POST", "/sales", body);
1910
+ transactionId: options?.transactionId ?? null
1911
+ });
1378
1912
  },
1379
1913
  async list(query) {
1380
1914
  const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
@@ -1468,39 +2002,6 @@ function createSalesClient(config) {
1468
2002
  };
1469
2003
  }
1470
2004
 
1471
- // ../tracking-core/src/resources/sales/money.ts
1472
- var MINOR_UNIT_EXPONENT = {
1473
- USD: 2,
1474
- CAD: 2
1475
- };
1476
- function exponentFor(currency) {
1477
- return MINOR_UNIT_EXPONENT[currency] ?? 2;
1478
- }
1479
- function toMinor(amount, currency) {
1480
- return Math.round(amount * 10 ** exponentFor(currency));
1481
- }
1482
- function fromMinor(cents, currency) {
1483
- return cents / 10 ** exponentFor(currency);
1484
- }
1485
- function formatMoney(cents, currency, locale) {
1486
- return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
1487
- fromMinor(cents, currency)
1488
- );
1489
- }
1490
- function formatDateInTz(iso, timeZone, opts, locale) {
1491
- const date = new Date(iso);
1492
- if (Number.isNaN(date.getTime())) return iso;
1493
- return new Intl.DateTimeFormat(locale, {
1494
- year: "numeric",
1495
- month: "short",
1496
- day: "2-digit",
1497
- hour: "2-digit",
1498
- minute: "2-digit",
1499
- ...opts,
1500
- timeZone
1501
- }).format(date);
1502
- }
1503
-
1504
2005
  // ../tracking-core/src/resources/sales/schema.ts
1505
2006
  var import_zod11 = require("zod");
1506
2007
  var SUPPORTED_CURRENCIES = ["USD", "CAD"];
@@ -1899,11 +2400,19 @@ var ANIMATION_KEYFRAMES = `
1899
2400
  }
1900
2401
  `;
1901
2402
 
1902
- // src/GoogleAdsTracking.tsx
2403
+ // src/AdPlatformTracking.tsx
1903
2404
  var import_react3 = require("react");
1904
- function GoogleAdsTracking(props) {
1905
- const { gtagId, gtagIds } = props;
2405
+ function AdPlatformTracking({
2406
+ gtagId,
2407
+ gtagIds,
2408
+ metaPixelId,
2409
+ metaPixelIds
2410
+ }) {
1906
2411
  const gtagIdsKey = (0, import_react3.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
2412
+ const metaPixelIdsKey = (0, import_react3.useMemo)(
2413
+ () => metaPixelIds ? JSON.stringify(metaPixelIds) : "",
2414
+ [metaPixelIds]
2415
+ );
1907
2416
  (0, import_react3.useEffect)(() => {
1908
2417
  if (gtagIds && Object.keys(gtagIds).length > 0) {
1909
2418
  bootstrapMultipleGtags(gtagIds);
@@ -1911,21 +2420,43 @@ function GoogleAdsTracking(props) {
1911
2420
  bootstrapGoogleAdsTracking(gtagId);
1912
2421
  }
1913
2422
  }, [gtagId, gtagIdsKey]);
2423
+ (0, import_react3.useEffect)(() => {
2424
+ if (metaPixelIds && Object.keys(metaPixelIds).length > 0) {
2425
+ bootstrapMultiplePixels(metaPixelIds);
2426
+ } else if (metaPixelId) {
2427
+ bootstrapMetaPixel(metaPixelId);
2428
+ }
2429
+ }, [metaPixelId, metaPixelIdsKey]);
2430
+ return null;
2431
+ }
2432
+
2433
+ // src/GoogleAdsTracking.tsx
2434
+ var import_react4 = require("react");
2435
+ function GoogleAdsTracking(props) {
2436
+ const { gtagId, gtagIds } = props;
2437
+ const gtagIdsKey = (0, import_react4.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
2438
+ (0, import_react4.useEffect)(() => {
2439
+ if (gtagIds && Object.keys(gtagIds).length > 0) {
2440
+ bootstrapMultipleGtags(gtagIds);
2441
+ } else if (gtagId) {
2442
+ bootstrapGoogleAdsTracking(gtagId);
2443
+ }
2444
+ }, [gtagId, gtagIdsKey]);
1914
2445
  return null;
1915
2446
  }
1916
2447
 
1917
2448
  // src/factory.tsx
1918
- var import_react5 = require("react");
2449
+ var import_react6 = require("react");
1919
2450
 
1920
2451
  // package.json
1921
- var version = "0.12.2";
2452
+ var version = "0.14.0";
1922
2453
 
1923
2454
  // ../tracking-core/src/phone-react.tsx
1924
- var import_react4 = require("react");
2455
+ var import_react5 = require("react");
1925
2456
  var import_jsx_runtime2 = require("react/jsx-runtime");
1926
2457
  var _phoneConfigContext;
1927
2458
  function phoneConfigContext() {
1928
- return _phoneConfigContext ?? (_phoneConfigContext = (0, import_react4.createContext)(null));
2459
+ return _phoneConfigContext ?? (_phoneConfigContext = (0, import_react5.createContext)(null));
1929
2460
  }
1930
2461
  function PhoneConfigProvider({
1931
2462
  value,
@@ -1935,7 +2466,7 @@ function PhoneConfigProvider({
1935
2466
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Ctx.Provider, { value, children });
1936
2467
  }
1937
2468
  function usePhoneConfig() {
1938
- const ctx = (0, import_react4.useContext)(phoneConfigContext());
2469
+ const ctx = (0, import_react5.useContext)(phoneConfigContext());
1939
2470
  return {
1940
2471
  defaultCountry: ctx?.defaultCountry ?? DEFAULT_PHONE_COUNTRY,
1941
2472
  display: ctx?.display ?? "national"
@@ -1946,10 +2477,10 @@ function usePhoneField(opts = {}) {
1946
2477
  const country = opts.country ?? cfg.defaultCountry;
1947
2478
  const display = opts.display ?? cfg.display;
1948
2479
  const { onValueChange } = opts;
1949
- const [value, setValue] = (0, import_react4.useState)(() => formatPhoneAsTyped(opts.defaultValue ?? "", country));
1950
- const [touched, setTouched] = (0, import_react4.useState)(false);
1951
- const parsed = (0, import_react4.useMemo)(() => parsePhone(value, country), [value, country]);
1952
- const onChange = (0, import_react4.useCallback)(
2480
+ const [value, setValue] = (0, import_react5.useState)(() => formatPhoneAsTyped(opts.defaultValue ?? "", country));
2481
+ const [touched, setTouched] = (0, import_react5.useState)(false);
2482
+ const parsed = (0, import_react5.useMemo)(() => parsePhone(value, country), [value, country]);
2483
+ const onChange = (0, import_react5.useCallback)(
1953
2484
  (event) => {
1954
2485
  const next = formatPhoneAsTyped(event.target.value, country);
1955
2486
  setValue(next);
@@ -1957,7 +2488,7 @@ function usePhoneField(opts = {}) {
1957
2488
  },
1958
2489
  [country, onValueChange]
1959
2490
  );
1960
- const onBlur = (0, import_react4.useCallback)(
2491
+ const onBlur = (0, import_react5.useCallback)(
1961
2492
  (_event) => {
1962
2493
  setTouched(true);
1963
2494
  setValue((current) => {
@@ -1977,11 +2508,11 @@ function usePhoneField(opts = {}) {
1977
2508
  inputProps: { value, onChange, onBlur, type: "tel", inputMode: "tel", autoComplete: "tel" }
1978
2509
  };
1979
2510
  }
1980
- var PhoneField = (0, import_react4.forwardRef)(function PhoneField2({ country, value, defaultValue, onChange, onE164Change, ...rest }, ref) {
2511
+ var PhoneField = (0, import_react5.forwardRef)(function PhoneField2({ country, value, defaultValue, onChange, onE164Change, ...rest }, ref) {
1981
2512
  const cfg = usePhoneConfig();
1982
2513
  const resolvedCountry = country ?? cfg.defaultCountry;
1983
2514
  const isControlled = value !== void 0;
1984
- const [internal, setInternal] = (0, import_react4.useState)(
2515
+ const [internal, setInternal] = (0, import_react5.useState)(
1985
2516
  () => formatPhoneAsTyped(defaultValue ?? "", resolvedCountry)
1986
2517
  );
1987
2518
  const handleChange = (event) => {
@@ -2017,7 +2548,7 @@ var NOOP_CLIENT = {
2017
2548
  getVisitorId: () => ""
2018
2549
  };
2019
2550
  function createTracking(options) {
2020
- const { apiKey, endpoint, triggers, environment, debug, phone } = options;
2551
+ const { apiKey, endpoint, triggers, environment, debug, phone, conversionConfig } = options;
2021
2552
  if (!apiKey || !endpoint) {
2022
2553
  if (apiKey || endpoint) {
2023
2554
  console.warn(
@@ -2032,12 +2563,18 @@ function createTracking(options) {
2032
2563
  useTracking: () => noopTyped
2033
2564
  };
2034
2565
  }
2035
- const TrackingContext = (0, import_react5.createContext)(null);
2036
- function TrackingProvider({ gtagId, gtagIds, children }) {
2566
+ const TrackingContext = (0, import_react6.createContext)(null);
2567
+ function TrackingProvider({
2568
+ gtagId,
2569
+ gtagIds,
2570
+ metaPixelId,
2571
+ metaPixelIds,
2572
+ children
2573
+ }) {
2037
2574
  const resolvedGtagIds = gtagIds ? Object.fromEntries(
2038
2575
  Object.entries(gtagIds).filter((e) => e[1] != null)
2039
2576
  ) : gtagId ? { default: gtagId } : void 0;
2040
- const client = (0, import_react5.useMemo)(
2577
+ const client = (0, import_react6.useMemo)(
2041
2578
  () => createTypedClient(
2042
2579
  getOrCreateTrackingClient({
2043
2580
  apiKey,
@@ -2055,15 +2592,26 @@ function createTracking(options) {
2055
2592
  ),
2056
2593
  []
2057
2594
  );
2058
- const gtagIdsKey = (0, import_react5.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
2059
- (0, import_react5.useEffect)(() => {
2595
+ const gtagIdsKey = (0, import_react6.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
2596
+ (0, import_react6.useEffect)(() => {
2060
2597
  if (gtagIds && Object.keys(gtagIds).length > 0) {
2061
2598
  bootstrapMultipleGtags(gtagIds);
2062
2599
  } else if (gtagId) {
2063
2600
  bootstrapGoogleAdsTracking(gtagId);
2064
2601
  }
2065
2602
  }, [gtagId, gtagIdsKey]);
2066
- (0, import_react5.useEffect)(() => {
2603
+ const metaPixelIdsKey = (0, import_react6.useMemo)(
2604
+ () => metaPixelIds ? JSON.stringify(metaPixelIds) : "",
2605
+ [metaPixelIds]
2606
+ );
2607
+ (0, import_react6.useEffect)(() => {
2608
+ if (metaPixelIds && Object.keys(metaPixelIds).length > 0) {
2609
+ bootstrapMultiplePixels(metaPixelIds);
2610
+ } else if (metaPixelId) {
2611
+ bootstrapMetaPixel(metaPixelId);
2612
+ }
2613
+ }, [metaPixelId, metaPixelIdsKey]);
2614
+ (0, import_react6.useEffect)(() => {
2067
2615
  const detachers = [];
2068
2616
  const rawClient = getOrCreateTrackingClient({
2069
2617
  apiKey,
@@ -2075,27 +2623,32 @@ function createTracking(options) {
2075
2623
  activeGtagIds: resolvedGtagIds,
2076
2624
  debug
2077
2625
  });
2078
- detachers.push(attachAutoPageView(rawClient));
2079
- detachers.push(attachBfcacheRestore(rawClient));
2626
+ const conversionStore = conversionConfig ? resolveConversionConfig({
2627
+ cdnUrl: conversionConfig.cdnUrl,
2628
+ baked: conversionConfig.baked
2629
+ }) : null;
2630
+ const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
2631
+ detachers.push(attachAutoPageView(detectorClient));
2632
+ detachers.push(attachBfcacheRestore(detectorClient));
2080
2633
  const timeOnSite = triggers.automatic.time_on_site;
2081
2634
  if (timeOnSite) {
2082
- detachers.push(attachTimeOnSite(rawClient, timeOnSite));
2635
+ detachers.push(attachTimeOnSite(detectorClient, timeOnSite));
2083
2636
  }
2084
2637
  const specificPageVisit = triggers.automatic.specific_page_visit;
2085
2638
  if (specificPageVisit) {
2086
- detachers.push(attachSpecificPageVisit(rawClient, specificPageVisit));
2639
+ detachers.push(attachSpecificPageVisit(detectorClient, specificPageVisit));
2087
2640
  }
2088
2641
  const scrollDepth = triggers.automatic.scroll_depth;
2089
2642
  if (scrollDepth) {
2090
- detachers.push(attachScrollDepth(rawClient, scrollDepth));
2643
+ detachers.push(attachScrollDepth(detectorClient, scrollDepth));
2091
2644
  }
2092
2645
  const multiPageSession = triggers.automatic.multi_page_session;
2093
2646
  if (multiPageSession) {
2094
- detachers.push(attachMultiPageSession(rawClient, multiPageSession));
2647
+ detachers.push(attachMultiPageSession(detectorClient, multiPageSession));
2095
2648
  }
2096
2649
  const formStart = triggers.automatic.form_start;
2097
2650
  if (formStart) {
2098
- detachers.push(attachFormStart(rawClient, formStart));
2651
+ detachers.push(attachFormStart(detectorClient, formStart));
2099
2652
  }
2100
2653
  return () => {
2101
2654
  for (let i = detachers.length - 1; i >= 0; i--) {
@@ -2106,7 +2659,7 @@ function createTracking(options) {
2106
2659
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TrackingContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PhoneConfigProvider, { value: phone ?? null, children }) });
2107
2660
  }
2108
2661
  function useTracking() {
2109
- const client = (0, import_react5.useContext)(TrackingContext);
2662
+ const client = (0, import_react6.useContext)(TrackingContext);
2110
2663
  if (client === null) {
2111
2664
  throw new Error(
2112
2665
  "useTracking must be called inside a <TrackingProvider> returned by createTracking()"
@@ -2118,6 +2671,7 @@ function createTracking(options) {
2118
2671
  }
2119
2672
  // Annotate the CommonJS export names for ESM import in node:
2120
2673
  0 && (module.exports = {
2674
+ AdPlatformTracking,
2121
2675
  AranovaApiError,
2122
2676
  ConsentBanner,
2123
2677
  DEFAULT_PHONE_COUNTRY,
@@ -2143,6 +2697,7 @@ function createTracking(options) {
2143
2697
  parsePhone,
2144
2698
  phoneField,
2145
2699
  resetConsent,
2700
+ resolveConversionConfig,
2146
2701
  saleCreateSchema,
2147
2702
  saleItemSchema,
2148
2703
  saleServiceSchema,