@vestig/next 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +290 -0
- package/dist/client/hooks.d.ts +95 -0
- package/dist/client/hooks.d.ts.map +1 -0
- package/dist/client/hooks.js +128 -0
- package/dist/client/hooks.js.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +9 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/provider.d.ts +66 -0
- package/dist/client/provider.d.ts.map +1 -0
- package/dist/client/provider.js +126 -0
- package/dist/client/provider.js.map +1 -0
- package/dist/client/transport.d.ts +59 -0
- package/dist/client/transport.d.ts.map +1 -0
- package/dist/client/transport.js +148 -0
- package/dist/client/transport.js.map +1 -0
- package/dist/client.d.ts +43 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +47 -0
- package/dist/client.js.map +1 -0
- package/dist/config/defaults.d.ts +10 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +72 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +116 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +27 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +21 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +31 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/route/handler.d.ts +56 -0
- package/dist/route/handler.d.ts.map +1 -0
- package/dist/route/handler.js +250 -0
- package/dist/route/handler.js.map +1 -0
- package/dist/route/index.d.ts +2 -0
- package/dist/route/index.d.ts.map +1 -0
- package/dist/route/index.js +3 -0
- package/dist/route/index.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +10 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware.d.ts +108 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/middleware.js +182 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/route-handler.d.ts +93 -0
- package/dist/server/route-handler.d.ts.map +1 -0
- package/dist/server/route-handler.js +160 -0
- package/dist/server/route-handler.js.map +1 -0
- package/dist/server/server-action.d.ts +74 -0
- package/dist/server/server-action.d.ts.map +1 -0
- package/dist/server/server-action.js +132 -0
- package/dist/server/server-action.js.map +1 -0
- package/dist/server/server-component.d.ts +87 -0
- package/dist/server/server-component.d.ts.map +1 -0
- package/dist/server/server-component.js +122 -0
- package/dist/server/server-component.js.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/headers.d.ts +38 -0
- package/dist/utils/headers.d.ts.map +1 -0
- package/dist/utils/headers.js +42 -0
- package/dist/utils/headers.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/metadata.d.ts +41 -0
- package/dist/utils/metadata.d.ts.map +1 -0
- package/dist/utils/metadata.js +46 -0
- package/dist/utils/metadata.js.map +1 -0
- package/dist/utils/timing.d.ts +31 -0
- package/dist/utils/timing.d.ts.map +1 -0
- package/dist/utils/timing.js +46 -0
- package/dist/utils/timing.js.map +1 -0
- package/package.json +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# @vestig/next
|
|
2
|
+
|
|
3
|
+
First-class structured logging for Next.js applications. Built on top of [vestig](https://github.com/your-repo/vestig), this package provides automatic request correlation, middleware integration, and seamless client/server logging.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Automatic Request Correlation** - requestId, traceId, and spanId propagated across all logs
|
|
8
|
+
- **Middleware Integration** - Automatic request/response logging with timing
|
|
9
|
+
- **Server Components** - `getLogger()` with React `cache()` for per-request loggers
|
|
10
|
+
- **Route Handlers** - `withVestig()` wrapper with full context
|
|
11
|
+
- **Server Actions** - `vestigAction()` for action logging
|
|
12
|
+
- **Client Components** - `useLogger()` hook with automatic server sync
|
|
13
|
+
- **PII Sanitization** - All vestig sanitization presets work seamlessly
|
|
14
|
+
- **Edge Runtime Compatible** - Works in Edge middleware and Vercel Edge Functions
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @vestig/next vestig
|
|
20
|
+
# or
|
|
21
|
+
bun add @vestig/next vestig
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### 1. Add Middleware
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// middleware.ts
|
|
30
|
+
import { createVestigMiddleware } from '@vestig/next/middleware'
|
|
31
|
+
|
|
32
|
+
export const middleware = createVestigMiddleware({
|
|
33
|
+
level: 'info',
|
|
34
|
+
skipPaths: ['/_next', '/favicon.ico'],
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export const config = {
|
|
38
|
+
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. Wrap Your Layout
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// app/layout.tsx
|
|
46
|
+
import { VestigProvider } from '@vestig/next/client'
|
|
47
|
+
import { getRequestContext } from '@vestig/next'
|
|
48
|
+
|
|
49
|
+
export default async function RootLayout({
|
|
50
|
+
children,
|
|
51
|
+
}: {
|
|
52
|
+
children: React.ReactNode
|
|
53
|
+
}) {
|
|
54
|
+
const ctx = await getRequestContext()
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<html>
|
|
58
|
+
<body>
|
|
59
|
+
<VestigProvider initialContext={ctx} endpoint="/api/vestig" namespace="client">
|
|
60
|
+
{children}
|
|
61
|
+
</VestigProvider>
|
|
62
|
+
</body>
|
|
63
|
+
</html>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. Add the Vestig API Route (Optional)
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// app/api/vestig/route.ts
|
|
72
|
+
import { createVestigHandler } from '@vestig/next/route'
|
|
73
|
+
|
|
74
|
+
export const { GET, POST, DELETE } = createVestigHandler({
|
|
75
|
+
maxLogs: 500,
|
|
76
|
+
enableSSE: true,
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
### Server Components
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// app/users/page.tsx
|
|
86
|
+
import { getLogger, getRequestContext } from '@vestig/next'
|
|
87
|
+
|
|
88
|
+
export default async function UsersPage() {
|
|
89
|
+
const log = await getLogger('users-page')
|
|
90
|
+
const ctx = await getRequestContext()
|
|
91
|
+
|
|
92
|
+
log.info('Rendering users page', { requestId: ctx.requestId })
|
|
93
|
+
|
|
94
|
+
const users = await fetchUsers()
|
|
95
|
+
log.debug('Users fetched', { count: users.length })
|
|
96
|
+
|
|
97
|
+
return <UserList users={users} />
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Route Handlers
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// app/api/users/route.ts
|
|
105
|
+
import { withVestig } from '@vestig/next'
|
|
106
|
+
|
|
107
|
+
export const GET = withVestig(
|
|
108
|
+
async (request, { log, ctx, timing }) => {
|
|
109
|
+
log.debug('Fetching users from database')
|
|
110
|
+
|
|
111
|
+
const users = await db.users.findMany()
|
|
112
|
+
|
|
113
|
+
log.info('Users fetched', {
|
|
114
|
+
count: users.length,
|
|
115
|
+
duration: `${timing.elapsed().toFixed(2)}ms`,
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
return Response.json({
|
|
119
|
+
users,
|
|
120
|
+
meta: { requestId: ctx.requestId },
|
|
121
|
+
})
|
|
122
|
+
},
|
|
123
|
+
{ namespace: 'api:users', level: 'debug' }
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Client Components
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
'use client'
|
|
131
|
+
import { useLogger, useCorrelationContext } from '@vestig/next/client'
|
|
132
|
+
|
|
133
|
+
export default function UserProfile() {
|
|
134
|
+
const log = useLogger('user-profile')
|
|
135
|
+
const ctx = useCorrelationContext()
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
log.info('Profile loaded', { requestId: ctx.requestId })
|
|
139
|
+
}, [log, ctx.requestId])
|
|
140
|
+
|
|
141
|
+
const handleClick = () => {
|
|
142
|
+
log.info('Button clicked', {
|
|
143
|
+
email: 'user@example.com', // Auto-sanitized!
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return <button onClick={handleClick}>Click me</button>
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Server Actions
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// app/actions/user-actions.ts
|
|
155
|
+
'use server'
|
|
156
|
+
import { vestigAction } from '@vestig/next'
|
|
157
|
+
|
|
158
|
+
export const createUser = vestigAction(
|
|
159
|
+
async (data: { name: string; email: string }, { log, ctx }) => {
|
|
160
|
+
log.debug('Validating user data')
|
|
161
|
+
|
|
162
|
+
const user = await db.users.create({ data })
|
|
163
|
+
log.info('User created', { userId: user.id })
|
|
164
|
+
|
|
165
|
+
return user
|
|
166
|
+
},
|
|
167
|
+
{ namespace: 'actions:createUser' }
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## API Reference
|
|
172
|
+
|
|
173
|
+
### Middleware
|
|
174
|
+
|
|
175
|
+
#### `createVestigMiddleware(options)`
|
|
176
|
+
|
|
177
|
+
Create a middleware with custom configuration.
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
createVestigMiddleware({
|
|
181
|
+
level?: 'trace' | 'debug' | 'info' | 'warn' | 'error',
|
|
182
|
+
enabled?: boolean,
|
|
183
|
+
sanitize?: 'none' | 'minimal' | 'default' | 'gdpr' | 'hipaa' | 'pci-dss',
|
|
184
|
+
namespace?: string,
|
|
185
|
+
skipPaths?: string[],
|
|
186
|
+
timing?: boolean,
|
|
187
|
+
requestLogLevel?: LogLevel,
|
|
188
|
+
responseLogLevel?: LogLevel,
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Server Components
|
|
193
|
+
|
|
194
|
+
#### `getLogger(namespace?)`
|
|
195
|
+
|
|
196
|
+
Get a request-scoped logger in Server Components.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const log = await getLogger('my-component')
|
|
200
|
+
log.info('Hello world')
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### `getRequestContext()`
|
|
204
|
+
|
|
205
|
+
Get the correlation context from the current request.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
const ctx = await getRequestContext()
|
|
209
|
+
// { requestId, traceId, spanId, ... }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Route Handlers
|
|
213
|
+
|
|
214
|
+
#### `withVestig(handler, options)`
|
|
215
|
+
|
|
216
|
+
Wrap a route handler with automatic logging.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
export const GET = withVestig(
|
|
220
|
+
async (request, { log, ctx, timing, params }) => {
|
|
221
|
+
// Your handler logic
|
|
222
|
+
return Response.json({ data })
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
namespace?: string,
|
|
226
|
+
level?: LogLevel,
|
|
227
|
+
sanitize?: SanitizePreset,
|
|
228
|
+
logRequest?: boolean,
|
|
229
|
+
logResponse?: boolean,
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Client Components
|
|
235
|
+
|
|
236
|
+
#### `useLogger(namespace?)`
|
|
237
|
+
|
|
238
|
+
Get a logger instance in Client Components. No `useMemo` needed - the hook returns a stable reference.
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
const log = useLogger('my-component')
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### `useCorrelationContext()`
|
|
245
|
+
|
|
246
|
+
Get the correlation context passed from the server.
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const ctx = useCorrelationContext()
|
|
250
|
+
// { requestId, traceId, spanId }
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### VestigProvider Props
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
<VestigProvider
|
|
257
|
+
initialContext={ctx} // From getRequestContext()
|
|
258
|
+
endpoint="/api/vestig" // Where to send client logs
|
|
259
|
+
namespace="client" // Base namespace for client logs
|
|
260
|
+
level="info" // Minimum log level
|
|
261
|
+
sanitize="default" // PII sanitization preset
|
|
262
|
+
batchSize={10} // Batch size for HTTP transport
|
|
263
|
+
flushInterval={2000} // Flush interval in ms
|
|
264
|
+
>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Log Levels
|
|
268
|
+
|
|
269
|
+
All vestig log levels are supported:
|
|
270
|
+
|
|
271
|
+
- `trace` - Most verbose, for detailed debugging
|
|
272
|
+
- `debug` - Debug information
|
|
273
|
+
- `info` - General information
|
|
274
|
+
- `warn` - Warning messages
|
|
275
|
+
- `error` - Error messages
|
|
276
|
+
|
|
277
|
+
## PII Sanitization
|
|
278
|
+
|
|
279
|
+
All vestig sanitization presets work automatically:
|
|
280
|
+
|
|
281
|
+
- `none` - No sanitization
|
|
282
|
+
- `minimal` - Passwords only
|
|
283
|
+
- `default` - Passwords, credit cards, SSNs
|
|
284
|
+
- `gdpr` - EU GDPR compliance
|
|
285
|
+
- `hipaa` - Healthcare compliance
|
|
286
|
+
- `pci-dss` - Payment card compliance
|
|
287
|
+
|
|
288
|
+
## License
|
|
289
|
+
|
|
290
|
+
MIT
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { LogContext, Logger } from 'vestig';
|
|
2
|
+
/**
|
|
3
|
+
* Get a logger instance in client components
|
|
4
|
+
*
|
|
5
|
+
* Optionally create a child logger with a namespace.
|
|
6
|
+
* No need for useMemo - this hook handles it internally.
|
|
7
|
+
*
|
|
8
|
+
* @param namespace - Optional namespace for the logger
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // components/UserForm.tsx
|
|
13
|
+
* 'use client'
|
|
14
|
+
*
|
|
15
|
+
* import { useLogger } from '@vestig/next/client'
|
|
16
|
+
*
|
|
17
|
+
* export function UserForm() {
|
|
18
|
+
* const log = useLogger('user-form')
|
|
19
|
+
*
|
|
20
|
+
* const handleSubmit = (data: FormData) => {
|
|
21
|
+
* log.info('Form submitted', {
|
|
22
|
+
* email: data.get('email'), // Will be sanitized
|
|
23
|
+
* })
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* return <form onSubmit={handleSubmit}>...</form>
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function useLogger(namespace?: string): Logger;
|
|
31
|
+
/**
|
|
32
|
+
* Get the current correlation context
|
|
33
|
+
*
|
|
34
|
+
* Useful for passing IDs to external services or child components.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const ctx = useCorrelationContext()
|
|
39
|
+
* console.log(ctx.requestId) // "abc-123" or "client-xyz-456"
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function useCorrelationContext(): LogContext;
|
|
43
|
+
/**
|
|
44
|
+
* Check if client logging is connected to server
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const isConnected = useVestigConnection()
|
|
49
|
+
* // Show indicator if logs are being sent successfully
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function useVestigConnection(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Create a component-scoped logger with optional lifecycle logging
|
|
55
|
+
*
|
|
56
|
+
* @param componentName - Name of the component (used as namespace)
|
|
57
|
+
* @param options - Configuration options
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* function Dashboard() {
|
|
62
|
+
* const log = useComponentLogger('Dashboard', { logLifecycle: true })
|
|
63
|
+
* // Logs: "Component mounted" on mount
|
|
64
|
+
* // Logs: "Component unmounting" on unmount
|
|
65
|
+
*
|
|
66
|
+
* return <div>...</div>
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function useComponentLogger(componentName: string, options?: {
|
|
71
|
+
/** Log mount/unmount lifecycle events (default: false) */
|
|
72
|
+
logLifecycle?: boolean;
|
|
73
|
+
/** Additional context to include in all logs */
|
|
74
|
+
context?: Record<string, unknown>;
|
|
75
|
+
}): Logger;
|
|
76
|
+
/**
|
|
77
|
+
* Create a logger that tracks render count
|
|
78
|
+
*
|
|
79
|
+
* Useful for debugging performance issues.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* function ExpensiveComponent() {
|
|
84
|
+
* const { log, renderCount } = useRenderLogger('ExpensiveComponent')
|
|
85
|
+
* // Logs render count on each render
|
|
86
|
+
*
|
|
87
|
+
* return <div>Rendered {renderCount} times</div>
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function useRenderLogger(componentName: string): {
|
|
92
|
+
log: Logger;
|
|
93
|
+
renderCount: number;
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/client/hooks.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGhD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,IAAI,UAAU,CAGlD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAG7C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CACjC,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE;IACR,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC5B,GACJ,MAAM,CAyBR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG;IACvD,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;CACnB,CAWA"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { useVestigContext } from './provider';
|
|
4
|
+
/**
|
|
5
|
+
* Get a logger instance in client components
|
|
6
|
+
*
|
|
7
|
+
* Optionally create a child logger with a namespace.
|
|
8
|
+
* No need for useMemo - this hook handles it internally.
|
|
9
|
+
*
|
|
10
|
+
* @param namespace - Optional namespace for the logger
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* // components/UserForm.tsx
|
|
15
|
+
* 'use client'
|
|
16
|
+
*
|
|
17
|
+
* import { useLogger } from '@vestig/next/client'
|
|
18
|
+
*
|
|
19
|
+
* export function UserForm() {
|
|
20
|
+
* const log = useLogger('user-form')
|
|
21
|
+
*
|
|
22
|
+
* const handleSubmit = (data: FormData) => {
|
|
23
|
+
* log.info('Form submitted', {
|
|
24
|
+
* email: data.get('email'), // Will be sanitized
|
|
25
|
+
* })
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* return <form onSubmit={handleSubmit}>...</form>
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function useLogger(namespace) {
|
|
33
|
+
const { logger } = useVestigContext();
|
|
34
|
+
return useMemo(() => {
|
|
35
|
+
return namespace ? logger.child(namespace) : logger;
|
|
36
|
+
}, [logger, namespace]);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the current correlation context
|
|
40
|
+
*
|
|
41
|
+
* Useful for passing IDs to external services or child components.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const ctx = useCorrelationContext()
|
|
46
|
+
* console.log(ctx.requestId) // "abc-123" or "client-xyz-456"
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function useCorrelationContext() {
|
|
50
|
+
const { context } = useVestigContext();
|
|
51
|
+
return context;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Check if client logging is connected to server
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const isConnected = useVestigConnection()
|
|
59
|
+
* // Show indicator if logs are being sent successfully
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function useVestigConnection() {
|
|
63
|
+
const { isConnected } = useVestigContext();
|
|
64
|
+
return isConnected;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create a component-scoped logger with optional lifecycle logging
|
|
68
|
+
*
|
|
69
|
+
* @param componentName - Name of the component (used as namespace)
|
|
70
|
+
* @param options - Configuration options
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* function Dashboard() {
|
|
75
|
+
* const log = useComponentLogger('Dashboard', { logLifecycle: true })
|
|
76
|
+
* // Logs: "Component mounted" on mount
|
|
77
|
+
* // Logs: "Component unmounting" on unmount
|
|
78
|
+
*
|
|
79
|
+
* return <div>...</div>
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function useComponentLogger(componentName, options = {}) {
|
|
84
|
+
const { logger } = useVestigContext();
|
|
85
|
+
const { logLifecycle = false, context } = options;
|
|
86
|
+
const log = useMemo(() => {
|
|
87
|
+
return logger.child(componentName, context ? { context } : undefined);
|
|
88
|
+
}, [logger, componentName, context]);
|
|
89
|
+
// Track if this is initial mount
|
|
90
|
+
const isMounted = useRef(false);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (logLifecycle && !isMounted.current) {
|
|
93
|
+
log.debug('Component mounted');
|
|
94
|
+
isMounted.current = true;
|
|
95
|
+
}
|
|
96
|
+
return () => {
|
|
97
|
+
if (logLifecycle) {
|
|
98
|
+
log.debug('Component unmounting');
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}, [log, logLifecycle]);
|
|
102
|
+
return log;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create a logger that tracks render count
|
|
106
|
+
*
|
|
107
|
+
* Useful for debugging performance issues.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* function ExpensiveComponent() {
|
|
112
|
+
* const { log, renderCount } = useRenderLogger('ExpensiveComponent')
|
|
113
|
+
* // Logs render count on each render
|
|
114
|
+
*
|
|
115
|
+
* return <div>Rendered {renderCount} times</div>
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export function useRenderLogger(componentName) {
|
|
120
|
+
const log = useLogger(componentName);
|
|
121
|
+
const renderCount = useRef(0);
|
|
122
|
+
renderCount.current += 1;
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
log.trace('Component rendered', { renderCount: renderCount.current });
|
|
125
|
+
});
|
|
126
|
+
return { log, renderCount: renderCount.current };
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/client/hooks.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,SAAS,CAAC,SAAkB;IAC3C,MAAM,EAAE,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAA;IAErC,OAAO,OAAO,CAAC,GAAG,EAAE;QACnB,OAAO,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;IACpD,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;AACxB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB;IACpC,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACtC,OAAO,OAAO,CAAA;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB;IAClC,MAAM,EAAE,WAAW,EAAE,GAAG,gBAAgB,EAAE,CAAA;IAC1C,OAAO,WAAW,CAAA;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,kBAAkB,CACjC,aAAqB,EACrB,UAKI,EAAE;IAEN,MAAM,EAAE,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACrC,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAEjD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;QACxB,OAAO,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACtE,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC,CAAA;IAEpC,iCAAiC;IACjC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAE/B,SAAS,CAAC,GAAG,EAAE;QACd,IAAI,YAAY,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACxC,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAA;YAC9B,SAAS,CAAC,OAAO,GAAG,IAAI,CAAA;QACzB,CAAC;QAED,OAAO,GAAG,EAAE;YACX,IAAI,YAAY,EAAE,CAAC;gBAClB,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAA;YAClC,CAAC;QACF,CAAC,CAAA;IACF,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAA;IAEvB,OAAO,GAAG,CAAA;AACX,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAAC,aAAqB;IAIpD,MAAM,GAAG,GAAG,SAAS,CAAC,aAAa,CAAC,CAAA;IACpC,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IAE7B,WAAW,CAAC,OAAO,IAAI,CAAC,CAAA;IAExB,SAAS,CAAC,GAAG,EAAE;QACd,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,OAAO,EAAE,CAAA;AACjD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { VestigProvider, useVestigContext, type VestigProviderProps } from './provider';
|
|
2
|
+
export { useLogger, useCorrelationContext, useVestigConnection, useComponentLogger, useRenderLogger, } from './hooks';
|
|
3
|
+
export { ClientHTTPTransport, createClientTransport, type ClientHTTPTransportConfig, } from './transport';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGvF,OAAO,EACN,SAAS,EACT,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GACf,MAAM,SAAS,CAAA;AAGhB,OAAO,EACN,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,yBAAyB,GAC9B,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
// Client-side exports for @vestig/next/client
|
|
3
|
+
// Provider
|
|
4
|
+
export { VestigProvider, useVestigContext } from './provider';
|
|
5
|
+
// Hooks
|
|
6
|
+
export { useLogger, useCorrelationContext, useVestigConnection, useComponentLogger, useRenderLogger, } from './hooks';
|
|
7
|
+
// Transport (for advanced use cases)
|
|
8
|
+
export { ClientHTTPTransport, createClientTransport, } from './transport';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,8CAA8C;AAE9C,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAA4B,MAAM,YAAY,CAAA;AAEvF,QAAQ;AACR,OAAO,EACN,SAAS,EACT,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GACf,MAAM,SAAS,CAAA;AAEhB,qCAAqC;AACrC,OAAO,EACN,mBAAmB,EACnB,qBAAqB,GAErB,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type LogContext, type Logger } from 'vestig';
|
|
3
|
+
/**
|
|
4
|
+
* Context value provided by VestigProvider
|
|
5
|
+
*/
|
|
6
|
+
interface VestigContextValue {
|
|
7
|
+
/** Logger instance */
|
|
8
|
+
logger: Logger;
|
|
9
|
+
/** Correlation context */
|
|
10
|
+
context: LogContext;
|
|
11
|
+
/** Whether client is connected to server */
|
|
12
|
+
isConnected: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Props for VestigProvider
|
|
16
|
+
*/
|
|
17
|
+
export interface VestigProviderProps {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
/** Initial correlation context (e.g., from server) */
|
|
20
|
+
initialContext?: LogContext;
|
|
21
|
+
/** Override endpoint URL (default: '/api/vestig') */
|
|
22
|
+
endpoint?: string;
|
|
23
|
+
/** Logger namespace (default: 'client') */
|
|
24
|
+
namespace?: string;
|
|
25
|
+
/** Additional static context */
|
|
26
|
+
context?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Provider component for client-side vestig logging
|
|
30
|
+
*
|
|
31
|
+
* Provides:
|
|
32
|
+
* - Automatic log batching and sending to server
|
|
33
|
+
* - Request correlation with server
|
|
34
|
+
* - React context for accessing logger
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // app/layout.tsx
|
|
39
|
+
* import { VestigProvider } from '@vestig/next/client'
|
|
40
|
+
* import { getRequestContext } from '@vestig/next'
|
|
41
|
+
*
|
|
42
|
+
* export default async function RootLayout({ children }) {
|
|
43
|
+
* // Get server context for correlation
|
|
44
|
+
* const ctx = await getRequestContext()
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <html>
|
|
48
|
+
* <body>
|
|
49
|
+
* <VestigProvider initialContext={ctx}>
|
|
50
|
+
* {children}
|
|
51
|
+
* </VestigProvider>
|
|
52
|
+
* </body>
|
|
53
|
+
* </html>
|
|
54
|
+
* )
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function VestigProvider({ children, initialContext, endpoint, namespace, context: staticContext, }: VestigProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
59
|
+
/**
|
|
60
|
+
* Get the full vestig context
|
|
61
|
+
*
|
|
62
|
+
* @throws Error if used outside VestigProvider
|
|
63
|
+
*/
|
|
64
|
+
export declare function useVestigContext(): VestigContextValue;
|
|
65
|
+
export {};
|
|
66
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/client/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,SAAS,EAOd,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,MAAM,EAAgB,MAAM,QAAQ,CAAA;AAGnE;;GAEG;AACH,UAAU,kBAAkB;IAC3B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,0BAA0B;IAC1B,OAAO,EAAE,UAAU,CAAA;IACnB,4CAA4C;IAC5C,WAAW,EAAE,OAAO,CAAA;CACpB;AAID;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,SAAS,CAAA;IACnB,sDAAsD;IACtD,cAAc,CAAC,EAAE,UAAU,CAAA;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC;AASD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAAC,EAC9B,QAAQ,EACR,cAAc,EACd,QAAwB,EACxB,SAAoB,EACpB,OAAO,EAAE,aAAa,GACtB,EAAE,mBAAmB,2CAyFrB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,kBAAkB,CAMrD"}
|