@liiift-studio/sanity-visitor-insights 0.14.0 → 0.15.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.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as sanity from 'sanity';
2
2
  import React from 'react';
3
- import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-CEHxJQE6.mjs';
4
- export { C as CheckStatus, d as Coverage, e as DailyPoint, f as DateRange, g as DiagnosticCheck, E as EventCutover, h as JourneyOutcome, i as JourneyStep, L as LandingPage, P as PREEXISTING, j as REPORT_NAMES, k as ReportError, S as SiteAnalyticsConfig, l as SourceName, m as SourceRow, n as SourceStatus, o as TypefaceInterestRow, U as UnavailableReason, p as coverageForRange, q as isReportName, r as ok, s as partial, t as previousRange, u as resolveRange, v as unavailable, w as validateSiteConfig, x as valueOrNull } from './ranges-CEHxJQE6.mjs';
3
+ import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-BD8XH1Ef.mjs';
4
+ export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as DailyPoint, i as DateRange, j as DiagnosticCheck, E as EventCutover, k as JourneyOutcome, l as JourneyStep, L as LandingPage, P as PREEXISTING, m as REPORT_NAMES, n as ReportError, S as SiteAnalyticsConfig, o as SourceName, p as SourceRow, q as SourceStatus, r as TypefaceInterestRow, U as UnavailableReason, s as coverageForRange, t as estimated, u as isReportName, v as ok, w as partial, x as previousRange, y as resolveRange, z as unavailable, B as validateSiteConfig, F as valueOrNull } from './ranges-BD8XH1Ef.mjs';
5
5
 
