@iann29/rastro 0.1.0-alpha.1 → 0.1.0-alpha.11

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 (179) hide show
  1. package/README.md +693 -69
  2. package/agent/integration.md +801 -0
  3. package/agent/manifest.json +205 -0
  4. package/agent/manifest.schema.json +444 -0
  5. package/dist/client/federation.d.ts +381 -0
  6. package/dist/client/federation.d.ts.map +1 -0
  7. package/dist/client/federation.js +274 -0
  8. package/dist/client/federation.js.map +1 -0
  9. package/dist/client/index.d.ts +2673 -15
  10. package/dist/client/index.d.ts.map +1 -1
  11. package/dist/client/index.js +565 -33
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/component/_generated/api.d.ts +22 -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 +315 -4
  17. package/dist/component/_generated/component.d.ts.map +1 -1
  18. package/dist/component/_generated/server.d.ts +4 -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/affiliates.d.ts.map +1 -1
  22. package/dist/component/affiliates.js +6 -2
  23. package/dist/component/affiliates.js.map +1 -1
  24. package/dist/component/cardinality.d.ts +12 -0
  25. package/dist/component/cardinality.d.ts.map +1 -0
  26. package/dist/component/cardinality.js +94 -0
  27. package/dist/component/cardinality.js.map +1 -0
  28. package/dist/component/constants.d.ts +28 -1
  29. package/dist/component/constants.d.ts.map +1 -1
  30. package/dist/component/constants.js +44 -1
  31. package/dist/component/constants.js.map +1 -1
  32. package/dist/component/convex.config.d.ts +6 -1
  33. package/dist/component/convex.config.js +9 -1
  34. package/dist/component/convex.config.js.map +1 -1
  35. package/dist/component/coverage.d.ts +27 -0
  36. package/dist/component/coverage.d.ts.map +1 -0
  37. package/dist/component/coverage.js +56 -0
  38. package/dist/component/coverage.js.map +1 -0
  39. package/dist/component/diagnostics.d.ts +9 -0
  40. package/dist/component/diagnostics.d.ts.map +1 -0
  41. package/dist/component/diagnostics.js +47 -0
  42. package/dist/component/diagnostics.js.map +1 -0
  43. package/dist/component/errors.d.ts +1 -1
  44. package/dist/component/errors.d.ts.map +1 -1
  45. package/dist/component/errors.js.map +1 -1
  46. package/dist/component/eventStore.d.ts +21 -9
  47. package/dist/component/eventStore.d.ts.map +1 -1
  48. package/dist/component/eventStore.js +142 -152
  49. package/dist/component/eventStore.js.map +1 -1
  50. package/dist/component/funnels.d.ts.map +1 -1
  51. package/dist/component/funnels.js +5 -3
  52. package/dist/component/funnels.js.map +1 -1
  53. package/dist/component/geo.d.ts +73 -0
  54. package/dist/component/geo.d.ts.map +1 -0
  55. package/dist/component/geo.js +648 -0
  56. package/dist/component/geo.js.map +1 -0
  57. package/dist/component/goals.d.ts.map +1 -1
  58. package/dist/component/goals.js +8 -5
  59. package/dist/component/goals.js.map +1 -1
  60. package/dist/component/guards.d.ts.map +1 -1
  61. package/dist/component/guards.js.map +1 -1
  62. package/dist/component/http.d.ts.map +1 -1
  63. package/dist/component/http.js +281 -62
  64. package/dist/component/http.js.map +1 -1
  65. package/dist/component/identity.d.ts +13 -0
  66. package/dist/component/identity.d.ts.map +1 -0
  67. package/dist/component/identity.js +58 -0
  68. package/dist/component/identity.js.map +1 -0
  69. package/dist/component/ingest.d.ts +3 -1
  70. package/dist/component/ingest.d.ts.map +1 -1
  71. package/dist/component/ingest.js +498 -95
  72. package/dist/component/ingest.js.map +1 -1
  73. package/dist/component/live.d.ts.map +1 -1
  74. package/dist/component/live.js +7 -6
  75. package/dist/component/live.js.map +1 -1
  76. package/dist/component/localTime.d.ts +25 -0
  77. package/dist/component/localTime.d.ts.map +1 -0
  78. package/dist/component/localTime.js +126 -0
  79. package/dist/component/localTime.js.map +1 -0
  80. package/dist/component/reports.d.ts +266 -10
  81. package/dist/component/reports.d.ts.map +1 -1
  82. package/dist/component/reports.js +1243 -137
  83. package/dist/component/reports.js.map +1 -1
  84. package/dist/component/retention.d.ts +75 -1
  85. package/dist/component/retention.d.ts.map +1 -1
  86. package/dist/component/retention.js +561 -38
  87. package/dist/component/retention.js.map +1 -1
  88. package/dist/component/rollupStore.d.ts +320 -0
  89. package/dist/component/rollupStore.d.ts.map +1 -0
  90. package/dist/component/rollupStore.js +596 -0
  91. package/dist/component/rollupStore.js.map +1 -0
  92. package/dist/component/rollups.d.ts +20 -0
  93. package/dist/component/rollups.d.ts.map +1 -0
  94. package/dist/component/rollups.js +73 -0
  95. package/dist/component/rollups.js.map +1 -0
  96. package/dist/component/sanitize.d.ts +24 -1
  97. package/dist/component/sanitize.d.ts.map +1 -1
  98. package/dist/component/sanitize.js +96 -16
  99. package/dist/component/sanitize.js.map +1 -1
  100. package/dist/component/schema.d.ts +687 -65
  101. package/dist/component/schema.js +187 -20
  102. package/dist/component/schema.js.map +1 -1
  103. package/dist/component/sites.d.ts +12 -0
  104. package/dist/component/sites.d.ts.map +1 -1
  105. package/dist/component/sites.js +41 -7
  106. package/dist/component/sites.js.map +1 -1
  107. package/dist/component/useragent.d.ts +9 -0
  108. package/dist/component/useragent.d.ts.map +1 -0
  109. package/dist/component/useragent.js +152 -0
  110. package/dist/component/useragent.js.map +1 -0
  111. package/dist/component/validators.d.ts +124 -69
  112. package/dist/component/validators.d.ts.map +1 -1
  113. package/dist/component/validators.js +35 -14
  114. package/dist/component/validators.js.map +1 -1
  115. package/dist/component/visitors.d.ts +19 -0
  116. package/dist/component/visitors.d.ts.map +1 -0
  117. package/dist/component/visitors.js +86 -0
  118. package/dist/component/visitors.js.map +1 -0
  119. package/dist/component/vitals.d.ts +41 -0
  120. package/dist/component/vitals.d.ts.map +1 -0
  121. package/dist/component/vitals.js +115 -0
  122. package/dist/component/vitals.js.map +1 -0
  123. package/dist/react/index.d.ts.map +1 -1
  124. package/dist/react/index.js.map +1 -1
  125. package/dist/tracker/generated.d.ts +11 -4
  126. package/dist/tracker/generated.d.ts.map +1 -1
  127. package/dist/tracker/generated.js +11 -4
  128. package/dist/tracker/generated.js.map +1 -1
  129. package/dist/tracker/tracker.d.ts +1 -1
  130. package/dist/tracker/tracker.d.ts.map +1 -1
  131. package/dist/tracker/tracker.js +57 -20
  132. package/dist/tracker/tracker.js.map +1 -1
  133. package/dist/tracker/vitals.d.ts +10 -0
  134. package/dist/tracker/vitals.d.ts.map +1 -0
  135. package/dist/tracker/vitals.js +140 -0
  136. package/dist/tracker/vitals.js.map +1 -0
  137. package/dist/tracker.min.js +1 -1
  138. package/dist/vitals.min.js +1 -0
  139. package/docs/benchmarks/2026-08-20-realistic.md +76 -76
  140. package/docs/benchmarks/2026-08-21-formal-certification.md +353 -0
  141. package/docs/benchmarks/2026-08-30-alpha6-recertification.md +206 -0
  142. package/docs/federation-setup.md +464 -0
  143. package/docs/federation.md +352 -0
  144. package/docs/upgrading.md +344 -0
  145. package/llms.txt +72 -0
  146. package/package.json +55 -11
  147. package/scripts/benchmark-ingest.mjs +175 -73
  148. package/scripts/generate-federation-keys.mjs +20 -0
  149. package/src/component/_generated/api.ts +22 -0
  150. package/src/component/_generated/component.ts +381 -4
  151. package/src/component/_generated/server.ts +4 -0
  152. package/src/component/affiliates.ts +20 -5
  153. package/src/component/cardinality.ts +117 -0
  154. package/src/component/constants.ts +44 -1
  155. package/src/component/convex.config.ts +11 -1
  156. package/src/component/coverage.ts +71 -0
  157. package/src/component/diagnostics.ts +65 -0
  158. package/src/component/errors.ts +2 -1
  159. package/src/component/eventStore.ts +217 -193
  160. package/src/component/funnels.ts +19 -16
  161. package/src/component/geo.ts +835 -0
  162. package/src/component/goals.ts +29 -21
  163. package/src/component/guards.ts +3 -1
  164. package/src/component/http.ts +404 -70
  165. package/src/component/identity.ts +74 -0
  166. package/src/component/ingest.ts +894 -188
  167. package/src/component/live.ts +13 -7
  168. package/src/component/localTime.ts +167 -0
  169. package/src/component/reports.ts +1872 -197
  170. package/src/component/retention.ts +788 -96
  171. package/src/component/rollupStore.ts +799 -0
  172. package/src/component/rollups.ts +82 -0
  173. package/src/component/sanitize.ts +144 -29
  174. package/src/component/schema.ts +217 -21
  175. package/src/component/sites.ts +59 -12
  176. package/src/component/useragent.ts +171 -0
  177. package/src/component/validators.ts +49 -14
  178. package/src/component/visitors.ts +116 -0
  179. package/src/component/vitals.ts +146 -0
