@vestig/next 0.11.4 → 0.13.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/dist/client/error-boundary.d.ts +22 -0
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +89 -2
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/provider.d.ts +2 -0
- package/dist/client/provider.d.ts.map +1 -1
- package/dist/client/provider.js +16 -2
- package/dist/client/provider.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/query-logger.d.ts +6 -0
- package/dist/db/query-logger.d.ts.map +1 -1
- package/dist/db/query-logger.js +77 -7
- package/dist/db/query-logger.js.map +1 -1
- package/dist/wide-events/context.d.ts +73 -0
- package/dist/wide-events/context.d.ts.map +1 -0
- package/dist/wide-events/context.js +86 -0
- package/dist/wide-events/context.js.map +1 -0
- package/dist/wide-events/helpers.d.ts +138 -0
- package/dist/wide-events/helpers.d.ts.map +1 -0
- package/dist/wide-events/helpers.js +182 -0
- package/dist/wide-events/helpers.js.map +1 -0
- package/dist/wide-events/index.d.ts +63 -0
- package/dist/wide-events/index.d.ts.map +1 -0
- package/dist/wide-events/index.js +67 -0
- package/dist/wide-events/index.js.map +1 -0
- package/dist/wide-events/middleware.d.ts +65 -0
- package/dist/wide-events/middleware.d.ts.map +1 -0
- package/dist/wide-events/middleware.js +160 -0
- package/dist/wide-events/middleware.js.map +1 -0
- package/dist/wide-events/server-action.d.ts +91 -0
- package/dist/wide-events/server-action.d.ts.map +1 -0
- package/dist/wide-events/server-action.js +158 -0
- package/dist/wide-events/server-action.js.map +1 -0
- package/package.json +9 -2
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { createCorrelationContext, createLogger, createTraceparent, createWideEvent, parseTraceparent, } from 'vestig';
|
|
3
|
+
import { CORRELATION_HEADERS } from '../utils/headers';
|
|
4
|
+
import { runWithWideEvent } from './context';
|
|
5
|
+
const DEFAULT_OPTIONS = {
|
|
6
|
+
level: 'info',
|
|
7
|
+
enabled: true,
|
|
8
|
+
sanitize: 'default',
|
|
9
|
+
skipPaths: ['/_next', '/favicon.ico', '/api/vestig'],
|
|
10
|
+
requestIdHeader: CORRELATION_HEADERS.REQUEST_ID,
|
|
11
|
+
structured: true,
|
|
12
|
+
};
|
|
13
|
+
// Cached logger per middleware instance
|
|
14
|
+
const loggerCache = new WeakMap();
|
|
15
|
+
function getOrCreateLogger(options) {
|
|
16
|
+
const cached = loggerCache.get(options);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
const logger = createLogger({
|
|
20
|
+
level: options.level,
|
|
21
|
+
enabled: options.enabled,
|
|
22
|
+
sanitize: options.sanitize,
|
|
23
|
+
structured: options.structured,
|
|
24
|
+
tailSampling: options.tailSampling,
|
|
25
|
+
});
|
|
26
|
+
loggerCache.set(options, logger);
|
|
27
|
+
return logger;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create wide event middleware for Next.js
|
|
31
|
+
*
|
|
32
|
+
* This middleware automatically creates a wide event for each request
|
|
33
|
+
* and populates it with HTTP context. The wide event is available
|
|
34
|
+
* throughout the request lifecycle via `getWideEvent()`.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // middleware.ts
|
|
39
|
+
* import { createWideEventMiddleware } from '@vestig/next/wide-events'
|
|
40
|
+
*
|
|
41
|
+
* export const middleware = createWideEventMiddleware({
|
|
42
|
+
* skipPaths: ['/health', '/metrics'],
|
|
43
|
+
* tailSampling: {
|
|
44
|
+
* enabled: true,
|
|
45
|
+
* alwaysKeepStatuses: ['error'],
|
|
46
|
+
* slowThresholdMs: 2000,
|
|
47
|
+
* successSampleRate: 0.1,
|
|
48
|
+
* },
|
|
49
|
+
* })
|
|
50
|
+
*
|
|
51
|
+
* export const config = {
|
|
52
|
+
* matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export function createWideEventMiddleware(options = {}) {
|
|
57
|
+
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
58
|
+
return async function wideEventMiddleware(request) {
|
|
59
|
+
// Skip configured paths
|
|
60
|
+
const pathname = request.nextUrl.pathname;
|
|
61
|
+
const skipPaths = mergedOptions.skipPaths ?? DEFAULT_OPTIONS.skipPaths ?? [];
|
|
62
|
+
if (skipPaths.some((p) => pathname.startsWith(p))) {
|
|
63
|
+
return NextResponse.next();
|
|
64
|
+
}
|
|
65
|
+
const logger = getOrCreateLogger(mergedOptions);
|
|
66
|
+
const startTime = performance.now();
|
|
67
|
+
// Extract or generate correlation context
|
|
68
|
+
const requestIdHeader = mergedOptions.requestIdHeader ??
|
|
69
|
+
DEFAULT_OPTIONS.requestIdHeader ??
|
|
70
|
+
CORRELATION_HEADERS.REQUEST_ID;
|
|
71
|
+
const existingRequestId = request.headers.get(requestIdHeader) ?? undefined;
|
|
72
|
+
const traceparent = request.headers.get(CORRELATION_HEADERS.TRACEPARENT);
|
|
73
|
+
const parsed = traceparent ? parseTraceparent(traceparent) : null;
|
|
74
|
+
const ctx = createCorrelationContext({
|
|
75
|
+
requestId: existingRequestId,
|
|
76
|
+
traceId: parsed?.traceId,
|
|
77
|
+
spanId: parsed?.spanId,
|
|
78
|
+
});
|
|
79
|
+
// Create wide event for this request
|
|
80
|
+
const event = createWideEvent({
|
|
81
|
+
type: 'http.request',
|
|
82
|
+
context: {
|
|
83
|
+
requestId: ctx.requestId,
|
|
84
|
+
traceId: ctx.traceId,
|
|
85
|
+
spanId: ctx.spanId,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
// Populate initial HTTP context
|
|
89
|
+
event.merge('http', {
|
|
90
|
+
method: request.method,
|
|
91
|
+
path: pathname,
|
|
92
|
+
search: request.nextUrl.search || undefined,
|
|
93
|
+
host: request.headers.get('host'),
|
|
94
|
+
});
|
|
95
|
+
// Add user context from headers if available
|
|
96
|
+
const userAgent = request.headers.get('user-agent');
|
|
97
|
+
const ip = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??
|
|
98
|
+
request.headers.get('x-real-ip');
|
|
99
|
+
if (userAgent || ip) {
|
|
100
|
+
event.merge('client', {
|
|
101
|
+
userAgent: userAgent?.slice(0, 200),
|
|
102
|
+
ip,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
// Create request context
|
|
106
|
+
const eventContext = {
|
|
107
|
+
event,
|
|
108
|
+
startTime,
|
|
109
|
+
};
|
|
110
|
+
// Run middleware with wide event context
|
|
111
|
+
// These are guaranteed to exist from createCorrelationContext
|
|
112
|
+
const requestId = ctx.requestId ?? '';
|
|
113
|
+
const traceId = ctx.traceId ?? '';
|
|
114
|
+
const spanId = ctx.spanId ?? '';
|
|
115
|
+
return runWithWideEvent(eventContext, () => {
|
|
116
|
+
// Create new headers with correlation IDs
|
|
117
|
+
const requestHeaders = new Headers(request.headers);
|
|
118
|
+
requestHeaders.set(CORRELATION_HEADERS.REQUEST_ID, requestId);
|
|
119
|
+
requestHeaders.set(CORRELATION_HEADERS.TRACE_ID, traceId);
|
|
120
|
+
requestHeaders.set(CORRELATION_HEADERS.SPAN_ID, spanId);
|
|
121
|
+
requestHeaders.set(CORRELATION_HEADERS.TRACEPARENT, createTraceparent(traceId, spanId));
|
|
122
|
+
// Create response with updated headers
|
|
123
|
+
const response = NextResponse.next({
|
|
124
|
+
request: {
|
|
125
|
+
headers: requestHeaders,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
// Add correlation headers to response
|
|
129
|
+
response.headers.set(CORRELATION_HEADERS.REQUEST_ID, requestId);
|
|
130
|
+
response.headers.set(CORRELATION_HEADERS.TRACE_ID, traceId);
|
|
131
|
+
// Complete the wide event
|
|
132
|
+
const duration = performance.now() - startTime;
|
|
133
|
+
// Add final timing
|
|
134
|
+
event.set('performance', 'duration_ms', duration);
|
|
135
|
+
// End and emit the wide event
|
|
136
|
+
const completedEvent = event.end({
|
|
137
|
+
status: 'success',
|
|
138
|
+
level: 'info',
|
|
139
|
+
});
|
|
140
|
+
// Emit through the logger (applies tail sampling if configured)
|
|
141
|
+
logger.emitWideEvent(completedEvent);
|
|
142
|
+
return response;
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Pre-configured wide event middleware for direct export
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* // middleware.ts
|
|
152
|
+
* export { wideEventMiddleware as middleware } from '@vestig/next/wide-events'
|
|
153
|
+
*
|
|
154
|
+
* export const config = {
|
|
155
|
+
* matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export const wideEventMiddleware = createWideEventMiddleware();
|
|
160
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/wide-events/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type LogLevel, type SanitizePreset, type TailSamplingConfig, createWideEvent } from 'vestig';
|
|
2
|
+
/**
|
|
3
|
+
* Options for wide event server actions
|
|
4
|
+
*/
|
|
5
|
+
export interface WideEventActionOptions {
|
|
6
|
+
/** Action name (used as event type) */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Log level */
|
|
9
|
+
level?: LogLevel;
|
|
10
|
+
/** Enable/disable wide event emission */
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
/** PII sanitization preset */
|
|
13
|
+
sanitize?: SanitizePreset;
|
|
14
|
+
/** Use structured JSON output */
|
|
15
|
+
structured?: boolean;
|
|
16
|
+
/** Tail sampling configuration */
|
|
17
|
+
tailSampling?: TailSamplingConfig;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Context provided to wide event actions
|
|
21
|
+
*/
|
|
22
|
+
export interface WideEventActionContext {
|
|
23
|
+
/** The wide event builder for this action */
|
|
24
|
+
event: ReturnType<typeof createWideEvent>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Server action handler type with wide event context
|
|
28
|
+
*/
|
|
29
|
+
export type WideEventServerAction<TInput, TResult> = (input: TInput, ctx: WideEventActionContext) => Promise<TResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Wrap a server action with wide event tracking.
|
|
32
|
+
*
|
|
33
|
+
* If called within an existing wide event context (e.g., from middleware),
|
|
34
|
+
* it will enrich that event. Otherwise, it creates a new wide event.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // app/actions/user.ts
|
|
39
|
+
* 'use server'
|
|
40
|
+
*
|
|
41
|
+
* import { withWideEvent } from '@vestig/next/wide-events'
|
|
42
|
+
*
|
|
43
|
+
* export const createUser = withWideEvent(
|
|
44
|
+
* async (data: CreateUserInput, { event }) => {
|
|
45
|
+
* event.set('action', 'type', 'user.create')
|
|
46
|
+
* event.set('user', 'email', data.email)
|
|
47
|
+
*
|
|
48
|
+
* const user = await db.users.create({ data })
|
|
49
|
+
*
|
|
50
|
+
* event.set('user', 'id', user.id)
|
|
51
|
+
* return user
|
|
52
|
+
* },
|
|
53
|
+
* { name: 'action.user.create' }
|
|
54
|
+
* )
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function withWideEvent<TInput, TResult>(handler: WideEventServerAction<TInput, TResult>, options?: WideEventActionOptions): (input: TInput) => Promise<TResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Create a factory for wide event server actions with shared options.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* // app/actions/index.ts
|
|
64
|
+
* import { createWideEventAction } from '@vestig/next/wide-events'
|
|
65
|
+
*
|
|
66
|
+
* const action = createWideEventAction({
|
|
67
|
+
* tailSampling: {
|
|
68
|
+
* enabled: true,
|
|
69
|
+
* successSampleRate: 0.1,
|
|
70
|
+
* },
|
|
71
|
+
* })
|
|
72
|
+
*
|
|
73
|
+
* export const createUser = action(
|
|
74
|
+
* async (data, { event }) => {
|
|
75
|
+
* event.set('user', 'email', data.email)
|
|
76
|
+
* return await db.users.create({ data })
|
|
77
|
+
* },
|
|
78
|
+
* { name: 'action.user.create' }
|
|
79
|
+
* )
|
|
80
|
+
*
|
|
81
|
+
* export const updateUser = action(
|
|
82
|
+
* async ({ id, data }, { event }) => {
|
|
83
|
+
* event.set('user', 'id', id)
|
|
84
|
+
* return await db.users.update({ where: { id }, data })
|
|
85
|
+
* },
|
|
86
|
+
* { name: 'action.user.update' }
|
|
87
|
+
* )
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function createWideEventAction(defaultOptions?: WideEventActionOptions): <TInput, TResult>(handler: WideEventServerAction<TInput, TResult>, options?: WideEventActionOptions) => ((input: TInput) => Promise<TResult>);
|
|
91
|
+
//# sourceMappingURL=server-action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-action.d.ts","sourceRoot":"","sources":["../../src/wide-events/server-action.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,QAAQ,EAEb,KAAK,cAAc,EACnB,KAAK,kBAAkB,EAEvB,eAAe,EACf,MAAM,QAAQ,CAAA;AAGf;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gBAAgB;IAChB,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,iCAAiC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kCAAkC;IAClC,YAAY,CAAC,EAAE,kBAAkB,CAAA;CACjC;AAgCD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,6CAA6C;IAC7C,KAAK,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;CACzC;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAAC,MAAM,EAAE,OAAO,IAAI,CACpD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,sBAAsB,KACvB,OAAO,CAAC,OAAO,CAAC,CAAA;AAErB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,EAC5C,OAAO,EAAE,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/C,OAAO,GAAE,sBAA2B,GAClC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAmFrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,qBAAqB,CAAC,cAAc,GAAE,sBAA2B,IACxE,MAAM,EAAE,OAAO,EACtB,SAAS,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/C,UAAS,sBAA2B,KAClC,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAExC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { createLogger, createWideEvent, } from 'vestig';
|
|
2
|
+
import { getWideEvent, runWithWideEventAsync } from './context';
|
|
3
|
+
const DEFAULT_OPTIONS = {
|
|
4
|
+
level: 'info',
|
|
5
|
+
enabled: true,
|
|
6
|
+
sanitize: 'default',
|
|
7
|
+
structured: true,
|
|
8
|
+
};
|
|
9
|
+
// Cached logger
|
|
10
|
+
let cachedLogger = null;
|
|
11
|
+
function getOrCreateLogger(options) {
|
|
12
|
+
if (cachedLogger && options === DEFAULT_OPTIONS) {
|
|
13
|
+
return cachedLogger;
|
|
14
|
+
}
|
|
15
|
+
const logger = createLogger({
|
|
16
|
+
level: options.level,
|
|
17
|
+
enabled: options.enabled,
|
|
18
|
+
sanitize: options.sanitize,
|
|
19
|
+
structured: options.structured,
|
|
20
|
+
tailSampling: options.tailSampling,
|
|
21
|
+
});
|
|
22
|
+
if (options === DEFAULT_OPTIONS) {
|
|
23
|
+
cachedLogger = logger;
|
|
24
|
+
}
|
|
25
|
+
return logger;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Wrap a server action with wide event tracking.
|
|
29
|
+
*
|
|
30
|
+
* If called within an existing wide event context (e.g., from middleware),
|
|
31
|
+
* it will enrich that event. Otherwise, it creates a new wide event.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* // app/actions/user.ts
|
|
36
|
+
* 'use server'
|
|
37
|
+
*
|
|
38
|
+
* import { withWideEvent } from '@vestig/next/wide-events'
|
|
39
|
+
*
|
|
40
|
+
* export const createUser = withWideEvent(
|
|
41
|
+
* async (data: CreateUserInput, { event }) => {
|
|
42
|
+
* event.set('action', 'type', 'user.create')
|
|
43
|
+
* event.set('user', 'email', data.email)
|
|
44
|
+
*
|
|
45
|
+
* const user = await db.users.create({ data })
|
|
46
|
+
*
|
|
47
|
+
* event.set('user', 'id', user.id)
|
|
48
|
+
* return user
|
|
49
|
+
* },
|
|
50
|
+
* { name: 'action.user.create' }
|
|
51
|
+
* )
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export function withWideEvent(handler, options = {}) {
|
|
55
|
+
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
56
|
+
return async (input) => {
|
|
57
|
+
const startTime = performance.now();
|
|
58
|
+
const logger = getOrCreateLogger(mergedOptions);
|
|
59
|
+
// Check if we're already in a wide event context
|
|
60
|
+
const existingEvent = getWideEvent();
|
|
61
|
+
if (existingEvent) {
|
|
62
|
+
// Enrich existing event with action context
|
|
63
|
+
const actionName = mergedOptions.name ?? 'server-action';
|
|
64
|
+
existingEvent.set('action', 'name', actionName);
|
|
65
|
+
existingEvent.set('action', 'start_ms', performance.now() - startTime);
|
|
66
|
+
try {
|
|
67
|
+
const result = await handler(input, { event: existingEvent });
|
|
68
|
+
existingEvent.set('action', 'duration_ms', performance.now() - startTime);
|
|
69
|
+
existingEvent.set('action', 'status', 'success');
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
existingEvent.set('action', 'duration_ms', performance.now() - startTime);
|
|
74
|
+
existingEvent.set('action', 'status', 'error');
|
|
75
|
+
existingEvent.merge('error', {
|
|
76
|
+
name: error instanceof Error ? error.name : 'Error',
|
|
77
|
+
message: error instanceof Error ? error.message : String(error),
|
|
78
|
+
});
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Create new wide event for this action
|
|
83
|
+
const actionName = mergedOptions.name ?? 'server-action';
|
|
84
|
+
const event = createWideEvent({
|
|
85
|
+
type: actionName,
|
|
86
|
+
});
|
|
87
|
+
event.set('action', 'name', actionName);
|
|
88
|
+
const eventContext = {
|
|
89
|
+
event,
|
|
90
|
+
startTime,
|
|
91
|
+
};
|
|
92
|
+
return runWithWideEventAsync(eventContext, async () => {
|
|
93
|
+
try {
|
|
94
|
+
const result = await handler(input, { event });
|
|
95
|
+
// Complete and emit the wide event
|
|
96
|
+
const duration = performance.now() - startTime;
|
|
97
|
+
event.set('performance', 'duration_ms', duration);
|
|
98
|
+
const completedEvent = event.end({
|
|
99
|
+
status: 'success',
|
|
100
|
+
level: 'info',
|
|
101
|
+
});
|
|
102
|
+
logger.emitWideEvent(completedEvent);
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const duration = performance.now() - startTime;
|
|
107
|
+
event.set('performance', 'duration_ms', duration);
|
|
108
|
+
event.merge('error', {
|
|
109
|
+
name: error instanceof Error ? error.name : 'Error',
|
|
110
|
+
message: error instanceof Error ? error.message : String(error),
|
|
111
|
+
});
|
|
112
|
+
const completedEvent = event.end({
|
|
113
|
+
status: 'error',
|
|
114
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
115
|
+
level: 'error',
|
|
116
|
+
});
|
|
117
|
+
logger.emitWideEvent(completedEvent);
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Create a factory for wide event server actions with shared options.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* // app/actions/index.ts
|
|
129
|
+
* import { createWideEventAction } from '@vestig/next/wide-events'
|
|
130
|
+
*
|
|
131
|
+
* const action = createWideEventAction({
|
|
132
|
+
* tailSampling: {
|
|
133
|
+
* enabled: true,
|
|
134
|
+
* successSampleRate: 0.1,
|
|
135
|
+
* },
|
|
136
|
+
* })
|
|
137
|
+
*
|
|
138
|
+
* export const createUser = action(
|
|
139
|
+
* async (data, { event }) => {
|
|
140
|
+
* event.set('user', 'email', data.email)
|
|
141
|
+
* return await db.users.create({ data })
|
|
142
|
+
* },
|
|
143
|
+
* { name: 'action.user.create' }
|
|
144
|
+
* )
|
|
145
|
+
*
|
|
146
|
+
* export const updateUser = action(
|
|
147
|
+
* async ({ id, data }, { event }) => {
|
|
148
|
+
* event.set('user', 'id', id)
|
|
149
|
+
* return await db.users.update({ where: { id }, data })
|
|
150
|
+
* },
|
|
151
|
+
* { name: 'action.user.update' }
|
|
152
|
+
* )
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export function createWideEventAction(defaultOptions = {}) {
|
|
156
|
+
return (handler, options = {}) => withWideEvent(handler, { ...defaultOptions, ...options });
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=server-action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-action.js","sourceRoot":"","sources":["../../src/wide-events/server-action.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vestig/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "First-class Next.js 15+ integration for vestig logging library. Zero boilerplate, automatic request correlation, full type safety.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,6 +45,10 @@
|
|
|
45
45
|
"./db": {
|
|
46
46
|
"types": "./dist/db/index.d.ts",
|
|
47
47
|
"import": "./dist/db/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./wide-events": {
|
|
50
|
+
"types": "./dist/wide-events/index.d.ts",
|
|
51
|
+
"import": "./dist/wide-events/index.js"
|
|
48
52
|
}
|
|
49
53
|
},
|
|
50
54
|
"files": ["dist"],
|
|
@@ -70,7 +74,10 @@
|
|
|
70
74
|
"typescript",
|
|
71
75
|
"request-correlation",
|
|
72
76
|
"tracing",
|
|
73
|
-
"observability"
|
|
77
|
+
"observability",
|
|
78
|
+
"wide-events",
|
|
79
|
+
"canonical-log-lines",
|
|
80
|
+
"tail-sampling"
|
|
74
81
|
],
|
|
75
82
|
"author": "Arakiss",
|
|
76
83
|
"license": "MIT",
|