6
6
  /**
7
7
  * The Visitor Insights Studio tool.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as sanity from 'sanity';
2
2
  import React from 'react';
3
- import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-CEHxJQE6.js';
4
- export { C as CheckStatus, d as Coverage, e as DailyPoint, f as DateRange, g as DiagnosticCheck, E as EventCutover, h as JourneyOutcome, i as JourneyStep, L as LandingPage, P as PREEXISTING, j as REPORT_NAMES, k as ReportError, S as SiteAnalyticsConfig, l as SourceName, m as SourceRow, n as SourceStatus, o as TypefaceInterestRow, U as UnavailableReason, p as coverageForRange, q as isReportName, r as ok, s as partial, t as previousRange, u as resolveRange, v as unavailable, w as validateSiteConfig, x as valueOrNull } from './ranges-CEHxJQE6.js';
3
+ import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-BD8XH1Ef.js';
4
+ export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as DailyPoint, i as DateRange, j as DiagnosticCheck, E as EventCutover, k as JourneyOutcome, l as JourneyStep, L as LandingPage, P as PREEXISTING, m as REPORT_NAMES, n as ReportError, S as SiteAnalyticsConfig, o as SourceName, p as SourceRow, q as SourceStatus, r as TypefaceInterestRow, U as UnavailableReason, s as coverageForRange, t as estimated, u as isReportName, v as ok, w as partial, x as previousRange, y as resolveRange, z as unavailable, B as validateSiteConfig, F as valueOrNull } from './ranges-BD8XH1Ef.js';
5
5
 
6
6
  /**
7
7
  * The Visitor Insights Studio tool.
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ __export(index_exports, {
47
47
  VisitorInsightsTool: () => VisitorInsightsTool,
48
48
  coverageForRange: () => coverageForRange,
49
49
  default: () => index_default,
50
+ estimated: () => estimated,
50
51
  formatCount: () => formatCount,
51
52
  formatMoney: () => formatMoney,
52
53
  formatPercent: () => formatPercent,
@@ -213,6 +214,21 @@ function MetricFigure({ metric, label, size = 4, unit = "count" }) {
213
214
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Badge, { tone: "caution", fontSize: 0, children: "Partial" })
214
215
  ] });
215
216
  }
217
+ if (metric.status === "estimated") {
218
+ const range = unit === "percent" ? `${metric.low.toFixed(1)}% to ${metric.high.toFixed(1)}%` : `${formatCount(metric.low)} to ${formatCount(metric.high)}`;
219
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Stack, { space: 2, children: [
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Text, { size, "aria-label": `${label}: estimated ${formatted}, between ${range}. ${metric.basis}`, children: [
221
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: "~" }),
222
+ formatted
223
+ ] }),
224
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: range }),
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Badge, { tone: "primary", fontSize: 0, children: "Estimated" })
226
+ ] });
227
+ }
228
+ if (metric.status !== "ok") {
229
+ const unhandled = metric;
230
+ void unhandled;
231
+ }
216
232
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size, "aria-label": `${label}: ${formatted}`, children: formatted });
217
233
  }
218
234
  function ComparisonBar({ label, metric, max, tone = "default" }) {
@@ -889,6 +905,28 @@ function MeasurementHealthPanel({ data, previous }) {
889
905
  data.shortfallRatio !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, weight: "semibold", children: data.shortfallRatio >= 0 ? `GA4 saw ${formatPercent(data.shortfallRatio, 1)} fewer pageviews than Vercel` : `GA4 saw ${formatPercent(-data.shortfallRatio, 1)} more pageviews than Vercel` }),
890
906
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: data.interpretation })
891
907
  ] }) }),
908
+ ((data.capture?.estimates?.length ?? 0) > 0 || data.estimatedSessions?.status === "estimated") && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
909
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, style: sectionHeading, children: "How much GA4 is seeing" }),
910
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: cardGrid, children: (data.capture?.estimates ?? []).map((estimate) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
911
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Label, { size: 1, muted: true, children: estimate.basis === "orders" ? "Measured against orders" : estimate.basis === "email" ? "Measured against email clicks" : "Measured against Vercel" }),
912
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 4, children: formatPercent(Math.min(1, estimate.rate), 0) }),
913
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Text, { size: 0, muted: true, children: [
914
+ formatCount(estimate.observed),
915
+ " of ",
916
+ formatCount(estimate.actual),
917
+ ". ",
918
+ estimate.note
919
+ ] })
920
+ ] }) }, estimate.basis)) }),
921
+ data.capture?.discrepancy && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Card, { padding: 3, radius: 2, tone: "caution", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 2, children: [
922
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, weight: "medium", children: "The sources disagree, and that is informative" }),
923
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, children: data.capture.discrepancy })
924
+ ] }) }),
925
+ data.estimatedSessions && data.estimatedSessions.status === "estimated" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
926
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Label, { size: 1, muted: true, children: "Sessions, corrected for what GA4 misses" }),
927
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MetricFigure, { metric: data.estimatedSessions, label: "Estimated sessions" })
928
+ ] }) })
929
+ ] }),
892
930
  (data.daily?.length ?? 0) >= 3 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
893
931
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, style: sectionHeading, children: "Day by day" }),
894
932
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: "A gap that has always been there is consent and blocking. A gap that opens on one day is an incident." }),
@@ -1598,6 +1636,9 @@ function VisitorInsightsTool(props) {
1598
1636
  }
1599
1637
 
1600
1638
  // src/types.ts
1639
+ function estimated(value, low, high, basis) {
1640
+ return { status: "estimated", value, low, high, basis };
1641
+ }
1601
1642
  function ok(value) {
1602
1643
  return { status: "ok", value };
1603
1644
  }
@@ -1686,6 +1727,9 @@ function validateSiteConfig(config) {
1686
1727
  ["orders.totalField", config.orders?.totalField],
1687
1728
  ["orders.typefacesField", config.orders?.typefacesField]
1688
1729
  ];
1730
+ for (const name of Object.keys(config.orders?.licenceFields ?? {})) {
1731
+ fieldSlots.push([`orders.licenceFields.${name}`, name]);
1732
+ }
1689
1733
  for (const [field, value] of fieldSlots) {
1690
1734
  if (!value) continue;
1691
1735
  if (!FIELD_PATH.test(value)) {
@@ -1840,6 +1884,7 @@ var index_default = visitorInsights;
1840
1884
  TypefaceInterestPanel,
1841
1885
  VisitorInsightsTool,
1842
1886
  coverageForRange,
1887
+ estimated,
1843
1888
  formatCount,
1844
1889
  formatMoney,
1845
1890
  formatPercent,