@liiift-studio/sanity-visitor-insights 0.12.0 → 0.13.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.
Files changed (38) hide show
  1. package/README.md +50 -0
  2. package/dist/index.d.mts +4 -4
  3. package/dist/index.d.ts +4 -4
  4. package/dist/index.js +360 -35
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +361 -36
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/{ranges-YGStz1nR.d.mts → ranges-CiTnQEnz.d.mts} +158 -1
  9. package/dist/{ranges-YGStz1nR.d.ts → ranges-CiTnQEnz.d.ts} +158 -1
  10. package/dist/server.d.mts +4 -4
  11. package/dist/server.d.ts +4 -4
  12. package/dist/server.js +362 -83
  13. package/dist/server.js.map +1 -1
  14. package/dist/server.mjs +359 -82
  15. package/dist/server.mjs.map +1 -1
  16. package/dist/testing.d.mts +1 -1
  17. package/dist/testing.d.ts +1 -1
  18. package/dist/{vercel-C597eCC_.d.mts → vercel-CwILuQVm.d.mts} +14 -1
  19. package/dist/{vercel-C597eCC_.d.ts → vercel-CwILuQVm.d.ts} +14 -1
  20. package/package.json +1 -1
  21. package/src/core/core.test.ts +72 -0
  22. package/src/core/ranges.ts +59 -0
  23. package/src/core/siteConfig.ts +79 -0
  24. package/src/reportData.ts +57 -0
  25. package/src/server/createHandler.ts +31 -6
  26. package/src/server/diagnostics.ts +22 -5
  27. package/src/server/ga4.ts +71 -8
  28. package/src/server/orders.ts +233 -47
  29. package/src/server/reports/acquisition.ts +54 -10
  30. package/src/server/reports/journey.ts +94 -10
  31. package/src/server/reports/measurementHealth.ts +55 -26
  32. package/src/server/reports/reports.test.ts +263 -9
  33. package/src/server/reports/typefaceInterest.ts +58 -12
  34. package/src/studio/Figure.tsx +316 -13
  35. package/src/studio/VisitorInsightsTool.tsx +15 -2
  36. package/src/studio/panels.test.tsx +109 -10
  37. package/src/studio/panels.tsx +171 -8
  38. package/src/types.ts +10 -0
package/README.md CHANGED
@@ -192,6 +192,56 @@ empty charts — pasting a measurement id here is caught by name.
192
192
  The service account needs **Viewer** on each GA4 property. Nothing here is `NEXT_PUBLIC_`; none of
193
193
  it reaches the browser.
194
194
 
195
+ #### Scoping to your own hostnames
196
+
197
+ `ga4.hostnames` restricts every GA4 report to the hosts you name. A GA4 property is not necessarily
198
+ one website — Darden's also receives `impactsport.ca`, an unrelated business, which was inside the
199
+ headline session count, both percentages computed from it, and the funnel's entry rung. Omit the
200
+ field to accept every hostname, which is the old behaviour.
201
+
202
+ ```js
203
+ ga4: {
204
+ propertyId: '123456789',
205
+ timezone: 'America/Los_Angeles',
206
+ hostnames: ['www.dardenstudio.com', 'dardenstudio.com'],
207
+ }
208
+ ```
209
+
210
+ #### Orders: status and revenue
211
+
212
+ `orders.countedStatuses` names the statuses that count as a real sale; everything else is excluded
213
+ and reported separately. Leave it unset and test, failed, pending and refunded orders all count as
214
+ sales — at seven orders a quarter, one test order is a 14% error. The status breakdown is always
215
+ reported so you can see what vocabulary your own orders use before configuring this.
216
+
217
+ `orders.totalField` turns on revenue. Without it a $30 web licence and a $400 multi-seat desktop
218
+ licence are the same integer, so nothing can be ranked by what it is worth. An order total is not a
219
+ customer field; the PII projection allow-list is unchanged.
220
+
221
+ ```js
222
+ orders: {
223
+ documentType: 'order',
224
+ typefacesField: 'typefaces',
225
+ statusField: 'orderStatus',
226
+ countedStatuses: ['complete', 'paid'],
227
+ totalField: 'total',
228
+ currency: 'USD',
229
+ }
230
+ ```
231
+
232
+ #### Conversions that are not a sale
233
+
234
+ `eventNames.enquiry`, `.subscribe` and `.assetDownload` surface outcomes the funnel used to score as
235
+ drop-offs. A custom commission is worth many multiples of a licence, and the funnel ended at
236
+ `purchase` — so the visitor who read three typeface pages and emailed was counted as a leak.
237
+
238
+ ```js
239
+ eventNames: {
240
+ enquiry: ['enquiry_submit'],
241
+ subscribe: ['subscribe'],
242
+ }
243
+ ```
244
+
195
245
  #### The master switch
