@vestig/next 0.5.0 → 0.8.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 (157) hide show
  1. package/README.md +1 -1
  2. package/dist/__tests__/mocks/next-server.d.ts.map +1 -1
  3. package/dist/__tests__/mocks/next-server.js.map +1 -1
  4. package/dist/client/error-boundary.d.ts +80 -0
  5. package/dist/client/error-boundary.d.ts.map +1 -0
  6. package/dist/client/error-boundary.js +182 -0
  7. package/dist/client/error-boundary.js.map +1 -0
  8. package/dist/client/index.d.ts +2 -1
  9. package/dist/client/index.d.ts.map +1 -1
  10. package/dist/client/index.js +2 -0
  11. package/dist/client/index.js.map +1 -1
  12. package/dist/client/transport.d.ts +42 -0
  13. package/dist/client/transport.d.ts.map +1 -1
  14. package/dist/client/transport.js +143 -2
  15. package/dist/client/transport.js.map +1 -1
  16. package/dist/client.d.ts +2 -1
  17. package/dist/client.d.ts.map +1 -1
  18. package/dist/client.js +2 -0
  19. package/dist/client.js.map +1 -1
  20. package/dist/db/drizzle.d.ts +115 -0
  21. package/dist/db/drizzle.d.ts.map +1 -0
  22. package/dist/db/drizzle.js +174 -0
  23. package/dist/db/drizzle.js.map +1 -0
  24. package/dist/db/index.d.ts +49 -0
  25. package/dist/db/index.d.ts.map +1 -0
  26. package/dist/db/index.js +51 -0
  27. package/dist/db/index.js.map +1 -0
  28. package/dist/db/prisma.d.ts +114 -0
  29. package/dist/db/prisma.d.ts.map +1 -0
  30. package/dist/db/prisma.js +144 -0
  31. package/dist/db/prisma.js.map +1 -0
  32. package/dist/db/query-logger.d.ts +30 -0
  33. package/dist/db/query-logger.d.ts.map +1 -0
  34. package/dist/db/query-logger.js +169 -0
  35. package/dist/db/query-logger.js.map +1 -0
  36. package/dist/db/types.d.ts +102 -0
  37. package/dist/db/types.d.ts.map +1 -0
  38. package/dist/db/types.js +28 -0
  39. package/dist/db/types.js.map +1 -0
  40. package/dist/dev/api/index.d.ts +13 -0
  41. package/dist/dev/api/index.d.ts.map +1 -0
  42. package/dist/dev/api/index.js +13 -0
  43. package/dist/dev/api/index.js.map +1 -0
  44. package/dist/dev/api/logs-stream.d.ts +119 -0
  45. package/dist/dev/api/logs-stream.d.ts.map +1 -0
  46. package/dist/dev/api/logs-stream.js +156 -0
  47. package/dist/dev/api/logs-stream.js.map +1 -0
  48. package/dist/dev/filters.d.ts +17 -0
  49. package/dist/dev/filters.d.ts.map +1 -0
  50. package/dist/dev/filters.js +96 -0
  51. package/dist/dev/filters.js.map +1 -0
  52. package/dist/dev/hooks/use-logs.d.ts +53 -0
  53. package/dist/dev/hooks/use-logs.d.ts.map +1 -0
  54. package/dist/dev/hooks/use-logs.js +205 -0
  55. package/dist/dev/hooks/use-logs.js.map +1 -0
  56. package/dist/dev/index.d.ts +35 -0
  57. package/dist/dev/index.d.ts.map +1 -0
  58. package/dist/dev/index.js +41 -0
  59. package/dist/dev/index.js.map +1 -0
  60. package/dist/dev/log-entry.d.ts +12 -0
  61. package/dist/dev/log-entry.d.ts.map +1 -0
  62. package/dist/dev/log-entry.js +152 -0
  63. package/dist/dev/log-entry.js.map +1 -0
  64. package/dist/dev/log-viewer.d.ts +11 -0
  65. package/dist/dev/log-viewer.d.ts.map +1 -0
  66. package/dist/dev/log-viewer.js +49 -0
  67. package/dist/dev/log-viewer.js.map +1 -0
  68. package/dist/dev/metrics-card.d.ts +18 -0
  69. package/dist/dev/metrics-card.d.ts.map +1 -0
  70. package/dist/dev/metrics-card.js +75 -0
  71. package/dist/dev/metrics-card.js.map +1 -0
  72. package/dist/dev/metrics-histogram.d.ts +12 -0
  73. package/dist/dev/metrics-histogram.d.ts.map +1 -0
  74. package/dist/dev/metrics-histogram.js +69 -0
  75. package/dist/dev/metrics-histogram.js.map +1 -0
  76. package/dist/dev/metrics-panel.d.ts +10 -0
  77. package/dist/dev/metrics-panel.d.ts.map +1 -0
  78. package/dist/dev/metrics-panel.js +84 -0
  79. package/dist/dev/metrics-panel.js.map +1 -0
  80. package/dist/dev/overlay.d.ts +55 -0
  81. package/dist/dev/overlay.d.ts.map +1 -0
  82. package/dist/dev/overlay.js +204 -0
  83. package/dist/dev/overlay.js.map +1 -0
  84. package/dist/dev/store.d.ts +186 -0
  85. package/dist/dev/store.d.ts.map +1 -0
  86. package/dist/dev/store.js +214 -0
  87. package/dist/dev/store.js.map +1 -0
  88. package/dist/error/boundary.d.ts +36 -0
  89. package/dist/error/boundary.d.ts.map +1 -0
  90. package/dist/error/boundary.js +263 -0
  91. package/dist/error/boundary.js.map +1 -0
  92. package/dist/error/breadcrumbs.d.ts +95 -0
  93. package/dist/error/breadcrumbs.d.ts.map +1 -0
  94. package/dist/error/breadcrumbs.js +273 -0
  95. package/dist/error/breadcrumbs.js.map +1 -0
  96. package/dist/error/fingerprint.d.ts +42 -0
  97. package/dist/error/fingerprint.d.ts.map +1 -0
  98. package/dist/error/fingerprint.js +135 -0
  99. package/dist/error/fingerprint.js.map +1 -0
  100. package/dist/error/index.d.ts +52 -0
  101. package/dist/error/index.d.ts.map +1 -0
  102. package/dist/error/index.js +56 -0
  103. package/dist/error/index.js.map +1 -0
  104. package/dist/error/stack-parser.d.ts +43 -0
  105. package/dist/error/stack-parser.d.ts.map +1 -0
  106. package/dist/error/stack-parser.js +166 -0
  107. package/dist/error/stack-parser.js.map +1 -0
  108. package/dist/error/types.d.ts +152 -0
  109. package/dist/error/types.d.ts.map +1 -0
  110. package/dist/error/types.js +10 -0
  111. package/dist/error/types.js.map +1 -0
  112. package/dist/index.d.ts +1 -1
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/metrics/hooks/use-route-metrics.d.ts +91 -0
  115. package/dist/metrics/hooks/use-route-metrics.d.ts.map +1 -0
  116. package/dist/metrics/hooks/use-route-metrics.js +216 -0
  117. package/dist/metrics/hooks/use-route-metrics.js.map +1 -0
  118. package/dist/metrics/hooks/use-web-vitals.d.ts +70 -0
  119. package/dist/metrics/hooks/use-web-vitals.d.ts.map +1 -0
  120. package/dist/metrics/hooks/use-web-vitals.js +146 -0
  121. package/dist/metrics/hooks/use-web-vitals.js.map +1 -0
  122. package/dist/metrics/index.d.ts +51 -0
  123. package/dist/metrics/index.d.ts.map +1 -0
  124. package/dist/metrics/index.js +56 -0
  125. package/dist/metrics/index.js.map +1 -0
  126. package/dist/metrics/reporter.d.ts +87 -0
  127. package/dist/metrics/reporter.d.ts.map +1 -0
  128. package/dist/metrics/reporter.js +178 -0
  129. package/dist/metrics/reporter.js.map +1 -0
  130. package/dist/metrics/store.d.ts +34 -0
  131. package/dist/metrics/store.d.ts.map +1 -0
  132. package/dist/metrics/store.js +172 -0
  133. package/dist/metrics/store.js.map +1 -0
  134. package/dist/metrics/thresholds.d.ts +84 -0
  135. package/dist/metrics/thresholds.d.ts.map +1 -0
  136. package/dist/metrics/thresholds.js +148 -0
  137. package/dist/metrics/thresholds.js.map +1 -0
  138. package/dist/metrics/types.d.ts +211 -0
  139. package/dist/metrics/types.d.ts.map +1 -0
  140. package/dist/metrics/types.js +10 -0
  141. package/dist/metrics/types.js.map +1 -0
  142. package/dist/metrics/web-vitals.d.ts +72 -0
  143. package/dist/metrics/web-vitals.d.ts.map +1 -0
  144. package/dist/metrics/web-vitals.js +89 -0
  145. package/dist/metrics/web-vitals.js.map +1 -0
  146. package/dist/server/middleware.d.ts.map +1 -1
  147. package/dist/server/middleware.js +51 -37
  148. package/dist/server/middleware.js.map +1 -1
  149. package/dist/server/route-handler.d.ts.map +1 -1
  150. package/dist/server/route-handler.js +61 -40
  151. package/dist/server/route-handler.js.map +1 -1
  152. package/dist/server/server-action.d.ts.map +1 -1
  153. package/dist/server/server-action.js +54 -33
  154. package/dist/server/server-action.js.map +1 -1
  155. package/dist/types.d.ts +6 -2
  156. package/dist/types.d.ts.map +1 -1
  157. package/package.json +28 -6
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Core Web Vitals Thresholds
3
+ *
4
+ * Official thresholds from Google's Core Web Vitals program.
5
+ * These determine whether a metric is rated as "good", "needs-improvement", or "poor".
6
+ *
7
+ * @see https://web.dev/articles/vitals
8
+ * @packageDocumentation
9
+ */
10
+ /**
11
+ * Official Core Web Vitals thresholds
12
+ *
13
+ * Values represent the upper bounds:
14
+ * - good: value < threshold.good
15
+ * - needs-improvement: threshold.good <= value < threshold.poor
16
+ * - poor: value >= threshold.poor
17
+ */
18
+ export const THRESHOLDS = {
19
+ /**
20
+ * Largest Contentful Paint
21
+ * Measures loading performance - when the largest content element becomes visible
22
+ */
23
+ LCP: {
24
+ good: 2500,
25
+ poor: 4000,
26
+ unit: 'ms',
27
+ description: 'Largest Contentful Paint - Loading performance',
28
+ },
29
+ /**
30
+ * Cumulative Layout Shift
31
+ * Measures visual stability - how much the page layout shifts unexpectedly
32
+ */
33
+ CLS: {
34
+ good: 0.1,
35
+ poor: 0.25,
36
+ unit: 'score',
37
+ description: 'Cumulative Layout Shift - Visual stability',
38
+ },
39
+ /**
40
+ * Interaction to Next Paint
41
+ * Measures interactivity - time from user interaction to visual feedback
42
+ */
43
+ INP: {
44
+ good: 200,
45
+ poor: 500,
46
+ unit: 'ms',
47
+ description: 'Interaction to Next Paint - Interactivity',
48
+ },
49
+ /**
50
+ * Time to First Byte
51
+ * Measures server responsiveness - time until first byte of response
52
+ */
53
+ TTFB: {
54
+ good: 800,
55
+ poor: 1800,
56
+ unit: 'ms',
57
+ description: 'Time to First Byte - Server responsiveness',
58
+ },
59
+ /**
60
+ * First Contentful Paint
61
+ * Measures perceived load speed - when first content is rendered
62
+ */
63
+ FCP: {
64
+ good: 1800,
65
+ poor: 3000,
66
+ unit: 'ms',
67
+ description: 'First Contentful Paint - Perceived load speed',
68
+ },
69
+ };
70
+ /**
71
+ * Calculate rating for a metric value
72
+ *
73
+ * @param name - Web Vital metric name
74
+ * @param value - Metric value
75
+ * @returns Rating based on thresholds
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * getRating('LCP', 2000) // 'good'
80
+ * getRating('LCP', 3000) // 'needs-improvement'
81
+ * getRating('LCP', 5000) // 'poor'
82
+ * ```
83
+ */
84
+ export function getRating(name, value) {
85
+ const threshold = THRESHOLDS[name];
86
+ if (!threshold)
87
+ return 'needs-improvement';
88
+ if (value < threshold.good)
89
+ return 'good';
90
+ if (value < threshold.poor)
91
+ return 'needs-improvement';
92
+ return 'poor';
93
+ }
94
+ /**
95
+ * Get human-readable description for a metric
96
+ */
97
+ export function getMetricDescription(name) {
98
+ return THRESHOLDS[name]?.description ?? name;
99
+ }
100
+ /**
101
+ * Get unit for a metric
102
+ */
103
+ export function getMetricUnit(name) {
104
+ return THRESHOLDS[name]?.unit ?? 'ms';
105
+ }
106
+ /**
107
+ * Format a metric value for display
108
+ *
109
+ * @param name - Metric name
110
+ * @param value - Metric value
111
+ * @returns Formatted string
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * formatMetricValue('LCP', 2500) // '2.50s'
116
+ * formatMetricValue('CLS', 0.15) // '0.15'
117
+ * formatMetricValue('INP', 150) // '150ms'
118
+ * ```
119
+ */
120
+ export function formatMetricValue(name, value) {
121
+ const unit = getMetricUnit(name);
122
+ if (unit === 'score') {
123
+ return value.toFixed(3);
124
+ }
125
+ // For timing metrics
126
+ if (value < 1) {
127
+ return `${(value * 1000).toFixed(0)}μs`;
128
+ }
129
+ if (value < 1000) {
130
+ return `${value.toFixed(0)}ms`;
131
+ }
132
+ return `${(value / 1000).toFixed(2)}s`;
133
+ }
134
+ /**
135
+ * Rating colors for UI display
136
+ */
137
+ export const RATING_COLORS = {
138
+ good: { bg: '#dcfce7', text: '#166534', border: '#86efac' },
139
+ 'needs-improvement': { bg: '#fef3c7', text: '#92400e', border: '#fcd34d' },
140
+ poor: { bg: '#fee2e2', text: '#991b1b', border: '#fca5a5' },
141
+ };
142
+ /**
143
+ * Get color scheme for a rating
144
+ */
145
+ export function getRatingColors(rating) {
146
+ return RATING_COLORS[rating];
147
+ }
148
+ //# sourceMappingURL=thresholds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thresholds.js","sourceRoot":"","sources":["../../src/metrics/thresholds.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Core Web Vitals and Route Metrics Types
3
+ *
4
+ * These types define the structure for capturing and reporting
5
+ * performance metrics in Next.js applications.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ /**
10
+ * Web Vital metric names
11
+ * - LCP: Largest Contentful Paint (loading performance)
12
+ * - CLS: Cumulative Layout Shift (visual stability)
13
+ * - INP: Interaction to Next Paint (interactivity)
14
+ * - TTFB: Time to First Byte (server responsiveness)
15
+ * - FCP: First Contentful Paint (perceived load speed)
16
+ */
17
+ export type WebVitalName = 'LCP' | 'CLS' | 'INP' | 'TTFB' | 'FCP';
18
+ /**
19
+ * Rating for a metric based on Core Web Vitals thresholds
20
+ */
21
+ export type MetricRating = 'good' | 'needs-improvement' | 'poor';
22
+ /**
23
+ * Navigation type from Performance API
24
+ */
25
+ export type NavigationType = 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'restore';
26
+ /**
27
+ * Web Vital metric captured from the browser
28
+ */
29
+ export interface WebVitalMetric {
30
+ /** Metric name (LCP, CLS, INP, TTFB, FCP) */
31
+ name: WebVitalName;
32
+ /** Metric value (ms for timing metrics, score for CLS) */
33
+ value: number;
34
+ /** Rating based on Core Web Vitals thresholds */
35
+ rating: MetricRating;
36
+ /** Change since last measurement */
37
+ delta: number;
38
+ /** Unique identifier for this metric instance */
39
+ id: string;
40
+ /** How the page was navigated to */
41
+ navigationType: NavigationType;
42
+ /** Entries that contributed to this metric */
43
+ entries: PerformanceEntry[];
44
+ }
45
+ /**
46
+ * Route-specific performance metric
47
+ */
48
+ export interface RouteMetric {
49
+ /** Route pathname (e.g., /dashboard, /users/[id]) */
50
+ pathname: string;
51
+ /** Time to render the route in ms */
52
+ renderTime: number;
53
+ /** Time to hydrate the route in ms */
54
+ hydrationTime: number;
55
+ /** Time to fetch route data (if applicable) */
56
+ dataFetchTime?: number;
57
+ /** ISO timestamp when metric was captured */
58
+ timestamp: string;
59
+ /** Request ID for correlation with server logs */
60
+ requestId?: string;
61
+ }
62
+ /**
63
+ * Stored metric entry for Dev Overlay and reporting
64
+ */
65
+ export interface MetricEntry {
66
+ /** Unique identifier */
67
+ id: string;
68
+ /** ISO timestamp */
69
+ timestamp: string;
70
+ /** Type of metric */
71
+ type: 'web-vital' | 'route' | 'custom';
72
+ /** Metric name */
73
+ name: string;
74
+ /** Metric value */
75
+ value: number;
76
+ /** Rating (for web vitals) */
77
+ rating?: MetricRating;
78
+ /** Additional metadata */
79
+ metadata: {
80
+ pathname?: string;
81
+ requestId?: string;
82
+ traceId?: string;
83
+ userAgent?: string;
84
+ navigationType?: NavigationType;
85
+ delta?: number;
86
+ };
87
+ }
88
+ /**
89
+ * Histogram bucket for metric visualization
90
+ */
91
+ export interface HistogramBucket {
92
+ /** Lower bound of bucket (inclusive) */
93
+ min: number;
94
+ /** Upper bound of bucket (exclusive) */
95
+ max: number;
96
+ /** Count of values in this bucket */
97
+ count: number;
98
+ /** Percentage of total */
99
+ percentage: number;
100
+ }
101
+ /**
102
+ * Summary statistics for a metric
103
+ */
104
+ export interface MetricSummary {
105
+ /** Metric name */
106
+ name: string;
107
+ /** Number of samples */
108
+ count: number;
109
+ /** Average value */
110
+ avg: number;
111
+ /** Minimum value */
112
+ min: number;
113
+ /** Maximum value */
114
+ max: number;
115
+ /** 50th percentile (median) */
116
+ p50: number;
117
+ /** 75th percentile */
118
+ p75: number;
119
+ /** 95th percentile */
120
+ p95: number;
121
+ /** 99th percentile */
122
+ p99: number;
123
+ /** Overall rating based on p75 */
124
+ rating: MetricRating;
125
+ }
126
+ /**
127
+ * Configuration for VestigMetrics component
128
+ */
129
+ export interface VestigMetricsConfig {
130
+ /**
131
+ * Sampling rate for metrics collection (0.0 - 1.0)
132
+ * @default 1.0 in development, 0.1 in production
133
+ */
134
+ sampleRate?: number;
135
+ /**
136
+ * Endpoint to report metrics to
137
+ * @default '/api/vestig/metrics'
138
+ */
139
+ reportEndpoint?: string;
140
+ /**
141
+ * Enable/disable metrics collection
142
+ * @default true
143
+ */
144
+ enabled?: boolean;
145
+ /**
146
+ * Batch interval for reporting in milliseconds
147
+ * @default 5000
148
+ */
149
+ batchInterval?: number;
150
+ /**
151
+ * Report immediately when a metric has poor rating
152
+ * @default true
153
+ */
154
+ reportPoorImmediately?: boolean;
155
+ /**
156
+ * Capture route metrics (render time, hydration)
157
+ * @default true
158
+ */
159
+ captureRouteMetrics?: boolean;
160
+ /**
161
+ * Debug mode - logs metrics to console
162
+ * @default false
163
+ */
164
+ debug?: boolean;
165
+ }
166
+ /**
167
+ * Metrics store state
168
+ */
169
+ export interface MetricsState {
170
+ /** All captured metrics */
171
+ metrics: MetricEntry[];
172
+ /** Maximum number of metrics to keep in memory */
173
+ maxMetrics: number;
174
+ /** Latest value for each web vital */
175
+ latestVitals: Partial<Record<WebVitalName, MetricEntry>>;
176
+ }
177
+ /**
178
+ * Metrics store interface
179
+ */
180
+ export interface MetricsStore {
181
+ /** Subscribe to store changes */
182
+ subscribe: (listener: () => void) => () => void;
183
+ /** Get current snapshot of state */
184
+ getSnapshot: () => MetricsState;
185
+ /** Add a new metric */
186
+ addMetric: (entry: Omit<MetricEntry, 'id' | 'timestamp'>) => void;
187
+ /** Get histogram for a specific metric */
188
+ getHistogram: (name: string, bucketCount?: number) => HistogramBucket[];
189
+ /** Get summary statistics for a metric */
190
+ getSummary: (name: string) => MetricSummary | null;
191
+ /** Get all summaries for web vitals */
192
+ getVitalsSummary: () => Partial<Record<WebVitalName, MetricSummary>>;
193
+ /** Get the latest metric for a given name */
194
+ getLatest: (name: string) => MetricEntry | null;
195
+ /** Clear all metrics */
196
+ clear: () => void;
197
+ }
198
+ /**
199
+ * Payload for metrics reporting
200
+ */
201
+ export interface MetricsReportPayload {
202
+ /** Metrics to report */
203
+ metrics: MetricEntry[];
204
+ /** Client metadata */
205
+ client: {
206
+ userAgent: string;
207
+ pathname: string;
208
+ timestamp: string;
209
+ };
210
+ }
211
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/metrics/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Core Web Vitals and Route Metrics Types
3
+ *
4
+ * These types define the structure for capturing and reporting
5
+ * performance metrics in Next.js applications.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/metrics/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * VestigMetrics Component
3
+ *
4
+ * Drop-in component for capturing Core Web Vitals and route metrics.
5
+ * Add this to your root layout for automatic performance monitoring.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // app/layout.tsx
10
+ * import { VestigMetrics } from '@vestig/next/metrics'
11
+ *
12
+ * export default function RootLayout({ children }) {
13
+ * return (
14
+ * <html>
15
+ * <body>
16
+ * {children}
17
+ * <VestigMetrics
18
+ * sampleRate={0.1} // 10% sampling in production
19
+ * reportEndpoint="/api/vestig/metrics"
20
+ * />
21
+ * </body>
22
+ * </html>
23
+ * )
24
+ * }
25
+ * ```
26
+ *
27
+ * @packageDocumentation
28
+ */
29
+ import type { VestigMetricsConfig } from './types';
30
+ /**
31
+ * Props for VestigMetrics component
32
+ */
33
+ export interface VestigMetricsProps extends VestigMetricsConfig {
34
+ }
35
+ /**
36
+ * VestigMetrics - Core Web Vitals and Route Metrics Component
37
+ *
38
+ * This component automatically captures:
39
+ * - **LCP** (Largest Contentful Paint) - Loading performance
40
+ * - **CLS** (Cumulative Layout Shift) - Visual stability
41
+ * - **INP** (Interaction to Next Paint) - Interactivity
42
+ * - **TTFB** (Time to First Byte) - Server responsiveness
43
+ * - **FCP** (First Contentful Paint) - Perceived load speed
44
+ * - **Route metrics** - Navigation and hydration times
45
+ *
46
+ * @example Basic usage
47
+ * ```tsx
48
+ * <VestigMetrics />
49
+ * ```
50
+ *
51
+ * @example With configuration
52
+ * ```tsx
53
+ * <VestigMetrics
54
+ * sampleRate={0.1} // 10% of users
55
+ * reportEndpoint="/api/metrics"
56
+ * reportPoorImmediately // Alert on poor metrics
57
+ * captureRouteMetrics // Track route changes
58
+ * debug={process.env.NODE_ENV === 'development'}
59
+ * />
60
+ * ```
61
+ *
62
+ * @example Production setup
63
+ * ```tsx
64
+ * <VestigMetrics
65
+ * enabled={process.env.NODE_ENV === 'production'}
66
+ * sampleRate={0.1}
67
+ * reportPoorImmediately
68
+ * />
69
+ * ```
70
+ */
71
+ export declare function VestigMetrics({ enabled, sampleRate, reportEndpoint, reportPoorImmediately, captureRouteMetrics, debug, }: VestigMetricsProps): null;
72
+ //# sourceMappingURL=web-vitals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-vitals.d.ts","sourceRoot":"","sources":["../../src/metrics/web-vitals.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAIlD;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;CAAG;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,aAAa,CAAC,EAC7B,OAAc,EACd,UAAU,EACV,cAAsC,EACtC,qBAA4B,EAC5B,mBAA0B,EAC1B,KAAa,GACb,EAAE,kBAAkB,GAAG,IAAI,CAwB3B"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * VestigMetrics Component
3
+ *
4
+ * Drop-in component for capturing Core Web Vitals and route metrics.
5
+ * Add this to your root layout for automatic performance monitoring.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // app/layout.tsx
10
+ * import { VestigMetrics } from '@vestig/next/metrics'
11
+ *
12
+ * export default function RootLayout({ children }) {
13
+ * return (
14
+ * <html>
15
+ * <body>
16
+ * {children}
17
+ * <VestigMetrics
18
+ * sampleRate={0.1} // 10% sampling in production
19
+ * reportEndpoint="/api/vestig/metrics"
20
+ * />
21
+ * </body>
22
+ * </html>
23
+ * )
24
+ * }
25
+ * ```
26
+ *
27
+ * @packageDocumentation
28
+ */
29
+ 'use client';
30
+ import { useWebVitals } from './hooks/use-web-vitals';
31
+ import { useRouteMetrics } from './hooks/use-route-metrics';
32
+ /**
33
+ * VestigMetrics - Core Web Vitals and Route Metrics Component
34
+ *
35
+ * This component automatically captures:
36
+ * - **LCP** (Largest Contentful Paint) - Loading performance
37
+ * - **CLS** (Cumulative Layout Shift) - Visual stability
38
+ * - **INP** (Interaction to Next Paint) - Interactivity
39
+ * - **TTFB** (Time to First Byte) - Server responsiveness
40
+ * - **FCP** (First Contentful Paint) - Perceived load speed
41
+ * - **Route metrics** - Navigation and hydration times
42
+ *
43
+ * @example Basic usage
44
+ * ```tsx
45
+ * <VestigMetrics />
46
+ * ```
47
+ *
48
+ * @example With configuration
49
+ * ```tsx
50
+ * <VestigMetrics
51
+ * sampleRate={0.1} // 10% of users
52
+ * reportEndpoint="/api/metrics"
53
+ * reportPoorImmediately // Alert on poor metrics
54
+ * captureRouteMetrics // Track route changes
55
+ * debug={process.env.NODE_ENV === 'development'}
56
+ * />
57
+ * ```
58
+ *
59
+ * @example Production setup
60
+ * ```tsx
61
+ * <VestigMetrics
62
+ * enabled={process.env.NODE_ENV === 'production'}
63
+ * sampleRate={0.1}
64
+ * reportPoorImmediately
65
+ * />
66
+ * ```
67
+ */
68
+ export function VestigMetrics({ enabled = true, sampleRate, reportEndpoint = '/api/vestig/metrics', reportPoorImmediately = true, captureRouteMetrics = true, debug = false, }) {
69
+ // Determine sample rate based on environment if not specified
70
+ const effectiveSampleRate = sampleRate ??
71
+ (typeof window !== 'undefined' && process.env.NODE_ENV === 'production' ? 0.1 : 1.0);
72
+ // Capture Core Web Vitals
73
+ useWebVitals({
74
+ enabled,
75
+ sampleRate: effectiveSampleRate,
76
+ reportEndpoint,
77
+ reportPoorImmediately,
78
+ debug,
79
+ });
80
+ // Capture route metrics
81
+ useRouteMetrics({
82
+ enabled: enabled && captureRouteMetrics,
83
+ reportEndpoint,
84
+ debug,
85
+ });
86
+ // This component doesn't render anything
87
+ return null;
88
+ }
89
+ //# sourceMappingURL=web-vitals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-vitals.js","sourceRoot":"","sources":["../../src/metrics/web-vitals.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,YAAY,CAAA;AAGZ,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAO3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,aAAa,CAAC,EAC7B,OAAO,GAAG,IAAI,EACd,UAAU,EACV,cAAc,GAAG,qBAAqB,EACtC,qBAAqB,GAAG,IAAI,EAC5B,mBAAmB,GAAG,IAAI,EAC1B,KAAK,GAAG,KAAK,GACO;IACpB,8DAA8D;IAC9D,MAAM,mBAAmB,GACxB,UAAU;QACV,CAAC,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAErF,0BAA0B;IAC1B,YAAY,CAAC;QACZ,OAAO;QACP,UAAU,EAAE,mBAAmB;QAC/B,cAAc;QACd,qBAAqB;QACrB,KAAK;KACL,CAAC,CAAA;IAEF,wBAAwB;IACxB,eAAe,CAAC;QACf,OAAO,EAAE,OAAO,IAAI,mBAAmB;QACvC,cAAc;QACd,KAAK;KACL,CAAC,CAAA;IAEF,yCAAyC;IACzC,OAAO,IAAI,CAAA;AACZ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EACN,KAAK,QAAQ,EAEb,KAAK,cAAc,EAKnB,MAAM,QAAQ,CAAA;AAIf,MAAM,WAAW,iBAAiB;IACjC,0CAA0C;IAC1C,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,wCAAwC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,sCAAsC;IACtC,eAAe,CAAC,EAAE,QAAQ,CAAA;IAC1B,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,QAAQ,CAAA;IAC3B,iCAAiC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAA;CACpB;AAmCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,iBAAsB,IAGpC,SAAS,WAAW,2BA2ErD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,YA3Fc,WAAW,0BA2FE,CAAA;AAGxD,YAAY,EAAE,iBAAiB,IAAI,YAAY,EAAE,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,aApHtB,WAAW,2BAwHrD;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,YAvImB,WAAW,0BAuIR,CAAA;AAE9C;;GAEG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,GAAE;IACR,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACb;;EAMN;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,2BAAqB,CAAA"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EACN,KAAK,QAAQ,EAEb,KAAK,cAAc,EAMnB,MAAM,QAAQ,CAAA;AAIf,MAAM,WAAW,iBAAiB;IACjC,0CAA0C;IAC1C,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,wCAAwC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,sCAAsC;IACtC,eAAe,CAAC,EAAE,QAAQ,CAAA;IAC1B,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,QAAQ,CAAA;IAC3B,iCAAiC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAA;CACpB;AAmCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,iBAAsB,IAGpC,SAAS,WAAW,2BA4FrD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,YA5Gc,WAAW,0BA4GE,CAAA;AAGxD,YAAY,EAAE,iBAAiB,IAAI,YAAY,EAAE,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,aArItB,WAAW,2BAyIrD;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,YAxJmB,WAAW,0BAwJR,CAAA;AAE9C;;GAEG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,GAAE;IACR,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACb;;EAMN;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,2BAAqB,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { NextResponse } from 'next/server';
2
- import { createCorrelationContext, createLogger, createTraceparent, parseTraceparent, } from 'vestig';
2
+ import { createCorrelationContext, createLogger, createTraceparent, parseTraceparent, spanSync, } from 'vestig';
3
3
  import { CORRELATION_HEADERS } from '../utils/headers';
