@liiift-studio/sanity-visitor-insights 0.2.2 → 0.3.1
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/README.md +7 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +26 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +26 -7
- package/dist/index.mjs.map +1 -1
- package/dist/{ranges-DSFapooC.d.mts → ranges-Bh9WCyYL.d.mts} +45 -9
- package/dist/{ranges-DSFapooC.d.ts → ranges-Bh9WCyYL.d.ts} +45 -9
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +62 -10
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +59 -10
- package/dist/server.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{vercel-BMEO-Jcw.d.mts → vercel-B6d1Ng48.d.mts} +5 -1
- package/dist/{vercel-BMEO-Jcw.d.ts → vercel-B6d1Ng48.d.ts} +5 -1
- package/package.json +2 -2
- package/src/core/core.test.ts +82 -1
- package/src/core/cutover.ts +113 -19
- package/src/server/vercel.ts +23 -1
- package/src/server.ts +1 -1
- package/src/studio/Figure.tsx +1 -0
- package/src/types.ts +2 -0
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
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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") {
|
|
@@ -370,6 +407,12 @@ function sumFirstMetric(report) {
|
|
|
370
407
|
|
|
371
408
|
// src/server/vercel.ts
|
|
372
409
|
var API_BASE = "https://api.vercel.com/v1/query/web-analytics";
|
|
410
|
+
function granularityFor(start, end) {
|
|
411
|
+
const days = Math.round((Date.parse(`${end}T00:00:00Z`) - Date.parse(`${start}T00:00:00Z`)) / 864e5) + 1;
|
|
412
|
+
if (days <= 62) return "day";
|
|
413
|
+
if (days <= 26 * 7) return "week";
|
|
414
|
+
return "month";
|
|
415
|
+
}
|
|
373
416
|
function createVercelClient(projectId, token, teamId) {
|
|
374
417
|
async function query(path, extra) {
|
|
375
418
|
const params = new URLSearchParams({ projectId, ...extra });
|
|
@@ -392,8 +435,11 @@ function createVercelClient(projectId, token, teamId) {
|
|
|
392
435
|
query("visits/aggregate", {
|
|
393
436
|
since: start,
|
|
394
437
|
until: end,
|
|
395
|
-
by:
|
|
438
|
+
by: granularityFor(start, end),
|
|
396
439
|
limit: "100"
|
|
440
|
+
}).catch((e) => {
|
|
441
|
+
console.error("Visitor insights: Vercel series unavailable:", e.message);
|
|
442
|
+
return { data: [] };
|
|
397
443
|
})
|
|
398
444
|
]);
|
|
399
445
|
const byDate = {};
|
|
@@ -1151,6 +1197,8 @@ export {
|
|
|
1151
1197
|
createVercelClient,
|
|
1152
1198
|
createVisitorInsightsHandler,
|
|
1153
1199
|
daysBetween,
|
|
1200
|
+
describeOutage,
|
|
1201
|
+
eventNameFilter,
|
|
1154
1202
|
formatInTimeZone,
|
|
1155
1203
|
isReportName,
|
|
1156
1204
|
isValidTimeZone,
|
|
@@ -1164,6 +1212,7 @@ export {
|
|
|
1164
1212
|
resolveRange,
|
|
1165
1213
|
runDiagnostics,
|
|
1166
1214
|
shiftDays,
|
|
1215
|
+
sumFirstMetric,
|
|
1167
1216
|
unavailable,
|
|
1168
1217
|
validateSiteConfig,
|
|
1169
1218
|
valueOrNull,
|