@@ -0,0 +1,146 @@
1
+ import { VITAL_HISTOGRAM_EDGES, MAX_VITAL_VALUE } from "./constants.js";
2
+
3
+ /**
4
+ * Field-measured Web Vitals. Values are integers: milliseconds for the time
5
+ * metrics, and CLS scaled by 1000 so one shared histogram covers every metric.
6
+ */
7
+ export const VITAL_METRICS = ["LCP", "CLS", "INP", "FCP", "TTFB"] as const;
8
+
9
+ export type VitalMetric = (typeof VITAL_METRICS)[number];
10
+
11
+ /**
12
+ * The Google-published rating thresholds. Every threshold is also a histogram
13
+ * edge, so good/needs-improvement/poor counts are exact, never interpolated.
14
+ */
15
+ export const VITAL_THRESHOLDS: Record<
16
+ VitalMetric,
17
+ { good: number; poor: number }
18
+ > = {
19
+ LCP: { good: 2_500, poor: 4_000 },
20
+ CLS: { good: 100, poor: 250 },
21
+ INP: { good: 200, poor: 500 },
22
+ FCP: { good: 1_800, poor: 3_000 },
23
+ TTFB: { good: 800, poor: 1_800 },
24
+ };
25
+
26
+ /** Sentinel row keys; sanitized paths always start with "/" so neither collides. */
27
+ export const VITAL_ALL = "(all)";
28
+ export const VITAL_OTHER_PAGES = "(other)";
29
+
30
+ /** Bounded device classes; anything else folds into "unknown". */
31
+ export const VITAL_DEVICES = ["desktop", "mobile", "tablet"] as const;
32
+
33
+ export function vitalDevice(device: string | undefined): string {
34
+ return device && (VITAL_DEVICES as readonly string[]).includes(device)
35
+ ? device
36
+ : "unknown";
37
+ }
38
+
39
+ export const VITAL_HISTOGRAM_BUCKETS = VITAL_HISTOGRAM_EDGES.length + 1;
40
+
41
+ export function isVitalMetric(value: string): value is VitalMetric {
42
+ return (VITAL_METRICS as readonly string[]).includes(value);
43
+ }
44
+
45
+ export function isValidVitalValue(value: number): boolean {
46
+ return Number.isFinite(value) && value >= 0 && value <= MAX_VITAL_VALUE;
47
+ }
48
+
49
+ export function emptyVitalHistogram(): number[] {
50
+ return Array.from({ length: VITAL_HISTOGRAM_BUCKETS }, () => 0);
51
+ }
52
+
53
+ /** Bucket i holds values in (edge[i-1], edge[i]]; the last bucket is open. */
54
+ export function vitalHistogramBucket(value: number): number {
55
+ for (let index = 0; index < VITAL_HISTOGRAM_EDGES.length; index += 1) {
56
+ if (value <= VITAL_HISTOGRAM_EDGES[index]) return index;
57
+ }
58
+ return VITAL_HISTOGRAM_EDGES.length;
59
+ }
60
+
61
+ export function addToVitalHistogram(
62
+ histogram: number[],
63
+ value: number,
64
+ ): number[] {
65
+ const next = normalizedVitalHistogram(histogram);
66
+ next[vitalHistogramBucket(value)] += 1;
67
+ return next;
68
+ }
69
+
70
+ export function mergeVitalHistograms(
71
+ left: number[],
72
+ right: number[],
73
+ ): number[] {
74
+ const result = normalizedVitalHistogram(left);
75
+ const addition = normalizedVitalHistogram(right);
76
+ for (let index = 0; index < result.length; index += 1) {
77
+ result[index] += addition[index];
78
+ }
79
+ return result;
80
+ }
81
+
82
+ /**
83
+ * Percentile estimated by linear interpolation inside the winning bucket. The
84
+ * top bucket is open-ended, so estimates saturate at the highest edge; a
85
+ * reported p75 equal to that edge means "at least this much".
86
+ */
87
+ export function vitalHistogramPercentile(
88
+ histogram: number[],
89
+ fraction: number,
90
+ ): number {
91
+ const buckets = normalizedVitalHistogram(histogram);
92
+ const total = buckets.reduce((sum, count) => sum + count, 0);
93
+ if (total === 0) return 0;
94
+ const target = Math.ceil(total * fraction);
95
+ let cumulative = 0;
96
+ for (let index = 0; index < buckets.length; index += 1) {
97
+ const count = buckets[index];
98
+ if (count === 0) continue;
99
+ if (cumulative + count >= target) {
100
+ const lower = index === 0 ? 0 : VITAL_HISTOGRAM_EDGES[index - 1];
101
+ const upper =
102
+ index < VITAL_HISTOGRAM_EDGES.length
103
+ ? VITAL_HISTOGRAM_EDGES[index]
104
+ : VITAL_HISTOGRAM_EDGES[VITAL_HISTOGRAM_EDGES.length - 1];
105
+ const position = (target - cumulative) / count;
106
+ return Math.round(Math.min(upper, lower + position * (upper - lower)));
107
+ }
108
+ cumulative += count;
109
+ }
110
+ return VITAL_HISTOGRAM_EDGES[VITAL_HISTOGRAM_EDGES.length - 1];
111
+ }
112
+
113
+ /** Exact rating counts; every threshold is a bucket edge by construction. */
114
+ export function vitalRatingCounts(
115
+ histogram: number[],
116
+ metric: VitalMetric,
117
+ ): { good: number; needsImprovement: number; poor: number } {
118
+ const buckets = normalizedVitalHistogram(histogram);
119
+ const thresholds = VITAL_THRESHOLDS[metric];
120
+ let good = 0;
121
+ let needsImprovement = 0;
122
+ let poor = 0;
123
+ for (let index = 0; index < buckets.length; index += 1) {
124
+ const upper =
125
+ index < VITAL_HISTOGRAM_EDGES.length
126
+ ? VITAL_HISTOGRAM_EDGES[index]
127
+ : Number.POSITIVE_INFINITY;
128
+ if (upper <= thresholds.good) good += buckets[index];
129
+ else if (upper <= thresholds.poor) needsImprovement += buckets[index];
130
+ else poor += buckets[index];
131
+ }
132
+ return { good, needsImprovement, poor };
133
+ }
134
+
135
+ function normalizedVitalHistogram(histogram: number[]): number[] {
136
+ const result = Array.from({ length: VITAL_HISTOGRAM_BUCKETS }, () => 0);
137
+ for (
138
+ let index = 0;
139
+ index < Math.min(histogram.length, result.length);
140
+ index += 1
141
+ ) {
142
+ const count = histogram[index];
143
+ result[index] = Number.isSafeInteger(count) && count > 0 ? count : 0;
144
+ }
145
+ return result;
146
+ }