@iann29/rastro 0.3.0 → 0.5.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 (128) hide show
  1. package/README.md +199 -50
  2. package/agent/integration.md +26 -10
  3. package/agent/manifest.json +10 -5
  4. package/agent/manifest.schema.json +14 -5
  5. package/dist/client/federation.d.ts +28 -8
  6. package/dist/client/federation.d.ts.map +1 -1
  7. package/dist/client/federation.js +12 -1
  8. package/dist/client/federation.js.map +1 -1
  9. package/dist/client/index.d.ts +262 -9
  10. package/dist/client/index.d.ts.map +1 -1
  11. package/dist/client/index.js +119 -2
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/component/_generated/api.d.ts +6 -0
  14. package/dist/component/_generated/api.d.ts.map +1 -1
  15. package/dist/component/_generated/api.js.map +1 -1
  16. package/dist/component/_generated/component.d.ts +72 -1
  17. package/dist/component/_generated/component.d.ts.map +1 -1
  18. package/dist/component/_generated/server.d.ts +1 -0
  19. package/dist/component/_generated/server.d.ts.map +1 -1
  20. package/dist/component/_generated/server.js.map +1 -1
  21. package/dist/component/constants.d.ts +9 -2
  22. package/dist/component/constants.d.ts.map +1 -1
  23. package/dist/component/constants.js +31 -3
  24. package/dist/component/constants.js.map +1 -1
  25. package/dist/component/convex.config.d.ts +1 -0
  26. package/dist/component/convex.config.js +3 -0
  27. package/dist/component/convex.config.js.map +1 -1
  28. package/dist/component/coverage.d.ts +1 -0
  29. package/dist/component/coverage.d.ts.map +1 -1
  30. package/dist/component/coverage.js +6 -1
  31. package/dist/component/coverage.js.map +1 -1
  32. package/dist/component/eventStore.d.ts +2 -0
  33. package/dist/component/eventStore.d.ts.map +1 -1
  34. package/dist/component/geo.d.ts +1 -0
  35. package/dist/component/geo.d.ts.map +1 -1
  36. package/dist/component/geo.js +1 -1
  37. package/dist/component/geo.js.map +1 -1
  38. package/dist/component/http.d.ts.map +1 -1
  39. package/dist/component/http.js +65 -2
  40. package/dist/component/http.js.map +1 -1
  41. package/dist/component/identity.d.ts +12 -0
  42. package/dist/component/identity.d.ts.map +1 -1
  43. package/dist/component/identity.js +30 -2
  44. package/dist/component/identity.js.map +1 -1
  45. package/dist/component/ingest.d.ts +36 -0
  46. package/dist/component/ingest.d.ts.map +1 -1
  47. package/dist/component/ingest.js +111 -20
  48. package/dist/component/ingest.js.map +1 -1
  49. package/dist/component/live.d.ts.map +1 -1
  50. package/dist/component/live.js +34 -4
  51. package/dist/component/live.js.map +1 -1
  52. package/dist/component/origin.d.ts +70 -0
  53. package/dist/component/origin.d.ts.map +1 -0
  54. package/dist/component/origin.js +230 -0
  55. package/dist/component/origin.js.map +1 -0
  56. package/dist/component/platforms.d.ts +33 -0
  57. package/dist/component/platforms.d.ts.map +1 -0
  58. package/dist/component/platforms.js +328 -0
  59. package/dist/component/platforms.js.map +1 -0
  60. package/dist/component/reports.d.ts +27 -72
  61. package/dist/component/reports.d.ts.map +1 -1
  62. package/dist/component/reports.js +72 -16
  63. package/dist/component/reports.js.map +1 -1
  64. package/dist/component/rollupStore.d.ts +7 -4
  65. package/dist/component/rollupStore.d.ts.map +1 -1
  66. package/dist/component/rollupStore.js +37 -17
  67. package/dist/component/rollupStore.js.map +1 -1
  68. package/dist/component/rollups.d.ts +27 -8
  69. package/dist/component/rollups.d.ts.map +1 -1
  70. package/dist/component/rollups.js +110 -32
  71. package/dist/component/rollups.js.map +1 -1
  72. package/dist/component/sanitize.d.ts +5 -0
  73. package/dist/component/sanitize.d.ts.map +1 -1
  74. package/dist/component/sanitize.js +33 -1
  75. package/dist/component/sanitize.js.map +1 -1
  76. package/dist/component/schema.d.ts +68 -9
  77. package/dist/component/schema.js +21 -3
  78. package/dist/component/schema.js.map +1 -1
  79. package/dist/component/trackedLinks.d.ts +91 -0
  80. package/dist/component/trackedLinks.d.ts.map +1 -0
  81. package/dist/component/trackedLinks.js +314 -0
  82. package/dist/component/trackedLinks.js.map +1 -0
  83. package/dist/component/useragent.d.ts +6 -0
  84. package/dist/component/useragent.d.ts.map +1 -1
  85. package/dist/component/useragent.js +9 -0
  86. package/dist/component/useragent.js.map +1 -1
  87. package/dist/component/validators.d.ts +51 -11
  88. package/dist/component/validators.d.ts.map +1 -1
  89. package/dist/component/validators.js +35 -1
  90. package/dist/component/validators.js.map +1 -1
  91. package/dist/tracker/generated.d.ts +11 -11
  92. package/dist/tracker/generated.d.ts.map +1 -1
  93. package/dist/tracker/generated.js +11 -11
  94. package/dist/tracker/generated.js.map +1 -1
  95. package/dist/tracker/tracker.d.ts +1 -0
  96. package/dist/tracker/tracker.d.ts.map +1 -1
  97. package/dist/tracker/tracker.js +104 -47
  98. package/dist/tracker/tracker.js.map +1 -1
  99. package/dist/tracker/vitals.d.ts.map +1 -1
  100. package/dist/tracker/vitals.js +22 -4
  101. package/dist/tracker/vitals.js.map +1 -1
  102. package/dist/tracker.min.js +1 -1
  103. package/dist/vitals.min.js +1 -1
  104. package/docs/upgrading.md +234 -45
  105. package/llms.txt +9 -4
  106. package/package.json +2 -2
  107. package/src/component/_generated/api.ts +6 -0
  108. package/src/component/_generated/component.ts +153 -1
  109. package/src/component/_generated/server.ts +1 -0
  110. package/src/component/constants.ts +31 -3
  111. package/src/component/convex.config.ts +3 -0
  112. package/src/component/coverage.ts +7 -1
  113. package/src/component/geo.ts +1 -1
  114. package/src/component/http.ts +71 -2
  115. package/src/component/identity.ts +41 -2
  116. package/src/component/ingest.ts +146 -33
  117. package/src/component/live.ts +51 -4
  118. package/src/component/origin.ts +273 -0
  119. package/src/component/platforms.ts +359 -0
  120. package/src/component/reports.ts +98 -18
  121. package/src/component/rollupStore.ts +51 -20
  122. package/src/component/rollups.ts +141 -32
  123. package/src/component/sanitize.ts +39 -1
  124. package/src/component/schema.ts +24 -3
  125. package/src/component/trackedLinks.ts +384 -0
  126. package/src/component/useragent.ts +11 -0
  127. package/src/component/validators.ts +71 -0
  128. package/src/tracker/generated.ts +11 -11
