@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,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sentry tracing type definitions
|
|
3
|
+
* Sentry tracing type definitions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transaction context for starting a new transaction
|
|
8
|
+
*/
|
|
9
|
+
export interface TransactionContext {
|
|
10
|
+
name: string;
|
|
11
|
+
op?: string;
|
|
12
|
+
tags?: Record<string, string>;
|
|
13
|
+
data?: Record<string, any>;
|
|
14
|
+
startTimestamp?: number;
|
|
15
|
+
parentSpanId?: string;
|
|
16
|
+
parentSampled?: boolean;
|
|
17
|
+
trimEnd?: boolean;
|
|
18
|
+
metadata?: {
|
|
19
|
+
source?: 'custom' | 'route' | 'url';
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Span context for creating child spans
|
|
26
|
+
*/
|
|
27
|
+
export interface SpanContext {
|
|
28
|
+
name: string;
|
|
29
|
+
op?: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
tags?: Record<string, string>;
|
|
32
|
+
data?: Record<string, any>;
|
|
33
|
+
startTimestamp?: number;
|
|
34
|
+
status?: SpanStatus;
|
|
35
|
+
origin?: string;
|
|
36
|
+
attributes?: Record<string, any>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Span status values
|
|
41
|
+
*/
|
|
42
|
+
export type SpanStatus =
|
|
43
|
+
| 'ok'
|
|
44
|
+
| 'cancelled'
|
|
45
|
+
| 'internal_error'
|
|
46
|
+
| 'invalid_argument'
|
|
47
|
+
| 'deadline_exceeded'
|
|
48
|
+
| 'not_found'
|
|
49
|
+
| 'already_exists'
|
|
50
|
+
| 'permission_denied'
|
|
51
|
+
| 'resource_exhausted'
|
|
52
|
+
| 'failed_precondition'
|
|
53
|
+
| 'aborted'
|
|
54
|
+
| 'out_of_range'
|
|
55
|
+
| 'unimplemented'
|
|
56
|
+
| 'unavailable'
|
|
57
|
+
| 'data_loss'
|
|
58
|
+
| 'unauthenticated';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Transaction interface
|
|
62
|
+
*/
|
|
63
|
+
export interface Transaction {
|
|
64
|
+
name: string;
|
|
65
|
+
spanId: string;
|
|
66
|
+
traceId: string;
|
|
67
|
+
startTimestamp: number;
|
|
68
|
+
tags: Record<string, string>;
|
|
69
|
+
data: Record<string, any>;
|
|
70
|
+
|
|
71
|
+
// Methods
|
|
72
|
+
setName(name: string): void;
|
|
73
|
+
setTag(key: string, value: string | number | boolean | null): void;
|
|
74
|
+
setData(key: string, value: any): void;
|
|
75
|
+
setStatus(status: SpanStatus): void;
|
|
76
|
+
setHttpStatus(httpStatus: number): void;
|
|
77
|
+
setMeasurement(name: string, value: number, unit?: string): void;
|
|
78
|
+
finish(endTimestamp?: number): void;
|
|
79
|
+
startChild(spanContext?: SpanContext): Span;
|
|
80
|
+
toTraceparent(): string;
|
|
81
|
+
toContext(): TransactionContext;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Span interface
|
|
86
|
+
*/
|
|
87
|
+
export interface Span {
|
|
88
|
+
spanId: string;
|
|
89
|
+
traceId: string;
|
|
90
|
+
parentSpanId?: string;
|
|
91
|
+
op?: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
startTimestamp: number;
|
|
94
|
+
tags: Record<string, string>;
|
|
95
|
+
data: Record<string, any>;
|
|
96
|
+
|
|
97
|
+
// Methods
|
|
98
|
+
setTag(key: string, value: string | number | boolean | null): void;
|
|
99
|
+
setData(key: string, value: any): void;
|
|
100
|
+
setStatus(status: SpanStatus): void;
|
|
101
|
+
setHttpStatus(httpStatus: number): void;
|
|
102
|
+
finish(endTimestamp?: number): void;
|
|
103
|
+
startChild(spanContext?: SpanContext): Span;
|
|
104
|
+
isRecording(): boolean;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Scope interface for managing context
|
|
109
|
+
*/
|
|
110
|
+
export interface Scope {
|
|
111
|
+
setTag(key: string, value: string | number | boolean | null): void;
|
|
112
|
+
setTags(tags: Record<string, string | number | boolean | null>): void;
|
|
113
|
+
setContext(key: string, context: Record<string, any> | null): void;
|
|
114
|
+
setUser(user: Record<string, any> | null): void;
|
|
115
|
+
setLevel(level: SeverityLevel): void;
|
|
116
|
+
setFingerprint(fingerprint: string[]): void;
|
|
117
|
+
setRequestSession(requestSession?: RequestSession): void;
|
|
118
|
+
setPropagationContext(context: PropagationContext): void;
|
|
119
|
+
clear(): void;
|
|
120
|
+
addBreadcrumb(breadcrumb: SentryBreadcrumb, maxBreadcrumbs?: number): void;
|
|
121
|
+
clearBreadcrumbs(): void;
|
|
122
|
+
setSpan(span: Span | undefined): void;
|
|
123
|
+
getSpan(): Span | undefined;
|
|
124
|
+
setTransaction(transaction: Transaction | undefined): void;
|
|
125
|
+
getTransaction(): Transaction | undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Hub interface for managing scopes and clients
|
|
130
|
+
*/
|
|
131
|
+
export interface Hub {
|
|
132
|
+
getClient(): any;
|
|
133
|
+
getScope(): Scope;
|
|
134
|
+
configureScope(callback: (scope: Scope) => void): void;
|
|
135
|
+
pushScope(): Scope;
|
|
136
|
+
popScope(): boolean;
|
|
137
|
+
withScope(callback: (scope: Scope) => void): void;
|
|
138
|
+
startTransaction(context: TransactionContext, customSamplingContext?: any): Transaction;
|
|
139
|
+
startSpan(context: SpanContext): Span;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Propagation context for distributed tracing
|
|
144
|
+
*/
|
|
145
|
+
export interface PropagationContext {
|
|
146
|
+
traceId: string;
|
|
147
|
+
spanId: string;
|
|
148
|
+
parentSpanId?: string;
|
|
149
|
+
sampled?: boolean;
|
|
150
|
+
dsc?: DynamicSamplingContext;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Dynamic sampling context
|
|
155
|
+
*/
|
|
156
|
+
export interface DynamicSamplingContext {
|
|
157
|
+
trace_id: string;
|
|
158
|
+
public_key: string;
|
|
159
|
+
sample_rate?: string;
|
|
160
|
+
release?: string;
|
|
161
|
+
environment?: string;
|
|
162
|
+
transaction?: string;
|
|
163
|
+
user_segment?: string;
|
|
164
|
+
[key: string]: string | undefined;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Traceparent data extracted from headers
|
|
169
|
+
*/
|
|
170
|
+
export interface TraceparentData {
|
|
171
|
+
traceId?: string;
|
|
172
|
+
parentSpanId?: string;
|
|
173
|
+
parentSampled?: boolean;
|
|
174
|
+
baggage?: Record<string, string>;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Sentry-specific breadcrumb interface
|
|
179
|
+
* Note: Use core Breadcrumb type for plugin-agnostic code.
|
|
180
|
+
* This type matches Sentry SDK's expected format.
|
|
181
|
+
*/
|
|
182
|
+
export interface SentryBreadcrumb {
|
|
183
|
+
type?: string;
|
|
184
|
+
level?: SeverityLevel;
|
|
185
|
+
category?: string;
|
|
186
|
+
message?: string;
|
|
187
|
+
data?: Record<string, any>;
|
|
188
|
+
timestamp?: number;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Severity levels
|
|
193
|
+
*/
|
|
194
|
+
export type SeverityLevel = 'fatal' | 'error' | 'warning' | 'log' | 'info' | 'debug';
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Request session status
|
|
198
|
+
*/
|
|
199
|
+
export interface RequestSession {
|
|
200
|
+
status?: 'ok' | 'errored' | 'crashed';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Sampling context for trace sampling decisions
|
|
205
|
+
*/
|
|
206
|
+
export interface SamplingContext {
|
|
207
|
+
transactionContext: TransactionContext;
|
|
208
|
+
parentSampled?: boolean;
|
|
209
|
+
request?: any;
|
|
210
|
+
location?: {
|
|
211
|
+
href?: string;
|
|
212
|
+
pathname?: string;
|
|
213
|
+
search?: string;
|
|
214
|
+
hash?: string;
|
|
215
|
+
[key: string]: unknown;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Custom sampling function type
|
|
221
|
+
*/
|
|
222
|
+
export type TraceSampler = (samplingContext: SamplingContext) => number | boolean;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Measurement units
|
|
226
|
+
*/
|
|
227
|
+
export type MeasurementUnit =
|
|
228
|
+
| 'nanosecond'
|
|
229
|
+
| 'microsecond'
|
|
230
|
+
| 'millisecond'
|
|
231
|
+
| 'second'
|
|
232
|
+
| 'minute'
|
|
233
|
+
| 'hour'
|
|
234
|
+
| 'day'
|
|
235
|
+
| 'week'
|
|
236
|
+
| 'bit'
|
|
237
|
+
| 'byte'
|
|
238
|
+
| 'kilobyte'
|
|
239
|
+
| 'kibibyte'
|
|
240
|
+
| 'megabyte'
|
|
241
|
+
| 'mebibyte'
|
|
242
|
+
| 'gigabyte'
|
|
243
|
+
| 'gibibyte'
|
|
244
|
+
| 'terabyte'
|
|
245
|
+
| 'tebibyte'
|
|
246
|
+
| 'petabyte'
|
|
247
|
+
| 'pebibyte'
|
|
248
|
+
| 'exabyte'
|
|
249
|
+
| 'exbibyte'
|
|
250
|
+
| 'ratio'
|
|
251
|
+
| 'percent'
|
|
252
|
+
| 'none';
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Environment configuration for Sentry Micro Frontend Plugin
|
|
3
|
+
* Environment configuration for Sentry Micro Frontend Plugin
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logWarn } from '@repo/shared/logger';
|
|
7
|
+
import { createEnv } from '@t3-oss/env-core';
|
|
8
|
+
import { z } from 'zod/v4';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Environment configuration specific to Sentry micro frontend functionality
|
|
12
|
+
*/
|
|
13
|
+
export const env = createEnv({
|
|
14
|
+
server: {
|
|
15
|
+
// Backstage app-specific DSNs for server-side
|
|
16
|
+
SENTRY_DSN_CMS: z.string().url().optional(),
|
|
17
|
+
SENTRY_DSN_WORKFLOWS: z.string().url().optional(),
|
|
18
|
+
SENTRY_DSN_AUTHMGMT: z.string().url().optional(),
|
|
19
|
+
|
|
20
|
+
// Micro frontend configuration
|
|
21
|
+
SENTRY_MICROFRONTEND_MODE: z.enum(['host', 'child', 'standalone']).optional(),
|
|
22
|
+
SENTRY_MICROFRONTEND_ZONE: z.string().optional(),
|
|
23
|
+
|
|
24
|
+
// Feature toggles
|
|
25
|
+
SENTRY_MICROFRONTEND_ENABLED: z.boolean().optional(),
|
|
26
|
+
SENTRY_MICROFRONTEND_MULTIPLEXED_TRANSPORT: z.boolean().optional(),
|
|
27
|
+
},
|
|
28
|
+
client: {
|
|
29
|
+
// Backstage app-specific DSNs for client-side
|
|
30
|
+
NEXT_PUBLIC_SENTRY_DSN_CMS: z.string().url().optional(),
|
|
31
|
+
NEXT_PUBLIC_SENTRY_DSN_WORKFLOWS: z.string().url().optional(),
|
|
32
|
+
NEXT_PUBLIC_SENTRY_DSN_AUTHMGMT: z.string().url().optional(),
|
|
33
|
+
|
|
34
|
+
// Client-side micro frontend configuration
|
|
35
|
+
NEXT_PUBLIC_SENTRY_MICROFRONTEND_MODE: z.enum(['host', 'child', 'standalone']).optional(),
|
|
36
|
+
NEXT_PUBLIC_SENTRY_MICROFRONTEND_ZONE: z.string().optional(),
|
|
37
|
+
|
|
38
|
+
// Feature toggles
|
|
39
|
+
NEXT_PUBLIC_SENTRY_MICROFRONTEND_ENABLED: z.boolean().optional(),
|
|
40
|
+
},
|
|
41
|
+
clientPrefix: 'NEXT_PUBLIC_',
|
|
42
|
+
runtimeEnv: process.env,
|
|
43
|
+
skipValidation: process.env.SKIP_ENV_VALIDATION === 'true' || process.env.NODE_ENV === 'test',
|
|
44
|
+
emptyStringAsUndefined: true,
|
|
45
|
+
onInvalidAccess: (variable: string) => {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`❌ Attempted to access a server-side environment variable on the client: ${variable}`,
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
onValidationError: error => {
|
|
51
|
+
// Non-critical plugin, warn but don't throw
|
|
52
|
+
logWarn('Sentry Micro Frontend Plugin env validation failed', { error });
|
|
53
|
+
return undefined as never;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Safe environment access for non-Next.js contexts.
|
|
59
|
+
*
|
|
60
|
+
* Provides fallback environment variable access for Node.js, workers, and test environments
|
|
61
|
+
* where the validated env object may not be available. Returns fallback values for Sentry
|
|
62
|
+
* micro frontend configuration.
|
|
63
|
+
*
|
|
64
|
+
* @returns Environment object with Sentry micro frontend configuration values
|
|
65
|
+
*/
|
|
66
|
+
export function safeEnv() {
|
|
67
|
+
if (env) {
|
|
68
|
+
return env;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Fallback for non-Next.js contexts
|
|
72
|
+
return {
|
|
73
|
+
// Server
|
|
74
|
+
SENTRY_DSN_CMS: process.env.SENTRY_DSN_CMS,
|
|
75
|
+
SENTRY_DSN_WORKFLOWS: process.env.SENTRY_DSN_WORKFLOWS,
|
|
76
|
+
SENTRY_DSN_AUTHMGMT: process.env.SENTRY_DSN_AUTHMGMT,
|
|
77
|
+
SENTRY_MICROFRONTEND_MODE: process.env.SENTRY_MICROFRONTEND_MODE as
|
|
78
|
+
| 'host'
|
|
79
|
+
| 'child'
|
|
80
|
+
| 'standalone'
|
|
81
|
+
| undefined,
|
|
82
|
+
SENTRY_MICROFRONTEND_APP:
|
|
83
|
+
process.env.SENTRY_MICROFRONTEND_APP ?? process.env.SENTRY_MICROFRONTEND_ZONE,
|
|
84
|
+
SENTRY_MICROFRONTEND_ENABLED: process.env.SENTRY_MICROFRONTEND_ENABLED === 'true',
|
|
85
|
+
SENTRY_MICROFRONTEND_MULTIPLEXED_TRANSPORT:
|
|
86
|
+
process.env.SENTRY_MICROFRONTEND_MULTIPLEXED_TRANSPORT === 'true',
|
|
87
|
+
|
|
88
|
+
// Client
|
|
89
|
+
NEXT_PUBLIC_SENTRY_DSN_CMS: process.env.NEXT_PUBLIC_SENTRY_DSN_CMS,
|
|
90
|
+
NEXT_PUBLIC_SENTRY_DSN_WORKFLOWS: process.env.NEXT_PUBLIC_SENTRY_DSN_WORKFLOWS,
|
|
91
|
+
NEXT_PUBLIC_SENTRY_DSN_AUTHMGMT: process.env.NEXT_PUBLIC_SENTRY_DSN_AUTHMGMT,
|
|
92
|
+
NEXT_PUBLIC_SENTRY_MICROFRONTEND_MODE: process.env.NEXT_PUBLIC_SENTRY_MICROFRONTEND_MODE as
|
|
93
|
+
| 'host'
|
|
94
|
+
| 'child'
|
|
95
|
+
| 'standalone'
|
|
96
|
+
| undefined,
|
|
97
|
+
NEXT_PUBLIC_SENTRY_MICROFRONTEND_APP:
|
|
98
|
+
process.env.NEXT_PUBLIC_SENTRY_MICROFRONTEND_APP ??
|
|
99
|
+
process.env.NEXT_PUBLIC_SENTRY_MICROFRONTEND_ZONE,
|
|
100
|
+
NEXT_PUBLIC_SENTRY_MICROFRONTEND_ENABLED:
|
|
101
|
+
process.env.NEXT_PUBLIC_SENTRY_MICROFRONTEND_ENABLED === 'true',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type Env = typeof env;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sentry Micro Frontend Plugin
|
|
3
|
+
* Sentry Micro Frontend Plugin
|
|
4
|
+
*
|
|
5
|
+
* Provides specialized Sentry integration for micro frontend architectures.
|
|
6
|
+
* Supports both host and child modes with automatic parent detection.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { createMultiplexedTransport } from './multiplexed-transport';
|
|
10
|
+
export { SentryMicroFrontendPlugin, createSentryMicroFrontendPlugin } from './plugin';
|
|
11
|
+
export type { BackstageAppConfig, MicroFrontendMode, SentryMicroFrontendConfig } from './types';
|
|
12
|
+
export { createBackstageScope, detectCurrentBackstageApp, isHostEnvironment } from './utils';
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Multiplexed transport utilities for Sentry Micro Frontend Plugin
|
|
3
|
+
* Multiplexed transport utilities for Sentry Micro Frontend Plugin
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logWarn } from '@repo/shared/logs';
|
|
7
|
+
|
|
8
|
+
import type { BackstageAppConfig } from './types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create a multiplexed transport that routes events to different Sentry projects.
|
|
12
|
+
*
|
|
13
|
+
* Creates a Sentry transport that routes events to different DSNs based on the
|
|
14
|
+
* backstageApp information in the event. Supports edge runtime environments.
|
|
15
|
+
*
|
|
16
|
+
* @param backstage - Array of backstage app configurations with DSNs
|
|
17
|
+
* @param fallbackDsn - Optional fallback DSN if no backstageApp match is found
|
|
18
|
+
* @param sentryClient - Optional Sentry client instance (defaults to global Sentry)
|
|
19
|
+
* @returns Multiplexed transport instance, or undefined if Sentry is not available
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export function createMultiplexedTransport(
|
|
23
|
+
backstage: BackstageAppConfig[],
|
|
24
|
+
fallbackDsn?: string,
|
|
25
|
+
|
|
26
|
+
sentryClient?: any,
|
|
27
|
+
): any {
|
|
28
|
+
// Import Sentry dynamically or use provided client (edge runtime compatible)
|
|
29
|
+
const Sentry =
|
|
30
|
+
sentryClient !== undefined
|
|
31
|
+
? sentryClient
|
|
32
|
+
: typeof globalThis !== 'undefined'
|
|
33
|
+
? (globalThis as any).Sentry
|
|
34
|
+
: null;
|
|
35
|
+
|
|
36
|
+
if (!Sentry?.makeMultiplexedTransport || !Sentry.makeFetchTransport) {
|
|
37
|
+
logWarn('Sentry multiplexed transport not available');
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return Sentry.makeMultiplexedTransport(Sentry.makeFetchTransport, (args: any) => {
|
|
42
|
+
const event = args.getEvent();
|
|
43
|
+
|
|
44
|
+
if (!event) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Extract backstageApp information from various sources
|
|
49
|
+
const backstageApp =
|
|
50
|
+
event.tags?.backstageApp ??
|
|
51
|
+
event.extra?.backstageApp ??
|
|
52
|
+
event.contexts?.microFrontend?.backstageApp;
|
|
53
|
+
|
|
54
|
+
if (backstageApp) {
|
|
55
|
+
// Find backstageApp configuration
|
|
56
|
+
const backstageAppConfig = backstage.find(z => z.name === backstageApp);
|
|
57
|
+
|
|
58
|
+
if (backstageAppConfig?.dsn) {
|
|
59
|
+
// Route to backstageApp-specific DSN
|
|
60
|
+
|
|
61
|
+
const envelope: any[] = [
|
|
62
|
+
{
|
|
63
|
+
dsn: backstageAppConfig.dsn,
|
|
64
|
+
release: backstageAppConfig.release ?? event.release,
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
// Add backstageApp-specific tags if configured
|
|
69
|
+
if (backstageAppConfig.tags && event.tags) {
|
|
70
|
+
Object.assign(event.tags, backstageAppConfig.tags);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return envelope;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Use fallback DSN if provided
|
|
78
|
+
if (fallbackDsn) {
|
|
79
|
+
return [{ dsn: fallbackDsn }];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Let the default DSN handle it
|
|
83
|
+
return [];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Create a transport matcher function for more complex routing logic.
|
|
89
|
+
*
|
|
90
|
+
* Creates a matcher function that can be used with Sentry's multiplexed transport
|
|
91
|
+
* to route events based on custom logic, including stack frame analysis.
|
|
92
|
+
*
|
|
93
|
+
* @param backstage - Array of backstage app configurations
|
|
94
|
+
* @param customMatcher - Optional custom matcher function to extract backstageApp from event
|
|
95
|
+
* @returns Matcher function that returns an array of transport configurations
|
|
96
|
+
*/
|
|
97
|
+
export function createTransportMatcher(
|
|
98
|
+
backstage: BackstageAppConfig[],
|
|
99
|
+
|
|
100
|
+
customMatcher?: (event: any) => string | undefined,
|
|
101
|
+
): (args: any) => any[] {
|
|
102
|
+
return (args: any) => {
|
|
103
|
+
const event = args.getEvent();
|
|
104
|
+
|
|
105
|
+
if (!event) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Use custom matcher if provided
|
|
110
|
+
let backstageApp: string | undefined;
|
|
111
|
+
if (customMatcher) {
|
|
112
|
+
backstageApp = customMatcher(event);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Fall back to default backstageApp detection
|
|
116
|
+
backstageApp ??=
|
|
117
|
+
event.tags?.backstageApp ??
|
|
118
|
+
event.extra?.backstageApp ??
|
|
119
|
+
event.contexts?.microFrontend?.backstageApp;
|
|
120
|
+
|
|
121
|
+
// Try to detect backstageApp from stack frames
|
|
122
|
+
if (!backstageApp && event.exception?.values?.[0]?.stacktrace?.frames) {
|
|
123
|
+
const { frames } = event.exception.values[0].stacktrace;
|
|
124
|
+
for (const frame of frames) {
|
|
125
|
+
if (frame.filename) {
|
|
126
|
+
// Check if filename contains backstageApp hints
|
|
127
|
+
if (frame.filename.includes('/cms/')) {
|
|
128
|
+
backstageApp = 'cms';
|
|
129
|
+
break;
|
|
130
|
+
} else if (frame.filename.includes('/workflows/')) {
|
|
131
|
+
backstageApp = 'workflows';
|
|
132
|
+
break;
|
|
133
|
+
} else if (frame.filename.includes('/authmgmt/')) {
|
|
134
|
+
backstageApp = 'authmgmt';
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (backstageApp) {
|
|
142
|
+
const backstageAppConfig = backstage.find(z => z.name === backstageApp);
|
|
143
|
+
if (backstageAppConfig?.dsn) {
|
|
144
|
+
return [
|
|
145
|
+
{
|
|
146
|
+
dsn: backstageAppConfig.dsn,
|
|
147
|
+
release: backstageAppConfig.release,
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return [];
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Enhance an event with Backstage app information before sending.
|
|
159
|
+
*
|
|
160
|
+
* Adds backstageApp tags, context, and extra data to a Sentry event.
|
|
161
|
+
* This ensures events are properly tagged for micro frontend routing.
|
|
162
|
+
*
|
|
163
|
+
* @param event - Sentry event to enhance
|
|
164
|
+
* @param backstageApp - Name of the backstage app
|
|
165
|
+
* @param additionalContext - Optional additional context to add
|
|
166
|
+
* @returns Enhanced event with backstageApp information
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
export function enhanceEventWithBackstageApp(
|
|
170
|
+
event: any,
|
|
171
|
+
backstageApp: string,
|
|
172
|
+
|
|
173
|
+
additionalContext?: Record<string, any>,
|
|
174
|
+
): any {
|
|
175
|
+
// Add backstageApp tag
|
|
176
|
+
event.tags ??= {};
|
|
177
|
+
event.tags.backstageApp = backstageApp;
|
|
178
|
+
event.tags.microFrontend = true;
|
|
179
|
+
|
|
180
|
+
// Add backstageApp context
|
|
181
|
+
event.contexts ??= {};
|
|
182
|
+
event.contexts.microFrontend = {
|
|
183
|
+
backstageApp,
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
185
|
+
...additionalContext,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// Add backstageApp to extra for backward compatibility
|
|
189
|
+
event.extra ??= {};
|
|
190
|
+
event.extra.backstageApp = backstageApp;
|
|
191
|
+
|
|
192
|
+
return event;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Create a beforeSend hook that adds backstageApp information.
|
|
197
|
+
*
|
|
198
|
+
* Creates a Sentry beforeSend hook that enhances events with backstageApp information
|
|
199
|
+
* before they are sent. Can wrap an existing beforeSend hook.
|
|
200
|
+
*
|
|
201
|
+
* @param backstageApp - Name of the backstage app
|
|
202
|
+
* @param originalBeforeSend - Optional original beforeSend hook to wrap
|
|
203
|
+
* @returns beforeSend hook function
|
|
204
|
+
*/
|
|
205
|
+
export function createBackstageBeforeSend(
|
|
206
|
+
backstageApp: string,
|
|
207
|
+
|
|
208
|
+
originalBeforeSend?: (event: any, hint: any) => any,
|
|
209
|
+
): (event: any, hint: any) => any {
|
|
210
|
+
return (event: any, hint: any) => {
|
|
211
|
+
// Enhance with backstageApp information
|
|
212
|
+
enhanceEventWithBackstageApp(event, backstageApp);
|
|
213
|
+
|
|
214
|
+
// Call original beforeSend if provided
|
|
215
|
+
if (originalBeforeSend) {
|
|
216
|
+
return originalBeforeSend(event, hint);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return event;
|
|
220
|
+
};
|
|
221
|
+
}
|