@aranova/tracking-react 0.19.0 → 0.19.2

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.d.mts CHANGED
@@ -2,8 +2,8 @@ import * as react from 'react';
2
2
  import { ReactNode, CSSProperties, InputHTMLAttributes, ChangeEvent, FocusEvent } from 'react';
3
3
  import { T as TrackingParams, a as TrackingInstallSurface, b as TrackingEnvironment, c as TrackingClientContext, d as TrackingEventCreatePayload, e as TrackingSessionUpsertPayload, F as FormSubmitConfig, f as FormSubmitMetadata, G as GtagEnvironmentMap, M as MetaPixelEnvironmentMap, C as ConsentState, g as ConsentChoiceState, h as ConsentSource, P as PhoneConfig, i as ParsedPhone, j as PhoneDisplayFormat } from './phone-utils-B2vHJkNz.mjs';
4
4
  export { k as ConsentChoice, D as DEFAULT_DECLINE_TTL_DAYS, l as DEFAULT_PHONE_COUNTRY, J as JsonValue, S as SetConsentOptions, m as TrackedField, n as TrackingInitConfig, o as formSubmitConfigSchema, p as formSubmitMetadataSchema, q as formatPhone, r as formatPhoneAsTyped, s as getConsentChoice, t as getConsentState, u as jsonValueSchema, v as onConsentChange, w as optIn, x as optOut, y as parsePhone, z as phoneField, A as resetConsent, B as setConsentState, E as toE164 } from './phone-utils-B2vHJkNz.mjs';
5
- import { T as TrackingConfigReference, C as ConversionConfig } from './sales--WzOzyiO.mjs';
6
- export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, c as CompareTo, d as ConversionConfigStore, e as ConversionUserData, f as CurrencyRevenue, g as CustomerCurrencyDelta, h as CustomerCurrencyTotal, i as CustomerGetOptions, j as CustomerGetResult, k as CustomerKpis, l as CustomerKpisDeltas, m as CustomerKpisPrevious, n as CustomerListPage, o as CustomerListQuery, p as CustomerProfile, q as CustomerSegment, r as CustomerSegmentCount, s as CustomerSortField, t as CustomerSummary, u as CustomerSummaryQuery, D as DistinctCustomersByCurrency, G as Granularity, N as NAMED_RANGES, v as NamedRange, P as PublicServiceItem, S as SUPPORTED_CURRENCIES, w as Sale, x as SaleCursorPage, y as SaleFilters, z as SaleInput, E as SaleItem, F as SaleItemInput, H as SaleKeysetSortField, I as SaleListPage, J as SaleListQuery, K as SaleListQueryV2, L as SaleService, M as SaleServiceInput, O as SaleSortField, Q as SaleSortOrder, R as SaleSummary, U as SaleSummaryPrevious, V as SaleSummaryQuery, W as SaleSummaryQueryV2, X as SaleSummaryV2, Y as SaleUpdateInput, Z as SalesBusinessClient, _ as SalesCategoryBreakdown, $ as SalesClient, a0 as SalesClientConfig, a1 as SalesCustomersClient, a2 as SalesServiceBreakdown, a3 as SalesTransportConfig, a4 as SalesTrendPoint, a5 as SummaryCurrencyDelta, a6 as SummaryDeltas, a7 as SummaryWindow, a8 as SupportedCurrency, a9 as TRACKING_RANGES, aa as TrackingOverviewRange, ab as clearStashedUserData, ac as createSalesClient, ad as fetchServices, ae as formatDateInTz, af as formatMoney, ag as fromMinor, ah as getTrackingConfigRuntime, ai as resolveConversionConfig, aj as saleCreateSchema, ak as saleItemSchema, al as saleServiceSchema, am as saleUpdateSchema, an as salesRequest, ao as stashUserData, ap as toMinor } from './sales--WzOzyiO.mjs';
5
+ import { T as TrackingConfigReference, C as ConversionConfig } from './sales-DrH6dY5F.mjs';
6
+ export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, c as CompareTo, d as ConversionConfigStore, e as ConversionUserData, f as CurrencyRevenue, g as CustomerCurrencyDelta, h as CustomerCurrencyTotal, i as CustomerGetOptions, j as CustomerGetResult, k as CustomerKpis, l as CustomerKpisDeltas, m as CustomerKpisPrevious, n as CustomerListPage, o as CustomerListQuery, p as CustomerProfile, q as CustomerSegment, r as CustomerSegmentCount, s as CustomerSortField, t as CustomerSummary, u as CustomerSummaryQuery, D as DistinctCustomersByCurrency, G as Granularity, N as NAMED_RANGES, v as NamedRange, P as PublicServiceItem, S as SUPPORTED_CURRENCIES, w as Sale, x as SaleCursorPage, y as SaleFilters, z as SaleInput, E as SaleItem, F as SaleItemInput, H as SaleKeysetSortField, I as SaleListPage, J as SaleListQuery, K as SaleListQueryV2, L as SaleService, M as SaleServiceInput, O as SaleSortField, Q as SaleSortOrder, R as SaleSummary, U as SaleSummaryPrevious, V as SaleSummaryQuery, W as SaleSummaryQueryV2, X as SaleSummaryV2, Y as SaleUpdateInput, Z as SalesBusinessClient, _ as SalesCategoryBreakdown, $ as SalesClient, a0 as SalesClientConfig, a1 as SalesCustomersClient, a2 as SalesServiceBreakdown, a3 as SalesTransportConfig, a4 as SalesTrendPoint, a5 as SummaryCurrencyDelta, a6 as SummaryDeltas, a7 as SummaryWindow, a8 as SupportedCurrency, a9 as TRACKING_RANGES, aa as TrackingOverviewRange, ab as clearStashedUserData, ac as createSalesClient, ad as fetchServices, ae as formatDateInTz, af as formatMoney, ag as fromMinor, ah as getTrackingConfigRuntime, ai as resolveConversionConfig, aj as saleCreateSchema, ak as saleItemSchema, al as saleServiceSchema, am as saleUpdateSchema, an as salesRequest, ao as stashUserData, ap as toMinor } from './sales-DrH6dY5F.mjs';
7
7
  import * as src from 'src';