@@ -1,4 +1,4 @@
1
- import type { Id } from "./_generated/dataModel.js";
1
+ import type { Doc, Id } from "./_generated/dataModel.js";
2
2
  export declare const overview: import("convex/server").RegisteredQuery<"public", {
3
3
  from: number;
4
4
  interval?: "day" | "hour" | undefined;
@@ -75,6 +75,21 @@ export declare const overview: import("convex/server").RegisteredQuery<"public",
75
75
  count: number;
76
76
  revenueCents: number;
77
77
  }[];
78
+ topPlatforms: {
79
+ value: string;
80
+ count: number;
81
+ revenueCents: number;
82
+ }[];
83
+ topChannels: {
84
+ value: string;
85
+ count: number;
86
+ revenueCents: number;
87
+ }[];
88
+ topEvidence: {
89
+ value: string;
90
+ count: number;
91
+ revenueCents: number;
92
+ }[];
78
93
  metadata: {
79
94
  visitors: {
80
95
  basis: "bucketOccurrences" | "estimatedUnique";
@@ -94,6 +109,9 @@ export declare const overview: import("convex/server").RegisteredQuery<"public",
94
109
  topGoals: "goalCompletionVolume";
95
110
  topMediums: "eventVolume" | "sessions";
96
111
  topOutbound: "eventVolume";
112
+ topPlatforms: "eventVolume" | "sessions";
113
+ topChannels: "eventVolume" | "sessions";
114
+ topEvidence: "eventVolume" | "sessions";
97
115
  };
98
116
  dimensionsSince: number | null;
99
117
  engagement: "counted" | "unavailable";
@@ -227,45 +245,12 @@ export declare const siteMap: import("convex/server").RegisteredQuery<"public",
227
245
  };
