@od-oneapp/observability 2026.1.1301
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 +523 -0
- package/dist/client-next.d.mts +20 -0
- package/dist/client-next.d.mts.map +1 -0
- package/dist/client-next.mjs +64 -0
- package/dist/client-next.mjs.map +1 -0
- package/dist/client.d.mts +11 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +47 -0
- package/dist/client.mjs.map +1 -0
- package/dist/env.d.mts +15 -0
- package/dist/env.d.mts.map +1 -0
- package/dist/env.mjs +45 -0
- package/dist/env.mjs.map +1 -0
- package/dist/factory-DkY353r8.mjs +380 -0
- package/dist/factory-DkY353r8.mjs.map +1 -0
- package/dist/hooks-useObservability.d.mts +11 -0
- package/dist/hooks-useObservability.d.mts.map +1 -0
- package/dist/hooks-useObservability.mjs +174 -0
- package/dist/hooks-useObservability.mjs.map +1 -0
- package/dist/index-CpcdzWrF.d.mts +24 -0
- package/dist/index-CpcdzWrF.d.mts.map +1 -0
- package/dist/index.d.mts +88 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +97 -0
- package/dist/index.mjs.map +1 -0
- package/dist/manager-BxQqOPEg.d.mts +33 -0
- package/dist/manager-BxQqOPEg.d.mts.map +1 -0
- package/dist/plugin-Bfq-o3nr.d.mts +60 -0
- package/dist/plugin-Bfq-o3nr.d.mts.map +1 -0
- package/dist/plugin-Bt-ygG1m.d.mts +254 -0
- package/dist/plugin-Bt-ygG1m.d.mts.map +1 -0
- package/dist/plugin-CLFwRERa.mjs +593 -0
- package/dist/plugin-CLFwRERa.mjs.map +1 -0
- package/dist/plugin-CP895lBx.mjs +534 -0
- package/dist/plugin-CP895lBx.mjs.map +1 -0
- package/dist/plugin-CaQxviDs.d.mts +61 -0
- package/dist/plugin-CaQxviDs.d.mts.map +1 -0
- package/dist/plugin-lPdJirTY.mjs +234 -0
- package/dist/plugin-lPdJirTY.mjs.map +1 -0
- package/dist/plugins-betterstack-env.d.mts +29 -0
- package/dist/plugins-betterstack-env.d.mts.map +1 -0
- package/dist/plugins-betterstack-env.mjs +75 -0
- package/dist/plugins-betterstack-env.mjs.map +1 -0
- package/dist/plugins-betterstack.d.mts +4 -0
- package/dist/plugins-betterstack.mjs +4 -0
- package/dist/plugins-console.d.mts +37 -0
- package/dist/plugins-console.d.mts.map +1 -0
- package/dist/plugins-console.mjs +196 -0
- package/dist/plugins-console.mjs.map +1 -0
- package/dist/plugins-sentry-env.d.mts +37 -0
- package/dist/plugins-sentry-env.d.mts.map +1 -0
- package/dist/plugins-sentry-env.mjs +79 -0
- package/dist/plugins-sentry-env.mjs.map +1 -0
- package/dist/plugins-sentry-microfrontend-env.d.mts +49 -0
- package/dist/plugins-sentry-microfrontend-env.d.mts.map +1 -0
- package/dist/plugins-sentry-microfrontend-env.mjs +80 -0
- package/dist/plugins-sentry-microfrontend-env.mjs.map +1 -0
- package/dist/plugins-sentry-microfrontend.d.mts +2 -0
- package/dist/plugins-sentry-microfrontend.mjs +3 -0
- package/dist/plugins-sentry.d.mts +5 -0
- package/dist/plugins-sentry.mjs +6 -0
- package/dist/server-edge.d.mts +15 -0
- package/dist/server-edge.d.mts.map +1 -0
- package/dist/server-edge.mjs +53 -0
- package/dist/server-edge.mjs.map +1 -0
- package/dist/server-next.d.mts +17 -0
- package/dist/server-next.d.mts.map +1 -0
- package/dist/server-next.mjs +64 -0
- package/dist/server-next.mjs.map +1 -0
- package/dist/server.d.mts +11 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.mjs +48 -0
- package/dist/server.mjs.map +1 -0
- package/dist/utils-CuGrTcD6.d.mts +77 -0
- package/dist/utils-CuGrTcD6.d.mts.map +1 -0
- package/env.ts +67 -0
- package/package.json +147 -0
- package/src/client-next.ts +131 -0
- package/src/client.ts +70 -0
- package/src/core/index.ts +15 -0
- package/src/core/manager.ts +361 -0
- package/src/core/plugin.ts +61 -0
- package/src/core/types.ts +151 -0
- package/src/factory/builder.ts +132 -0
- package/src/factory/index.ts +67 -0
- package/src/factory/presets.ts +78 -0
- package/src/hooks/useObservability.ts +206 -0
- package/src/plugins/betterstack/env.ts +101 -0
- package/src/plugins/betterstack/index.ts +15 -0
- package/src/plugins/betterstack/plugin.ts +373 -0
- package/src/plugins/console/index.ts +323 -0
- package/src/plugins/sentry/__tests__/plugin-tracing.test.ts +511 -0
- package/src/plugins/sentry/env.ts +93 -0
- package/src/plugins/sentry/index.ts +28 -0
- package/src/plugins/sentry/plugin.ts +953 -0
- package/src/plugins/sentry/types.ts +252 -0
- package/src/plugins/sentry-microfrontend/env.ts +105 -0
- package/src/plugins/sentry-microfrontend/index.ts +12 -0
- package/src/plugins/sentry-microfrontend/multiplexed-transport.ts +221 -0
- package/src/plugins/sentry-microfrontend/plugin.ts +500 -0
- package/src/plugins/sentry-microfrontend/sentry-types.ts +140 -0
- package/src/plugins/sentry-microfrontend/types.ts +130 -0
- package/src/plugins/sentry-microfrontend/utils.ts +326 -0
- package/src/server-edge.ts +113 -0
- package/src/server-next.ts +114 -0
- package/src/server.ts +71 -0
- package/src/shared.ts +148 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Factory functions for creating observability instances
|
|
3
|
+
* Factory functions for creating observability instances
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ObservabilityManager } from '../core/manager';
|
|
7
|
+
|
|
8
|
+
import { ObservabilityBuilder } from './builder';
|
|
9
|
+
|
|
10
|
+
import type { ObservabilityPlugin, ObservabilityServerPlugin } from '../core/plugin';
|
|
11
|
+
|
|
12
|
+
export { ObservabilityManager } from '../core/manager';
|
|
13
|
+
export { ObservabilityBuilder } from './builder';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create an observability instance with the provided plugins.
|
|
17
|
+
*
|
|
18
|
+
* Factory function that creates a configured ObservabilityManager with the given plugins.
|
|
19
|
+
* Provides a simpler API than using ObservabilityBuilder directly.
|
|
20
|
+
*
|
|
21
|
+
* @param plugins - Array of observability plugins to include
|
|
22
|
+
* @param options - Optional configuration options
|
|
23
|
+
* @param options.autoInitialize - Whether to auto-initialize plugins (default: true)
|
|
24
|
+
* @returns Configured ObservabilityManager instance
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const obs = createObservability([
|
|
29
|
+
* createConsolePlugin(),
|
|
30
|
+
* createSentryPlugin({ dsn: '...' }),
|
|
31
|
+
* ], { autoInitialize: true });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function createObservability(
|
|
35
|
+
plugins: (ObservabilityPlugin | ObservabilityServerPlugin)[],
|
|
36
|
+
options?: {
|
|
37
|
+
autoInitialize?: boolean;
|
|
38
|
+
},
|
|
39
|
+
): ObservabilityManager {
|
|
40
|
+
const builder = new ObservabilityBuilder();
|
|
41
|
+
|
|
42
|
+
if (options?.autoInitialize !== undefined) {
|
|
43
|
+
builder.withAutoInitialize(options.autoInitialize);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return builder.withPlugins(plugins).build();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Create a no-op observability instance for testing or when observability is disabled.
|
|
51
|
+
*
|
|
52
|
+
* Returns an ObservabilityManager with no plugins configured. All observability methods
|
|
53
|
+
* will be no-ops. Useful for testing or when observability should be disabled.
|
|
54
|
+
*
|
|
55
|
+
* Note: For logging, use @repo/shared/logger instead.
|
|
56
|
+
*
|
|
57
|
+
* @returns Empty ObservabilityManager instance
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const obs = createNoOpObservability();
|
|
62
|
+
* obs.captureMessage('This will not be logged'); // No-op
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function createNoOpObservability(): ObservabilityManager {
|
|
66
|
+
return new ObservabilityManager();
|
|
67
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Common observability configurations and presets
|
|
3
|
+
* Common observability configurations and presets
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { env } from '../../env';
|
|
7
|
+
import { createBetterStackPlugin } from '../plugins/betterstack';
|
|
8
|
+
import { env as betterStackEnv } from '../plugins/betterstack/env';
|
|
9
|
+
import { createConsolePlugin } from '../plugins/console';
|
|
10
|
+
import { createSentryPlugin } from '../plugins/sentry';
|
|
11
|
+
import { env as sentryEnv } from '../plugins/sentry/env';
|
|
12
|
+
|
|
13
|
+
import { ObservabilityBuilder } from './builder';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create development preset observability configuration.
|
|
17
|
+
*
|
|
18
|
+
* Configures observability for development environments with console logging enabled.
|
|
19
|
+
* Automatically detects development mode and adds appropriate plugins.
|
|
20
|
+
*
|
|
21
|
+
* @returns ObservabilityBuilder configured for development
|
|
22
|
+
*/
|
|
23
|
+
export async function createDevelopmentObservability(): Promise<ObservabilityBuilder> {
|
|
24
|
+
const builder = ObservabilityBuilder.create();
|
|
25
|
+
|
|
26
|
+
// Always add console in development
|
|
27
|
+
if (env.NEXT_PUBLIC_NODE_ENV === 'development') {
|
|
28
|
+
builder.withPlugin(createConsolePlugin());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return builder;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create production preset observability configuration.
|
|
36
|
+
*
|
|
37
|
+
* Configures observability for production environments with error tracking (Sentry)
|
|
38
|
+
* and logging (Better Stack) if configured. Only adds plugins when credentials are available.
|
|
39
|
+
*
|
|
40
|
+
* @returns ObservabilityBuilder configured for production
|
|
41
|
+
*/
|
|
42
|
+
export async function createProductionObservability(): Promise<ObservabilityBuilder> {
|
|
43
|
+
const builder = ObservabilityBuilder.create();
|
|
44
|
+
|
|
45
|
+
// Add Sentry if DSN is configured
|
|
46
|
+
if (sentryEnv.SENTRY_DSN || sentryEnv.NEXT_PUBLIC_SENTRY_DSN) {
|
|
47
|
+
builder.withPlugin(createSentryPlugin());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Add Better Stack if token is configured
|
|
51
|
+
const hasToken =
|
|
52
|
+
betterStackEnv.BETTER_STACK_SOURCE_TOKEN ??
|
|
53
|
+
betterStackEnv.BETTERSTACK_SOURCE_TOKEN ??
|
|
54
|
+
betterStackEnv.LOGTAIL_SOURCE_TOKEN;
|
|
55
|
+
|
|
56
|
+
if (hasToken) {
|
|
57
|
+
builder.withPlugin(createBetterStackPlugin());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return builder;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create observability configuration based on environment.
|
|
65
|
+
*
|
|
66
|
+
* Automatically selects the appropriate preset (development or production) based on
|
|
67
|
+
* the NODE_ENV environment variable. Provides a convenient way to get environment-appropriate
|
|
68
|
+
* observability configuration.
|
|
69
|
+
*
|
|
70
|
+
* @returns ObservabilityBuilder configured for the current environment
|
|
71
|
+
*/
|
|
72
|
+
export async function createAutoConfiguredObservability(): Promise<ObservabilityBuilder> {
|
|
73
|
+
if (env.NEXT_PUBLIC_NODE_ENV === 'production') {
|
|
74
|
+
return createProductionObservability();
|
|
75
|
+
} else {
|
|
76
|
+
return createDevelopmentObservability();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview React hooks for observability integration
|
|
3
|
+
* React hooks for observability integration
|
|
4
|
+
* Optimized for React 19 features including use() hook and automatic error boundaries
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use client';
|
|
8
|
+
|
|
9
|
+
import { use, useEffect, useSyncExternalStore } from 'react';
|
|
10
|
+
|
|
11
|
+
import { logDebug, logError } from '@repo/shared/logs';
|
|
12
|
+
|
|
13
|
+
import type { ObservabilityManager } from '../core/manager';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Global observability instance promise for React 19's use() hook
|
|
17
|
+
* This allows components to suspend while waiting for initialization
|
|
18
|
+
*/
|
|
19
|
+
let observabilityPromise: Promise<ObservabilityManager> | null = null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Set the observability promise for React 19 Suspense integration
|
|
23
|
+
* @param promise - Promise that resolves to ObservabilityManager
|
|
24
|
+
*/
|
|
25
|
+
export function setObservabilityPromise(promise: Promise<ObservabilityManager>): void {
|
|
26
|
+
observabilityPromise = promise;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* React 19+ hook that suspends until observability is ready
|
|
31
|
+
* Uses the new use() hook for automatic Suspense integration
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* 'use client';
|
|
36
|
+
*
|
|
37
|
+
* import { Suspense } from 'react';
|
|
38
|
+
* import { useObservability } from '@repo/observability/hooks/useObservability';
|
|
39
|
+
* import { logInfo } from '@repo/shared/logs';
|
|
40
|
+
*
|
|
41
|
+
* function MyComponent() {
|
|
42
|
+
* const observability = useObservability();
|
|
43
|
+
*
|
|
44
|
+
* useEffect(() => {
|
|
45
|
+
* logInfo('Component mounted');
|
|
46
|
+
* }, [observability]);
|
|
47
|
+
*
|
|
48
|
+
* return <div>Hello</div>;
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* export default function Page() {
|
|
52
|
+
* return (
|
|
53
|
+
* <Suspense fallback={<div>Loading...</div>}>
|
|
54
|
+
* <MyComponent />
|
|
55
|
+
* </Suspense>
|
|
56
|
+
* );
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function useObservability(): ObservabilityManager {
|
|
61
|
+
if (!observabilityPromise) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
'Observability promise not set. Call setObservabilityPromise() during module initialization.',
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// React 19's use() hook automatically suspends until promise resolves
|
|
68
|
+
return use(observabilityPromise);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Module-level state for legacy hook (fixes state recreation bug)
|
|
72
|
+
let legacyCurrentInstance: ObservabilityManager | undefined = undefined;
|
|
73
|
+
const legacyListeners = new Set<() => void>();
|
|
74
|
+
let legacyInitialized = false;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Legacy hook for React 18 compatibility
|
|
78
|
+
* Returns observability instance once available, undefined during initialization
|
|
79
|
+
* Does not use Suspense
|
|
80
|
+
*
|
|
81
|
+
* @deprecated Use useObservability() with Suspense for React 19+
|
|
82
|
+
*/
|
|
83
|
+
export function useObservabilityLegacy(): ObservabilityManager | undefined {
|
|
84
|
+
const subscribe = (callback: () => void) => {
|
|
85
|
+
legacyListeners.add(callback);
|
|
86
|
+
|
|
87
|
+
// If promise exists and instance not yet resolved, wait for it
|
|
88
|
+
if (observabilityPromise && !legacyInitialized) {
|
|
89
|
+
legacyInitialized = true;
|
|
90
|
+
void (async () => {
|
|
91
|
+
try {
|
|
92
|
+
const instance = await observabilityPromise;
|
|
93
|
+
legacyCurrentInstance = instance;
|
|
94
|
+
legacyListeners.forEach(listener => {
|
|
95
|
+
listener();
|
|
96
|
+
});
|
|
97
|
+
} catch {
|
|
98
|
+
legacyInitialized = false; // Allow retry on failure
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return () => {
|
|
104
|
+
legacyListeners.delete(callback);
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const getSnapshot = (): ObservabilityManager | undefined => {
|
|
109
|
+
return legacyCurrentInstance;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return useSyncExternalStore(subscribe, getSnapshot);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Hook to track component lifecycle events
|
|
117
|
+
* Automatically logs mount, update, and unmount events
|
|
118
|
+
*
|
|
119
|
+
* @param componentName - Name of the component for logging
|
|
120
|
+
* @param deps - Dependencies to track for updates
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* 'use client';
|
|
125
|
+
*
|
|
126
|
+
* import { useObservabilityLifecycle } from '@repo/observability/hooks/useObservability';
|
|
127
|
+
*
|
|
128
|
+
* function UserProfile({ userId }: { userId: string }) {
|
|
129
|
+
* useObservabilityLifecycle('UserProfile', [userId]);
|
|
130
|
+
*
|
|
131
|
+
* return <div>User {userId}</div>;
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function useObservabilityLifecycle(
|
|
136
|
+
componentName: string,
|
|
137
|
+
deps: readonly unknown[] = [],
|
|
138
|
+
): void {
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
// Log mount
|
|
141
|
+
logDebug(`Component mounted: ${componentName}`, {
|
|
142
|
+
component: componentName,
|
|
143
|
+
event: 'mount',
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Log unmount
|
|
147
|
+
return () => {
|
|
148
|
+
logDebug(`Component unmounted: ${componentName}`, {
|
|
149
|
+
component: componentName,
|
|
150
|
+
event: 'unmount',
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
}, deps);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Hook to automatically report errors to observability
|
|
158
|
+
* Compatible with React 19 error boundaries
|
|
159
|
+
*
|
|
160
|
+
* @param error - Error to report
|
|
161
|
+
* @param errorInfo - Additional error information
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```tsx
|
|
165
|
+
* 'use client';
|
|
166
|
+
*
|
|
167
|
+
* import { useObservabilityError } from '@repo/observability/hooks/useObservability';
|
|
168
|
+
*
|
|
169
|
+
* function MyComponent() {
|
|
170
|
+
* const [error, setError] = useState<Error | null>(null);
|
|
171
|
+
*
|
|
172
|
+
* useObservabilityError(error, { component: 'MyComponent' });
|
|
173
|
+
*
|
|
174
|
+
* if (error) {
|
|
175
|
+
* return <div>Error occurred</div>;
|
|
176
|
+
* }
|
|
177
|
+
*
|
|
178
|
+
* return <div>Hello</div>;
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export function useObservabilityError(
|
|
183
|
+
error: Error | null | undefined,
|
|
184
|
+
errorInfo?: Record<string, unknown>,
|
|
185
|
+
): void {
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
if (error && observabilityPromise) {
|
|
188
|
+
void (async () => {
|
|
189
|
+
try {
|
|
190
|
+
const obs = await observabilityPromise;
|
|
191
|
+
obs.captureException(error, {
|
|
192
|
+
extra: errorInfo,
|
|
193
|
+
tags: {
|
|
194
|
+
source: 'react-component',
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
} catch (reportError) {
|
|
198
|
+
logError('Failed to report error to observability', {
|
|
199
|
+
error: reportError,
|
|
200
|
+
originalError: error,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
})();
|
|
204
|
+
}
|
|
205
|
+
}, [error, errorInfo]);
|
|
206
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Better Stack (Logtail) environment configuration
|
|
3
|
+
* Better Stack (Logtail) environment configuration
|
|
4
|
+
* Updated to support official @logtail packages
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { logWarn } from '@repo/shared/logger';
|
|
8
|
+
import { createEnv } from '@t3-oss/env-core';
|
|
9
|
+
import { z } from 'zod/v4';
|
|
10
|
+
|
|
11
|
+
// Create validated env object
|
|
12
|
+
export const env = createEnv({
|
|
13
|
+
server: {
|
|
14
|
+
// Legacy support
|
|
15
|
+
LOGTAIL_SOURCE_TOKEN: z.string().optional(),
|
|
16
|
+
BETTERSTACK_SOURCE_TOKEN: z.string().optional(),
|
|
17
|
+
|
|
18
|
+
// Official Better Stack environment variables
|
|
19
|
+
BETTER_STACK_SOURCE_TOKEN: z.string().optional(),
|
|
20
|
+
BETTER_STACK_INGESTING_URL: z.string().url().optional(),
|
|
21
|
+
BETTER_STACK_LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error', 'off']).optional(),
|
|
22
|
+
},
|
|
23
|
+
client: {
|
|
24
|
+
// Legacy support
|
|
25
|
+
NEXT_PUBLIC_LOGTAIL_TOKEN: z.string().optional(),
|
|
26
|
+
NEXT_PUBLIC_BETTERSTACK_TOKEN: z.string().optional(),
|
|
27
|
+
|
|
28
|
+
// Official Better Stack client environment variables
|
|
29
|
+
NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN: z.string().optional(),
|
|
30
|
+
NEXT_PUBLIC_BETTER_STACK_INGESTING_URL: z.string().url().optional(),
|
|
31
|
+
NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL: z
|
|
32
|
+
.enum(['debug', 'info', 'warn', 'error', 'off'])
|
|
33
|
+
.optional(),
|
|
34
|
+
},
|
|
35
|
+
clientPrefix: 'NEXT_PUBLIC_',
|
|
36
|
+
runtimeEnv: process.env,
|
|
37
|
+
emptyStringAsUndefined: true,
|
|
38
|
+
onInvalidAccess: (variable: string) => {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`❌ Attempted to access a server-side environment variable on the client: ${variable}`,
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
onValidationError: error => {
|
|
44
|
+
logWarn('Better Stack environment validation failed', { error });
|
|
45
|
+
// Don't throw in packages - use fallbacks
|
|
46
|
+
return undefined as never;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Safe environment access for non-Next.js contexts.
|
|
52
|
+
*
|
|
53
|
+
* Provides fallback environment variable access for Node.js, workers, and test environments
|
|
54
|
+
* where the validated env object may not be available. Returns fallback values with proper
|
|
55
|
+
* priority handling for legacy and official Better Stack variable names.
|
|
56
|
+
*
|
|
57
|
+
* @returns Environment object with Better Stack configuration values
|
|
58
|
+
*/
|
|
59
|
+
export function safeEnv() {
|
|
60
|
+
if (env) return env;
|
|
61
|
+
|
|
62
|
+
// Fallback values for resilience with proper priority
|
|
63
|
+
return {
|
|
64
|
+
// Legacy support
|
|
65
|
+
LOGTAIL_SOURCE_TOKEN:
|
|
66
|
+
process.env.LOGTAIL_SOURCE_TOKEN ?? process.env.BETTERSTACK_SOURCE_TOKEN ?? '',
|
|
67
|
+
BETTERSTACK_SOURCE_TOKEN:
|
|
68
|
+
process.env.BETTERSTACK_SOURCE_TOKEN ?? process.env.LOGTAIL_SOURCE_TOKEN ?? '',
|
|
69
|
+
NEXT_PUBLIC_LOGTAIL_TOKEN:
|
|
70
|
+
process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? '',
|
|
71
|
+
NEXT_PUBLIC_BETTERSTACK_TOKEN:
|
|
72
|
+
process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? '',
|
|
73
|
+
|
|
74
|
+
// Official Better Stack (preferred)
|
|
75
|
+
BETTER_STACK_SOURCE_TOKEN:
|
|
76
|
+
process.env.BETTER_STACK_SOURCE_TOKEN ??
|
|
77
|
+
process.env.LOGTAIL_SOURCE_TOKEN ??
|
|
78
|
+
process.env.BETTERSTACK_SOURCE_TOKEN ??
|
|
79
|
+
'',
|
|
80
|
+
BETTER_STACK_INGESTING_URL: process.env.BETTER_STACK_INGESTING_URL ?? '',
|
|
81
|
+
BETTER_STACK_LOG_LEVEL:
|
|
82
|
+
(process.env.BETTER_STACK_LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error' | 'off') ?? 'info',
|
|
83
|
+
NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN:
|
|
84
|
+
process.env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??
|
|
85
|
+
process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ??
|
|
86
|
+
process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ??
|
|
87
|
+
'',
|
|
88
|
+
NEXT_PUBLIC_BETTER_STACK_INGESTING_URL:
|
|
89
|
+
process.env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL ?? '',
|
|
90
|
+
NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL:
|
|
91
|
+
(process.env.NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL as
|
|
92
|
+
| 'debug'
|
|
93
|
+
| 'info'
|
|
94
|
+
| 'warn'
|
|
95
|
+
| 'error'
|
|
96
|
+
| 'off') ?? 'info',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Export type
|
|
101
|
+
export type Env = typeof env;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Better Stack (Logtail) plugin exports
|
|
3
|
+
* Better Stack (Logtail) plugin exports
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Export plugin and factory
|
|
7
|
+
export { BetterStackPlugin, createBetterStackPlugin } from './plugin';
|
|
8
|
+
export type { BetterStackPluginConfig } from './plugin';
|
|
9
|
+
|
|
10
|
+
// Re-export Better Stack environment configuration
|
|
11
|
+
export { env, safeEnv } from './env';
|
|
12
|
+
export type { Env } from './env';
|
|
13
|
+
|
|
14
|
+
// Export types
|
|
15
|
+
export type { ObservabilityPlugin, ObservabilityServerPlugin } from '../../core/plugin';
|