@aranova/tracking-react 0.22.3 → 0.23.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.mjs CHANGED
@@ -1041,8 +1041,21 @@ function formatMoney(cents, currency, locale) {
1041
1041
  }
1042
1042
 
1043
1043
  // ../tracking-core/src/resources/tracking-config-runtime.ts
1044
+ var DEFAULT_CDN_BASE_URL = "https://demos.aranova.io";
1045
+ function trackingConfigKey(businessId, environment) {
1046
+ return `tracking-config/v1/${businessId}-${environment}.json`;
1047
+ }
1048
+ function resolveTrackingConfigUrl(ref) {
1049
+ if (ref.cdnUrl) return ref.cdnUrl;
1050
+ const configured = ref.cdnBaseUrl?.trim();
1051
+ const base = (configured || DEFAULT_CDN_BASE_URL).replace(/\/+$/, "");
1052
+ return `${base}/${trackingConfigKey(ref.businessId, ref.environment)}`;
1053
+ }
1044
1054
  var CACHE_PREFIX2 = "_aranova_cfg_runtime_";
1045
1055
  var AUTHORITY_TTL_MS = 6e4;
1056
+ var MAX_QUEUE_LENGTH = 50;
1057
+ var RETRY_BASE_MS = 5e3;
1058
+ var RETRY_MAX_MS = 5 * 6e4;
1046
1059
  var runtimes = /* @__PURE__ */ new Map();
1047
1060
  var configuredIds = /* @__PURE__ */ new Set();
1048
1061
  var scriptLoad = null;
@@ -1050,6 +1063,10 @@ var jsInitialized = false;
1050
1063
  function cacheKey2(url) {
1051
1064
  return `${CACHE_PREFIX2}${url}`;
1052
1065
  }
