@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.mjs CHANGED
@@ -258,6 +258,43 @@ var aranovaConsent = (function () {
258
258
  `.trim();
259
259
  }
260
260
 
261
+ // ../tracking-core/src/capabilities.ts
262
+ var TRACKING_CAPABILITIES = [
263
+ "ad_tags_google",
264
+ "ad_tags_meta",
265
+ "base_tracking",
266
+ "blog_rendering",
267
+ "calendar_read",
268
+ "calendar_write",
269
+ "consent_controls",
270
+ "conversion_goals_auto",
271
+ "conversion_goals_manual",
272
+ "cta_click_capture",
273
+ "form_capture",
274
+ "phone_click_capture",
275
+ "phone_fields"
276
+ ];
277
+ var CAPABILITY_DOM_ATTRIBUTE = "data-aranova-capability";
278
+ var registered = /* @__PURE__ */ new Set();
279
+ function registerCapability(capability) {
280
+ registered.add(capability);
281
+ }
282
+ function getRegisteredCapabilities() {
283
+ const all = new Set(registered);
284
+ for (const marker of readDomMarkers()) all.add(marker);
285
+ return Array.from(all).sort();
286
+ }
287
+ function readDomMarkers() {
288
+ if (typeof document === "undefined") return [];
289
+ const known = new Set(TRACKING_CAPABILITIES);
290
+ const found = [];
291
+ for (const node of document.querySelectorAll(`[${CAPABILITY_DOM_ATTRIBUTE}]`)) {
292
+ const value = node.getAttribute(CAPABILITY_DOM_ATTRIBUTE);
293
+ if (value && known.has(value)) found.push(value);
294
+ }
295
+ return found;
296
+ }
297
+
261
298
  // ../tracking-core/src/tracking.ts
262
299
  var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
263
300
  var TRACKING_PARAM_KEYS = [
@@ -602,7 +639,8 @@ function createTrackingClientContext(surface, input = {}) {
602
639
  page_title: input.pageTitle ?? (typeof document === "undefined" ? null : document.title || null),
603
640
  referrer: input.referrer ?? (typeof document === "undefined" ? null : document.referrer || null),
604
641
  environment: input.environment ?? "production",
605
- active_gtag_ids: input.activeGtagIds ?? null
642
+ active_gtag_ids: input.activeGtagIds ?? null,
643
+ capabilities: getRegisteredCapabilities()
606
644
  };
607
645
  }
608
646
  function createTrackingSessionUpsertPayload(trackingParams, input, context) {
@@ -1582,6 +1620,9 @@ function buildHeartbeatMetadata(surface, sdkVersion, packageName, triggers, gtag
1582
1620
  var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
1583
1621
  var DEFAULT_MAX_QUEUE_SIZE = 10;
1584
1622
  var HARD_MAX_BATCH = 50;
1623
+ var MAX_RETRY_BACKOFF_MS = 6e4;
1624
+ var MAX_BUFFERED_EVENTS2 = 200;
1625
+ var RETRY_BUFFER_KEY_PREFIX = "aranova_tracking_pending_v1";
1585
1626
  var API_KEY_HEADER = "X-Aranova-Api-Key";
1586
1627
  var SDK_VERSION_HEADER = "X-Aranova-Sdk-Version";
1587
1628
  var SDK_PACKAGE_HEADER = "X-Aranova-Sdk-Package";
@@ -1596,7 +1637,10 @@ function buildContext(surface, sdkVersion, packageName, environment, activeGtagI
1596
1637
  page_title: typeof document === "undefined" ? null : document.title || null,
1597
1638
  referrer: typeof document === "undefined" ? null : document.referrer || null,
1598
1639
  environment,
1599
- active_gtag_ids: activeGtagIds
1640
+ active_gtag_ids: activeGtagIds,
1641
+ // Rebuilt per flush (this runs inside the payload builder), so a client
1642
+ // constructed later on a deeper route still gets reported.
1643
+ capabilities: getRegisteredCapabilities()
1600
1644
  };
1601
1645
  }
1602
1646
  function readTrackingParams() {
@@ -1621,9 +1665,9 @@ function consentSnapshot() {
1621
1665
  }
1622
1666
  }
1623
1667
  async function postWithFetch(url, body, apiKey, identity, keepalive) {
1624
- if (typeof fetch !== "function") return;
1668
+ if (typeof fetch !== "function") return "drop";
1625
1669
  try {
1626
- await fetch(url, {
1670
+ const response = await fetch(url, {
1627
1671
  method: "POST",
1628
1672
  headers: {
1629
1673
  "Content-Type": "application/json",
@@ -1639,8 +1683,48 @@ async function postWithFetch(url, body, apiKey, identity, keepalive) {
1639
1683
  credentials: "omit",
1640
1684
  mode: "cors"
1641
1685
  });
1686
+ if (response.ok) return "ok";
1687
+ if (response.status === 408 || response.status === 429 || response.status >= 500) {
1688
+ return "retry";
1689
+ }
1690
+ return "drop";
1691
+ } catch {
1692
+ return "retry";
1693
+ }
1694
+ }
1695
+ function retryBufferKey(apiKey, endpoint) {
1696
+ return `${RETRY_BUFFER_KEY_PREFIX}:${apiKey}:${endpoint}`;
1697
+ }
1698
+ function readPendingBatches(key) {
1699
+ if (typeof window === "undefined") return [];
1700
+ try {
1701
+ const raw = window.localStorage.getItem(key);
1702
+ if (!raw) return [];
1703
+ const parsed = JSON.parse(raw);
1704
+ if (!Array.isArray(parsed)) return [];
1705
+ return parsed.filter(
1706
+ (entry) => typeof entry === "object" && entry !== null && "session" in entry && Array.isArray(entry.events)
1707
+ );
1642
1708
  } catch {
1709
+ return [];
1710
+ }
1711
+ }
1712
+ function writePendingBatches(key, batches) {
1713
+ if (typeof window === "undefined") return;
1714
+ try {
1715
+ if (batches.length === 0) window.localStorage.removeItem(key);
1716
+ else window.localStorage.setItem(key, JSON.stringify(batches));
1717
+ } catch {
1718
+ }
1719
+ }
1720
+ function trimToBufferCap(batches) {
1721
+ let total = batches.reduce((sum, batch) => sum + batch.events.length, 0);
1722
+ const trimmed = batches.slice();
1723
+ while (total > MAX_BUFFERED_EVENTS2 && trimmed.length > 1) {
1724
+ const dropped = trimmed.shift();
1725
+ total -= dropped ? dropped.events.length : 0;
1643
1726
  }
1727
+ return trimmed;
1644
1728
  }
1645
1729
  var globalClient = null;
1646
1730
  var globalClientKey = null;
@@ -1697,6 +1781,10 @@ function createTrackingClient(config) {
1697
1781
  };
1698
1782
  let queue = [];
1699
1783
  let flushTimer = null;
1784
+ const bufferKey = retryBufferKey(config.apiKey, endpointBase);
1785
+ let pending = readPendingBatches(bufferKey);
1786
+ let flushChain = Promise.resolve();
1787
+ let retryAttempt = 0;
1700
1788
  let firstPage = null;
1701
1789
  let initialParams = createEmptyTrackingParams();
1702
1790
  let destroyed = false;
@@ -1733,6 +1821,9 @@ function createTrackingClient(config) {
1733
1821
  if (initialSession.isNew) {
1734
1822
  enqueueHeartbeat();
1735
1823
  }
1824
+ if (pending.length > 0) {
1825
+ scheduleFlush();
1826
+ }
1736
1827
  function buildSessionPayload() {
1737
1828
  const rotated = getOrRotateSessionId();
1738
1829
  if (rotated.isNew && rotated.id !== sessionId) {
@@ -1771,12 +1862,12 @@ function createTrackingClient(config) {
1771
1862
  context
1772
1863
  };
1773
1864
  }
1774
- function scheduleFlush() {
1865
+ function scheduleFlush(delayMs = flushIntervalMs) {
1775
1866
  if (flushTimer !== null || destroyed) return;
1776
1867
  flushTimer = setTimeout(() => {
1777
1868
  flushTimer = null;
1778
1869
  void flush();
1779
- }, flushIntervalMs);
1870
+ }, delayMs);
1780
1871
  }
1781
1872
  function clearScheduledFlush() {
1782
1873
  if (flushTimer !== null) {
@@ -1784,17 +1875,50 @@ function createTrackingClient(config) {
1784
1875
  flushTimer = null;
1785
1876
  }
1786
1877
  }
1787
- async function flush() {
1878
+ function bufferQueued() {
1788
1879
  if (queue.length === 0) return;
1789
1880
  const events = queue.slice(0, HARD_MAX_BATCH);
1790
1881
  queue = queue.slice(events.length);
1882
+ pending = trimToBufferCap([...pending, { session: buildSessionPayload(), events }]);
1883
+ writePendingBatches(bufferKey, pending);
1884
+ }
1885
+ function flush() {
1886
+ flushChain = flushChain.then(runFlush).catch(() => {
1887
+ });
1888
+ return flushChain;
1889
+ }
1890
+ async function runFlush() {
1891
+ if (destroyed) return;
1791
1892
  clearScheduledFlush();
1792
- const body = {
1793
- session: buildSessionPayload(),
1794
- events
1795
- };
1796
- const serialized = JSON.stringify(body);
1797
- await postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, false);
1893
+ bufferQueued();
1894
+ if (pending.length === 0) return;
1895
+ try {
1896
+ while (pending.length > 0) {
1897
+ const batch = pending[0];
1898
+ const body = { session: batch.session, events: batch.events };
1899
+ const outcome = await postWithFetch(
1900
+ eventsUrl,
1901
+ JSON.stringify(body),
1902
+ config.apiKey,
1903
+ identityHeaders2,
1904
+ false
1905
+ );
1906
+ if (outcome === "retry") {
1907
+ retryAttempt += 1;
1908
+ return;
1909
+ }
1910
+ pending = pending.slice(1);
1911
+ writePendingBatches(bufferKey, pending);
1912
+ retryAttempt = 0;
1913
+ }
1914
+ } finally {
1915
+ if (pending.length > 0) {
1916
+ const backoff = Math.min(flushIntervalMs * 2 ** retryAttempt, MAX_RETRY_BACKOFF_MS);
1917
+ scheduleFlush(backoff);
1918
+ } else if (queue.length > 0) {
1919
+ scheduleFlush();
1920
+ }
1921
+ }
1798
1922
  }
1799
1923
  function trackEvent(input) {
1800
1924
  if (destroyed) return;
@@ -1820,16 +1944,14 @@ function createTrackingClient(config) {
1820
1944
  }
1821
1945
  }
1822
1946
  function flushOnUnload() {
1823
- if (queue.length === 0) return;
1824
- const events = queue.slice(0, HARD_MAX_BATCH);
1825
- queue = queue.slice(events.length);
1947
+ bufferQueued();
1826
1948
  clearScheduledFlush();
1827
- const body = {
1828
- session: buildSessionPayload(),
1829
- events
1830
- };
1831
- const serialized = JSON.stringify(body);
1832
- void postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, true);
1949
+ if (pending.length === 0) return;
1950
+ const batch = pending[0];
1951
+ pending = pending.slice(1);
1952
+ writePendingBatches(bufferKey, pending);
1953
+ const body = { session: batch.session, events: batch.events };
1954
+ void postWithFetch(eventsUrl, JSON.stringify(body), config.apiKey, identityHeaders2, true);
1833
1955
  }
1834
1956
  if (typeof window !== "undefined") {
1835
1957
  window.addEventListener("pagehide", flushOnUnload);
@@ -2189,8 +2311,9 @@ function getEventDefinition(name) {
2189
2311
  }
2190
2312
 
2191
2313
  // ../tracking-core/src/ingest-typed.ts
2192
- function createTypedClient(raw, _registry, options = {}) {
2314
+ function createTypedClient(raw, registry, options = {}) {
2193
2315
  const debug = options.debug ?? false;
2316
+ if (registry.manual?.form_submit) registerCapability("form_capture");
2194
2317
  return {
2195
2318
  trackEvent(eventType, metadata, opts) {
2196
2319
  if (debug) {
@@ -2597,6 +2720,7 @@ function attachCtaClickCapture(client, config) {
2597
2720
  return () => {
2598
2721
  };
2599
2722
  }
2723
+ registerCapability("cta_click_capture");
2600
2724
  const selector = autoCapture.selector ?? DEFAULT_CTA_SELECTOR;
2601
2725
  function onClick(event) {
2602
2726
  const target = event.target;
@@ -2653,6 +2777,7 @@ function attachPhoneClickCapture(client, config) {
2653
2777
  return () => {
2654
2778
  };
2655
2779
  }
2780
+ registerCapability("phone_click_capture");
2656
2781
  const selector = autoCapture.selector ?? DEFAULT_TEL_SELECTOR;
2657
2782
  function onClick(event) {
2658
2783
  const target = event.target;
@@ -2769,6 +2894,7 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
2769
2894
  }
2770
2895
  }
2771
2896
  function createSalesClient(config) {
2897
+ if (config.firing) registerCapability("conversion_goals_manual");
2772
2898
  async function record(input) {
2773
2899
  const currency = input.currency ?? config.defaultCurrency;
2774
2900
  if (!currency) {
@@ -3012,6 +3138,9 @@ var saleUpdateSchema = z12.object({
3012
3138
  items: z12.array(saleItemSchema).optional(),
3013
3139
  metadata: metadataSchema.nullable().optional(),
3014
3140
  customer_name: customerNameSchema.nullable().optional(),
3141
+ // Re-attest when changing a filler-looking name; the server clears the
3142
+ // prior attestation whenever `customer_name` changes.
3143
+ customer_name_placeholder_confirmed: z12.boolean().optional(),
3015
3144
  customer_phone: customerPhoneSchema.nullable().optional(),
3016
3145
  customer_email: customerEmailSchema.nullable().optional(),
3017
3146
  // NOT NULL server-side: omit to leave unchanged (explicit null is rejected).
@@ -3068,6 +3197,7 @@ var DEFAULT_CHOICE2 = {
3068
3197
  expiresAt: null
3069
3198
  };
3070
3199
  function useCookiePreferences(options) {
3200
+ registerCapability("consent_controls");
3071
3201
  const [choice, setChoice] = useState(DEFAULT_CHOICE2);
3072
3202
  const ttlDays = options?.declineTtlDays;
3073
3203
  useEffect(() => {
@@ -3335,6 +3465,8 @@ function AdPlatformTracking({
3335
3465
  }, [trackingConfigKey, standalonePageView]);
3336
3466
  const gtagAll = trackingConfig ? [] : gtagIds ? Object.values(gtagIds).filter((id) => id != null) : gtagId ? [gtagId] : [];
3337
3467
  const metaAll = metaPixelIds ? Object.values(metaPixelIds).filter((id) => id != null) : metaPixelId ? [metaPixelId] : [];
3468
+ if (trackingConfig || gtagAll.length > 0) registerCapability("ad_tags_google");
3469
+ if (metaAll.length > 0) registerCapability("ad_tags_meta");
3338
3470
  const gtagLoaderId = gtagAll[0];
3339
3471
  const gtagInitScript = gtagAll.length === 1 ? createGtagInitScript(gtagAll[0]) : createGtagInitScriptMulti(gtagAll);
3340
3472
  const metaInitScript = metaAll.length === 1 ? createMetaPixelInitScript(metaAll[0]) : createMetaPixelInitScriptMulti(metaAll);
@@ -3383,7 +3515,7 @@ function GoogleAdsTracking(props) {
3383
3515
  import { usePathname, useSearchParams } from "next/navigation";
3384
3516
 
3385
3517
  // package.json
3386
- var version = "0.21.0";
3518
+ var version = "0.22.2";
3387
3519
 
3388
3520
  // src/factory.tsx
3389
3521
  import {
@@ -3425,6 +3557,7 @@ function usePhoneConfig() {
3425
3557
  };
3426
3558
  }
3427
3559
  function usePhoneField(opts = {}) {
3560
+ registerCapability("phone_fields");
3428
3561
  const cfg = usePhoneConfig();
3429
3562
  const country = opts.country ?? cfg.defaultCountry;
3430
3563
  const display = opts.display ?? cfg.display;
@@ -3511,6 +3644,8 @@ function createTracking(options) {
3511
3644
  conversionConfig,
3512
3645
  trackingConfig
3513
3646
  } = options;
3647
+ registerCapability("base_tracking");
3648
+ if (trackingConfig) registerCapability("conversion_goals_auto");
3514
3649
  if (!apiKey || !endpoint) {
3515
3650
  if (apiKey || endpoint) {
3516
3651
  console.warn(
@@ -3752,6 +3887,7 @@ function withBusiness(config, path) {
3752
3887
  return `${path}${separator}business_id=${encodeURIComponent(config.businessId)}`;
3753
3888
  }
3754
3889
  function createCalendarReadClient(config) {
3890
+ registerCapability("calendar_read");
3755
3891
  return {
3756
3892
  async listCalendars() {
3757
3893
  return calendarRequest(config, "GET", withBusiness(config, "/calendars"));