228
246
  };
229
247
  }>>;
248
+ type SessionRow = Omit<Doc<"sessions">, "geoLookupAttemptedAt" | "lastPageviewAt">;
230
249
  /** Metadata for a selected session, independent of list pagination. */
231
250
  export declare const getSession: import("convex/server").RegisteredQuery<"public", {
232
251
  sessionId: string;
233
252
  siteId: import("convex/values").GenericId<"sites">;
234
- }, Promise<{
235
- _creationTime: number;
236
- _id: import("convex/values").GenericId<"sessions">;
237
- affiliateAttributedAt?: number | undefined;
238
- affiliateExpiresAt?: number | undefined;
239
- affiliateId?: import("convex/values").GenericId<"affiliates"> | undefined;
240
- affiliateSlug?: string | undefined;
241
- browser: string;
242
- city?: string | undefined;
243
- conversionCount: number;
244
- country?: string | undefined;
245
- currency?: string | undefined;
246
- device: string;
247
- durationMs: number;
248
- entryPath: string;
249
- eventCount: number;
250
- exitPath: string;
251
- lastSeenAt: number;
252
- latitude?: number | undefined;
253
- longitude?: number | undefined;
254
- newVisitor?: boolean | undefined;
255
- os: string;
256
- pageviewCount: number;
257
- referrer?: string | undefined;
258
- revenueCents: number;
259
- sessionId: string;
260
- siteId: import("convex/values").GenericId<"sites">;
261
- source: string;
262
- startedAt: number;
263
- utmCampaign?: string | undefined;
264
- utmMedium?: string | undefined;
265
- utmSource?: string | undefined;
266
- visitorId: string;
267
- visitorKey?: string | undefined;
268
- } | null>>;
253
+ }, Promise<SessionRow | null>>;
269
254
  /** Exact commissions alongside overview's period revenue/conversion totals. */