1066
+ function pushBounded(queue, item) {
1067
+ queue.push(item);
1068
+ if (queue.length > MAX_QUEUE_LENGTH) queue.splice(0, queue.length - MAX_QUEUE_LENGTH);
1069
+ }
1053
1070
  function readCache2(url) {
1054
1071
  if (typeof window === "undefined") return null;
1055
1072
  try {
@@ -1130,16 +1147,25 @@ var TrackingConfigRuntime = class {
1130
1147
  this.flushRequested = false;
1131
1148
  this.retryTimer = null;
1132
1149
  this.started = false;
1150
+ /** Consecutive failed authority attempts — drives the revalidate backoff. */
1151
+ this.authorityFailures = 0;
1152
+ /** Epoch ms before which `ensureAuthority` must not issue another request. */
1153
+ this.nextAuthorityAttemptAt = 0;
1133
1154
  this.conversionQueue = [];
1134
1155
  this.automaticQueue = [];
1135
1156
  this.pageQueue = [];
1136
1157
  this.listeners = /* @__PURE__ */ new Set();
1137
1158
  this.fetchImpl = fetchImpl.bind(globalThis);
1138
- const cached = readCache2(ref.cdnUrl);
1159
+ this.url = resolveTrackingConfigUrl(ref);
1160
+ const cached = readCache2(this.url);
1139
1161
  this.current = cached?.config ?? null;
1140
1162
  this.etag = cached?.etag ?? null;
1141
1163
  this.start();
1142
1164
  }
1165
+ /** The URL this runtime actually fetches (composed or explicit). */
1166
+ configUrl() {
1167
+ return this.url;
1168
+ }
1143
1169
  /**
1144
1170
  * Explicitly start authority resolution and Google-tag bootstrap.
1145
1171
  *
@@ -1168,6 +1194,15 @@ var TrackingConfigRuntime = class {
1168
1194
  }
1169
1195
  __unsafeExpireAuthorityForTests() {
1170
1196
  this.confirmedAt = Number.NEGATIVE_INFINITY;
1197
+ this.nextAuthorityAttemptAt = 0;
1198
+ }
1199
+ /** Queue depths — asserted by tests to pin the bound. */
1200
+ __queueDepthsForTests() {
1201
+ return {
1202
+ conversions: this.conversionQueue.length,
1203
+ automatic: this.automaticQueue.length,
1204
+ pages: this.pageQueue.length
1205
+ };
1171
1206
  }
1172
1207
  subscribe(listener) {
1173
1208
  this.listeners.add(listener);
@@ -1177,10 +1212,12 @@ var TrackingConfigRuntime = class {
1177
1212
  if (this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS) {
1178
1213
  return true;
1179
1214
  }
1215
+ if (Date.now() < this.nextAuthorityAttemptAt) return false;
1180
1216
  await this.revalidateAuthority();
1181
1217
  return this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS;
1182
1218
  }
1183
1219
  async revalidate() {
1220
+ this.nextAuthorityAttemptAt = 0;
1184
1221
  await this.revalidateAuthority();
1185
1222
  await this.flush();
1186
1223
  }
@@ -1194,15 +1231,20 @@ var TrackingConfigRuntime = class {
1194
1231
  }
1195
1232
  queuePageView(snapshot = pageViewSnapshot()) {
1196
1233
  if (!snapshot) return;
1197
- this.pageQueue.push(snapshot);
1234
+ pushBounded(this.pageQueue, snapshot);
1198
1235
  void this.flush();
1199
1236
  }
1200
1237
  fireConversion(key, options) {
1201
- this.conversionQueue.push({ key, ...options });
1238
+ pushBounded(this.conversionQueue, { key, ...options });
1202
1239
  void this.flush();
1203
1240
  }
1204
1241
  queueAutomaticEvent(eventType, metadata, transactionPath, transactionScope) {
1205
- this.automaticQueue.push({ eventType, metadata, transactionPath, transactionScope });
1242
+ pushBounded(this.automaticQueue, {
1243
+ eventType,
1244
+ metadata,
1245
+ transactionPath,
1246
+ transactionScope
1247
+ });
1206
1248
  void this.flush();
1207
1249
  }
1208
1250
  listGoals() {
@@ -1212,7 +1254,7 @@ var TrackingConfigRuntime = class {
1212
1254
  try {
1213
1255
  const headers = {};
1214
1256
  if (this.etag) headers["If-None-Match"] = this.etag;
1215
- const response = await this.fetchImpl(this.ref.cdnUrl, {
1257
+ const response = await this.fetchImpl(this.url, {
1216
1258
  method: "GET",
1217
1259
  headers,
1218
1260
  cache: "no-cache"
@@ -1242,14 +1284,19 @@ var TrackingConfigRuntime = class {
1242
1284
  expireAuthority() {
1243
1285
  this.authorityGeneration += 1;
1244
1286
  if (this.stateValue !== "unconfirmed") this.stateValue = "unconfirmed";
1287
+ this.authorityFailures += 1;
1288
+ const delay = Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** (this.authorityFailures - 1));
1289
+ this.nextAuthorityAttemptAt = Date.now() + delay;
1245
1290
  }
1246
1291
  confirm(config, etag) {
1247
1292
  this.authorityGeneration += 1;
1248
1293
  this.current = config;
1249
1294
  this.etag = etag;
1250
1295
  this.confirmedAt = Date.now();
1296
+ this.authorityFailures = 0;
1297
+ this.nextAuthorityAttemptAt = 0;
1251
1298
  this.stateValue = isTombstone(config) ? "tombstone" : "active";
1252
- writeCache2(this.ref.cdnUrl, { etag, config });
1299
+ writeCache2(this.url, { etag, config });
1253
1300
  if (this.stateValue === "tombstone") {
1254
1301
  if (this.retryTimer !== null) {
1255
1302
  window.clearTimeout(this.retryTimer);
@@ -1328,7 +1375,7 @@ var TrackingConfigRuntime = class {
1328
1375
  for (const goal of config.goals) {
1329
1376
  if (goal.kind !== "event" || !goal.firing) continue;
1330
1377
  if (!automaticThresholdMet(goal, event.eventType, event.metadata)) continue;
1331
- this.conversionQueue.push({
1378
+ pushBounded(this.conversionQueue, {
1332
1379
  key: goal.key,
1333
1380
  transactionId: getAutomaticTransactionId(
1334
1381
  event.transactionScope,
@@ -1364,7 +1411,7 @@ var TrackingConfigRuntime = class {
1364
1411
  }
1365
1412
  };
1366
1413
  function getTrackingConfigRuntime(ref, fetchImpl) {
1367
- const key = `${ref.cdnUrl}|${ref.businessId}|${ref.environment}`;
1414
+ const key = `${resolveTrackingConfigUrl(ref)}|${ref.businessId}|${ref.environment}`;
1368
1415
  const existing = runtimes.get(key);
1369
1416
  if (existing) return existing;
1370
1417
  const runtime = new TrackingConfigRuntime(ref, fetchImpl ?? globalThis.fetch);
@@ -3649,7 +3696,7 @@ function AdPlatformTracking({
3649
3696
  metaPixelId,
3650
3697
  metaPixelIds
3651
3698
  }) {
3652
- const trackingConfigKey = trackingConfig ? `${trackingConfig.cdnUrl}:${trackingConfig.businessId}:${trackingConfig.environment}` : "";
3699
+ const trackingConfigKey2 = trackingConfig ? `${resolveTrackingConfigUrl(trackingConfig)}:${trackingConfig.businessId}:${trackingConfig.environment}` : "";
3653
3700
  const gtagIdsKey = useMemo(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
3654
3701
  const metaPixelIdsKey = useMemo(
3655
3702
  () => metaPixelIds ? JSON.stringify(metaPixelIds) : "",
@@ -3671,7 +3718,7 @@ function AdPlatformTracking({
3671
3718
  } else if (gtagId) {
3672
3719
  bootstrapGoogleAdsTracking(gtagId);
3673
3720
  }
3674
- }, [gtagId, gtagIdsKey, trackingConfigKey, standalonePageView]);
3721
+ }, [gtagId, gtagIdsKey, trackingConfigKey2, standalonePageView]);
3675
3722
  useEffect3(() => {
3676
3723
  if (metaPixelIds && Object.keys(metaPixelIds).length > 0) {
3677
3724
  bootstrapMultiplePixels(metaPixelIds);
@@ -3701,7 +3748,7 @@ function GoogleAdsTracking(props) {
3701
3748
  import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
3702
3749
 
3703
3750
  // package.json
3704
- var version = "0.22.3";
3751
+ var version = "0.23.0";
3705
3752
 
3706
3753
  // ../tracking-core/src/phone-react.tsx
3707
3754
  import {
@@ -3998,6 +4045,7 @@ export {
3998
4045
  phoneField,
3999
4046
  resetConsent,
4000
4047
  resolveConversionConfig,
4048
+ resolveTrackingConfigUrl,
4001
4049
  saleCreateSchema,
4002
4050
  saleItemSchema,
4003
4051
  saleServiceSchema,