@liiift-studio/sanity-visitor-insights 0.2.2 → 0.3.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/server.mjs CHANGED
@@ -86,19 +86,41 @@ ${detail}`);
86
86
 
87
87
  // src/core/cutover.ts
88
88
  var PREEXISTING = "preexisting";
89
+ function toHistory(cutover) {
90
+ if (cutover === null || cutover === void 0) return null;
91
+ if (typeof cutover === "string") return { from: cutover };
92
+ if (!cutover.from) return null;
93
+ return cutover;
94
+ }
95
+ function overlaps(aStart, aEnd, bStart, bEnd) {
96
+ return aStart <= bEnd && (aEnd === null || aEnd >= bStart);
97
+ }
89
98
  function coverageForRange(cutovers, eventName, range) {
90
99
  if (!(eventName in cutovers)) return { status: "none", reason: "unknown_event" };
91
- const cutover = cutovers[eventName];
92
- if (cutover === null || cutover === void 0) return { status: "none", reason: "not_instrumented" };
93
- if (cutover === PREEXISTING) return { status: "full" };
94
- const cutoverTime = Date.parse(cutover);
95
- if (Number.isNaN(cutoverTime)) return { status: "none", reason: "unknown_event" };
96
- if (Date.parse(range.end) < cutoverTime) return { status: "none", reason: "before_cutover", cutover };
97
- if (Date.parse(range.start) < cutoverTime) return { status: "partial", cutover };
100
+ const history = toHistory(cutovers[eventName]);
101
+ if (!history) return { status: "none", reason: "not_instrumented" };
102
+ let cutover;
103
+ let startsBeforeCutover = false;
104
+ if (history.from !== PREEXISTING) {
105
+ const cutoverTime = Date.parse(history.from);
106
+ if (Number.isNaN(cutoverTime)) return { status: "none", reason: "unknown_event" };
107
+ cutover = history.from;
108
+ if (Date.parse(range.end) < cutoverTime) return { status: "none", reason: "before_cutover", cutover };
109
+ startsBeforeCutover = Date.parse(range.start) < cutoverTime;
110
+ }
111
+ const hit = (history.outages ?? []).filter((o) => overlaps(o.start, o.until, range.start, range.end));
112
+ const swallowed = hit.find((o) => o.start <= range.start && (o.until === null || o.until > range.end));
113
+ if (swallowed) return { status: "none", reason: "outage", outages: [swallowed], cutover };
114
+ if (hit.length > 0) return { status: "partial", reason: "spans_outage", outages: hit, cutover };
115
+ if (startsBeforeCutover) return { status: "partial", reason: "spans_cutover", outages: [], cutover };
98
116
  return { status: "full" };
99
117
  }
100
118
  function applyCoverage(count, coverage) {
101
119
  if (coverage.status === "none") {
120
+ if (coverage.reason === "outage") {
121
+ const outage = coverage.outages?.[0];
122
+ return unavailable("outage", outage ? describeOutage(outage) : void 0);
123
+ }
102
124
  return unavailable(
103
125
  coverage.reason === "before_cutover" ? "before_cutover" : "not_instrumented",
104
126
  coverage.cutover ? `Instrumented from ${coverage.cutover}` : void 0
@@ -106,16 +128,31 @@ function applyCoverage(count, coverage) {
106
128
  }
107
129
  if (count === null) return unavailable("source_error");
108
130
  if (coverage.status === "partial") {
109
- return partial(count, coverage.cutover, `Only counted from ${coverage.cutover}, when this event was added`);
131
+ if (coverage.reason === "spans_outage") {
132
+ const outage = coverage.outages[0];
133
+ const from2 = outage?.until ?? outage?.start ?? coverage.cutover ?? "";
134
+ return partial(count, from2, `Undercounted: ${describeOutage(outage)}`);
135
+ }
136
+ const from = coverage.cutover ?? "";
137
+ return partial(count, from, `Only counted from ${from}, when this event was added`);
110
138
  }
111
139
  return { status: "ok", value: count };
112
140
  }
141
+ function describeOutage(outage) {
142
+ if (!outage) return "an outage affected part of this range";
143
+ const period = outage.until ? `${outage.start} to ${outage.until}` : `${outage.start} onwards`;
144
+ return outage.reason ? `not recorded ${period} (${outage.reason})` : `not recorded ${period}`;
145
+ }
113
146
  function coverageNotices(cutovers, eventNames, range) {
114
147
  const notices = [];
115
148
  for (const name of eventNames) {
116
149
  const coverage = coverageForRange(cutovers, name, range);
117
- if (coverage.status === "partial") {
150
+ if (coverage.status === "partial" && coverage.reason === "spans_outage") {
151
+ notices.push(`${name} was ${describeOutage(coverage.outages[0])}, so figures for this range are too low \u2014 not a real decline.`);
152
+ } else if (coverage.status === "partial") {
118
153
  notices.push(`${name} was instrumented on ${coverage.cutover}; figures before that date are missing, not zero.`);
154
+ } else if (coverage.status === "none" && coverage.reason === "outage") {
155
+ notices.push(`${name} was ${describeOutage(coverage.outages?.[0])}, covering this whole range. The figure is unavailable, not zero.`);
119
156
  } else if (coverage.status === "none" && coverage.reason === "not_instrumented") {
120
157
  notices.push(`${name} is not instrumented on this site, so it cannot be reported for any range.`);
121
158
  } else if (coverage.status === "none" && coverage.reason === "before_cutover") {
@@ -1151,6 +1188,8 @@ export {
1151
1188
  createVercelClient,
1152
1189
  createVisitorInsightsHandler,
1153
1190
  daysBetween,
1191
+ describeOutage,
1192
+ eventNameFilter,
1154
1193
  formatInTimeZone,
1155
1194
  isReportName,
1156
1195
  isValidTimeZone,
@@ -1164,6 +1203,7 @@ export {
1164
1203
  resolveRange,
1165
1204
  runDiagnostics,
1166
1205
  shiftDays,
1206
+ sumFirstMetric,
1167
1207
  unavailable,
1168
1208
  validateSiteConfig,
1169
1209
  valueOrNull,