@aranova/tracking-next 0.21.0 → 0.22.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.
Files changed (53) hide show
  1. package/dist/blog-server.js +12 -0
  2. package/dist/blog-server.js.map +1 -1
  3. package/dist/blog-server.mjs +12 -0
  4. package/dist/blog-server.mjs.map +1 -1
  5. package/dist/blog.js +7 -0
  6. package/dist/blog.js.map +1 -1
  7. package/dist/blog.mjs +7 -0
  8. package/dist/blog.mjs.map +1 -1
  9. package/dist/calendar-server.d.mts +1 -1
  10. package/dist/calendar-server.d.ts +1 -1
  11. package/dist/calendar-server.js.map +1 -1
  12. package/dist/calendar-server.mjs.map +1 -1
  13. package/dist/calendar.d.mts +2 -2
  14. package/dist/calendar.d.ts +2 -2
  15. package/dist/calendar.js +7 -0
  16. package/dist/calendar.js.map +1 -1
  17. package/dist/calendar.mjs +7 -0
  18. package/dist/calendar.mjs.map +1 -1
  19. package/dist/index.d.mts +6 -6
  20. package/dist/index.d.ts +6 -6
  21. package/dist/index.js +160 -24
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +160 -24
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/middleware.js +3 -0
  26. package/dist/middleware.js.map +1 -1
  27. package/dist/middleware.mjs +3 -0
  28. package/dist/middleware.mjs.map +1 -1
  29. package/dist/{phone-utils-B2vHJkNz.d.mts → phone-utils-BhWfNuPS.d.mts} +8 -0
  30. package/dist/{phone-utils-B2vHJkNz.d.ts → phone-utils-BhWfNuPS.d.ts} +8 -0
  31. package/dist/phone.d.mts +1 -1
  32. package/dist/phone.d.ts +1 -1
  33. package/dist/phone.js +3 -0
  34. package/dist/phone.js.map +1 -1
  35. package/dist/phone.mjs +3 -0
  36. package/dist/phone.mjs.map +1 -1
  37. package/dist/{sales-B3BnYncU.d.mts → sales-BZsIQ27L.d.mts} +13 -4
  38. package/dist/{sales-CDjXRdmd.d.ts → sales-CZLLYCHv.d.ts} +13 -4
  39. package/dist/sales.d.mts +1 -1
  40. package/dist/sales.d.ts +1 -1
  41. package/dist/sales.js +10 -0
  42. package/dist/sales.js.map +1 -1
  43. package/dist/sales.mjs +10 -0
  44. package/dist/sales.mjs.map +1 -1
  45. package/dist/server.d.mts +1 -1
  46. package/dist/server.d.ts +1 -1
  47. package/dist/server.js +3 -0
  48. package/dist/server.js.map +1 -1
  49. package/dist/server.mjs +3 -0
  50. package/dist/server.mjs.map +1 -1
  51. package/package.json +1 -1
  52. package/dist/{transport-DsOY6kcW.d.ts → transport-C-_rFSR4.d.ts} +8 -8
  53. package/dist/{transport-Bku8zftU.d.mts → transport-yUF5Wize.d.mts} +8 -8