196
246
 
197
247
  `VISITOR_INSIGHTS_ENABLED` is an explicit opt-in. Unset, the route answers `503` with
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-YGStz1nR.mjs';
4
- export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-YGStz1nR.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-CiTnQEnz.mjs';
4
+ export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-CiTnQEnz.mjs';
5
5
 
6
6
  /**
7
7
  * The Visitor Insights Studio tool.
@@ -93,7 +93,6 @@ declare function useReport<T>({ apiBaseUrl, report, range, custom }: UseReportOp
93
93
  declare function formatCount(value: number): string;
94
94
  /** Format a 0–1 ratio as a percentage. */
95
95
  declare function formatPercent(ratio: number, digits?: number): string;
96
- /** Props for MetricFigure. */
97
96
  interface MetricFigureProps {
98
97
  metric: MetricValue;
99
98
  /** Accessible label describing what this number counts. */
@@ -168,8 +167,9 @@ declare function MeasurementHealthPanel({ data }: {
168
167
  data: MeasurementHealthData;
169
168
  }): React.ReactElement;
170
169
  /** Acquisition — where visitors came from, with design-industry referrers called out. */
171
- declare function AcquisitionPanel({ data }: {
170
+ declare function AcquisitionPanel({ data, previous }: {
172
171
  data: AcquisitionData;
172
+ previous?: AcquisitionData;
173
173
  }): React.ReactElement;
174
174
  /** Journey — a funnel, drawn as a tracked sequence or as independent totals, whichever the report used. */
175
175
  declare function JourneyPanel({ data }: {
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-YGStz1nR.js';
4
- export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-YGStz1nR.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-CiTnQEnz.js';
4
+ export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-CiTnQEnz.js';
5
5
 
6
6
  /**
7
7
  * The Visitor Insights Studio tool.
@@ -93,7 +93,6 @@ declare function useReport<T>({ apiBaseUrl, report, range, custom }: UseReportOp
93
93
  declare function formatCount(value: number): string;
94
94
  /** Format a 0–1 ratio as a percentage. */
95
95
  declare function formatPercent(ratio: number, digits?: number): string;
96
- /** Props for MetricFigure. */
97
96
  interface MetricFigureProps {
98
97
  metric: MetricValue;
99
98
  /** Accessible label describing what this number counts. */
@@ -168,8 +167,9 @@ declare function MeasurementHealthPanel({ data }: {
168
167
  data: MeasurementHealthData;
169
168
  }): React.ReactElement;
170
169
  /** Acquisition — where visitors came from, with design-industry referrers called out. */
171
- declare function AcquisitionPanel({ data }: {
170
+ declare function AcquisitionPanel({ data, previous }: {
172
171
  data: AcquisitionData;
172
+ previous?: AcquisitionData;
173
173
  }): React.ReactElement;
174
174
  /** Journey — a funnel, drawn as a tracked sequence or as independent totals, whichever the report used. */
175
175
  declare function JourneyPanel({ data }: {