@aranova/tracking-next 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
@@ -1020,8 +1020,21 @@ function formatMoney(cents, currency, locale) {
1020
1020
  }
1021
1021
 
1022
1022
  // ../tracking-core/src/resources/tracking-config-runtime.ts
1023
+ var DEFAULT_CDN_BASE_URL = "https://demos.aranova.io";
1024
+ function trackingConfigKey(businessId, environment) {
1025
+ return `tracking-config/v1/${businessId}-${environment}.json`;
1026
+ }
1027
+ function resolveTrackingConfigUrl(ref) {
1028
+ if (ref.cdnUrl) return ref.cdnUrl;
1029
+ const configured = ref.cdnBaseUrl?.trim();
1030
+ const base = (configured || DEFAULT_CDN_BASE_URL).replace(/\/+$/, "");
1031
+ return `${base}/${trackingConfigKey(ref.businessId, ref.environment)}`;
1032
+ }
1023
1033
  var CACHE_PREFIX2 = "_aranova_cfg_runtime_";
1024
1034
  var AUTHORITY_TTL_MS = 6e4;
1035
+ var MAX_QUEUE_LENGTH = 50;
1036
+ var RETRY_BASE_MS = 5e3;
1037
+ var RETRY_MAX_MS = 5 * 6e4;
1025
1038
  var runtimes = /* @__PURE__ */ new Map();
1026
1039
  var configuredIds = /* @__PURE__ */ new Set();
1027
1040
  var scriptLoad = null;
@@ -1029,6 +1042,10 @@ var jsInitialized = false;
1029
1042
  function cacheKey2(url) {
1030
1043
  return `${CACHE_PREFIX2}${url}`;
1031
1044
  }