8
8
  import { z } from 'zod';
9
9
  import { CountryCode } from 'libphonenumber-js';
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import * as react from 'react';
2
2
  import { ReactNode, CSSProperties, InputHTMLAttributes, ChangeEvent, FocusEvent } from 'react';
3
3
  import { T as TrackingParams, a as TrackingInstallSurface, b as TrackingEnvironment, c as TrackingClientContext, d as TrackingEventCreatePayload, e as TrackingSessionUpsertPayload, F as FormSubmitConfig, f as FormSubmitMetadata, G as GtagEnvironmentMap, M as MetaPixelEnvironmentMap, C as ConsentState, g as ConsentChoiceState, h as ConsentSource, P as PhoneConfig, i as ParsedPhone, j as PhoneDisplayFormat } from './phone-utils-B2vHJkNz.js';
4
4
  export { k as ConsentChoice, D as DEFAULT_DECLINE_TTL_DAYS, l as DEFAULT_PHONE_COUNTRY, J as JsonValue, S as SetConsentOptions, m as TrackedField, n as TrackingInitConfig, o as formSubmitConfigSchema, p as formSubmitMetadataSchema, q as formatPhone, r as formatPhoneAsTyped, s as getConsentChoice, t as getConsentState, u as jsonValueSchema, v as onConsentChange, w as optIn, x as optOut, y as parsePhone, z as phoneField, A as resetConsent, B as setConsentState, E as toE164 } from './phone-utils-B2vHJkNz.js';
5
- import { T as TrackingConfigReference, C as ConversionConfig } from './sales--WzOzyiO.js';
6
- export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, c as CompareTo, d as ConversionConfigStore, e as ConversionUserData, f as CurrencyRevenue, g as CustomerCurrencyDelta, h as CustomerCurrencyTotal, i as CustomerGetOptions, j as CustomerGetResult, k as CustomerKpis, l as CustomerKpisDeltas, m as CustomerKpisPrevious, n as CustomerListPage, o as CustomerListQuery, p as CustomerProfile, q as CustomerSegment, r as CustomerSegmentCount, s as CustomerSortField, t as CustomerSummary, u as CustomerSummaryQuery, D as DistinctCustomersByCurrency, G as Granularity, N as NAMED_RANGES, v as NamedRange, P as PublicServiceItem, S as SUPPORTED_CURRENCIES, w as Sale, x as SaleCursorPage, y as SaleFilters, z as SaleInput, E as SaleItem, F as SaleItemInput, H as SaleKeysetSortField, I as SaleListPage, J as SaleListQuery, K as SaleListQueryV2, L as SaleService, M as SaleServiceInput, O as SaleSortField, Q as SaleSortOrder, R as SaleSummary, U as SaleSummaryPrevious, V as SaleSummaryQuery, W as SaleSummaryQueryV2, X as SaleSummaryV2, Y as SaleUpdateInput, Z as SalesBusinessClient, _ as SalesCategoryBreakdown, $ as SalesClient, a0 as SalesClientConfig, a1 as SalesCustomersClient, a2 as SalesServiceBreakdown, a3 as SalesTransportConfig, a4 as SalesTrendPoint, a5 as SummaryCurrencyDelta, a6 as SummaryDeltas, a7 as SummaryWindow, a8 as SupportedCurrency, a9 as TRACKING_RANGES, aa as TrackingOverviewRange, ab as clearStashedUserData, ac as createSalesClient, ad as fetchServices, ae as formatDateInTz, af as formatMoney, ag as fromMinor, ah as getTrackingConfigRuntime, ai as resolveConversionConfig, aj as saleCreateSchema, ak as saleItemSchema, al as saleServiceSchema, am as saleUpdateSchema, an as salesRequest, ao as stashUserData, ap as toMinor } from './sales--WzOzyiO.js';
5
+ import { T as TrackingConfigReference, C as ConversionConfig } from './sales-DrH6dY5F.js';
6
+ export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, c as CompareTo, d as ConversionConfigStore, e as ConversionUserData, f as CurrencyRevenue, g as CustomerCurrencyDelta, h as CustomerCurrencyTotal, i as CustomerGetOptions, j as CustomerGetResult, k as CustomerKpis, l as CustomerKpisDeltas, m as CustomerKpisPrevious, n as CustomerListPage, o as CustomerListQuery, p as CustomerProfile, q as CustomerSegment, r as CustomerSegmentCount, s as CustomerSortField, t as CustomerSummary, u as CustomerSummaryQuery, D as DistinctCustomersByCurrency, G as Granularity, N as NAMED_RANGES, v as NamedRange, P as PublicServiceItem, S as SUPPORTED_CURRENCIES, w as Sale, x as SaleCursorPage, y as SaleFilters, z as SaleInput, E as SaleItem, F as SaleItemInput, H as SaleKeysetSortField, I as SaleListPage, J as SaleListQuery, K as SaleListQueryV2, L as SaleService, M as SaleServiceInput, O as SaleSortField, Q as SaleSortOrder, R as SaleSummary, U as SaleSummaryPrevious, V as SaleSummaryQuery, W as SaleSummaryQueryV2, X as SaleSummaryV2, Y as SaleUpdateInput, Z as SalesBusinessClient, _ as SalesCategoryBreakdown, $ as SalesClient, a0 as SalesClientConfig, a1 as SalesCustomersClient, a2 as SalesServiceBreakdown, a3 as SalesTransportConfig, a4 as SalesTrendPoint, a5 as SummaryCurrencyDelta, a6 as SummaryDeltas, a7 as SummaryWindow, a8 as SupportedCurrency, a9 as TRACKING_RANGES, aa as TrackingOverviewRange, ab as clearStashedUserData, ac as createSalesClient, ad as fetchServices, ae as formatDateInTz, af as formatMoney, ag as fromMinor, ah as getTrackingConfigRuntime, ai as resolveConversionConfig, aj as saleCreateSchema, ak as saleItemSchema, al as saleServiceSchema, am as saleUpdateSchema, an as salesRequest, ao as stashUserData, ap as toMinor } from './sales-DrH6dY5F.js';
7
7
  import * as src from 'src';