270
255
  export declare const revenueSummary: import("convex/server").RegisteredQuery<"public", {
271
256
  from: number;
@@ -287,41 +272,7 @@ export declare const listSessions: import("convex/server").RegisteredQuery<"publ
287
272
  siteId: import("convex/values").GenericId<"sites">;
288
273
  to: number;
289
274
  }, Promise<{
290
- page: {
291
- _creationTime: number;
292
- _id: import("convex/values").GenericId<"sessions">;
293
- affiliateAttributedAt?: number | undefined;
294
- affiliateExpiresAt?: number | undefined;
295
- affiliateId?: import("convex/values").GenericId<"affiliates"> | undefined;
296
- affiliateSlug?: string | undefined;
297
- browser: string;
298
- city?: string | undefined;
299
- conversionCount: number;
300
- country?: string | undefined;
301
- currency?: string | undefined;
302
- device: string;
303
- durationMs: number;
304
- entryPath: string;
305
- eventCount: number;
306
- exitPath: string;
307
- lastSeenAt: number;
308
- latitude?: number | undefined;
309
- longitude?: number | undefined;
310
- newVisitor?: boolean | undefined;
311
- os: string;
312
- pageviewCount: number;
313
- referrer?: string | undefined;
314
- revenueCents: number;
315
- sessionId: string;
316
- siteId: import("convex/values").GenericId<"sites">;
317
- source: string;
318
- startedAt: number;
319
- utmCampaign?: string | undefined;
320
- utmMedium?: string | undefined;
321
- utmSource?: string | undefined;
322
- visitorId: string;
323
- visitorKey?: string | undefined;
324
- }[];
275
+ page: SessionRow[];
325
276
  isDone: boolean;
326
277
  continueCursor: string;
327
278
  }>>;
@@ -353,9 +304,11 @@ export declare const sessionJourney: import("convex/server").RegisteredQuery<"pu
353
304
  os: string;
354
305
  device: string;
355
306
  affiliateSlug?: string | undefined;
307
+ clid?: string[] | undefined;
356
308
  currency?: string | undefined;
357
309
  eventId: string;
358
310
  href?: string | undefined;
311
+ inApp?: string | undefined;
359
312
  name?: string | undefined;
360
313
  path: string;
361
314
  properties?: Record<string, string | number | boolean | null> | undefined;
@@ -426,9 +379,11 @@ export declare const visitorJourney: import("convex/server").RegisteredQuery<"pu
426
379
  os: string;
427
380
  device: string;
428
381
  affiliateSlug?: string | undefined;
382
+ clid?: string[] | undefined;
429
383
  currency?: string | undefined;
430
384
  eventId: string;
431
385
  href?: string | undefined;
386
+ inApp?: string | undefined;
432
387
  name?: string | undefined;
433
388
  path: string;
434
389
  properties?: Record<string, string | number | boolean | null> | undefined;
@@ -629,7 +584,7 @@ export declare const dataCoverage: import("convex/server").RegisteredQuery<"publ
629
584
  from: number;
630
585
  to: number;
