@vestig/next 0.6.0 → 0.9.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/README.md +1 -1
- package/dist/__tests__/mocks/next-server.d.ts.map +1 -1
- package/dist/__tests__/mocks/next-server.js.map +1 -1
- package/dist/client/error-boundary.d.ts +80 -0
- package/dist/client/error-boundary.d.ts.map +1 -0
- package/dist/client/error-boundary.js +182 -0
- package/dist/client/error-boundary.js.map +1 -0
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/transport.d.ts +50 -0
- package/dist/client/transport.d.ts.map +1 -1
- package/dist/client/transport.js +200 -3
- package/dist/client/transport.js.map +1 -1
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -1
- package/dist/db/drizzle.d.ts +115 -0
- package/dist/db/drizzle.d.ts.map +1 -0
- package/dist/db/drizzle.js +174 -0
- package/dist/db/drizzle.js.map +1 -0
- package/dist/db/index.d.ts +49 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +51 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/prisma.d.ts +114 -0
- package/dist/db/prisma.d.ts.map +1 -0
- package/dist/db/prisma.js +144 -0
- package/dist/db/prisma.js.map +1 -0
- package/dist/db/query-logger.d.ts +30 -0
- package/dist/db/query-logger.d.ts.map +1 -0
- package/dist/db/query-logger.js +169 -0
- package/dist/db/query-logger.js.map +1 -0
- package/dist/db/types.d.ts +102 -0
- package/dist/db/types.d.ts.map +1 -0
- package/dist/db/types.js +28 -0
- package/dist/db/types.js.map +1 -0
- package/dist/dev/api/index.d.ts +13 -0
- package/dist/dev/api/index.d.ts.map +1 -0
- package/dist/dev/api/index.js +13 -0
- package/dist/dev/api/index.js.map +1 -0
- package/dist/dev/api/logs-stream.d.ts +119 -0
- package/dist/dev/api/logs-stream.d.ts.map +1 -0
- package/dist/dev/api/logs-stream.js +156 -0
- package/dist/dev/api/logs-stream.js.map +1 -0
- package/dist/dev/filters.d.ts +17 -0
- package/dist/dev/filters.d.ts.map +1 -0
- package/dist/dev/filters.js +100 -0
- package/dist/dev/filters.js.map +1 -0
- package/dist/dev/hooks/use-logs.d.ts +55 -0
- package/dist/dev/hooks/use-logs.d.ts.map +1 -0
- package/dist/dev/hooks/use-logs.js +202 -0
- package/dist/dev/hooks/use-logs.js.map +1 -0
- package/dist/dev/index.d.ts +35 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +41 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/log-entry.d.ts +12 -0
- package/dist/dev/log-entry.d.ts.map +1 -0
- package/dist/dev/log-entry.js +152 -0
- package/dist/dev/log-entry.js.map +1 -0
- package/dist/dev/log-viewer.d.ts +11 -0
- package/dist/dev/log-viewer.d.ts.map +1 -0
- package/dist/dev/log-viewer.js +49 -0
- package/dist/dev/log-viewer.js.map +1 -0
- package/dist/dev/metrics-card.d.ts +18 -0
- package/dist/dev/metrics-card.d.ts.map +1 -0
- package/dist/dev/metrics-card.js +75 -0
- package/dist/dev/metrics-card.js.map +1 -0
- package/dist/dev/metrics-histogram.d.ts +12 -0
- package/dist/dev/metrics-histogram.d.ts.map +1 -0
- package/dist/dev/metrics-histogram.js +69 -0
- package/dist/dev/metrics-histogram.js.map +1 -0
- package/dist/dev/metrics-panel.d.ts +10 -0
- package/dist/dev/metrics-panel.d.ts.map +1 -0
- package/dist/dev/metrics-panel.js +84 -0
- package/dist/dev/metrics-panel.js.map +1 -0
- package/dist/dev/overlay.d.ts +55 -0
- package/dist/dev/overlay.d.ts.map +1 -0
- package/dist/dev/overlay.js +216 -0
- package/dist/dev/overlay.js.map +1 -0
- package/dist/dev/store.d.ts +126 -0
- package/dist/dev/store.d.ts.map +1 -0
- package/dist/dev/store.js +210 -0
- package/dist/dev/store.js.map +1 -0
- package/dist/error/boundary.d.ts +36 -0
- package/dist/error/boundary.d.ts.map +1 -0
- package/dist/error/boundary.js +263 -0
- package/dist/error/boundary.js.map +1 -0
- package/dist/error/breadcrumbs.d.ts +95 -0
- package/dist/error/breadcrumbs.d.ts.map +1 -0
- package/dist/error/breadcrumbs.js +273 -0
- package/dist/error/breadcrumbs.js.map +1 -0
- package/dist/error/fingerprint.d.ts +42 -0
- package/dist/error/fingerprint.d.ts.map +1 -0
- package/dist/error/fingerprint.js +135 -0
- package/dist/error/fingerprint.js.map +1 -0
- package/dist/error/index.d.ts +52 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +56 -0
- package/dist/error/index.js.map +1 -0
- package/dist/error/stack-parser.d.ts +43 -0
- package/dist/error/stack-parser.d.ts.map +1 -0
- package/dist/error/stack-parser.js +166 -0
- package/dist/error/stack-parser.js.map +1 -0
- package/dist/error/types.d.ts +152 -0
- package/dist/error/types.d.ts.map +1 -0
- package/dist/error/types.js +10 -0
- package/dist/error/types.js.map +1 -0
- package/dist/metrics/hooks/use-route-metrics.d.ts +93 -0
- package/dist/metrics/hooks/use-route-metrics.d.ts.map +1 -0
- package/dist/metrics/hooks/use-route-metrics.js +217 -0
- package/dist/metrics/hooks/use-route-metrics.js.map +1 -0
- package/dist/metrics/hooks/use-web-vitals.d.ts +73 -0
- package/dist/metrics/hooks/use-web-vitals.d.ts.map +1 -0
- package/dist/metrics/hooks/use-web-vitals.js +141 -0
- package/dist/metrics/hooks/use-web-vitals.js.map +1 -0
- package/dist/metrics/index.d.ts +51 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +56 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/reporter.d.ts +87 -0
- package/dist/metrics/reporter.d.ts.map +1 -0
- package/dist/metrics/reporter.js +178 -0
- package/dist/metrics/reporter.js.map +1 -0
- package/dist/metrics/store.d.ts +67 -0
- package/dist/metrics/store.d.ts.map +1 -0
- package/dist/metrics/store.js +187 -0
- package/dist/metrics/store.js.map +1 -0
- package/dist/metrics/thresholds.d.ts +84 -0
- package/dist/metrics/thresholds.d.ts.map +1 -0
- package/dist/metrics/thresholds.js +148 -0
- package/dist/metrics/thresholds.js.map +1 -0
- package/dist/metrics/types.d.ts +215 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +10 -0
- package/dist/metrics/types.js.map +1 -0
- package/dist/metrics/web-vitals.d.ts +72 -0
- package/dist/metrics/web-vitals.d.ts.map +1 -0
- package/dist/metrics/web-vitals.js +89 -0
- package/dist/metrics/web-vitals.js.map +1 -0
- package/package.json +28 -6
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Vitals Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for capturing Core Web Vitals metrics.
|
|
5
|
+
* Uses simple useState + useEffect pattern (React Compiler handles memoization).
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { MetricEntry, MetricSummary, WebVitalName } from '../types';
|
|
10
|
+
/**
|
|
11
|
+
* Options for useWebVitals hook
|
|
12
|
+
*/
|
|
13
|
+
interface UseWebVitalsOptions {
|
|
14
|
+
/** Enable Web Vitals collection */
|
|
15
|
+
enabled?: boolean;
|
|
16
|
+
/** Sampling rate (0.0 - 1.0) */
|
|
17
|
+
sampleRate?: number;
|
|
18
|
+
/** Report endpoint */
|
|
19
|
+
reportEndpoint?: string;
|
|
20
|
+
/** Report immediately when rating is poor */
|
|
21
|
+
reportPoorImmediately?: boolean;
|
|
22
|
+
/** Debug mode */
|
|
23
|
+
debug?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hook to capture Core Web Vitals
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* function MyComponent() {
|
|
31
|
+
* useWebVitals({
|
|
32
|
+
* enabled: process.env.NODE_ENV === 'development',
|
|
33
|
+
* sampleRate: 0.1,
|
|
34
|
+
* reportPoorImmediately: true,
|
|
35
|
+
* })
|
|
36
|
+
*
|
|
37
|
+
* return <div>My App</div>
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function useWebVitals(options?: UseWebVitalsOptions): void;
|
|
42
|
+
/**
|
|
43
|
+
* Hook to get the current Web Vitals from the store
|
|
44
|
+
*
|
|
45
|
+
* Simple useState + useEffect pattern - React Compiler handles memoization.
|
|
46
|
+
* No useSyncExternalStore = no hydration headaches.
|
|
47
|
+
*
|
|
48
|
+
* @returns Latest Web Vitals values
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* function MetricsDisplay() {
|
|
53
|
+
* const vitals = useWebVitalsData()
|
|
54
|
+
*
|
|
55
|
+
* return (
|
|
56
|
+
* <div>
|
|
57
|
+
* <p>LCP: {vitals.LCP?.value ?? 'N/A'}</p>
|
|
58
|
+
* <p>CLS: {vitals.CLS?.value ?? 'N/A'}</p>
|
|
59
|
+
* <p>INP: {vitals.INP?.value ?? 'N/A'}</p>
|
|
60
|
+
* </div>
|
|
61
|
+
* )
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function useWebVitalsData(): Partial<Record<WebVitalName, MetricEntry>>;
|
|
66
|
+
/**
|
|
67
|
+
* Hook to get Web Vitals summary statistics
|
|
68
|
+
*
|
|
69
|
+
* @returns Summary statistics for all Web Vitals
|
|
70
|
+
*/
|
|
71
|
+
export declare function useWebVitalsSummary(): Partial<Record<WebVitalName, MetricSummary>>;
|
|
72
|
+
export {};
|
|
73
|
+
//# sourceMappingURL=use-web-vitals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-web-vitals.d.ts","sourceRoot":"","sources":["../../../src/metrics/hooks/use-web-vitals.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAkB,YAAY,EAAE,MAAM,UAAU,CAAA;AAExF;;GAEG;AACH,UAAU,mBAAmB;IAC5B,mCAAmC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6CAA6C;IAC7C,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,iBAAiB;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CACf;AAmBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,IAAI,CAqDpE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAgB7E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAclF"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Vitals Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for capturing Core Web Vitals metrics.
|
|
5
|
+
* Uses simple useState + useEffect pattern (React Compiler handles memoization).
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
'use client';
|
|
10
|
+
import { useEffect, useState } from 'react';
|
|
11
|
+
import { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';
|
|
12
|
+
import { MetricsReporter } from '../reporter';
|
|
13
|
+
import { metricsStore } from '../store';
|
|
14
|
+
/**
|
|
15
|
+
* Convert web-vitals Metric to our MetricEntry format
|
|
16
|
+
*/
|
|
17
|
+
function toMetricEntry(metric) {
|
|
18
|
+
return {
|
|
19
|
+
type: 'web-vital',
|
|
20
|
+
name: metric.name,
|
|
21
|
+
value: metric.value,
|
|
22
|
+
rating: metric.rating,
|
|
23
|
+
metadata: {
|
|
24
|
+
navigationType: metric.navigationType,
|
|
25
|
+
delta: metric.delta,
|
|
26
|
+
pathname: typeof window !== 'undefined' ? window.location.pathname : undefined,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Hook to capture Core Web Vitals
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* function MyComponent() {
|
|
36
|
+
* useWebVitals({
|
|
37
|
+
* enabled: process.env.NODE_ENV === 'development',
|
|
38
|
+
* sampleRate: 0.1,
|
|
39
|
+
* reportPoorImmediately: true,
|
|
40
|
+
* })
|
|
41
|
+
*
|
|
42
|
+
* return <div>My App</div>
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function useWebVitals(options = {}) {
|
|
47
|
+
const { enabled = true, sampleRate = 1.0, reportEndpoint = '/api/vestig/metrics', reportPoorImmediately = true, debug = false, } = options;
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!enabled)
|
|
50
|
+
return;
|
|
51
|
+
if (Math.random() > sampleRate)
|
|
52
|
+
return;
|
|
53
|
+
const reporter = new MetricsReporter({
|
|
54
|
+
endpoint: reportEndpoint,
|
|
55
|
+
debug,
|
|
56
|
+
});
|
|
57
|
+
const handleMetric = (metric) => {
|
|
58
|
+
const entry = toMetricEntry(metric);
|
|
59
|
+
metricsStore.addMetric(entry);
|
|
60
|
+
if (debug) {
|
|
61
|
+
console.log(`[vestig-metrics] ${metric.name}:`, {
|
|
62
|
+
value: metric.value,
|
|
63
|
+
rating: metric.rating,
|
|
64
|
+
delta: metric.delta,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const fullEntry = {
|
|
68
|
+
...entry,
|
|
69
|
+
id: `m_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`,
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
if (reportPoorImmediately && metric.rating === 'poor') {
|
|
73
|
+
reporter.reportImmediate(fullEntry);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
reporter.report(fullEntry);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
onLCP(handleMetric);
|
|
80
|
+
onCLS(handleMetric);
|
|
81
|
+
onINP(handleMetric);
|
|
82
|
+
onTTFB(handleMetric);
|
|
83
|
+
onFCP(handleMetric);
|
|
84
|
+
return () => {
|
|
85
|
+
reporter.destroy();
|
|
86
|
+
};
|
|
87
|
+
}, [enabled, sampleRate, reportEndpoint, reportPoorImmediately, debug]);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Hook to get the current Web Vitals from the store
|
|
91
|
+
*
|
|
92
|
+
* Simple useState + useEffect pattern - React Compiler handles memoization.
|
|
93
|
+
* No useSyncExternalStore = no hydration headaches.
|
|
94
|
+
*
|
|
95
|
+
* @returns Latest Web Vitals values
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```tsx
|
|
99
|
+
* function MetricsDisplay() {
|
|
100
|
+
* const vitals = useWebVitalsData()
|
|
101
|
+
*
|
|
102
|
+
* return (
|
|
103
|
+
* <div>
|
|
104
|
+
* <p>LCP: {vitals.LCP?.value ?? 'N/A'}</p>
|
|
105
|
+
* <p>CLS: {vitals.CLS?.value ?? 'N/A'}</p>
|
|
106
|
+
* <p>INP: {vitals.INP?.value ?? 'N/A'}</p>
|
|
107
|
+
* </div>
|
|
108
|
+
* )
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function useWebVitalsData() {
|
|
113
|
+
const [vitals, setVitals] = useState({});
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
// Get initial state
|
|
116
|
+
setVitals(metricsStore.getLatestVitals());
|
|
117
|
+
// Subscribe to updates
|
|
118
|
+
const unsubscribe = metricsStore.subscribe(() => {
|
|
119
|
+
setVitals(metricsStore.getLatestVitals());
|
|
120
|
+
});
|
|
121
|
+
return unsubscribe;
|
|
122
|
+
}, []);
|
|
123
|
+
return vitals;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Hook to get Web Vitals summary statistics
|
|
127
|
+
*
|
|
128
|
+
* @returns Summary statistics for all Web Vitals
|
|
129
|
+
*/
|
|
130
|
+
export function useWebVitalsSummary() {
|
|
131
|
+
const [summary, setSummary] = useState({});
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
setSummary(metricsStore.getVitalsSummary());
|
|
134
|
+
const unsubscribe = metricsStore.subscribe(() => {
|
|
135
|
+
setSummary(metricsStore.getVitalsSummary());
|
|
136
|
+
});
|
|
137
|
+
return unsubscribe;
|
|
138
|
+
}, []);
|
|
139
|
+
return summary;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=use-web-vitals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-web-vitals.js","sourceRoot":"","sources":["../../../src/metrics/hooks/use-web-vitals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vestig/next/metrics - Performance Metrics Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides Core Web Vitals and route-level performance
|
|
5
|
+
* monitoring for Next.js applications.
|
|
6
|
+
*
|
|
7
|
+
* @example Quick Start
|
|
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
|
+
* </body>
|
|
19
|
+
* </html>
|
|
20
|
+
* )
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example With Dev Overlay
|
|
25
|
+
* ```tsx
|
|
26
|
+
* import { VestigDevOverlay } from '@vestig/next/dev'
|
|
27
|
+
* import { VestigMetrics } from '@vestig/next/metrics'
|
|
28
|
+
*
|
|
29
|
+
* export default function RootLayout({ children }) {
|
|
30
|
+
* return (
|
|
31
|
+
* <html>
|
|
32
|
+
* <body>
|
|
33
|
+
* {children}
|
|
34
|
+
* {process.env.NODE_ENV === 'development' && <VestigDevOverlay />}
|
|
35
|
+
* <VestigMetrics />
|
|
36
|
+
* </body>
|
|
37
|
+
* </html>
|
|
38
|
+
* )
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @packageDocumentation
|
|
43
|
+
*/
|
|
44
|
+
export { VestigMetrics, type VestigMetricsProps } from './web-vitals';
|
|
45
|
+
export { metricsStore } from './store';
|
|
46
|
+
export { useWebVitals, useWebVitalsData, useWebVitalsSummary, } from './hooks/use-web-vitals';
|
|
47
|
+
export { useRouteMetrics, useRouteMetricsData, useRenderTiming, useDataFetchTiming, } from './hooks/use-route-metrics';
|
|
48
|
+
export { THRESHOLDS, RATING_COLORS, getRating, getRatingColors, getMetricDescription, getMetricUnit, formatMetricValue, } from './thresholds';
|
|
49
|
+
export { MetricsReporter } from './reporter';
|
|
50
|
+
export type { WebVitalName, MetricRating, NavigationType, WebVitalMetric, RouteMetric, MetricEntry, MetricSummary, HistogramBucket, MetricsState, MetricsStore, VestigMetricsConfig, MetricsReportPayload, } from './types';
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAKH,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAGrE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAGtC,OAAO,EACN,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,GACnB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACN,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,kBAAkB,GAClB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EACN,UAAU,EACV,aAAa,EACb,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GACjB,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAG5C,YAAY,EACX,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,cAAc,EACd,WAAW,EACX,WAAW,EACX,aAAa,EACb,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,GACpB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vestig/next/metrics - Performance Metrics Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides Core Web Vitals and route-level performance
|
|
5
|
+
* monitoring for Next.js applications.
|
|
6
|
+
*
|
|
7
|
+
* @example Quick Start
|
|
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
|
+
* </body>
|
|
19
|
+
* </html>
|
|
20
|
+
* )
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example With Dev Overlay
|
|
25
|
+
* ```tsx
|
|
26
|
+
* import { VestigDevOverlay } from '@vestig/next/dev'
|
|
27
|
+
* import { VestigMetrics } from '@vestig/next/metrics'
|
|
28
|
+
*
|
|
29
|
+
* export default function RootLayout({ children }) {
|
|
30
|
+
* return (
|
|
31
|
+
* <html>
|
|
32
|
+
* <body>
|
|
33
|
+
* {children}
|
|
34
|
+
* {process.env.NODE_ENV === 'development' && <VestigDevOverlay />}
|
|
35
|
+
* <VestigMetrics />
|
|
36
|
+
* </body>
|
|
37
|
+
* </html>
|
|
38
|
+
* )
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @packageDocumentation
|
|
43
|
+
*/
|
|
44
|
+
'use client';
|
|
45
|
+
// Main component
|
|
46
|
+
export { VestigMetrics } from './web-vitals';
|
|
47
|
+
// Store for programmatic access
|
|
48
|
+
export { metricsStore } from './store';
|
|
49
|
+
// Hooks
|
|
50
|
+
export { useWebVitals, useWebVitalsData, useWebVitalsSummary, } from './hooks/use-web-vitals';
|
|
51
|
+
export { useRouteMetrics, useRouteMetricsData, useRenderTiming, useDataFetchTiming, } from './hooks/use-route-metrics';
|
|
52
|
+
// Thresholds and utilities
|
|
53
|
+
export { THRESHOLDS, RATING_COLORS, getRating, getRatingColors, getMetricDescription, getMetricUnit, formatMetricValue, } from './thresholds';
|
|
54
|
+
// Reporter for custom integrations
|
|
55
|
+
export { MetricsReporter } from './reporter';
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,YAAY,CAAA;AAEZ,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAA2B,MAAM,cAAc,CAAA;AAErE,gCAAgC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,QAAQ;AACR,OAAO,EACN,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,GACnB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACN,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,kBAAkB,GAClB,MAAM,2BAA2B,CAAA;AAElC,2BAA2B;AAC3B,OAAO,EACN,UAAU,EACV,aAAa,EACb,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GACjB,MAAM,cAAc,CAAA;AAErB,mCAAmC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Reporter
|
|
3
|
+
*
|
|
4
|
+
* Handles batched reporting of metrics to the server.
|
|
5
|
+
* Uses sendBeacon for reliable delivery on page unload.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { MetricEntry } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* Reporter configuration
|
|
12
|
+
*/
|
|
13
|
+
interface ReporterConfig {
|
|
14
|
+
/** Endpoint to report metrics to */
|
|
15
|
+
endpoint: string;
|
|
16
|
+
/** Batch interval in milliseconds */
|
|
17
|
+
batchInterval: number;
|
|
18
|
+
/** Maximum batch size before forced flush */
|
|
19
|
+
maxBatchSize: number;
|
|
20
|
+
/** Enable debug logging */
|
|
21
|
+
debug: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Metrics Reporter class
|
|
25
|
+
*
|
|
26
|
+
* Collects metrics and sends them in batches to minimize network overhead.
|
|
27
|
+
* Uses sendBeacon on page unload to ensure metrics are not lost.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const reporter = new MetricsReporter({
|
|
32
|
+
* endpoint: '/api/vestig/metrics',
|
|
33
|
+
* batchInterval: 5000,
|
|
34
|
+
* maxBatchSize: 50,
|
|
35
|
+
* debug: false
|
|
36
|
+
* })
|
|
37
|
+
*
|
|
38
|
+
* reporter.report(metric)
|
|
39
|
+
* reporter.reportImmediate(criticalMetric) // Bypass batch
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class MetricsReporter {
|
|
43
|
+
private config;
|
|
44
|
+
private queue;
|
|
45
|
+
private flushTimer;
|
|
46
|
+
private isDestroyed;
|
|
47
|
+
constructor(config?: Partial<ReporterConfig>);
|
|
48
|
+
/**
|
|
49
|
+
* Add a metric to the batch queue
|
|
50
|
+
*/
|
|
51
|
+
report(metric: MetricEntry): void;
|
|
52
|
+
/**
|
|
53
|
+
* Report a metric immediately (bypasses batch)
|
|
54
|
+
* Use for critical metrics like "poor" ratings
|
|
55
|
+
*/
|
|
56
|
+
reportImmediate(metric: MetricEntry): void;
|
|
57
|
+
/**
|
|
58
|
+
* Flush all queued metrics
|
|
59
|
+
*/
|
|
60
|
+
flush(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Destroy the reporter and clean up
|
|
63
|
+
*/
|
|
64
|
+
destroy(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Start the batch timer
|
|
67
|
+
*/
|
|
68
|
+
private startBatchTimer;
|
|
69
|
+
/**
|
|
70
|
+
* Set up page unload handler to flush metrics
|
|
71
|
+
*/
|
|
72
|
+
private setupUnloadHandler;
|
|
73
|
+
/**
|
|
74
|
+
* Flush metrics using sendBeacon (for page unload)
|
|
75
|
+
*/
|
|
76
|
+
private flushWithBeacon;
|
|
77
|
+
/**
|
|
78
|
+
* Send metrics via fetch
|
|
79
|
+
*/
|
|
80
|
+
private sendMetrics;
|
|
81
|
+
/**
|
|
82
|
+
* Create the report payload
|
|
83
|
+
*/
|
|
84
|
+
private createPayload;
|
|
85
|
+
}
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/metrics/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAwB,MAAM,SAAS,CAAA;AAEhE;;GAEG;AACH,UAAU,cAAc;IACvB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAA;IACrB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAA;IACpB,2BAA2B;IAC3B,KAAK,EAAE,OAAO,CAAA;CACd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,eAAe;IAC3B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,WAAW,CAAQ;gBAEf,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM;IAYhD;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAejC;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAU1C;;OAEG;IACH,KAAK,IAAI,IAAI;IAab;;OAEG;IACH,OAAO,IAAI,IAAI;IAYf;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,eAAe;IAsBvB;;OAEG;YACW,WAAW;IAwBzB;;OAEG;IACH,OAAO,CAAC,aAAa;CAUrB"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Reporter
|
|
3
|
+
*
|
|
4
|
+
* Handles batched reporting of metrics to the server.
|
|
5
|
+
* Uses sendBeacon for reliable delivery on page unload.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Metrics Reporter class
|
|
11
|
+
*
|
|
12
|
+
* Collects metrics and sends them in batches to minimize network overhead.
|
|
13
|
+
* Uses sendBeacon on page unload to ensure metrics are not lost.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const reporter = new MetricsReporter({
|
|
18
|
+
* endpoint: '/api/vestig/metrics',
|
|
19
|
+
* batchInterval: 5000,
|
|
20
|
+
* maxBatchSize: 50,
|
|
21
|
+
* debug: false
|
|
22
|
+
* })
|
|
23
|
+
*
|
|
24
|
+
* reporter.report(metric)
|
|
25
|
+
* reporter.reportImmediate(criticalMetric) // Bypass batch
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class MetricsReporter {
|
|
29
|
+
config;
|
|
30
|
+
queue = [];
|
|
31
|
+
flushTimer = null;
|
|
32
|
+
isDestroyed = false;
|
|
33
|
+
constructor(config = {}) {
|
|
34
|
+
this.config = {
|
|
35
|
+
endpoint: config.endpoint ?? '/api/vestig/metrics',
|
|
36
|
+
batchInterval: config.batchInterval ?? 5000,
|
|
37
|
+
maxBatchSize: config.maxBatchSize ?? 50,
|
|
38
|
+
debug: config.debug ?? false,
|
|
39
|
+
};
|
|
40
|
+
this.startBatchTimer();
|
|
41
|
+
this.setupUnloadHandler();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Add a metric to the batch queue
|
|
45
|
+
*/
|
|
46
|
+
report(metric) {
|
|
47
|
+
if (this.isDestroyed)
|
|
48
|
+
return;
|
|
49
|
+
this.queue.push(metric);
|
|
50
|
+
if (this.config.debug) {
|
|
51
|
+
console.log('[vestig-metrics] Queued:', metric.name, metric.value);
|
|
52
|
+
}
|
|
53
|
+
// Force flush if queue is full
|
|
54
|
+
if (this.queue.length >= this.config.maxBatchSize) {
|
|
55
|
+
this.flush();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Report a metric immediately (bypasses batch)
|
|
60
|
+
* Use for critical metrics like "poor" ratings
|
|
61
|
+
*/
|
|
62
|
+
reportImmediate(metric) {
|
|
63
|
+
if (this.isDestroyed)
|
|
64
|
+
return;
|
|
65
|
+
if (this.config.debug) {
|
|
66
|
+
console.log('[vestig-metrics] Immediate report:', metric.name, metric.value);
|
|
67
|
+
}
|
|
68
|
+
this.sendMetrics([metric]);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Flush all queued metrics
|
|
72
|
+
*/
|
|
73
|
+
flush() {
|
|
74
|
+
if (this.queue.length === 0)
|
|
75
|
+
return;
|
|
76
|
+
const metrics = [...this.queue];
|
|
77
|
+
this.queue = [];
|
|
78
|
+
if (this.config.debug) {
|
|
79
|
+
console.log('[vestig-metrics] Flushing', metrics.length, 'metrics');
|
|
80
|
+
}
|
|
81
|
+
this.sendMetrics(metrics);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Destroy the reporter and clean up
|
|
85
|
+
*/
|
|
86
|
+
destroy() {
|
|
87
|
+
this.isDestroyed = true;
|
|
88
|
+
if (this.flushTimer) {
|
|
89
|
+
clearInterval(this.flushTimer);
|
|
90
|
+
this.flushTimer = null;
|
|
91
|
+
}
|
|
92
|
+
// Final flush
|
|
93
|
+
this.flush();
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Start the batch timer
|
|
97
|
+
*/
|
|
98
|
+
startBatchTimer() {
|
|
99
|
+
this.flushTimer = setInterval(() => {
|
|
100
|
+
this.flush();
|
|
101
|
+
}, this.config.batchInterval);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Set up page unload handler to flush metrics
|
|
105
|
+
*/
|
|
106
|
+
setupUnloadHandler() {
|
|
107
|
+
if (typeof document === 'undefined')
|
|
108
|
+
return;
|
|
109
|
+
const handleVisibilityChange = () => {
|
|
110
|
+
if (document.visibilityState === 'hidden') {
|
|
111
|
+
this.flushWithBeacon();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
// visibilitychange is more reliable than beforeunload
|
|
115
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Flush metrics using sendBeacon (for page unload)
|
|
119
|
+
*/
|
|
120
|
+
flushWithBeacon() {
|
|
121
|
+
if (this.queue.length === 0)
|
|
122
|
+
return;
|
|
123
|
+
const metrics = [...this.queue];
|
|
124
|
+
this.queue = [];
|
|
125
|
+
const payload = this.createPayload(metrics);
|
|
126
|
+
// Use sendBeacon for reliable delivery during page unload
|
|
127
|
+
if (typeof navigator !== 'undefined' && navigator.sendBeacon) {
|
|
128
|
+
const blob = new Blob([JSON.stringify(payload)], { type: 'application/json' });
|
|
129
|
+
navigator.sendBeacon(this.config.endpoint, blob);
|
|
130
|
+
if (this.config.debug) {
|
|
131
|
+
console.log('[vestig-metrics] Beacon sent:', metrics.length, 'metrics');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// Fallback to fetch
|
|
136
|
+
this.sendMetrics(metrics);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Send metrics via fetch
|
|
141
|
+
*/
|
|
142
|
+
async sendMetrics(metrics) {
|
|
143
|
+
if (metrics.length === 0)
|
|
144
|
+
return;
|
|
145
|
+
const payload = this.createPayload(metrics);
|
|
146
|
+
try {
|
|
147
|
+
const response = await fetch(this.config.endpoint, {
|
|
148
|
+
method: 'POST',
|
|
149
|
+
headers: { 'Content-Type': 'application/json' },
|
|
150
|
+
body: JSON.stringify(payload),
|
|
151
|
+
// Use keepalive for reliability during page transitions
|
|
152
|
+
keepalive: true,
|
|
153
|
+
});
|
|
154
|
+
if (!response.ok && this.config.debug) {
|
|
155
|
+
console.error('[vestig-metrics] Report failed:', response.status);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (this.config.debug) {
|
|
160
|
+
console.error('[vestig-metrics] Report error:', error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Create the report payload
|
|
166
|
+
*/
|
|
167
|
+
createPayload(metrics) {
|
|
168
|
+
return {
|
|
169
|
+
metrics,
|
|
170
|
+
client: {
|
|
171
|
+
userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown',
|
|
172
|
+
pathname: typeof window !== 'undefined' ? window.location.pathname : 'unknown',
|
|
173
|
+
timestamp: new Date().toISOString(),
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/metrics/reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Store
|
|
3
|
+
*
|
|
4
|
+
* Simple pub/sub store for performance metrics.
|
|
5
|
+
* Designed for reliability over cleverness - no useSyncExternalStore magic.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { HistogramBucket, MetricEntry, MetricSummary, MetricsState, WebVitalName } from './types';
|
|
10
|
+
type Listener = () => void;
|
|
11
|
+
/**
|
|
12
|
+
* Simple metrics store - no React magic, just data + subscriptions
|
|
13
|
+
*/
|
|
14
|
+
declare class SimpleMetricsStore {
|
|
15
|
+
private state;
|
|
16
|
+
private listeners;
|
|
17
|
+
/**
|
|
18
|
+
* Subscribe to store changes
|
|
19
|
+
*/
|
|
20
|
+
subscribe(listener: Listener): () => void;
|
|
21
|
+
/**
|
|
22
|
+
* Notify all listeners of a change
|
|
23
|
+
*/
|
|
24
|
+
private notify;
|
|
25
|
+
/**
|
|
26
|
+
* Add a new metric to the store
|
|
27
|
+
*/
|
|
28
|
+
addMetric(entry: Omit<MetricEntry, 'id' | 'timestamp'>): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get latest vitals - returns a new object each time (React will handle memoization)
|
|
31
|
+
*/
|
|
32
|
+
getLatestVitals(): Partial<Record<WebVitalName, MetricEntry>>;
|
|
33
|
+
/**
|
|
34
|
+
* Get vitals summary
|
|
35
|
+
*/
|
|
36
|
+
getVitalsSummary(): Partial<Record<WebVitalName, MetricSummary>>;
|
|
37
|
+
/**
|
|
38
|
+
* Get route metrics
|
|
39
|
+
*/
|
|
40
|
+
getRouteMetrics(): MetricEntry[];
|
|
41
|
+
/**
|
|
42
|
+
* Get histogram for a specific metric
|
|
43
|
+
*/
|
|
44
|
+
getHistogram(name: string, bucketCount?: number): HistogramBucket[];
|
|
45
|
+
/**
|
|
46
|
+
* Get summary statistics for a metric
|
|
47
|
+
*/
|
|
48
|
+
getSummary(name: string): MetricSummary | null;
|
|
49
|
+
/**
|
|
50
|
+
* Get the latest metric for a given name
|
|
51
|
+
*/
|
|
52
|
+
getLatest(name: string): MetricEntry | null;
|
|
53
|
+
/**
|
|
54
|
+
* Get current snapshot (for debugging)
|
|
55
|
+
*/
|
|
56
|
+
getSnapshot(): MetricsState;
|
|
57
|
+
/**
|
|
58
|
+
* Clear all metrics
|
|
59
|
+
*/
|
|
60
|
+
clear(): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Global metrics store singleton
|
|
64
|
+
*/
|
|
65
|
+
export declare const metricsStore: SimpleMetricsStore;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=store.d.ts.map
|