8
8
  import { z } from 'zod';
9
9
  import { CountryCode } from 'libphonenumber-js';
package/dist/index.js CHANGED
@@ -763,10 +763,17 @@ function markFired(input) {
763
763
  }
764
764
  }
765
765
  function fireConversionWithConsent(input, options) {
766
- if (getConsentState() === "denied") return;
767
- if (alreadyFired(input)) return;
768
- applyUserDataForConversion(options?.userData);
769
- if (fireGtagConversion(input)) markFired(input);
766
+ if (getConsentState() === "denied") return "denied";
767
+ if (alreadyFired(input)) return "duplicate";
768
+ if (!isValidSendTo(input.sendTo)) return "invalid";
769
+ try {
770
+ applyUserDataForConversion(options?.userData);
771
+ if (!fireGtagConversion(input)) return "retryable";
772
+ markFired(input);
773
+ return "fired";
774
+ } catch {
775
+ return "retryable";
776
+ }
770
777
  }
771
778
 
772
779
  // ../tracking-core/src/resources/conversion-config.ts
@@ -940,6 +947,103 @@ function resolveConversionConfig(options) {
940
947
  };
941
948
  }
942
949
 
950
+ // ../tracking-core/src/resources/automatic-transaction.ts
951
+ var STORAGE_KEY = "_aranova_auto_txn_map";
952
+ var transactionIds = /* @__PURE__ */ new Map();
953
+ var legacyCounter = 0;
954
+ function scopeKey(sessionId, goalKey, path) {
955
+ return JSON.stringify([sessionId, goalKey, path]);
956
+ }
957
+ function randomId() {
958
+ const cryptoApi = globalThis.crypto;
959
+ if (typeof cryptoApi?.randomUUID === "function") return cryptoApi.randomUUID();
960
+ if (typeof cryptoApi?.getRandomValues === "function") {
961
+ const bytes = cryptoApi.getRandomValues(new Uint8Array(16));
962
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
963
+ }
964
+ legacyCounter = (legacyCounter + 1) % 4294967296;
965
+ const timestamp = Date.now().toString(16).padStart(12, "0");
966
+ const counter = legacyCounter.toString(16).padStart(8, "0");
967
+ const random = Math.floor(Math.random() * 281474976710655).toString(16).padStart(12, "0");
968
+ return `${timestamp}${counter}${random}`.slice(0, 32);
969
+ }
970
+ function isValidTransactionId(value) {
971
+ return typeof value === "string" && /^auto:(?:[0-9a-f]{32}|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/i.test(
972
+ value
973
+ ) && value.length <= 64;
974
+ }
975
+ function readStoredMap(sessionId) {
976
+ if (typeof window === "undefined") return { sessionId, entries: {} };
977
+ try {
978
+ const raw = window.localStorage.getItem(STORAGE_KEY);
979
+ if (!raw) return { sessionId, entries: {} };
980
+ const parsed = JSON.parse(raw);
981
+ if (parsed.sessionId !== sessionId || !parsed.entries || typeof parsed.entries !== "object" || Array.isArray(parsed.entries)) {
982
+ return { sessionId, entries: {} };
983
+ }
984
+ return { sessionId, entries: parsed.entries };
985
+ } catch {
986
+ return { sessionId, entries: {} };
987
+ }
988
+ }
989
+ function writeStoredMap(stored) {
990
+ if (typeof window === "undefined") return;
991
+ try {
992
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(stored));
993
+ } catch {
994
+ }
995
+ }
996
+ function getAutomaticTransactionId(sessionId, goalKey, path) {
997
+ const key = scopeKey(sessionId, goalKey, path);
998
+ const existing = transactionIds.get(key);
999
+ if (existing) return existing;
1000
+ const stored = readStoredMap(sessionId);
1001
+ const storedId = stored.entries[key];
1002
+ if (isValidTransactionId(storedId)) {
1003
+ transactionIds.set(key, storedId);
1004
+ return storedId;
1005
+ }
1006
+ const transactionId = `auto:${randomId()}`;
1007
+ transactionIds.set(key, transactionId);
1008
+ const latest = readStoredMap(sessionId);
1009
+ const concurrentId = latest.entries[key];
1010
+ if (isValidTransactionId(concurrentId)) {
1011
+ transactionIds.set(key, concurrentId);
1012
+ return concurrentId;
1013
+ }
1014
+ latest.entries[key] = transactionId;
1015
+ writeStoredMap(latest);
1016
+ return transactionId;
1017
+ }
1018
+
1019
+ // ../tracking-core/src/resources/automatic-trigger.ts
1020
+ function hasNumberField(metadata, key) {
1021
+ return typeof metadata[key] === "number";
1022
+ }
1023
+ function hasStringField(metadata, key) {
1024
+ return typeof metadata[key] === "string";
1025
+ }
1026
+ function automaticThresholdMet(goal, eventType, metadata) {
1027
+ const trigger = goal.trigger;
1028
+ if (!trigger || trigger.event_type !== eventType) return false;
1029
+ switch (eventType) {
1030
+ case "scroll_depth":
1031
+ return hasNumberField(metadata, "depth_percent") && trigger.threshold_percent != null && metadata.depth_percent >= trigger.threshold_percent;
1032
+ case "time_on_site":
1033
+ return hasNumberField(metadata, "duration_ms") && trigger.threshold_seconds != null && metadata.duration_ms >= trigger.threshold_seconds * 1e3;
1034
+ case "multi_page_session":
1035
+ return hasNumberField(metadata, "page_count") && trigger.page_threshold != null && metadata.page_count >= trigger.page_threshold;
1036
+ case "specific_page_visit":
1037
+ return hasStringField(metadata, "page_name") && metadata.page_name === trigger.page_name;
1038
+ case "page_view":
1039
+ case "form_start":
1040
+ case "phone_click":
1041
+ return true;
1042
+ default:
1043
+ return false;
1044
+ }
1045
+ }
1046
+
943
1047
  // ../tracking-core/src/resources/sales/money.ts