631
586
  datasets: {
632
- dataset: "affiliates" | "conversions" | "events" | "funnels" | "goals" | "overviewDay" | "overviewHour" | "overviewLocalDay" | "sessions" | "siteMap" | "vitals";
587
+ dataset: "affiliates" | "conversions" | "events" | "funnels" | "goals" | "origin" | "overviewDay" | "overviewHour" | "overviewLocalDay" | "sessions" | "siteMap" | "vitals";
633
588
  coverage: {
634
589
  state: "complete" | "partial" | "retained" | "unavailable";
635
590
  generation: 1 | null;
@@ -1 +1 @@
1
- {"version":3,"file":"reports.d.ts","sourceRoot":"","sources":["../../src/component/reports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reports.d.ts","sourceRoot":"","sources":["../../src/component/reports.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@ import { fail } from "./errors.js";
7
7
  import { isLocalDayAligned, localDayStart, localDayStarts, localDayTimezone, sharedLocalTimezone, } from "./localTime.js";
8
8
  import { compareJourneyEvents, hydrateEventContexts, loadSessionJourneyEvents, loadVisitorJourneyEvents, } from "./eventStore.js";
9
9
  import { isPlainRecord } from "./guards.js";
10
+ import { classifyOrigin } from "./origin.js";
11
+ import { externalReferrer } from "./sanitize.js";
10
12
  import { affiliateFieldsValidator, eventFieldsValidator, funnelFieldsValidator, goalFieldsValidator, sessionFieldsValidator, vitalMetricValidator, } from "./validators.js";
11
13
  import { resolveVisitorIdentities } from "./visitors.js";
12
14
  import { mergeVitalHistograms, VITAL_ALL, VITAL_METRICS, vitalHistogramPercentile, vitalRatingCounts, } from "./vitals.js";
@@ -145,6 +147,11 @@ export const overview = query({
145
147
  topMediums: v.array(topItemValidator),
146
148
  // Destination hosts of outbound clicks, ranked by clicks.
147
149
  topOutbound: v.array(topItemValidator),
150
+ // The session's origin (origin.ts), ranked like sources: platform ids,
151
+ // channel ids, and the evidence that decided them.
152
+ topPlatforms: v.array(topItemValidator),
153
+ topChannels: v.array(topItemValidator),
154
+ topEvidence: v.array(topItemValidator),
148
155
  metadata: v.object({
149
156
  visitors: v.object({
150
157
  basis: v.union(v.literal("estimatedUnique"), v.literal("bucketOccurrences")),
@@ -164,6 +171,9 @@ export const overview = query({
164
171
  topGoals: v.literal("goalCompletionVolume"),
165
172
  topMediums: breakdownBasisValidator,
166
173
  topOutbound: v.literal("eventVolume"),
174
+ topPlatforms: breakdownBasisValidator,
175
+ topChannels: breakdownBasisValidator,
176
+ topEvidence: breakdownBasisValidator,
167
177
  }),
168
178
  // Since when every site in the request records the medium and outbound
169
179
  // slots; null while one of them has not stamped it. A range that starts
@@ -247,10 +257,13 @@ export const overview = query({
247
257
  const bucketCount = localDays
248
258
  ? bucketStarts.length
249
259
  : Math.floor((lastBucket - firstBucket) / intervalMs) + 1;
250
- const perSiteLimit = bucketCount *
251
- (interval === "hour" ? HOURLY_AGGREGATE_SHARDS : AGGREGATE_SHARDS);
260
+ const shards = interval === "hour" ? HOURLY_AGGREGATE_SHARDS : AGGREGATE_SHARDS;
261
+ const perSiteLimit = bucketCount * shards;
252
262
  if (perSiteLimit * siteIds.length > MAX_OVERVIEW_AGGREGATE_ROWS) {
253
- fail("LIMIT_EXCEEDED", "overview range is too wide for the requested number of sites", { maximumAggregateRows: MAX_OVERVIEW_AGGREGATE_ROWS });
263
+ // The row budget, not MAX_REPORT_RANGE_DAYS, bounds the overview: 101
264
+ // days for one site and 10 for ten; 24 hours for two, 5 for ten.
265
+ const maximumBuckets = Math.floor(MAX_OVERVIEW_AGGREGATE_ROWS / (shards * siteIds.length));
266
+ fail("LIMIT_EXCEEDED", `overview range is too wide: ${siteIds.length === 1 ? "one site" : `${siteIds.length} sites`} can read at most ${maximumBuckets} ${interval}s`, { maximumAggregateRows: MAX_OVERVIEW_AGGREGATE_ROWS, maximumBuckets });
254
267
  }
255
268
  const totals = emptyTotals();
256
269
  const points = new Map();
@@ -266,14 +279,26 @@ export const overview = query({
266
279
  : "overviewLocalDay";
267
280
  await assertSourceAvailable(ctx, siteIds, [overviewDataset], from);
268
281
  for (const siteId of siteIds) {
269
- const buckets = await ctx.db
282
+ // Iterated rather than taken whole: within the row budget a busy range
283
+ // can still cross the bytes a query may read. Values are length-capped,
284
+ // so sixteen buckets stay far below the reserve, and running out fails
285
+ // with REPORT_INCOMPLETE, as the feature reports do, instead of a raw
286
+ // limit error.
287
+ const buckets = [];
288
+ for await (const bucket of ctx.db
270
289
  .query("aggregateBuckets")
271
290
  .withIndex("by_siteId_and_granularity_and_bucketStart", (range) => range
272
291
  .eq("siteId", siteId)
273
292
  .eq("granularity", granularity)
274
293
  .gte("bucketStart", firstBucket)
275
- .lte("bucketStart", lastBucket))
276
- .take(perSiteLimit + 1);
294
+ .lte("bucketStart", lastBucket))) {
295
+ buckets.push(bucket);
296
+ if (buckets.length > perSiteLimit)
297
+ break;
298
+ if (buckets.length % 16 === 0) {
299
+ await requireFeatureReadHeadroom(ctx, "overview aggregate buckets");
300
+ }
301
+ }
277
302
  failIfIncomplete(buckets, perSiteLimit, "overview aggregate buckets");
278
303
  for (const bucket of buckets) {
279
304
  if (localDays &&
@@ -375,6 +400,9 @@ export const overview = query({
375
400
  topGoals: top("goal", "eventVolume"),
376
401
  topMediums: top("medium", sessionBasis),
377
402
  topOutbound: top("outbound", "eventVolume"),
403
+ topPlatforms: top("platform", sessionBasis),
404
+ topChannels: top("channel", sessionBasis),
405
+ topEvidence: top("evidence", sessionBasis),
378
406
  metadata: {
379
407
  visitors: {
380
408
  basis: visitorBasis,
@@ -394,6 +422,9 @@ export const overview = query({
394
422
  topGoals: "goalCompletionVolume",
395
423
  topMediums: sessionBasis,
396
424
  topOutbound: "eventVolume",
425
+ topPlatforms: sessionBasis,
426
+ topChannels: sessionBasis,
427
+ topEvidence: sessionBasis,
397
428
  },
398
429
  dimensionsSince: controls.every((control) => control?.dimensionsSince !== undefined)
399
430
  ? Math.max(...controls.map((control) => control.dimensionsSince))
@@ -705,6 +736,22 @@ async function readRouteRollups(ctx, siteId, from, to, budget) {
705
736
  }
706
737
  return { rows, completeFrom: cutAt + DAY_MS };
707
738
  }
739
+ /**
740
+ * A session recorded before origins existed, classified on read from what it
741
+ * kept (utm fields, referrer, affiliate) and marked `legacy`: it carries no
742
+ * click IDs or in-app signal, and it never enters the aggregates.
743
+ */
744
+ function withOrigin(session, domains) {
745
+ if (session.platform !== undefined)
746
+ return session;
747
+ const origin = classifyOrigin({
748
+ utmSource: session.utmSource,
749
+ utmMedium: session.utmMedium,
750
+ referrer: externalReferrer(session.referrer, domains),
751
+ affiliate: session.affiliateSlug !== undefined,
752
+ });
753
+ return { ...session, ...origin, evidence: "legacy" };
754
+ }
708
755
  /** Metadata for a selected session, independent of list pagination. */
709
756
  export const getSession = query({
710
757
  args: { siteId: v.id("sites"), sessionId: v.string() },
@@ -717,7 +764,8 @@ export const getSession = query({
717
764
  if (!session)
718
765
  return null;
719
766
  const { geoLookupAttemptedAt: _geo, lastPageviewAt: _pageview, ...result } = session;
720
- return result;
767
+ const site = await ctx.db.get("sites", args.siteId);
768
+ return withOrigin(result, site?.domains ?? []);
721
769
  },
722
770
  });
723
771
  /** Exact commissions alongside overview's period revenue/conversion totals. */
@@ -829,7 +877,8 @@ export const listSessions = query({
829
877
  .order("desc")
830
878
  .take(take)));
831
879
  }
832
- const publicRows = rows.map(({ geoLookupAttemptedAt: _attemptedAt, lastPageviewAt: _lastPageviewAt, ...row }) => row);
880
+ const site = await ctx.db.get("sites", args.siteId);
881
+ const publicRows = rows.map(({ geoLookupAttemptedAt: _attemptedAt, lastPageviewAt: _lastPageviewAt, ...row }) => withOrigin(row, site?.domains ?? []));
833
882
  return keysetPaginationResult(publicRows, pagination, (row) => ({
834
883
  timestamp: row.lastSeenAt,
835
884
  creationTime: row._creationTime,
@@ -1366,7 +1415,7 @@ export const vitalsReport = query({
1366
1415
  };
1367
1416
  },
1368
1417
  });
1369
- const coverageDatasetValidator = v.union(v.literal("overviewHour"), v.literal("overviewDay"), v.literal("overviewLocalDay"), v.literal("events"), v.literal("sessions"), v.literal("conversions"), v.literal("goals"), v.literal("funnels"), v.literal("affiliates"), v.literal("vitals"), v.literal("siteMap"));
1418
+ const coverageDatasetValidator = v.union(v.literal("overviewHour"), v.literal("overviewDay"), v.literal("overviewLocalDay"), v.literal("events"), v.literal("sessions"), v.literal("conversions"), v.literal("goals"), v.literal("funnels"), v.literal("affiliates"), v.literal("vitals"), v.literal("siteMap"), v.literal("origin"));
1370
1419
  export const dataCoverage = query({
1371
1420
  args: {
1372
1421
  siteId: v.id("sites"),
@@ -1396,6 +1445,7 @@ export const dataCoverage = query({
1396
1445
  "affiliates",
1397
1446
  "vitals",
1398
1447
  "siteMap",
1448
+ "origin",
1399
1449
  ];
1400
1450
  return {
1401
1451
  siteId: args.siteId,
@@ -1586,7 +1636,12 @@ async function assertSourceAvailable(ctx, siteIds, sources, from) {
1586
1636
  }
1587
1637
  async function datasetCoverageForRange(ctx, siteId, dataset, from, to) {
1588
1638
  if (dataset === "siteMap") {
1589
- return siteMapDatasetCoverage(ctx, siteId, from, to);
1639
+ return stampedDatasetCoverage(ctx, siteId, from, to, "siteMapSince", siteMapCoverageDataset);
1640
+ }
1641
+ // Origins exist in sessions and aggregate slots from the site's stamp, and
1642
+ // the overview reads them from the daily aggregates retention trims.
1643
+ if (dataset === "origin") {
1644
+ return stampedDatasetCoverage(ctx, siteId, from, to, "originSince", "overviewDay");
1590
1645
  }
1591
1646
  // Vitals have no legacy fallback source; the rollup either covers the range
1592
1647
  // or the coverage states say how much of it exists.
@@ -1620,17 +1675,18 @@ async function datasetCoverageForRange(ctx, siteId, dataset, from, to) {
1620
1675
  return options.sort((left, right) => coverageRank(right.state) - coverageRank(left.state))[0];
1621
1676
  }
1622
1677
  /**
1623
- * The site map's coverage without reading its rows: it starts at the site's
1624
- * `siteMapSince` and ends where retention cut it. The report itself may still
1625
- * narrow the window when the range exceeds its row budget.
1678
+ * A stamped dataset's coverage without reading its rows: it starts at the
1679
+ * site's stamp (`siteMapSince`, `originSince`) and ends where retention cut
1680
+ * it. The site map report may still narrow the window when the range exceeds
1681
+ * its row budget.
1626
1682
  */
1627
- async function siteMapDatasetCoverage(ctx, siteId, from, to) {
1683
+ async function stampedDatasetCoverage(ctx, siteId, from, to, stamp, retainedDataset) {
1628
1684
  const control = await ctx.db
1629
1685
  .query("analyticsCoverage")
1630
1686
  .withIndex("by_siteId", (range) => range.eq("siteId", siteId))
1631
1687
  .unique();
1632
- const since = control?.siteMapSince ?? null;
1633
- const retainedBefore = control?.retained.find((item) => item.dataset === siteMapCoverageDataset)
1688
+ const since = control?.[stamp] ?? null;
1689
+ const retainedBefore = control?.retained.find((item) => item.dataset === retainedDataset)
1634
1690
  ?.before ?? null;
1635
1691
  const unavailable = since === null ||
1636
1692
  to < since ||