4
4
  import { createRequestTiming, formatDuration } from '../utils/timing';
5
5
  // Default options
@@ -70,46 +70,60 @@ export function createVestigMiddleware(options = {}) {
70
70
  traceId: parsed?.traceId,
71
71
  spanId: parsed?.spanId,
72
72
  });
73
- // Log incoming request
74
- const requestLogLevel = mergedOptions.requestLogLevel;
75
- log[requestLogLevel]('Request received', {
76
- method: request.method,
77
- path: pathname,
78
- search: request.nextUrl.search || undefined,
79
- userAgent: request.headers.get('user-agent')?.slice(0, 100),
80
- ip: request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??
81
- request.headers.get('x-real-ip'),
82
- requestId: ctx.requestId,
83
- traceId: ctx.traceId,
84
- });
85
- // Create new headers with correlation IDs
86
- const requestHeaders = new Headers(request.headers);
87
- requestHeaders.set(CORRELATION_HEADERS.REQUEST_ID, ctx.requestId);
88
- requestHeaders.set(CORRELATION_HEADERS.TRACE_ID, ctx.traceId);
89
- requestHeaders.set(CORRELATION_HEADERS.SPAN_ID, ctx.spanId);
90
- requestHeaders.set(CORRELATION_HEADERS.TRACEPARENT, createTraceparent(ctx.traceId, ctx.spanId));
91
- // Create response with updated headers
92
- const response = NextResponse.next({
93
- request: {
94
- headers: requestHeaders,
95
- },
96
- });
97
- // Add correlation headers to response
98
- response.headers.set(CORRELATION_HEADERS.REQUEST_ID, ctx.requestId);
99
- response.headers.set(CORRELATION_HEADERS.TRACE_ID, ctx.traceId);
100
- // Log response with timing if enabled
101
- if (mergedOptions.timing) {
102
- const duration = timing.complete();
103
- const responseLogLevel = mergedOptions.responseLogLevel;
104
- log[responseLogLevel]('Response sent', {
73
+ // Wrap middleware processing in a span
74
+ return spanSync(`middleware:${mergedOptions.namespace}`, (s) => {
75
+ // Set HTTP attributes on span
76
+ s.setAttributes({
77
+ 'http.method': request.method,
78
+ 'http.path': pathname,
79
+ 'http.request_id': ctx.requestId,
80
+ 'http.trace_id': ctx.traceId,
81
+ });
82
+ // Log incoming request
83
+ const requestLogLevel = mergedOptions.requestLogLevel;
84
+ log[requestLogLevel]('Request received', {
105
85
  method: request.method,
106
86
  path: pathname,
107
- duration: formatDuration(duration),
108
- durationMs: duration,
87
+ search: request.nextUrl.search || undefined,
88
+ userAgent: request.headers.get('user-agent')?.slice(0, 100),
89
+ ip: request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??
90
+ request.headers.get('x-real-ip'),
109
91
  requestId: ctx.requestId,
92
+ traceId: ctx.traceId,
110
93
  });
111
- }
112
- return response;
94
+ s.addEvent('request-received');
95
+ // Create new headers with correlation IDs
96
+ const requestHeaders = new Headers(request.headers);
97
+ requestHeaders.set(CORRELATION_HEADERS.REQUEST_ID, ctx.requestId);
98
+ requestHeaders.set(CORRELATION_HEADERS.TRACE_ID, ctx.traceId);
99
+ requestHeaders.set(CORRELATION_HEADERS.SPAN_ID, ctx.spanId);
100
+ requestHeaders.set(CORRELATION_HEADERS.TRACEPARENT, createTraceparent(ctx.traceId, ctx.spanId));
101
+ // Create response with updated headers
102
+ const response = NextResponse.next({
103
+ request: {
104
+ headers: requestHeaders,
105
+ },
106
+ });
107
+ // Add correlation headers to response
108
+ response.headers.set(CORRELATION_HEADERS.REQUEST_ID, ctx.requestId);
109
+ response.headers.set(CORRELATION_HEADERS.TRACE_ID, ctx.traceId);
110
+ // Log response with timing if enabled
111
+ if (mergedOptions.timing) {
112
+ const duration = timing.complete();
113
+ s.setAttribute('http.duration_ms', duration);
114
+ s.addEvent('response-sent');
115
+ const responseLogLevel = mergedOptions.responseLogLevel;
116
+ log[responseLogLevel]('Response sent', {
117
+ method: request.method,
118
+ path: pathname,
119
+ duration: formatDuration(duration),
120
+ durationMs: duration,
121
+ requestId: ctx.requestId,
122
+ });
123
+ }
124
+ s.setStatus('ok');
125
+ return response;
126
+ });
113
127
  };
114
128
  }
115
129
  /**