evlog 1.4.0 → 1.6.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 +17 -0
- package/dist/adapters/axiom.mjs +2 -8
- package/dist/adapters/otlp.mjs +2 -8
- package/dist/adapters/posthog.d.mts +72 -0
- package/dist/adapters/posthog.d.ts +72 -0
- package/dist/adapters/posthog.mjs +73 -0
- package/dist/adapters/sentry.d.mts +78 -0
- package/dist/adapters/sentry.d.ts +78 -0
- package/dist/adapters/sentry.mjs +176 -0
- package/dist/index.mjs +0 -1
- package/dist/logger.mjs +18 -3
- package/dist/nitro/plugin.mjs +9 -5
- package/dist/nuxt/module.d.mts +46 -0
- package/dist/nuxt/module.d.ts +46 -0
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +0 -1
- package/dist/shared/evlog.Bc35pxiY.mjs +10 -0
- package/dist/workers.mjs +0 -1
- package/package.json +21 -7
package/README.md
CHANGED
|
@@ -431,6 +431,23 @@ Set environment variables:
|
|
|
431
431
|
NUXT_OTLP_ENDPOINT=http://localhost:4318
|
|
432
432
|
```
|
|
433
433
|
|
|
434
|
+
### Sentry
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
// server/plugins/evlog-drain.ts
|
|
438
|
+
import { createSentryDrain } from 'evlog/sentry'
|
|
439
|
+
|
|
440
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
441
|
+
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
|
|
442
|
+
})
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Set environment variables:
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
|
|
449
|
+
```
|
|
450
|
+
|
|
434
451
|
### Multiple Destinations
|
|
435
452
|
|
|
436
453
|
Send logs to multiple services:
|
package/dist/adapters/axiom.mjs
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { useRuntimeConfig } = require("nitropack/runtime");
|
|
4
|
-
return useRuntimeConfig();
|
|
5
|
-
} catch {
|
|
6
|
-
return void 0;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
9
3
|
function createAxiomDrain(overrides) {
|
|
10
4
|
return async (ctx) => {
|
|
11
5
|
const runtimeConfig = getRuntimeConfig();
|
package/dist/adapters/otlp.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
1
3
|
const SEVERITY_MAP = {
|
|
2
4
|
debug: 5,
|
|
3
5
|
// DEBUG
|
|
@@ -14,14 +16,6 @@ const SEVERITY_TEXT_MAP = {
|
|
|
14
16
|
warn: "WARN",
|
|
15
17
|
error: "ERROR"
|
|
16
18
|
};
|
|
17
|
-
function getRuntimeConfig() {
|
|
18
|
-
try {
|
|
19
|
-
const { useRuntimeConfig } = require("nitropack/runtime");
|
|
20
|
-
return useRuntimeConfig();
|
|
21
|
-
} catch {
|
|
22
|
-
return void 0;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
19
|
function toAttributeValue(value) {
|
|
26
20
|
if (typeof value === "boolean") {
|
|
27
21
|
return { boolValue: value };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.mjs';
|
|
2
|
+
|
|
3
|
+
interface PostHogConfig {
|
|
4
|
+
/** PostHog project API key */
|
|
5
|
+
apiKey: string;
|
|
6
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
7
|
+
host?: string;
|
|
8
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
9
|
+
eventName?: string;
|
|
10
|
+
/** Override distinct_id (defaults to event.service) */
|
|
11
|
+
distinctId?: string;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** PostHog event structure for the batch API */
|
|
16
|
+
interface PostHogEvent {
|
|
17
|
+
event: string;
|
|
18
|
+
distinct_id: string;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
properties: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert a WideEvent to a PostHog event format.
|
|
24
|
+
*/
|
|
25
|
+
declare function toPostHogEvent(event: WideEvent, config: PostHogConfig): PostHogEvent;
|
|
26
|
+
/**
|
|
27
|
+
* Create a drain function for sending logs to PostHog.
|
|
28
|
+
*
|
|
29
|
+
* Configuration priority (highest to lowest):
|
|
30
|
+
* 1. Overrides passed to createPostHogDrain()
|
|
31
|
+
* 2. runtimeConfig.evlog.posthog
|
|
32
|
+
* 3. runtimeConfig.posthog
|
|
33
|
+
* 4. Environment variables: NUXT_POSTHOG_*, POSTHOG_*
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Zero config - just set NUXT_POSTHOG_API_KEY env var
|
|
38
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain())
|
|
39
|
+
*
|
|
40
|
+
* // With overrides
|
|
41
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain({
|
|
42
|
+
* apiKey: 'phc_...',
|
|
43
|
+
* host: 'https://eu.i.posthog.com',
|
|
44
|
+
* }))
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function createPostHogDrain(overrides?: Partial<PostHogConfig>): (ctx: DrainContext) => Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Send a single event to PostHog.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* await sendToPostHog(event, {
|
|
54
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function sendToPostHog(event: WideEvent, config: PostHogConfig): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Send a batch of events to PostHog.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* await sendBatchToPostHog(events, {
|
|
65
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function sendBatchToPostHog(events: WideEvent[], config: PostHogConfig): Promise<void>;
|
|
70
|
+
|
|
71
|
+
export { createPostHogDrain, sendBatchToPostHog, sendToPostHog, toPostHogEvent };
|
|
72
|
+
export type { PostHogConfig, PostHogEvent };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.js';
|
|
2
|
+
|
|
3
|
+
interface PostHogConfig {
|
|
4
|
+
/** PostHog project API key */
|
|
5
|
+
apiKey: string;
|
|
6
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
7
|
+
host?: string;
|
|
8
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
9
|
+
eventName?: string;
|
|
10
|
+
/** Override distinct_id (defaults to event.service) */
|
|
11
|
+
distinctId?: string;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** PostHog event structure for the batch API */
|
|
16
|
+
interface PostHogEvent {
|
|
17
|
+
event: string;
|
|
18
|
+
distinct_id: string;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
properties: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert a WideEvent to a PostHog event format.
|
|
24
|
+
*/
|
|
25
|
+
declare function toPostHogEvent(event: WideEvent, config: PostHogConfig): PostHogEvent;
|
|
26
|
+
/**
|
|
27
|
+
* Create a drain function for sending logs to PostHog.
|
|
28
|
+
*
|
|
29
|
+
* Configuration priority (highest to lowest):
|
|
30
|
+
* 1. Overrides passed to createPostHogDrain()
|
|
31
|
+
* 2. runtimeConfig.evlog.posthog
|
|
32
|
+
* 3. runtimeConfig.posthog
|
|
33
|
+
* 4. Environment variables: NUXT_POSTHOG_*, POSTHOG_*
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Zero config - just set NUXT_POSTHOG_API_KEY env var
|
|
38
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain())
|
|
39
|
+
*
|
|
40
|
+
* // With overrides
|
|
41
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain({
|
|
42
|
+
* apiKey: 'phc_...',
|
|
43
|
+
* host: 'https://eu.i.posthog.com',
|
|
44
|
+
* }))
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function createPostHogDrain(overrides?: Partial<PostHogConfig>): (ctx: DrainContext) => Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Send a single event to PostHog.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* await sendToPostHog(event, {
|
|
54
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function sendToPostHog(event: WideEvent, config: PostHogConfig): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Send a batch of events to PostHog.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* await sendBatchToPostHog(events, {
|
|
65
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function sendBatchToPostHog(events: WideEvent[], config: PostHogConfig): Promise<void>;
|
|
70
|
+
|
|
71
|
+
export { createPostHogDrain, sendBatchToPostHog, sendToPostHog, toPostHogEvent };
|
|
72
|
+
export type { PostHogConfig, PostHogEvent };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
3
|
+
function toPostHogEvent(event, config) {
|
|
4
|
+
const { timestamp, level, service, ...rest } = event;
|
|
5
|
+
return {
|
|
6
|
+
event: config.eventName ?? "evlog_wide_event",
|
|
7
|
+
distinct_id: config.distinctId ?? service,
|
|
8
|
+
timestamp,
|
|
9
|
+
properties: {
|
|
10
|
+
level,
|
|
11
|
+
service,
|
|
12
|
+
...rest
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function createPostHogDrain(overrides) {
|
|
17
|
+
return async (ctx) => {
|
|
18
|
+
const runtimeConfig = getRuntimeConfig();
|
|
19
|
+
const evlogPostHog = runtimeConfig?.evlog?.posthog;
|
|
20
|
+
const rootPostHog = runtimeConfig?.posthog;
|
|
21
|
+
const config = {
|
|
22
|
+
apiKey: overrides?.apiKey ?? evlogPostHog?.apiKey ?? rootPostHog?.apiKey ?? process.env.NUXT_POSTHOG_API_KEY ?? process.env.POSTHOG_API_KEY,
|
|
23
|
+
host: overrides?.host ?? evlogPostHog?.host ?? rootPostHog?.host ?? process.env.NUXT_POSTHOG_HOST ?? process.env.POSTHOG_HOST,
|
|
24
|
+
eventName: overrides?.eventName ?? evlogPostHog?.eventName ?? rootPostHog?.eventName,
|
|
25
|
+
distinctId: overrides?.distinctId ?? evlogPostHog?.distinctId ?? rootPostHog?.distinctId,
|
|
26
|
+
timeout: overrides?.timeout ?? evlogPostHog?.timeout ?? rootPostHog?.timeout
|
|
27
|
+
};
|
|
28
|
+
if (!config.apiKey) {
|
|
29
|
+
console.error("[evlog/posthog] Missing apiKey. Set NUXT_POSTHOG_API_KEY/POSTHOG_API_KEY env var or pass to createPostHogDrain()");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
await sendToPostHog(ctx.event, config);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("[evlog/posthog] Failed to send event:", error);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function sendToPostHog(event, config) {
|
|
40
|
+
await sendBatchToPostHog([event], config);
|
|
41
|
+
}
|
|
42
|
+
async function sendBatchToPostHog(events, config) {
|
|
43
|
+
if (events.length === 0) return;
|
|
44
|
+
const host = (config.host ?? "https://us.i.posthog.com").replace(/\/$/, "");
|
|
45
|
+
const timeout = config.timeout ?? 5e3;
|
|
46
|
+
const url = `${host}/batch/`;
|
|
47
|
+
const batch = events.map((event) => toPostHogEvent(event, config));
|
|
48
|
+
const payload = {
|
|
49
|
+
api_key: config.apiKey,
|
|
50
|
+
batch
|
|
51
|
+
};
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
54
|
+
try {
|
|
55
|
+
const response = await fetch(url, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: {
|
|
58
|
+
"Content-Type": "application/json"
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify(payload),
|
|
61
|
+
signal: controller.signal
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
const text = await response.text().catch(() => "Unknown error");
|
|
65
|
+
const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text;
|
|
66
|
+
throw new Error(`PostHog API error: ${response.status} ${response.statusText} - ${safeText}`);
|
|
67
|
+
}
|
|
68
|
+
} finally {
|
|
69
|
+
clearTimeout(timeoutId);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { createPostHogDrain, sendBatchToPostHog, sendToPostHog, toPostHogEvent };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.mjs';
|
|
2
|
+
|
|
3
|
+
interface SentryConfig {
|
|
4
|
+
/** Sentry DSN */
|
|
5
|
+
dsn: string;
|
|
6
|
+
/** Environment override (defaults to event.environment) */
|
|
7
|
+
environment?: string;
|
|
8
|
+
/** Release version override (defaults to event.version) */
|
|
9
|
+
release?: string;
|
|
10
|
+
/** Additional tags to attach as attributes */
|
|
11
|
+
tags?: Record<string, string>;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** Sentry Log attribute value with type annotation */
|
|
16
|
+
interface SentryAttributeValue {
|
|
17
|
+
value: string | number | boolean;
|
|
18
|
+
type: 'string' | 'integer' | 'double' | 'boolean';
|
|
19
|
+
}
|
|
20
|
+
/** Sentry Structured Log payload */
|
|
21
|
+
interface SentryLog {
|
|
22
|
+
timestamp: number;
|
|
23
|
+
trace_id: string;
|
|
24
|
+
level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
25
|
+
body: string;
|
|
26
|
+
severity_number: number;
|
|
27
|
+
attributes?: Record<string, SentryAttributeValue>;
|
|
28
|
+
}
|
|
29
|
+
declare function toSentryLog(event: WideEvent, config: SentryConfig): SentryLog;
|
|
30
|
+
/**
|
|
31
|
+
* Create a drain function for sending logs to Sentry.
|
|
32
|
+
*
|
|
33
|
+
* Sends wide events as Sentry Structured Logs, visible in Explore > Logs
|
|
34
|
+
* in the Sentry dashboard.
|
|
35
|
+
*
|
|
36
|
+
* Configuration priority (highest to lowest):
|
|
37
|
+
* 1. Overrides passed to createSentryDrain()
|
|
38
|
+
* 2. runtimeConfig.evlog.sentry
|
|
39
|
+
* 3. runtimeConfig.sentry
|
|
40
|
+
* 4. Environment variables: NUXT_SENTRY_*, SENTRY_*
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* // Zero config - just set NUXT_SENTRY_DSN env var
|
|
45
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain())
|
|
46
|
+
*
|
|
47
|
+
* // With overrides
|
|
48
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain({
|
|
49
|
+
* dsn: 'https://public@o0.ingest.sentry.io/123',
|
|
50
|
+
* }))
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare function createSentryDrain(overrides?: Partial<SentryConfig>): (ctx: DrainContext) => Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Send a single event to Sentry as a structured log.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* await sendToSentry(event, {
|
|
60
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
61
|
+
* })
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function sendToSentry(event: WideEvent, config: SentryConfig): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Send a batch of events to Sentry as structured logs via the Envelope endpoint.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* await sendBatchToSentry(events, {
|
|
71
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
72
|
+
* })
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function sendBatchToSentry(events: WideEvent[], config: SentryConfig): Promise<void>;
|
|
76
|
+
|
|
77
|
+
export { createSentryDrain, sendBatchToSentry, sendToSentry, toSentryLog };
|
|
78
|
+
export type { SentryAttributeValue, SentryConfig, SentryLog };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.js';
|
|
2
|
+
|
|
3
|
+
interface SentryConfig {
|
|
4
|
+
/** Sentry DSN */
|
|
5
|
+
dsn: string;
|
|
6
|
+
/** Environment override (defaults to event.environment) */
|
|
7
|
+
environment?: string;
|
|
8
|
+
/** Release version override (defaults to event.version) */
|
|
9
|
+
release?: string;
|
|
10
|
+
/** Additional tags to attach as attributes */
|
|
11
|
+
tags?: Record<string, string>;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** Sentry Log attribute value with type annotation */
|
|
16
|
+
interface SentryAttributeValue {
|
|
17
|
+
value: string | number | boolean;
|
|
18
|
+
type: 'string' | 'integer' | 'double' | 'boolean';
|
|
19
|
+
}
|
|
20
|
+
/** Sentry Structured Log payload */
|
|
21
|
+
interface SentryLog {
|
|
22
|
+
timestamp: number;
|
|
23
|
+
trace_id: string;
|
|
24
|
+
level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
25
|
+
body: string;
|
|
26
|
+
severity_number: number;
|
|
27
|
+
attributes?: Record<string, SentryAttributeValue>;
|
|
28
|
+
}
|
|
29
|
+
declare function toSentryLog(event: WideEvent, config: SentryConfig): SentryLog;
|
|
30
|
+
/**
|
|
31
|
+
* Create a drain function for sending logs to Sentry.
|
|
32
|
+
*
|
|
33
|
+
* Sends wide events as Sentry Structured Logs, visible in Explore > Logs
|
|
34
|
+
* in the Sentry dashboard.
|
|
35
|
+
*
|
|
36
|
+
* Configuration priority (highest to lowest):
|
|
37
|
+
* 1. Overrides passed to createSentryDrain()
|
|
38
|
+
* 2. runtimeConfig.evlog.sentry
|
|
39
|
+
* 3. runtimeConfig.sentry
|
|
40
|
+
* 4. Environment variables: NUXT_SENTRY_*, SENTRY_*
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* // Zero config - just set NUXT_SENTRY_DSN env var
|
|
45
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain())
|
|
46
|
+
*
|
|
47
|
+
* // With overrides
|
|
48
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain({
|
|
49
|
+
* dsn: 'https://public@o0.ingest.sentry.io/123',
|
|
50
|
+
* }))
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare function createSentryDrain(overrides?: Partial<SentryConfig>): (ctx: DrainContext) => Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Send a single event to Sentry as a structured log.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* await sendToSentry(event, {
|
|
60
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
61
|
+
* })
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function sendToSentry(event: WideEvent, config: SentryConfig): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Send a batch of events to Sentry as structured logs via the Envelope endpoint.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* await sendBatchToSentry(events, {
|
|
71
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
72
|
+
* })
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function sendBatchToSentry(events: WideEvent[], config: SentryConfig): Promise<void>;
|
|
76
|
+
|
|
77
|
+
export { createSentryDrain, sendBatchToSentry, sendToSentry, toSentryLog };
|
|
78
|
+
export type { SentryAttributeValue, SentryConfig, SentryLog };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
3
|
+
const SEVERITY_MAP = {
|
|
4
|
+
debug: 5,
|
|
5
|
+
info: 9,
|
|
6
|
+
warn: 13,
|
|
7
|
+
error: 17
|
|
8
|
+
};
|
|
9
|
+
function parseSentryDsn(dsn) {
|
|
10
|
+
const url = new URL(dsn);
|
|
11
|
+
const publicKey = url.username;
|
|
12
|
+
if (!publicKey) {
|
|
13
|
+
throw new Error("Invalid Sentry DSN: missing public key");
|
|
14
|
+
}
|
|
15
|
+
const secretKey = url.password || void 0;
|
|
16
|
+
const pathParts = url.pathname.split("/").filter(Boolean);
|
|
17
|
+
const projectId = pathParts.pop();
|
|
18
|
+
if (!projectId) {
|
|
19
|
+
throw new Error("Invalid Sentry DSN: missing project ID");
|
|
20
|
+
}
|
|
21
|
+
const basePath = pathParts.length > 0 ? `/${pathParts.join("/")}` : "";
|
|
22
|
+
return {
|
|
23
|
+
publicKey,
|
|
24
|
+
secretKey,
|
|
25
|
+
projectId,
|
|
26
|
+
origin: `${url.protocol}//${url.host}`,
|
|
27
|
+
basePath
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function getSentryEnvelopeUrl(dsn) {
|
|
31
|
+
const { publicKey, secretKey, projectId, origin, basePath } = parseSentryDsn(dsn);
|
|
32
|
+
const url = `${origin}${basePath}/api/${projectId}/envelope/`;
|
|
33
|
+
let authHeader = `Sentry sentry_version=7, sentry_key=${publicKey}, sentry_client=evlog`;
|
|
34
|
+
if (secretKey) {
|
|
35
|
+
authHeader += `, sentry_secret=${secretKey}`;
|
|
36
|
+
}
|
|
37
|
+
return { url, authHeader };
|
|
38
|
+
}
|
|
39
|
+
function createTraceId() {
|
|
40
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
41
|
+
return globalThis.crypto.randomUUID().replace(/-/g, "");
|
|
42
|
+
}
|
|
43
|
+
return Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
|
|
44
|
+
}
|
|
45
|
+
function getFirstStringValue(event, keys) {
|
|
46
|
+
for (const key of keys) {
|
|
47
|
+
const value = event[key];
|
|
48
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
49
|
+
}
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
function toAttributeValue(value) {
|
|
53
|
+
if (value === null || value === void 0) {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
if (typeof value === "string") {
|
|
57
|
+
return { value, type: "string" };
|
|
58
|
+
}
|
|
59
|
+
if (typeof value === "boolean") {
|
|
60
|
+
return { value, type: "boolean" };
|
|
61
|
+
}
|
|
62
|
+
if (typeof value === "number") {
|
|
63
|
+
if (Number.isInteger(value)) {
|
|
64
|
+
return { value, type: "integer" };
|
|
65
|
+
}
|
|
66
|
+
return { value, type: "double" };
|
|
67
|
+
}
|
|
68
|
+
return { value: JSON.stringify(value), type: "string" };
|
|
69
|
+
}
|
|
70
|
+
function toSentryLog(event, config) {
|
|
71
|
+
const { timestamp, level, service, environment, version, ...rest } = event;
|
|
72
|
+
const body = getFirstStringValue(event, ["message", "action", "path"]) ?? "evlog wide event";
|
|
73
|
+
const traceId = typeof event.traceId === "string" && event.traceId.length > 0 ? event.traceId : createTraceId();
|
|
74
|
+
const attributes = {};
|
|
75
|
+
const env = config.environment ?? environment;
|
|
76
|
+
if (env) {
|
|
77
|
+
attributes["sentry.environment"] = { value: env, type: "string" };
|
|
78
|
+
}
|
|
79
|
+
const rel = config.release ?? version;
|
|
80
|
+
if (typeof rel === "string" && rel.length > 0) {
|
|
81
|
+
attributes["sentry.release"] = { value: rel, type: "string" };
|
|
82
|
+
}
|
|
83
|
+
attributes["service"] = { value: service, type: "string" };
|
|
84
|
+
if (config.tags) {
|
|
85
|
+
for (const [key, value] of Object.entries(config.tags)) {
|
|
86
|
+
attributes[key] = { value, type: "string" };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
90
|
+
if (key === "traceId" || key === "spanId") continue;
|
|
91
|
+
if (value === void 0 || value === null) continue;
|
|
92
|
+
const attr = toAttributeValue(value);
|
|
93
|
+
if (attr) {
|
|
94
|
+
attributes[key] = attr;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
timestamp: new Date(timestamp).getTime() / 1e3,
|
|
99
|
+
trace_id: traceId,
|
|
100
|
+
level,
|
|
101
|
+
body,
|
|
102
|
+
severity_number: SEVERITY_MAP[level] ?? 9,
|
|
103
|
+
attributes
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function buildEnvelopeBody(logs, dsn) {
|
|
107
|
+
const envelopeHeader = JSON.stringify({
|
|
108
|
+
dsn,
|
|
109
|
+
sent_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
110
|
+
});
|
|
111
|
+
const itemHeader = JSON.stringify({
|
|
112
|
+
type: "log",
|
|
113
|
+
item_count: logs.length,
|
|
114
|
+
content_type: "application/vnd.sentry.items.log+json"
|
|
115
|
+
});
|
|
116
|
+
const itemPayload = JSON.stringify({ items: logs });
|
|
117
|
+
return `${envelopeHeader}
|
|
118
|
+
${itemHeader}
|
|
119
|
+
${itemPayload}
|
|
120
|
+
`;
|
|
121
|
+
}
|
|
122
|
+
function createSentryDrain(overrides) {
|
|
123
|
+
return async (ctx) => {
|
|
124
|
+
const runtimeConfig = getRuntimeConfig();
|
|
125
|
+
const evlogSentry = runtimeConfig?.evlog?.sentry;
|
|
126
|
+
const rootSentry = runtimeConfig?.sentry;
|
|
127
|
+
const config = {
|
|
128
|
+
dsn: overrides?.dsn ?? evlogSentry?.dsn ?? rootSentry?.dsn ?? process.env.NUXT_SENTRY_DSN ?? process.env.SENTRY_DSN,
|
|
129
|
+
environment: overrides?.environment ?? evlogSentry?.environment ?? rootSentry?.environment ?? process.env.NUXT_SENTRY_ENVIRONMENT ?? process.env.SENTRY_ENVIRONMENT,
|
|
130
|
+
release: overrides?.release ?? evlogSentry?.release ?? rootSentry?.release ?? process.env.NUXT_SENTRY_RELEASE ?? process.env.SENTRY_RELEASE,
|
|
131
|
+
tags: overrides?.tags ?? evlogSentry?.tags ?? rootSentry?.tags,
|
|
132
|
+
timeout: overrides?.timeout ?? evlogSentry?.timeout ?? rootSentry?.timeout
|
|
133
|
+
};
|
|
134
|
+
if (!config.dsn) {
|
|
135
|
+
console.error("[evlog/sentry] Missing DSN. Set NUXT_SENTRY_DSN/SENTRY_DSN env var or pass to createSentryDrain()");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
await sendToSentry(ctx.event, config);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("[evlog/sentry] Failed to send log:", error);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function sendToSentry(event, config) {
|
|
146
|
+
await sendBatchToSentry([event], config);
|
|
147
|
+
}
|
|
148
|
+
async function sendBatchToSentry(events, config) {
|
|
149
|
+
if (events.length === 0) return;
|
|
150
|
+
const { url, authHeader } = getSentryEnvelopeUrl(config.dsn);
|
|
151
|
+
const timeout = config.timeout ?? 5e3;
|
|
152
|
+
const logs = events.map((event) => toSentryLog(event, config));
|
|
153
|
+
const body = buildEnvelopeBody(logs, config.dsn);
|
|
154
|
+
const controller = new AbortController();
|
|
155
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
156
|
+
try {
|
|
157
|
+
const response = await fetch(url, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
headers: {
|
|
160
|
+
"Content-Type": "application/x-sentry-envelope",
|
|
161
|
+
"X-Sentry-Auth": authHeader
|
|
162
|
+
},
|
|
163
|
+
body,
|
|
164
|
+
signal: controller.signal
|
|
165
|
+
});
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
const text = await response.text().catch(() => "Unknown error");
|
|
168
|
+
const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text;
|
|
169
|
+
throw new Error(`Sentry API error: ${response.status} ${response.statusText} - ${safeText}`);
|
|
170
|
+
}
|
|
171
|
+
} finally {
|
|
172
|
+
clearTimeout(timeoutId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export { createSentryDrain, sendBatchToSentry, sendToSentry, toSentryLog };
|
package/dist/index.mjs
CHANGED
package/dist/logger.mjs
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import { defu } from 'defu';
|
|
2
1
|
import { isDev, detectEnvironment, formatDuration, matchesPattern, getConsoleMethod, colors, getLevelColor } from './utils.mjs';
|
|
3
2
|
|
|
3
|
+
function isPlainObject(val) {
|
|
4
|
+
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
5
|
+
}
|
|
6
|
+
function deepDefaults(base, defaults) {
|
|
7
|
+
const result = { ...base };
|
|
8
|
+
for (const key in defaults) {
|
|
9
|
+
const baseVal = result[key];
|
|
10
|
+
const defaultVal = defaults[key];
|
|
11
|
+
if (baseVal === void 0 || baseVal === null) {
|
|
12
|
+
result[key] = defaultVal;
|
|
13
|
+
} else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {
|
|
14
|
+
result[key] = deepDefaults(baseVal, defaultVal);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
4
19
|
let globalEnv = {
|
|
5
20
|
service: "app",
|
|
6
21
|
environment: "development"
|
|
@@ -154,7 +169,7 @@ function createRequestLogger(options = {}) {
|
|
|
154
169
|
let hasError = false;
|
|
155
170
|
return {
|
|
156
171
|
set(data) {
|
|
157
|
-
context =
|
|
172
|
+
context = deepDefaults(data, context);
|
|
158
173
|
},
|
|
159
174
|
error(error, errorContext) {
|
|
160
175
|
hasError = true;
|
|
@@ -167,7 +182,7 @@ function createRequestLogger(options = {}) {
|
|
|
167
182
|
stack: err.stack
|
|
168
183
|
}
|
|
169
184
|
};
|
|
170
|
-
context =
|
|
185
|
+
context = deepDefaults(errorData, context);
|
|
171
186
|
},
|
|
172
187
|
emit(overrides) {
|
|
173
188
|
const durationMs = Date.now() - startTime;
|
package/dist/nitro/plugin.mjs
CHANGED
|
@@ -2,7 +2,6 @@ import { defineNitroPlugin, useRuntimeConfig } from 'nitropack/runtime';
|
|
|
2
2
|
import { getHeaders } from 'h3';
|
|
3
3
|
import { initLogger, createRequestLogger } from '../logger.mjs';
|
|
4
4
|
import { matchesPattern } from '../utils.mjs';
|
|
5
|
-
import 'defu';
|
|
6
5
|
|
|
7
6
|
function shouldLog(path, include, exclude) {
|
|
8
7
|
if (exclude && exclude.length > 0) {
|
|
@@ -63,9 +62,9 @@ function callDrainHook(nitroApp, emittedEvent, event) {
|
|
|
63
62
|
}).catch((err) => {
|
|
64
63
|
console.error("[evlog] drain failed:", err);
|
|
65
64
|
});
|
|
66
|
-
const
|
|
67
|
-
if (typeof waitUntil === "function") {
|
|
68
|
-
waitUntil(drainPromise);
|
|
65
|
+
const waitUntilCtx = event.context.cloudflare?.context ?? event.context;
|
|
66
|
+
if (typeof waitUntilCtx?.waitUntil === "function") {
|
|
67
|
+
waitUntilCtx.waitUntil(drainPromise);
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
const plugin = defineNitroPlugin((nitroApp) => {
|
|
@@ -82,10 +81,15 @@ const plugin = defineNitroPlugin((nitroApp) => {
|
|
|
82
81
|
return;
|
|
83
82
|
}
|
|
84
83
|
e.context._evlogStartTime = Date.now();
|
|
84
|
+
let requestIdOverride = void 0;
|
|
85
|
+
if (globalThis.navigator?.userAgent === "Cloudflare-Workers") {
|
|
86
|
+
const cfRay = getSafeHeaders(event)?.["cf-ray"];
|
|
87
|
+
if (cfRay) requestIdOverride = cfRay;
|
|
88
|
+
}
|
|
85
89
|
const log = createRequestLogger({
|
|
86
90
|
method: e.method,
|
|
87
91
|
path: e.path,
|
|
88
|
-
requestId: e.context.requestId || crypto.randomUUID()
|
|
92
|
+
requestId: requestIdOverride || e.context.requestId || crypto.randomUUID()
|
|
89
93
|
});
|
|
90
94
|
const routeService = getServiceForPath(e.path, evlogConfig?.routes);
|
|
91
95
|
if (routeService) {
|
package/dist/nuxt/module.d.mts
CHANGED
|
@@ -118,6 +118,52 @@ interface ModuleOptions {
|
|
|
118
118
|
/** Request timeout in milliseconds. Default: 5000 */
|
|
119
119
|
timeout?: number;
|
|
120
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* PostHog adapter configuration.
|
|
123
|
+
* When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* posthog: {
|
|
128
|
+
* apiKey: process.env.POSTHOG_API_KEY,
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
posthog?: {
|
|
133
|
+
/** PostHog project API key */
|
|
134
|
+
apiKey: string;
|
|
135
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
136
|
+
host?: string;
|
|
137
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
138
|
+
eventName?: string;
|
|
139
|
+
/** Override distinct_id (defaults to event.service) */
|
|
140
|
+
distinctId?: string;
|
|
141
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
142
|
+
timeout?: number;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Sentry adapter configuration.
|
|
146
|
+
* When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* sentry: {
|
|
151
|
+
* dsn: process.env.SENTRY_DSN,
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
sentry?: {
|
|
156
|
+
/** Sentry DSN */
|
|
157
|
+
dsn: string;
|
|
158
|
+
/** Environment override (defaults to event.environment) */
|
|
159
|
+
environment?: string;
|
|
160
|
+
/** Release version override (defaults to event.version) */
|
|
161
|
+
release?: string;
|
|
162
|
+
/** Additional tags to attach as attributes */
|
|
163
|
+
tags?: Record<string, string>;
|
|
164
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
165
|
+
timeout?: number;
|
|
166
|
+
};
|
|
121
167
|
}
|
|
122
168
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
123
169
|
|
package/dist/nuxt/module.d.ts
CHANGED
|
@@ -118,6 +118,52 @@ interface ModuleOptions {
|
|
|
118
118
|
/** Request timeout in milliseconds. Default: 5000 */
|
|
119
119
|
timeout?: number;
|
|
120
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* PostHog adapter configuration.
|
|
123
|
+
* When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* posthog: {
|
|
128
|
+
* apiKey: process.env.POSTHOG_API_KEY,
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
posthog?: {
|
|
133
|
+
/** PostHog project API key */
|
|
134
|
+
apiKey: string;
|
|
135
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
136
|
+
host?: string;
|
|
137
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
138
|
+
eventName?: string;
|
|
139
|
+
/** Override distinct_id (defaults to event.service) */
|
|
140
|
+
distinctId?: string;
|
|
141
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
142
|
+
timeout?: number;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Sentry adapter configuration.
|
|
146
|
+
* When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* sentry: {
|
|
151
|
+
* dsn: process.env.SENTRY_DSN,
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
sentry?: {
|
|
156
|
+
/** Sentry DSN */
|
|
157
|
+
dsn: string;
|
|
158
|
+
/** Environment override (defaults to event.environment) */
|
|
159
|
+
environment?: string;
|
|
160
|
+
/** Release version override (defaults to event.version) */
|
|
161
|
+
release?: string;
|
|
162
|
+
/** Additional tags to attach as attributes */
|
|
163
|
+
tags?: Record<string, string>;
|
|
164
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
165
|
+
timeout?: number;
|
|
166
|
+
};
|
|
121
167
|
}
|
|
122
168
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
123
169
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { defineEventHandler, readBody, setResponseStatus, getHeader, getRequestHost, createError } from 'h3';
|
|
2
2
|
import { useNitroApp } from 'nitropack/runtime';
|
|
3
3
|
import { getEnvironment } from '../../../../logger.mjs';
|
|
4
|
-
import 'defu';
|
|
5
4
|
import '../../../../utils.mjs';
|
|
6
5
|
|
|
7
6
|
const VALID_LEVELS = ["info", "error", "warn", "debug"];
|
package/dist/workers.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evlog",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Wide event logging library with structured error handling. Inspired by LoggingSucks.",
|
|
5
5
|
"author": "HugoRCD <contact@hrcd.fr>",
|
|
6
6
|
"homepage": "https://evlog.dev",
|
|
@@ -46,6 +46,14 @@
|
|
|
46
46
|
"./otlp": {
|
|
47
47
|
"types": "./dist/adapters/otlp.d.mts",
|
|
48
48
|
"import": "./dist/adapters/otlp.mjs"
|
|
49
|
+
},
|
|
50
|
+
"./posthog": {
|
|
51
|
+
"types": "./dist/adapters/posthog.d.mts",
|
|
52
|
+
"import": "./dist/adapters/posthog.mjs"
|
|
53
|
+
},
|
|
54
|
+
"./sentry": {
|
|
55
|
+
"types": "./dist/adapters/sentry.d.mts",
|
|
56
|
+
"import": "./dist/adapters/sentry.mjs"
|
|
49
57
|
}
|
|
50
58
|
},
|
|
51
59
|
"main": "./dist/index.mjs",
|
|
@@ -69,6 +77,12 @@
|
|
|
69
77
|
],
|
|
70
78
|
"otlp": [
|
|
71
79
|
"./dist/adapters/otlp.d.mts"
|
|
80
|
+
],
|
|
81
|
+
"posthog": [
|
|
82
|
+
"./dist/adapters/posthog.d.mts"
|
|
83
|
+
],
|
|
84
|
+
"sentry": [
|
|
85
|
+
"./dist/adapters/sentry.d.mts"
|
|
72
86
|
]
|
|
73
87
|
}
|
|
74
88
|
},
|
|
@@ -87,27 +101,27 @@
|
|
|
87
101
|
"test:coverage": "vitest run --coverage",
|
|
88
102
|
"typecheck": "echo 'Typecheck handled by build'"
|
|
89
103
|
},
|
|
90
|
-
"dependencies": {
|
|
91
|
-
"@nuxt/kit": "^4.3.0",
|
|
92
|
-
"defu": "^6.1.4"
|
|
93
|
-
},
|
|
94
104
|
"devDependencies": {
|
|
95
105
|
"@nuxt/devtools": "^3.1.1",
|
|
96
|
-
"@nuxt/schema": "^4.3.
|
|
106
|
+
"@nuxt/schema": "^4.3.1",
|
|
97
107
|
"@nuxt/test-utils": "^3.23.0",
|
|
98
108
|
"changelogen": "^0.6.2",
|
|
99
109
|
"h3": "^1.15.5",
|
|
100
110
|
"nitropack": "^2.13.1",
|
|
101
|
-
"nuxt": "^4.3.
|
|
111
|
+
"nuxt": "^4.3.1",
|
|
102
112
|
"typescript": "^5.9.3",
|
|
103
113
|
"unbuild": "^3.6.1"
|
|
104
114
|
},
|
|
105
115
|
"peerDependencies": {
|
|
116
|
+
"@nuxt/kit": "^4.3.1",
|
|
106
117
|
"h3": "^1.15.5",
|
|
107
118
|
"nitropack": "^2.13.1",
|
|
108
119
|
"ofetch": "^1.5.1"
|
|
109
120
|
},
|
|
110
121
|
"peerDependenciesMeta": {
|
|
122
|
+
"@nuxt/kit": {
|
|
123
|
+
"optional": true
|
|
124
|
+
},
|
|
111
125
|
"h3": {
|
|
112
126
|
"optional": true
|
|
113
127
|
},
|