package/dist/index.js CHANGED
@@ -382,6 +382,43 @@ var aranovaConsent = (function () {
382
382
  `.trim();
383
383
  }
384
384
 
385
+ // ../tracking-core/src/capabilities.ts
386
+ var TRACKING_CAPABILITIES = [
387
+ "ad_tags_google",
388
+ "ad_tags_meta",
389
+ "base_tracking",
390
+ "blog_rendering",
391
+ "calendar_read",
392
+ "calendar_write",
393
+ "consent_controls",
394
+ "conversion_goals_auto",
395
+ "conversion_goals_manual",
396
+ "cta_click_capture",
397
+ "form_capture",
398
+ "phone_click_capture",
399
+ "phone_fields"
400
+ ];
401
+ var CAPABILITY_DOM_ATTRIBUTE = "data-aranova-capability";
402
+ var registered = /* @__PURE__ */ new Set();
403
+ function registerCapability(capability) {
404
+ registered.add(capability);
405
+ }
406
+ function getRegisteredCapabilities() {
407
+ const all = new Set(registered);
408
+ for (const marker of readDomMarkers()) all.add(marker);
409
+ return Array.from(all).sort();
410
+ }
411
+ function readDomMarkers() {
412
+ if (typeof document === "undefined") return [];
413
+ const known = new Set(TRACKING_CAPABILITIES);
414
+ const found = [];
415
+ for (const node of document.querySelectorAll(`[${CAPABILITY_DOM_ATTRIBUTE}]`)) {
416
+ const value = node.getAttribute(CAPABILITY_DOM_ATTRIBUTE);
417
+ if (value && known.has(value)) found.push(value);
418
+ }
419
+ return found;
420
+ }
421
+
385
422
  // ../tracking-core/src/tracking.ts
386
423
  var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
387
424
  var TRACKING_PARAM_KEYS = [
@@ -726,7 +763,8 @@ function createTrackingClientContext(surface, input = {}) {
726
763
  page_title: input.pageTitle ?? (typeof document === "undefined" ? null : document.title || null),
727
764
  referrer: input.referrer ?? (typeof document === "undefined" ? null : document.referrer || null),
728
765
  environment: input.environment ?? "production",
729
- active_gtag_ids: input.activeGtagIds ?? null
766
+ active_gtag_ids: input.activeGtagIds ?? null,
767
+ capabilities: getRegisteredCapabilities()
730
768
  };
731
769
  }
732
770
  function createTrackingSessionUpsertPayload(trackingParams, input, context) {
@@ -1706,6 +1744,9 @@ function buildHeartbeatMetadata(surface, sdkVersion, packageName, triggers, gtag
1706
1744
  var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
1707
1745
  var DEFAULT_MAX_QUEUE_SIZE = 10;
1708
1746
  var HARD_MAX_BATCH = 50;
1747
+ var MAX_RETRY_BACKOFF_MS = 6e4;
1748
+ var MAX_BUFFERED_EVENTS2 = 200;
1749
+ var RETRY_BUFFER_KEY_PREFIX = "aranova_tracking_pending_v1";
1709
1750
  var API_KEY_HEADER = "X-Aranova-Api-Key";
1710
1751
  var SDK_VERSION_HEADER = "X-Aranova-Sdk-Version";
1711
1752
  var SDK_PACKAGE_HEADER = "X-Aranova-Sdk-Package";
@@ -1720,7 +1761,10 @@ function buildContext(surface, sdkVersion, packageName, environment, activeGtagI
1720
1761
  page_title: typeof document === "undefined" ? null : document.title || null,
1721
1762
  referrer: typeof document === "undefined" ? null : document.referrer || null,
1722
1763
  environment,
1723
- active_gtag_ids: activeGtagIds
1764
+ active_gtag_ids: activeGtagIds,
1765
+ // Rebuilt per flush (this runs inside the payload builder), so a client
1766
+ // constructed later on a deeper route still gets reported.
1767
+ capabilities: getRegisteredCapabilities()
1724
1768
  };
1725
1769
  }
1726
1770
  function readTrackingParams() {
@@ -1745,9 +1789,9 @@ function consentSnapshot() {
1745
1789
  }
1746
1790
  }
1747
1791
  async function postWithFetch(url, body, apiKey, identity, keepalive) {
1748
- if (typeof fetch !== "function") return;
1792
+ if (typeof fetch !== "function") return "drop";
1749
1793
  try {
1750
- await fetch(url, {
1794
+ const response = await fetch(url, {
1751
1795
  method: "POST",
1752
1796
  headers: {
1753
1797
  "Content-Type": "application/json",
@@ -1763,8 +1807,48 @@ async function postWithFetch(url, body, apiKey, identity, keepalive) {
1763
1807
  credentials: "omit",
1764
1808
  mode: "cors"
1765
1809
  });
1810
+ if (response.ok) return "ok";
1811
+ if (response.status === 408 || response.status === 429 || response.status >= 500) {
1812
+ return "retry";
1813
+ }
1814
+ return "drop";
1815
+ } catch {
1816
+ return "retry";
1817
+ }
1818
+ }
1819
+ function retryBufferKey(apiKey, endpoint) {
1820
+ return `${RETRY_BUFFER_KEY_PREFIX}:${apiKey}:${endpoint}`;
1821
+ }
1822
+ function readPendingBatches(key) {
1823
+ if (typeof window === "undefined") return [];
1824
+ try {
1825
+ const raw = window.localStorage.getItem(key);
1826
+ if (!raw) return [];
1827
+ const parsed = JSON.parse(raw);
1828
+ if (!Array.isArray(parsed)) return [];
1829
+ return parsed.filter(
1830
+ (entry) => typeof entry === "object" && entry !== null && "session" in entry && Array.isArray(entry.events)
1831
+ );
1766
1832
  } catch {
1833
+ return [];
1834
+ }
1835
+ }
1836
+ function writePendingBatches(key, batches) {
1837
+ if (typeof window === "undefined") return;
1838
+ try {
1839
+ if (batches.length === 0) window.localStorage.removeItem(key);
1840
+ else window.localStorage.setItem(key, JSON.stringify(batches));
1841
+ } catch {
1842
+ }
1843
+ }
1844
+ function trimToBufferCap(batches) {
1845
+ let total = batches.reduce((sum, batch) => sum + batch.events.length, 0);
1846
+ const trimmed = batches.slice();
1847
+ while (total > MAX_BUFFERED_EVENTS2 && trimmed.length > 1) {
1848
+ const dropped = trimmed.shift();
1849
+ total -= dropped ? dropped.events.length : 0;
1767
1850
  }
1851
+ return trimmed;
1768
1852
  }
1769
1853
  var globalClient = null;
1770
1854
  var globalClientKey = null;
@@ -1821,6 +1905,10 @@ function createTrackingClient(config) {
1821
1905
  };
1822
1906
  let queue = [];
1823
1907
  let flushTimer = null;
1908
+ const bufferKey = retryBufferKey(config.apiKey, endpointBase);
1909
+ let pending = readPendingBatches(bufferKey);
1910
+ let flushChain = Promise.resolve();
1911
+ let retryAttempt = 0;
1824
1912
  let firstPage = null;
1825
1913
  let initialParams = createEmptyTrackingParams();
1826
1914
  let destroyed = false;
@@ -1857,6 +1945,9 @@ function createTrackingClient(config) {
1857
1945
  if (initialSession.isNew) {
1858
1946
  enqueueHeartbeat();
1859
1947
  }
1948
+ if (pending.length > 0) {
1949
+ scheduleFlush();
1950
+ }
1860
1951
  function buildSessionPayload() {
1861
1952
  const rotated = getOrRotateSessionId();
1862
1953
  if (rotated.isNew && rotated.id !== sessionId) {
@@ -1895,12 +1986,12 @@ function createTrackingClient(config) {
1895
1986
  context
1896
1987
  };
1897
1988
  }
1898
- function scheduleFlush() {
1989
+ function scheduleFlush(delayMs = flushIntervalMs) {
1899
1990
  if (flushTimer !== null || destroyed) return;
1900
1991
  flushTimer = setTimeout(() => {
1901
1992
  flushTimer = null;
1902
1993
  void flush();
1903
- }, flushIntervalMs);
1994
+ }, delayMs);
1904
1995
  }
1905
1996
  function clearScheduledFlush() {
1906
1997
  if (flushTimer !== null) {
@@ -1908,17 +1999,50 @@ function createTrackingClient(config) {
1908
1999
  flushTimer = null;
1909
2000
  }
1910
2001
  }
1911
- async function flush() {
2002
+ function bufferQueued() {
1912
2003
  if (queue.length === 0) return;
1913
2004
  const events = queue.slice(0, HARD_MAX_BATCH);
1914
2005
  queue = queue.slice(events.length);
2006
+ pending = trimToBufferCap([...pending, { session: buildSessionPayload(), events }]);
2007
+ writePendingBatches(bufferKey, pending);
2008
+ }
2009
+ function flush() {
2010
+ flushChain = flushChain.then(runFlush).catch(() => {
2011
+ });
2012
+ return flushChain;
2013
+ }
2014
+ async function runFlush() {
2015
+ if (destroyed) return;
1915
2016
  clearScheduledFlush();
1916
- const body = {
1917
- session: buildSessionPayload(),
1918
- events
1919
- };
1920
- const serialized = JSON.stringify(body);
1921
- await postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, false);
2017
+ bufferQueued();
2018
+ if (pending.length === 0) return;
2019
+ try {
2020
+ while (pending.length > 0) {
2021
+ const batch = pending[0];
2022
+ const body = { session: batch.session, events: batch.events };
2023
+ const outcome = await postWithFetch(
2024
+ eventsUrl,
2025
+ JSON.stringify(body),
2026
+ config.apiKey,
2027
+ identityHeaders2,
2028
+ false
2029
+ );
2030
+ if (outcome === "retry") {
2031
+ retryAttempt += 1;
2032
+ return;
2033
+ }
2034
+ pending = pending.slice(1);
2035
+ writePendingBatches(bufferKey, pending);
2036
+ retryAttempt = 0;
2037
+ }
2038
+ } finally {
2039
+ if (pending.length > 0) {
2040
+ const backoff = Math.min(flushIntervalMs * 2 ** retryAttempt, MAX_RETRY_BACKOFF_MS);
2041
+ scheduleFlush(backoff);
2042
+ } else if (queue.length > 0) {
2043
+ scheduleFlush();
2044
+ }
2045
+ }
1922
2046
  }
1923
2047
  function trackEvent(input) {
1924
2048
  if (destroyed) return;
@@ -1944,16 +2068,14 @@ function createTrackingClient(config) {
1944
2068
  }
1945
2069
  }
1946
2070
  function flushOnUnload() {
1947
- if (queue.length === 0) return;
1948
- const events = queue.slice(0, HARD_MAX_BATCH);
1949
- queue = queue.slice(events.length);
2071
+ bufferQueued();
1950
2072
  clearScheduledFlush();
1951
- const body = {
1952
- session: buildSessionPayload(),
1953
- events
1954
- };
1955
- const serialized = JSON.stringify(body);
1956
- void postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, true);
2073
+ if (pending.length === 0) return;
2074
+ const batch = pending[0];
2075
+ pending = pending.slice(1);
2076
+ writePendingBatches(bufferKey, pending);
2077
+ const body = { session: batch.session, events: batch.events };
2078
+ void postWithFetch(eventsUrl, JSON.stringify(body), config.apiKey, identityHeaders2, true);
1957
2079
  }
1958
2080
  if (typeof window !== "undefined") {
1959
2081
  window.addEventListener("pagehide", flushOnUnload);
@@ -2313,8 +2435,9 @@ function getEventDefinition(name) {
2313
2435
  }
2314
2436
 
2315
2437
  // ../tracking-core/src/ingest-typed.ts
2316
- function createTypedClient(raw, _registry, options = {}) {
2438
+ function createTypedClient(raw, registry, options = {}) {
2317
2439
  const debug = options.debug ?? false;
2440
+ if (registry.manual?.form_submit) registerCapability("form_capture");
2318
2441
  return {
2319
2442
  trackEvent(eventType, metadata, opts) {
2320
2443
  if (debug) {
@@ -2721,6 +2844,7 @@ function attachCtaClickCapture(client, config) {
2721
2844
  return () => {
2722
2845
  };
2723
2846
  }
2847
+ registerCapability("cta_click_capture");
2724
2848
  const selector = autoCapture.selector ?? DEFAULT_CTA_SELECTOR;
2725
2849
  function onClick(event) {
2726
2850
  const target = event.target;
@@ -2777,6 +2901,7 @@ function attachPhoneClickCapture(client, config) {
2777
2901
  return () => {
2778
2902
  };
2779
2903
  }
2904
+ registerCapability("phone_click_capture");
2780
2905
  const selector = autoCapture.selector ?? DEFAULT_TEL_SELECTOR;
2781
2906
  function onClick(event) {
2782
2907
  const target = event.target;
@@ -2893,6 +3018,7 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
2893
3018
  }
2894
3019
  }
2895
3020
  function createSalesClient(config) {
3021
+ if (config.firing) registerCapability("conversion_goals_manual");
2896
3022
  async function record(input) {
2897
3023
  const currency = input.currency ?? config.defaultCurrency;
2898
3024
  if (!currency) {
@@ -3136,6 +3262,9 @@ var saleUpdateSchema = import_zod12.z.object({
3136
3262
  items: import_zod12.z.array(saleItemSchema).optional(),
3137
3263
  metadata: metadataSchema.nullable().optional(),
3138
3264
  customer_name: customerNameSchema.nullable().optional(),
3265
+ // Re-attest when changing a filler-looking name; the server clears the
3266
+ // prior attestation whenever `customer_name` changes.
3267
+ customer_name_placeholder_confirmed: import_zod12.z.boolean().optional(),
3139
3268
  customer_phone: customerPhoneSchema.nullable().optional(),
3140
3269
  customer_email: customerEmailSchema.nullable().optional(),
3141
3270
  // NOT NULL server-side: omit to leave unchanged (explicit null is rejected).
@@ -3192,6 +3321,7 @@ var DEFAULT_CHOICE2 = {
3192
3321
  expiresAt: null
3193
3322
  };
3194
3323
  function useCookiePreferences(options) {
3324
+ registerCapability("consent_controls");
3195
3325
  const [choice, setChoice] = (0, import_react.useState)(DEFAULT_CHOICE2);
3196
3326
  const ttlDays = options?.declineTtlDays;
3197
3327
  (0, import_react.useEffect)(() => {
@@ -3459,6 +3589,8 @@ function AdPlatformTracking({
3459
3589
  }, [trackingConfigKey, standalonePageView]);
3460
3590
  const gtagAll = trackingConfig ? [] : gtagIds ? Object.values(gtagIds).filter((id) => id != null) : gtagId ? [gtagId] : [];
3461
3591
  const metaAll = metaPixelIds ? Object.values(metaPixelIds).filter((id) => id != null) : metaPixelId ? [metaPixelId] : [];
3592
+ if (trackingConfig || gtagAll.length > 0) registerCapability("ad_tags_google");
3593
+ if (metaAll.length > 0) registerCapability("ad_tags_meta");
3462
3594
  const gtagLoaderId = gtagAll[0];
3463
3595
  const gtagInitScript = gtagAll.length === 1 ? createGtagInitScript(gtagAll[0]) : createGtagInitScriptMulti(gtagAll);
3464
3596
  const metaInitScript = metaAll.length === 1 ? createMetaPixelInitScript(metaAll[0]) : createMetaPixelInitScriptMulti(metaAll);
@@ -3507,7 +3639,7 @@ function GoogleAdsTracking(props) {
3507
3639
  var import_navigation3 = require("next/navigation");
3508
3640
 
3509
3641
  // package.json
3510
- var version = "0.21.0";
3642
+ var version = "0.22.2";
3511
3643
 
3512
3644
  // src/factory.tsx
3513
3645
  var import_react5 = require("react");
@@ -3534,6 +3666,7 @@ function usePhoneConfig() {
3534
3666
  };
3535
3667
  }
3536
3668
  function usePhoneField(opts = {}) {
3669
+ registerCapability("phone_fields");
3537
3670
  const cfg = usePhoneConfig();
3538
3671
  const country = opts.country ?? cfg.defaultCountry;
3539
3672
  const display = opts.display ?? cfg.display;
@@ -3620,6 +3753,8 @@ function createTracking(options) {
3620
3753
  conversionConfig,
3621
3754
  trackingConfig
3622
3755
  } = options;
3756
+ registerCapability("base_tracking");
3757
+ if (trackingConfig) registerCapability("conversion_goals_auto");
3623
3758
  if (!apiKey || !endpoint) {
3624
3759
  if (apiKey || endpoint) {
3625
3760
  console.warn(
@@ -3861,6 +3996,7 @@ function withBusiness(config, path) {
3861
3996
  return `${path}${separator}business_id=${encodeURIComponent(config.businessId)}`;
3862
3997
  }
3863
3998
  function createCalendarReadClient(config) {
3999
+ registerCapability("calendar_read");
3864
4000
  return {
3865
4001
  async listCalendars() {
3866
4002
  return calendarRequest(config, "GET", withBusiness(config, "/calendars"));