944
1048
  var MINOR_UNIT_EXPONENT = {
945
1049
  USD: 2,
@@ -1053,19 +1157,38 @@ function ensureScript(gtagId) {
1053
1157
  var TrackingConfigRuntime = class {
1054
1158
  constructor(ref, fetchImpl = globalThis.fetch) {
1055
1159
  this.ref = ref;
1056
- this.fetchImpl = fetchImpl;
1057
1160
  this.current = null;
1058
1161
  this.etag = null;
1059
1162
  this.stateValue = "unconfirmed";
1060
1163
  this.confirmedAt = 0;
1164
+ this.authorityGeneration = 0;
1061
1165
  this.inFlight = null;
1166
+ this.flushInFlight = null;
1167
+ this.flushRequested = false;
1168
+ this.retryTimer = null;
1169
+ this.started = false;
1062
1170
  this.conversionQueue = [];
1063
1171
  this.automaticQueue = [];
1064
1172
  this.pageQueue = [];
1065
1173
  this.listeners = /* @__PURE__ */ new Set();
1174
+ this.fetchImpl = fetchImpl.bind(globalThis);
1066
1175
  const cached = readCache2(ref.cdnUrl);
1067
1176
  this.current = cached?.config ?? null;
1068
1177
  this.etag = cached?.etag ?? null;
1178
+ this.start();
1179
+ }
1180
+ /**
1181
+ * Explicitly start authority resolution and Google-tag bootstrap.
1182
+ *
1183
+ * Idempotent so framework effects can call it after hydration without
1184
+ * depending on constructor timing.
1185
+ */
1186
+ start() {
1187
+ if (this.started) {
1188
+ void this.flush();
1189
+ return;
1190
+ }
1191
+ this.started = true;
1069
1192
  void this.revalidate();
1070
1193
  if (typeof window !== "undefined") {
1071
1194
  window.addEventListener("visibilitychange", () => {
@@ -1081,7 +1204,7 @@ var TrackingConfigRuntime = class {
1081
1204
  return this.stateValue === "active" || this.stateValue === "tombstone" ? this.current : null;
1082
1205
  }
1083
1206
  __unsafeExpireAuthorityForTests() {
1084
- this.confirmedAt = 0;
1207
+ this.confirmedAt = Number.NEGATIVE_INFINITY;
1085
1208
  }
1086
1209
  subscribe(listener) {
1087
1210
  this.listeners.add(listener);
@@ -1091,10 +1214,14 @@ var TrackingConfigRuntime = class {
1091
1214
  if (this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS) {
1092
1215
  return true;
1093
1216
  }
1094
- await this.revalidate();
1217
+ await this.revalidateAuthority();
1095
1218
  return this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS;
1096
1219
  }
1097
1220
  async revalidate() {
1221
+ await this.revalidateAuthority();
1222
+ await this.flush();
1223
+ }
1224
+ async revalidateAuthority() {
1098
1225
  if (typeof window === "undefined" || !this.fetchImpl) return;
1099
1226
  if (this.inFlight) return this.inFlight;
1100
1227
  this.inFlight = this.revalidateNow().finally(() => {
@@ -1111,8 +1238,8 @@ var TrackingConfigRuntime = class {
1111
1238
  this.conversionQueue.push({ key, ...options });
1112
1239
  void this.flush();
1113
1240
  }
1114
- queueAutomaticEvent(eventType, metadata, transactionPath) {
1115
- this.automaticQueue.push({ eventType, metadata, transactionPath });
1241
+ queueAutomaticEvent(eventType, metadata, transactionPath, transactionScope) {
1242
+ this.automaticQueue.push({ eventType, metadata, transactionPath, transactionScope });
1116
1243
  void this.flush();
1117
1244
  }
1118
1245
  listGoals() {
@@ -1129,7 +1256,6 @@ var TrackingConfigRuntime = class {
1129
1256
  });
1130
1257
  if (response.status === 304 && this.current && validateConfig(this.current, this.ref)) {
1131
1258
  this.confirm(this.current, this.etag);
1132
- await this.flush();
1133
1259
  return;
1134
1260
  }
1135
1261
  if (!response.ok) {
@@ -1146,21 +1272,26 @@ var TrackingConfigRuntime = class {
1146
1272
  return;
1147
1273
  }
1148
1274
  this.confirm(next, response.headers.get("ETag"));
1149
- await this.flush();
1150
1275
  } catch {
1151
1276
  this.expireAuthority();
1152
1277
  }
1153
1278
  }
1154
1279
  expireAuthority() {
1280
+ this.authorityGeneration += 1;
1155
1281
  if (this.stateValue !== "unconfirmed") this.stateValue = "unconfirmed";
1156
1282
  }
1157
1283
  confirm(config, etag) {
1284
+ this.authorityGeneration += 1;
1158
1285
  this.current = config;
1159
1286
  this.etag = etag;
1160
1287
  this.confirmedAt = Date.now();
1161
1288
  this.stateValue = isTombstone(config) ? "tombstone" : "active";
1162
1289
  writeCache2(this.ref.cdnUrl, { etag, config });
1163
1290
  if (this.stateValue === "tombstone") {
1291
+ if (this.retryTimer !== null) {
1292
+ window.clearTimeout(this.retryTimer);
1293
+ this.retryTimer = null;
1294
+ }
1164
1295
  this.conversionQueue.length = 0;
1165
1296
  this.automaticQueue.length = 0;
1166
1297
  this.pageQueue.length = 0;
@@ -1168,80 +1299,107 @@ var TrackingConfigRuntime = class {
1168
1299
  for (const listener of this.listeners) listener();
1169
1300
  }
1170
1301
  async flush() {
1302
+ if (this.flushInFlight) {
1303
+ this.flushRequested = true;
1304
+ return this.flushInFlight;
1305
+ }
1306
+ this.flushRequested = false;
1307
+ this.flushInFlight = this.flushNow().finally(() => {
1308
+ this.flushInFlight = null;
1309
+ if (this.flushRequested && this.stateValue === "active") void this.flush();
1310
+ });
1311
+ return this.flushInFlight;
1312
+ }
1313
+ scheduleRetry() {
1314
+ if (this.retryTimer !== null || typeof window === "undefined") return;
1315
+ this.retryTimer = window.setTimeout(() => {
1316
+ this.retryTimer = null;
1317
+ void this.flush();
1318
+ }, 1e3);
1319
+ }
1320
+ async flushNow() {
1171
1321
  if (!await this.ensureAuthority()) return;
1172
1322
  if (this.stateValue !== "active" || !this.current) return;
1173
- const ids = Object.values(this.current.gtag_ids).filter(
1323
+ const config = this.current;
1324
+ const generation = this.authorityGeneration;
1325
+ const ids = Object.values(config.gtag_ids).filter(
1174
1326
  (id) => typeof id === "string" && isValidGtagId(id)
1175
1327
  );
1176
1328
  if (ids.length === 0) return;
1177
1329
  await ensureScript(ids[0]);
1330
+ if (this.authorityGeneration !== generation || this.stateValue !== "active" || this.current !== config) {
1331
+ return;
1332
+ }
1178
1333
  const gtag = window.gtag;
1179
1334
  if (typeof gtag !== "function") return;
1180
- if (!jsInitialized) {
1181
- gtag("js", /* @__PURE__ */ new Date());
1182
- jsInitialized = true;
1183
- }
1184
- for (const id of ids) {
1185
- if (configuredIds.has(id)) continue;
1186
- gtag("config", id, { send_page_view: false });
1187
- configuredIds.add(id);
1188
- }
1189
- while (this.pageQueue.length) {
1190
- const page = this.pageQueue.shift();
1191
- gtag("event", "page_view", {
1192
- page_location: page.href,
1193
- page_title: page.title ?? void 0,
1194
- page_referrer: page.referrer ?? void 0
1195
- });
1335
+ try {
1336
+ if (!jsInitialized) {
1337
+ gtag("js", /* @__PURE__ */ new Date());
1338
+ jsInitialized = true;
1339
+ }
1340
+ for (const id of ids) {
1341
+ if (configuredIds.has(id)) continue;
1342
+ gtag("config", id, { send_page_view: false });
1343
+ configuredIds.add(id);
1344
+ }
1345
+ } catch {
1346
+ this.scheduleRetry();
1347
+ return;
1196
1348
  }
1197
- while (this.automaticQueue.length) {
1198
- const event = this.automaticQueue.shift();
1199
- for (const goal of this.current.goals) {
1349
+ while (this.pageQueue.length > 0) {
1350
+ const page = this.pageQueue[0];
1351
+ try {
1352
+ gtag("event", "page_view", {
1353
+ page_location: page.href,
1354
+ page_title: page.title ?? void 0,
1355
+ page_referrer: page.referrer ?? void 0
1356
+ });
1357
+ this.pageQueue.shift();
1358
+ } catch {
1359
+ this.scheduleRetry();
1360
+ return;
1361
+ }
1362
+ }
1363
+ while (this.automaticQueue.length > 0) {
1364
+ const event = this.automaticQueue[0];
1365
+ for (const goal of config.goals) {
1200
1366
  if (goal.kind !== "event" || !goal.firing) continue;
1201
1367
  if (!automaticThresholdMet(goal, event.eventType, event.metadata)) continue;
1202
1368
  this.conversionQueue.push({
1203
1369
  key: goal.key,
1204
- transactionId: `auto:${goal.key}:${event.transactionPath}`
1370
+ transactionId: getAutomaticTransactionId(
1371
+ event.transactionScope,
1372
+ goal.key,
1373
+ event.transactionPath
1374
+ )
1205
1375
  });
1206
1376
  }
1377
+ this.automaticQueue.shift();
1207
1378
  }
1208
- while (this.conversionQueue.length) {
1209
- const item = this.conversionQueue.shift();
1210
- const goal = this.current.goals.find((g) => g.key === item.key);
1379
+ while (this.conversionQueue.length > 0) {
1380
+ const item = this.conversionQueue[0];
1381
+ const goal = config.goals.find((g) => g.key === item.key);
1211
1382
  const firing = goal?.firing;
1212
- if (!firing || getConsentState() === "denied") continue;
1383
+ if (!firing) {
1384
+ this.conversionQueue.shift();
1385
+ continue;
1386
+ }
1213
1387
  const currency = item.currency ?? firing.currency ?? null;
1214
1388
  const value = item.value ?? (firing.value_cents != null && currency ? fromMinor(firing.value_cents, currency) : null);
1215
- applyUserDataForConversion();
1216
- fireGtagConversion({
1389
+ const outcome = fireConversionWithConsent({
1217
1390
  sendTo: firing.send_to,
1218
1391
  value,
1219
1392
  currency,
1220
1393
  transactionId: item.transactionId ?? null
1221
1394
  });
1395
+ if (outcome === "retryable") {
1396
+ this.scheduleRetry();
1397
+ return;
1398
+ }
1399
+ this.conversionQueue.shift();
1222
1400
  }
1223
1401
  }
1224
1402
  };
1225
- function automaticThresholdMet(goal, eventType, metadata) {
1226
- const t = goal.trigger;
1227
- if (!t || t.event_type !== eventType) return false;
1228
- switch (eventType) {
1229
- case "scroll_depth":
1230
- return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
1231
- case "time_on_site":
1232
- return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
1233
- case "multi_page_session":
1234
- return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
1235
- case "specific_page_visit":
1236
- return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
1237
- case "page_view":
1238
- case "form_start":
1239
- case "phone_click":
1240
- return true;
1241
- default:
1242
- return false;
1243
- }
1244
- }
1245
1403
  function getTrackingConfigRuntime(ref, fetchImpl) {
1246
1404
  const key = `${ref.cdnUrl}|${ref.businessId}|${ref.environment}`;
1247
1405
  const existing = runtimes.get(key);
@@ -1252,26 +1410,6 @@ function getTrackingConfigRuntime(ref, fetchImpl) {
1252
1410
  }
1253
1411
 
1254
1412
  // ../tracking-core/src/resources/conversion-autofire.ts
1255
- function thresholdMet(goal, eventType, metadata) {
1256
- const t = goal.trigger;
1257
- if (!t || t.event_type !== eventType) return false;
1258
- switch (eventType) {
1259
- case "scroll_depth":
1260
- return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
1261
- case "time_on_site":
1262
- return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
1263
- case "multi_page_session":
1264
- return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
1265
- case "specific_page_visit":
1266
- return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
1267
- case "page_view":
1268
- case "form_start":
1269
- case "phone_click":
1270
- return true;
1271
- default:
1272
- return false;
1273
- }
1274
- }
1275
1413
  function currentPath() {
1276
1414
  return typeof window === "undefined" ? "" : window.location.pathname;
1277
1415
  }
@@ -1279,13 +1417,14 @@ var MAX_BUFFERED_EVENTS = 50;
1279
1417
  function createConversionAutoFire(store) {
1280
1418
  const pending = [];
1281
1419
  let subscribed = false;
1282
- function fireMatching(eventType, metadata) {
1420
+ function fireMatching(eventType, metadata, transactionScope) {
1283
1421
  for (const goal of store.listGoals()) {
1284
1422
  if (goal.kind !== "event" || !goal.firing) continue;
1285
- if (!thresholdMet(goal, eventType, metadata)) continue;
1423
+ if (!automaticThresholdMet(goal, eventType, metadata)) continue;
1424
+ const transactionId = getAutomaticTransactionId(transactionScope, goal.key, currentPath());
1286
1425
  if ("queueAutomaticEvent" in store) {
1287
1426
  store.fireConversion(goal.key, {
1288
- transactionId: `auto:${goal.key}:${currentPath()}`
1427
+ transactionId
1289
1428
  });
1290
1429
  continue;
1291
1430
  }
@@ -1296,28 +1435,30 @@ function createConversionAutoFire(store) {
1296
1435
  sendTo: firing.send_to,
1297
1436
  value: cents != null && currency ? fromMinor(cents, currency) : null,
1298
1437
  currency,
1299
- // Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
1300
- // shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
1301
- transactionId: `auto:${goal.key}:${currentPath()}`
1438
+ transactionId
1302
1439
  });
1303
1440
  }
1304
1441
  }
1305
1442
  return {
1306
- onAutomaticEvent(eventType, metadata) {
1443
+ onAutomaticEvent(eventType, metadata, transactionScope) {
1307
1444
  if ("queueAutomaticEvent" in store) {
1308
- store.queueAutomaticEvent(eventType, metadata, currentPath());
1445
+ store.queueAutomaticEvent(eventType, metadata, currentPath(), transactionScope);
1309
1446
  return;
1310
1447
  }
1311
1448
  if (store.isReady()) {
1312
- fireMatching(eventType, metadata);
1449
+ fireMatching(eventType, metadata, transactionScope);
1313
1450
  return;
1314
1451
  }
1315
- if (pending.length < MAX_BUFFERED_EVENTS) pending.push({ eventType, metadata });
1452
+ if (pending.length < MAX_BUFFERED_EVENTS) {
1453
+ pending.push({ eventType, metadata, transactionScope });
1454
+ }
1316
1455
  if (!subscribed) {
1317
1456
  subscribed = true;
1318
1457
  store.onResolve(() => {
1319
1458
  const buffered = pending.splice(0);
1320
- for (const event of buffered) fireMatching(event.eventType, event.metadata);
1459
+ for (const event of buffered) {
1460
+ fireMatching(event.eventType, event.metadata, event.transactionScope);
1461
+ }
1321
1462
  });
1322
1463
  }
1323
1464
  }
@@ -1329,7 +1470,7 @@ function withConversionAutoFire(client, autoFire) {
1329
1470
  trackEvent: (input) => {
1330
1471
  client.trackEvent(input);
1331
1472
  try {
1332
- autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
1473
+ autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {}, client.getSessionId());
1333
1474
  } catch {
1334
1475
  }
1335
1476
  }
@@ -2462,7 +2603,7 @@ function attachScrollDepth(client, config) {
2462
2603
  }
2463
2604
 
2464
2605
  // ../tracking-core/src/triggers/multi-page-session.ts
2465
- var STORAGE_KEY = "aranova_tracking_mps_paths";
2606
+ var STORAGE_KEY2 = "aranova_tracking_mps_paths";
2466
2607
  var SESSION_KEY = "aranova_tracking_mps_session";
2467
2608
  var FIRED_KEY = "aranova_tracking_mps_fired";
2468
2609
  function getSessionStorage() {
@@ -2484,7 +2625,7 @@ function attachMultiPageSession(client, config) {
2484
2625
  let lastCheckedPath = "";
2485
2626
  function getDistinctPaths() {
2486
2627
  try {
2487
- const raw = storage.getItem(STORAGE_KEY);
2628
+ const raw = storage.getItem(STORAGE_KEY2);
2488
2629
  return raw ? new Set(JSON.parse(raw)) : /* @__PURE__ */ new Set();
2489
2630
  } catch {
2490
2631
  return /* @__PURE__ */ new Set();
@@ -2492,7 +2633,7 @@ function attachMultiPageSession(client, config) {
2492
2633
  }
2493
2634
  function saveDistinctPaths(paths) {
2494
2635
  try {
2495
- storage.setItem(STORAGE_KEY, JSON.stringify([...paths]));
2636
+ storage.setItem(STORAGE_KEY2, JSON.stringify([...paths]));
2496
2637
  } catch {
2497
2638
  }
2498
2639
  }
@@ -2501,7 +2642,7 @@ function attachMultiPageSession(client, config) {
2501
2642
  const storedSession = storage.getItem(SESSION_KEY);
2502
2643
  if (storedSession !== currentSession) {
2503
2644
  storage.setItem(SESSION_KEY, currentSession);
2504
- storage.removeItem(STORAGE_KEY);
2645
+ storage.removeItem(STORAGE_KEY2);
2505
2646
  storage.removeItem(FIRED_KEY);
2506
2647
  }
2507
2648
  }
@@ -3496,7 +3637,7 @@ function GoogleAdsTracking(props) {
3496
3637
  var import_react6 = require("react");
3497
3638
 
3498
3639
  // package.json
3499
- var version = "0.19.0";
3640
+ var version = "0.19.2";
3500
3641
 
3501
3642
  // ../tracking-core/src/phone-react.tsx
3502
3643
  var import_react5 = require("react");
@@ -3627,31 +3768,46 @@ function createTracking(options) {
3627
3768
  metaPixelIds,
3628
3769
  children
3629
3770
  }) {
3630
- const resolvedGtagIds = gtagIds ? Object.fromEntries(
3631
- Object.entries(gtagIds).filter((e) => e[1] != null)
3632
- ) : gtagId ? { default: gtagId } : void 0;
3633
- const client = (0, import_react6.useMemo)(
3634
- () => createTypedClient(
3635
- getOrCreateTrackingClient({
3636
- apiKey,
3637
- endpoint,
3638
- surface: "react",
3639
- packageName: "@aranova/tracking-react",
3640
- sdkVersion: version,
3641
- triggers,
3642
- environment,
3643
- activeGtagIds: resolvedGtagIds,
3644
- debug
3645
- }),
3771
+ const gtagIdsKey = (0, import_react6.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
3772
+ const resolvedGtagIds = (0, import_react6.useMemo)(
3773
+ () => gtagIds ? Object.fromEntries(
3774
+ Object.entries(gtagIds).filter((e) => e[1] != null)
3775
+ ) : gtagId ? { default: gtagId } : void 0,
3776
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- gtagIdsKey is stable proxy
3777
+ [gtagId, gtagIdsKey]
3778
+ );
3779
+ const rawClient = (0, import_react6.useMemo)(
3780
+ () => getOrCreateTrackingClient({
3781
+ apiKey,
3782
+ endpoint,
3783
+ surface: "react",
3784
+ packageName: "@aranova/tracking-react",
3785
+ sdkVersion: version,
3646
3786
  triggers,
3647
- { debug }
3648
- ),
3787
+ environment,
3788
+ activeGtagIds: resolvedGtagIds,
3789
+ debug
3790
+ }),
3791
+ [resolvedGtagIds]
3792
+ );
3793
+ const conversionStore = (0, import_react6.useMemo)(
3794
+ () => trackingConfig ? getTrackingConfigRuntime(trackingConfig) : conversionConfig ? resolveConversionConfig({
3795
+ cdnUrl: conversionConfig.cdnUrl,
3796
+ baked: conversionConfig.baked
3797
+ }) : null,
3649
3798
  []
3650
3799
  );
3651
- const gtagIdsKey = (0, import_react6.useMemo)(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
3800
+ const conversionClient = (0, import_react6.useMemo)(
3801
+ () => conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient,
3802
+ [rawClient, conversionStore]
3803
+ );
3804
+ const client = (0, import_react6.useMemo)(
3805
+ () => createTypedClient(conversionClient, triggers, { debug }),
3806
+ [conversionClient]
3807
+ );
3652
3808
  (0, import_react6.useEffect)(() => {
3653
3809
  if (trackingConfig) {
3654
- void getTrackingConfigRuntime(trackingConfig).revalidate();
3810
+ getTrackingConfigRuntime(trackingConfig).start();
3655
3811
  } else if (gtagIds && Object.keys(gtagIds).length > 0) {
3656
3812
  bootstrapMultipleGtags(gtagIds);
3657
3813
  } else if (gtagId) {
@@ -3670,23 +3826,9 @@ function createTracking(options) {
3670
3826
  }
3671
3827
  }, [metaPixelId, metaPixelIdsKey]);
3672
3828
  (0, import_react6.useEffect)(() => {
3673
- const rawClient = getOrCreateTrackingClient({
3674
- apiKey,
3675
- endpoint,
3676
- surface: "react",
3677
- packageName: "@aranova/tracking-react",
3678
- triggers,
3679
- environment,
3680
- activeGtagIds: resolvedGtagIds,
3681
- debug
3682
- });
3683
3829
  return attachClientCapturesOnce(rawClient, () => {
3684
3830
  const detachers = [];
3685
- const conversionStore = trackingConfig ? getTrackingConfigRuntime(trackingConfig) : conversionConfig ? resolveConversionConfig({
3686
- cdnUrl: conversionConfig.cdnUrl,
3687
- baked: conversionConfig.baked
3688
- }) : null;
3689
- const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
3831
+ const detectorClient = conversionStore ? conversionClient : rawClient;
3690
3832
  const pageClient = trackingConfig && conversionStore && "queuePageView" in conversionStore ? {
3691
3833
  ...detectorClient,
3692
3834
  trackEvent: (input) => {
@@ -3731,7 +3873,7 @@ function createTracking(options) {
3731
3873
  }
3732
3874
  };
3733
3875
  });
3734
- }, []);
3876
+ }, [conversionClient, conversionStore, rawClient]);
3735
3877
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TrackingContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PhoneConfigProvider, { value: phone ?? null, children }) });
3736
3878
  }
3737
3879
  function useTracking() {