1045
+ function pushBounded(queue, item) {
1046
+ queue.push(item);
1047
+ if (queue.length > MAX_QUEUE_LENGTH) queue.splice(0, queue.length - MAX_QUEUE_LENGTH);
1048
+ }
1032
1049
  function readCache2(url) {
1033
1050
  if (typeof window === "undefined") return null;
1034
1051
  try {
@@ -1109,16 +1126,25 @@ var TrackingConfigRuntime = class {
1109
1126
  this.flushRequested = false;
1110
1127
  this.retryTimer = null;
1111
1128
  this.started = false;
1129
+ /** Consecutive failed authority attempts — drives the revalidate backoff. */
1130
+ this.authorityFailures = 0;
1131
+ /** Epoch ms before which `ensureAuthority` must not issue another request. */
1132
+ this.nextAuthorityAttemptAt = 0;
1112
1133
  this.conversionQueue = [];
1113
1134
  this.automaticQueue = [];
1114
1135
  this.pageQueue = [];
1115
1136
  this.listeners = /* @__PURE__ */ new Set();
1116
1137
  this.fetchImpl = fetchImpl.bind(globalThis);
1117
- const cached = readCache2(ref.cdnUrl);
1138
+ this.url = resolveTrackingConfigUrl(ref);
1139
+ const cached = readCache2(this.url);
1118
1140
  this.current = cached?.config ?? null;
1119
1141
  this.etag = cached?.etag ?? null;
1120
1142
  this.start();
1121
1143
  }
1144
+ /** The URL this runtime actually fetches (composed or explicit). */
1145
+ configUrl() {
1146
+ return this.url;
1147
+ }
1122
1148
  /**
1123
1149
  * Explicitly start authority resolution and Google-tag bootstrap.
1124
1150
  *
@@ -1147,6 +1173,15 @@ var TrackingConfigRuntime = class {
1147
1173
  }
1148
1174
  __unsafeExpireAuthorityForTests() {
1149
1175
  this.confirmedAt = Number.NEGATIVE_INFINITY;
1176
+ this.nextAuthorityAttemptAt = 0;
1177
+ }
1178
+ /** Queue depths — asserted by tests to pin the bound. */
1179
+ __queueDepthsForTests() {
1180
+ return {
1181
+ conversions: this.conversionQueue.length,
1182
+ automatic: this.automaticQueue.length,
1183
+ pages: this.pageQueue.length
1184
+ };
1150
1185
  }
1151
1186
  subscribe(listener) {
1152
1187
  this.listeners.add(listener);
@@ -1156,10 +1191,12 @@ var TrackingConfigRuntime = class {
1156
1191
  if (this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS) {
1157
1192
  return true;
1158
1193
  }
1194
+ if (Date.now() < this.nextAuthorityAttemptAt) return false;
1159
1195
  await this.revalidateAuthority();
1160
1196
  return this.stateValue !== "unconfirmed" && Date.now() - this.confirmedAt < AUTHORITY_TTL_MS;
1161
1197
  }
1162
1198
  async revalidate() {
1199
+ this.nextAuthorityAttemptAt = 0;
1163
1200
  await this.revalidateAuthority();
1164
1201
  await this.flush();
1165
1202
  }
@@ -1173,15 +1210,20 @@ var TrackingConfigRuntime = class {
1173
1210
  }
1174
1211
  queuePageView(snapshot = pageViewSnapshot()) {
1175
1212
  if (!snapshot) return;
1176
- this.pageQueue.push(snapshot);
1213
+ pushBounded(this.pageQueue, snapshot);
1177
1214
  void this.flush();
1178
1215
  }
1179
1216
  fireConversion(key, options) {
1180
- this.conversionQueue.push({ key, ...options });
1217
+ pushBounded(this.conversionQueue, { key, ...options });
1181
1218
  void this.flush();
1182
1219
  }
1183
1220
  queueAutomaticEvent(eventType, metadata, transactionPath, transactionScope) {
1184
- this.automaticQueue.push({ eventType, metadata, transactionPath, transactionScope });
1221
+ pushBounded(this.automaticQueue, {
1222
+ eventType,
1223
+ metadata,
1224
+ transactionPath,
1225
+ transactionScope
1226
+ });
1185
1227
  void this.flush();
1186
1228
  }
1187
1229
  listGoals() {
@@ -1191,7 +1233,7 @@ var TrackingConfigRuntime = class {
1191
1233
  try {
1192
1234
  const headers = {};
1193
1235
  if (this.etag) headers["If-None-Match"] = this.etag;
1194
- const response = await this.fetchImpl(this.ref.cdnUrl, {
1236
+ const response = await this.fetchImpl(this.url, {
1195
1237
  method: "GET",
1196
1238
  headers,
1197
1239
  cache: "no-cache"
@@ -1221,14 +1263,19 @@ var TrackingConfigRuntime = class {
1221
1263
  expireAuthority() {
1222
1264
  this.authorityGeneration += 1;
1223
1265
  if (this.stateValue !== "unconfirmed") this.stateValue = "unconfirmed";
1266
+ this.authorityFailures += 1;
1267
+ const delay = Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** (this.authorityFailures - 1));
1268
+ this.nextAuthorityAttemptAt = Date.now() + delay;
1224
1269
  }
1225
1270
  confirm(config, etag) {
1226
1271
  this.authorityGeneration += 1;
1227
1272
  this.current = config;
1228
1273
  this.etag = etag;
1229
1274
  this.confirmedAt = Date.now();
1275
+ this.authorityFailures = 0;
1276
+ this.nextAuthorityAttemptAt = 0;
1230
1277
  this.stateValue = isTombstone(config) ? "tombstone" : "active";
1231
- writeCache2(this.ref.cdnUrl, { etag, config });
1278
+ writeCache2(this.url, { etag, config });
1232
1279
  if (this.stateValue === "tombstone") {
1233
1280
  if (this.retryTimer !== null) {
1234
1281
  window.clearTimeout(this.retryTimer);
@@ -1307,7 +1354,7 @@ var TrackingConfigRuntime = class {
1307
1354
  for (const goal of config.goals) {
1308
1355
  if (goal.kind !== "event" || !goal.firing) continue;
1309
1356
  if (!automaticThresholdMet(goal, event.eventType, event.metadata)) continue;
1310
- this.conversionQueue.push({
1357
+ pushBounded(this.conversionQueue, {
1311
1358
  key: goal.key,
1312
1359
  transactionId: getAutomaticTransactionId(
1313
1360
  event.transactionScope,
@@ -1343,7 +1390,7 @@ var TrackingConfigRuntime = class {
1343
1390
  }
1344
1391
  };
1345
1392
  function getTrackingConfigRuntime(ref, fetchImpl) {
1346
- const key = `${ref.cdnUrl}|${ref.businessId}|${ref.environment}`;
1393
+ const key = `${resolveTrackingConfigUrl(ref)}|${ref.businessId}|${ref.environment}`;
1347
1394
  const existing = runtimes.get(key);
1348
1395
  if (existing) return existing;
1349
1396
  const runtime = new TrackingConfigRuntime(ref, fetchImpl ?? globalThis.fetch);
@@ -3461,13 +3508,13 @@ function AdPlatformTracking({
3461
3508
  metaPixelId,
3462
3509
  metaPixelIds
3463
3510
  }) {
3464
- const trackingConfigKey = trackingConfig ? `${trackingConfig.cdnUrl}:${trackingConfig.businessId}:${trackingConfig.environment}` : "";
3511
+ const trackingConfigKey2 = trackingConfig ? `${resolveTrackingConfigUrl(trackingConfig)}:${trackingConfig.businessId}:${trackingConfig.environment}` : "";
3465
3512
  useEffect3(() => {
3466
3513
  if (!trackingConfig) return;
3467
3514
  const runtime = getTrackingConfigRuntime(trackingConfig);
3468
3515
  if (standalonePageView) runtime.queuePageView();
3469
3516
  else runtime.start();
3470
- }, [trackingConfigKey, standalonePageView]);
3517
+ }, [trackingConfigKey2, standalonePageView]);
3471
3518
  const gtagAll = trackingConfig ? [] : gtagIds ? Object.values(gtagIds).filter((id) => id != null) : gtagId ? [gtagId] : [];
3472
3519
  const metaAll = metaPixelIds ? Object.values(metaPixelIds).filter((id) => id != null) : metaPixelId ? [metaPixelId] : [];
3473
3520
  if (trackingConfig || gtagAll.length > 0) registerCapability("ad_tags_google");
@@ -3520,7 +3567,7 @@ function GoogleAdsTracking(props) {
3520
3567
  import { usePathname, useSearchParams } from "next/navigation";
3521
3568
 
3522
3569
  // package.json
3523
- var version = "0.22.3";
3570
+ var version = "0.23.0";
3524
3571
 
3525
3572
  // src/factory.tsx
3526
3573
  import {
@@ -4303,6 +4350,7 @@ export {
4303
4350
  resetConsent,
4304
4351
  resolveBrowserTimeZone,
4305
4352
  resolveConversionConfig,
4353
+ resolveTrackingConfigUrl,
4306
4354
  saleCreateSchema,
4307
4355
  saleItemSchema,
4308
4356
  saleServiceSchema,