@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,593 @@
|
|
|
1
|
+
import { logDebug, logError, logWarn } from "@od-oneapp/shared/logs";
|
|
2
|
+
import { SentryPlugin } from "@integrations/sentry/observability-plugin/plugin";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/sentry-microfrontend/multiplexed-transport.ts
|
|
5
|
+
/**
|
|
6
|
+
* @fileoverview Multiplexed transport utilities for Sentry Micro Frontend Plugin
|
|
7
|
+
* Multiplexed transport utilities for Sentry Micro Frontend Plugin
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Create a multiplexed transport that routes events to different Sentry projects.
|
|
11
|
+
*
|
|
12
|
+
* Creates a Sentry transport that routes events to different DSNs based on the
|
|
13
|
+
* backstageApp information in the event. Supports edge runtime environments.
|
|
14
|
+
*
|
|
15
|
+
* @param backstage - Array of backstage app configurations with DSNs
|
|
16
|
+
* @param fallbackDsn - Optional fallback DSN if no backstageApp match is found
|
|
17
|
+
* @param sentryClient - Optional Sentry client instance (defaults to global Sentry)
|
|
18
|
+
* @returns Multiplexed transport instance, or undefined if Sentry is not available
|
|
19
|
+
*/
|
|
20
|
+
function createMultiplexedTransport(backstage, fallbackDsn, sentryClient) {
|
|
21
|
+
const Sentry = sentryClient !== void 0 ? sentryClient : typeof globalThis !== "undefined" ? globalThis.Sentry : null;
|
|
22
|
+
if (!Sentry?.makeMultiplexedTransport || !Sentry.makeFetchTransport) {
|
|
23
|
+
logWarn("Sentry multiplexed transport not available");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
return Sentry.makeMultiplexedTransport(Sentry.makeFetchTransport, (args) => {
|
|
27
|
+
const event = args.getEvent();
|
|
28
|
+
if (!event) return [];
|
|
29
|
+
const backstageApp = event.tags?.backstageApp ?? event.extra?.backstageApp ?? event.contexts?.microFrontend?.backstageApp;
|
|
30
|
+
if (backstageApp) {
|
|
31
|
+
const backstageAppConfig = backstage.find((z) => z.name === backstageApp);
|
|
32
|
+
if (backstageAppConfig?.dsn) {
|
|
33
|
+
const envelope = [{
|
|
34
|
+
dsn: backstageAppConfig.dsn,
|
|
35
|
+
release: backstageAppConfig.release ?? event.release
|
|
36
|
+
}];
|
|
37
|
+
if (backstageAppConfig.tags && event.tags) Object.assign(event.tags, backstageAppConfig.tags);
|
|
38
|
+
return envelope;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (fallbackDsn) return [{ dsn: fallbackDsn }];
|
|
42
|
+
return [];
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Enhance an event with Backstage app information before sending.
|
|
47
|
+
*
|
|
48
|
+
* Adds backstageApp tags, context, and extra data to a Sentry event.
|
|
49
|
+
* This ensures events are properly tagged for micro frontend routing.
|
|
50
|
+
*
|
|
51
|
+
* @param event - Sentry event to enhance
|
|
52
|
+
* @param backstageApp - Name of the backstage app
|
|
53
|
+
* @param additionalContext - Optional additional context to add
|
|
54
|
+
* @returns Enhanced event with backstageApp information
|
|
55
|
+
*/
|
|
56
|
+
function enhanceEventWithBackstageApp(event, backstageApp, additionalContext) {
|
|
57
|
+
event.tags ??= {};
|
|
58
|
+
event.tags.backstageApp = backstageApp;
|
|
59
|
+
event.tags.microFrontend = true;
|
|
60
|
+
event.contexts ??= {};
|
|
61
|
+
event.contexts.microFrontend = {
|
|
62
|
+
backstageApp,
|
|
63
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64
|
+
...additionalContext
|
|
65
|
+
};
|
|
66
|
+
event.extra ??= {};
|
|
67
|
+
event.extra.backstageApp = backstageApp;
|
|
68
|
+
return event;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Create a beforeSend hook that adds backstageApp information.
|
|
72
|
+
*
|
|
73
|
+
* Creates a Sentry beforeSend hook that enhances events with backstageApp information
|
|
74
|
+
* before they are sent. Can wrap an existing beforeSend hook.
|
|
75
|
+
*
|
|
76
|
+
* @param backstageApp - Name of the backstage app
|
|
77
|
+
* @param originalBeforeSend - Optional original beforeSend hook to wrap
|
|
78
|
+
* @returns beforeSend hook function
|
|
79
|
+
*/
|
|
80
|
+
function createBackstageBeforeSend(backstageApp, originalBeforeSend) {
|
|
81
|
+
return (event, hint) => {
|
|
82
|
+
enhanceEventWithBackstageApp(event, backstageApp);
|
|
83
|
+
if (originalBeforeSend) return originalBeforeSend(event, hint);
|
|
84
|
+
return event;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/plugins/sentry-microfrontend/sentry-types.ts
|
|
90
|
+
/**
|
|
91
|
+
* Map LogLevel to Sentry Severity.
|
|
92
|
+
*
|
|
93
|
+
* Converts the observability package's LogLevel to Sentry's SeverityLevel format.
|
|
94
|
+
*
|
|
95
|
+
* @param level - Log level from observability package
|
|
96
|
+
* @returns Corresponding Sentry severity level
|
|
97
|
+
*/
|
|
98
|
+
function mapLogLevelToSentrySeverity(level) {
|
|
99
|
+
switch (level) {
|
|
100
|
+
case "error": return "error";
|
|
101
|
+
case "warning": return "warning";
|
|
102
|
+
case "info": return "info";
|
|
103
|
+
case "debug": return "debug";
|
|
104
|
+
default: return "info";
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/plugins/sentry-microfrontend/utils.ts
|
|
110
|
+
/**
|
|
111
|
+
* @fileoverview Utility functions for Sentry Micro Frontend Plugin
|
|
112
|
+
* Utility functions for Sentry Micro Frontend Plugin
|
|
113
|
+
*/
|
|
114
|
+
/**
|
|
115
|
+
* Detect the current micro frontend backstageApp based on URL path.
|
|
116
|
+
*
|
|
117
|
+
* Analyzes the current URL pathname to determine which micro frontend application
|
|
118
|
+
* is active. Supports custom path patterns and falls back to default patterns.
|
|
119
|
+
*
|
|
120
|
+
* @param customPatterns - Optional array of custom backstage app configurations with path patterns
|
|
121
|
+
* @returns Detected backstage app name, or undefined if not detected
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const app = detectCurrentBackstageApp([
|
|
126
|
+
* { name: 'admin', pathPatterns: ['/admin', '/manage'] },
|
|
127
|
+
* { name: 'dashboard', pathPatterns: [/^\/dashboard/] }
|
|
128
|
+
* ]);
|
|
129
|
+
* // Returns: 'admin' if pathname starts with '/admin' or '/manage'
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
function detectCurrentBackstageApp(customPatterns) {
|
|
133
|
+
if (typeof globalThis === "undefined" || !globalThis.location) {
|
|
134
|
+
if (typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BASE_PATH) return process.env.NEXT_PUBLIC_BASE_PATH.replace("/", "");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const path = globalThis.location?.pathname;
|
|
138
|
+
if (!path) return;
|
|
139
|
+
if (customPatterns) {
|
|
140
|
+
for (const config of customPatterns) if (config.pathPatterns) {
|
|
141
|
+
for (const pattern of config.pathPatterns) if (typeof pattern === "string" && path.startsWith(pattern)) return config.name;
|
|
142
|
+
else if (pattern instanceof RegExp && pattern.test(path)) return config.name;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (path.startsWith("/admin")) return "admin";
|
|
146
|
+
if (path.startsWith("/dashboard")) return "dashboard";
|
|
147
|
+
if (path.startsWith("/settings")) return "settings";
|
|
148
|
+
if (globalThis.__SENTRY_MICRO_FRONTEND_APP__) return globalThis.__SENTRY_MICRO_FRONTEND_APP__;
|
|
149
|
+
if (globalThis.__SENTRY_MICRO_FRONTEND_ZONE__) return globalThis.__SENTRY_MICRO_FRONTEND_ZONE__;
|
|
150
|
+
return "main";
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Check if running in a host environment.
|
|
154
|
+
*
|
|
155
|
+
* Determines whether the current application is acting as a host for micro frontends
|
|
156
|
+
* or as a child micro frontend. Checks for explicit host markers and Sentry initialization state.
|
|
157
|
+
*
|
|
158
|
+
* @returns True if running as host, false if child or standalone
|
|
159
|
+
*/
|
|
160
|
+
function isHostEnvironment() {
|
|
161
|
+
if (typeof globalThis === "undefined") return false;
|
|
162
|
+
if (globalThis.__SENTRY_MICRO_FRONTEND_HOST__) return true;
|
|
163
|
+
if (globalThis.Sentry && typeof globalThis.Sentry.getCurrentHub === "function") return false;
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Create a Sentry scope with backstageApp-specific context.
|
|
168
|
+
*
|
|
169
|
+
* Creates a new Sentry scope configured with micro frontend tags and context.
|
|
170
|
+
* Includes backstageApp tag, microFrontend context, and any additional tags provided.
|
|
171
|
+
*
|
|
172
|
+
* @param backstageApp - Name of the backstage app
|
|
173
|
+
* @param additionalTags - Optional additional tags to set on the scope
|
|
174
|
+
* @returns Sentry scope instance, or null if Sentry is not available
|
|
175
|
+
*/
|
|
176
|
+
function createBackstageScope(backstageApp, additionalTags) {
|
|
177
|
+
if (typeof globalThis === "undefined" || !globalThis.Sentry) return null;
|
|
178
|
+
const { Sentry } = globalThis;
|
|
179
|
+
if (!Sentry.Scope || typeof Sentry.Scope !== "function") return null;
|
|
180
|
+
try {
|
|
181
|
+
const scope = new Sentry.Scope();
|
|
182
|
+
scope.setTag("backstageApp", backstageApp);
|
|
183
|
+
scope.setTag("microFrontend", true);
|
|
184
|
+
scope.setContext("microFrontend", {
|
|
185
|
+
backstageApp,
|
|
186
|
+
isHost: globalThis.__SENTRY_MICRO_FRONTEND_HOST__ ?? false,
|
|
187
|
+
url: globalThis.location?.href ?? void 0
|
|
188
|
+
});
|
|
189
|
+
if (additionalTags) Object.entries(additionalTags).forEach(([key, value]) => {
|
|
190
|
+
scope.setTag(key, value);
|
|
191
|
+
});
|
|
192
|
+
return scope;
|
|
193
|
+
} catch (error) {
|
|
194
|
+
logError("[SentryMicroFrontendPlugin] Failed to create Backstage scope", { error });
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Check if Sentry is already initialized by a parent application.
|
|
200
|
+
*
|
|
201
|
+
* Verifies whether a parent Sentry instance exists in the global scope.
|
|
202
|
+
* Used to determine if the current micro frontend should use the parent's Sentry
|
|
203
|
+
* or initialize its own instance.
|
|
204
|
+
*
|
|
205
|
+
* @returns True if parent Sentry is available, false otherwise
|
|
206
|
+
*/
|
|
207
|
+
function hasParentSentry() {
|
|
208
|
+
if (typeof globalThis === "undefined") return false;
|
|
209
|
+
const { Sentry } = globalThis;
|
|
210
|
+
if (!Sentry) return false;
|
|
211
|
+
return [
|
|
212
|
+
"captureException",
|
|
213
|
+
"captureMessage",
|
|
214
|
+
"withScope"
|
|
215
|
+
].every((method) => typeof Sentry[method] === "function");
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get the parent Sentry instance if available.
|
|
219
|
+
*
|
|
220
|
+
* Returns the global Sentry instance if it exists and has been initialized
|
|
221
|
+
* by a parent application. Returns null if no parent Sentry is available.
|
|
222
|
+
*
|
|
223
|
+
* @returns Parent Sentry SDK instance, or null if not available
|
|
224
|
+
*/
|
|
225
|
+
function getParentSentry() {
|
|
226
|
+
if (hasParentSentry()) return globalThis.Sentry;
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Mark the current environment as a host.
|
|
231
|
+
*
|
|
232
|
+
* Sets global flags indicating that this application is acting as a host
|
|
233
|
+
* for micro frontends. This affects how Sentry events are routed and tagged.
|
|
234
|
+
*
|
|
235
|
+
* @param backstageApp - Optional backstage app name to set
|
|
236
|
+
*/
|
|
237
|
+
function markAsHost(backstageApp) {
|
|
238
|
+
if (typeof globalThis !== "undefined") {
|
|
239
|
+
globalThis.__SENTRY_MICRO_FRONTEND_HOST__ = true;
|
|
240
|
+
if (backstageApp) {
|
|
241
|
+
globalThis.__SENTRY_MICRO_FRONTEND_APP__ = backstageApp;
|
|
242
|
+
globalThis.__SENTRY_MICRO_FRONTEND_ZONE__ = backstageApp;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Ensure only one Sentry initialization happens (thread-safe).
|
|
248
|
+
*
|
|
249
|
+
* Prevents multiple Sentry initializations using global state tracking.
|
|
250
|
+
* Uses timestamps and unique IDs to detect concurrent initialization attempts.
|
|
251
|
+
* Throws an error if Sentry is already initialized or if concurrent initialization is detected.
|
|
252
|
+
*
|
|
253
|
+
* @throws Error if Sentry is already initialized or concurrent initialization detected
|
|
254
|
+
*/
|
|
255
|
+
function ensureSingleInit() {
|
|
256
|
+
const initKey = "__SENTRY_INIT_STATE__";
|
|
257
|
+
const now = Date.now();
|
|
258
|
+
if (typeof globalThis !== "undefined") {
|
|
259
|
+
const globalState = globalThis[initKey];
|
|
260
|
+
if (globalState) {
|
|
261
|
+
const { status, timestamp, id } = globalState;
|
|
262
|
+
if (status === "initialized") throw new Error("Sentry has already been initialized! Use hasParentSentry() to check before initializing.");
|
|
263
|
+
if (status === "initializing" && now - timestamp < 5e3) throw new Error(`Sentry initialization already in progress (started ${now - timestamp}ms ago by ${id})`);
|
|
264
|
+
}
|
|
265
|
+
const initId = `${now}-${Math.random().toString(36).substr(2, 9)}`;
|
|
266
|
+
globalThis[initKey] = {
|
|
267
|
+
status: "initializing",
|
|
268
|
+
timestamp: now,
|
|
269
|
+
id: initId
|
|
270
|
+
};
|
|
271
|
+
if (globalThis[initKey].id !== initId) throw new Error("Concurrent Sentry initialization detected");
|
|
272
|
+
globalThis[initKey] = {
|
|
273
|
+
status: "initialized",
|
|
274
|
+
timestamp: now,
|
|
275
|
+
id: initId
|
|
276
|
+
};
|
|
277
|
+
globalThis.__SENTRY_INITIALIZED__ = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/plugins/sentry-microfrontend/plugin.ts
|
|
283
|
+
/**
|
|
284
|
+
* @fileoverview Sentry Micro Frontend Plugin
|
|
285
|
+
* Sentry Micro Frontend Plugin
|
|
286
|
+
*
|
|
287
|
+
* Extends the base Sentry plugin with micro frontend-specific functionality
|
|
288
|
+
*/
|
|
289
|
+
/**
|
|
290
|
+
* Sentry plugin optimized for micro frontend architectures
|
|
291
|
+
*/
|
|
292
|
+
/**
|
|
293
|
+
* Sentry plugin optimized for micro frontend architectures.
|
|
294
|
+
*
|
|
295
|
+
* Extends SentryPlugin with micro frontend-specific features:
|
|
296
|
+
* - Host/child/standalone mode detection
|
|
297
|
+
* - Multiplexed transport for routing events to different Sentry projects
|
|
298
|
+
* - Backstage app context management
|
|
299
|
+
* - Parent Sentry instance detection and reuse
|
|
300
|
+
*/
|
|
301
|
+
var SentryMicroFrontendPlugin = class SentryMicroFrontendPlugin extends SentryPlugin {
|
|
302
|
+
mode;
|
|
303
|
+
backstageApp;
|
|
304
|
+
parentSentry;
|
|
305
|
+
backstageScope;
|
|
306
|
+
microFrontendConfig;
|
|
307
|
+
eventProcessorCleanup;
|
|
308
|
+
/**
|
|
309
|
+
* Create a new SentryMicroFrontendPlugin instance.
|
|
310
|
+
*
|
|
311
|
+
* @param config - Sentry micro frontend plugin configuration
|
|
312
|
+
*/
|
|
313
|
+
constructor(config = {}) {
|
|
314
|
+
const mode = SentryMicroFrontendPlugin.determineMode(config);
|
|
315
|
+
const baseConfig = SentryMicroFrontendPlugin.prepareConfig(config, mode);
|
|
316
|
+
super(baseConfig);
|
|
317
|
+
this.mode = mode;
|
|
318
|
+
this.microFrontendConfig = config;
|
|
319
|
+
this.backstageApp = config.backstageApp ?? detectCurrentBackstageApp(config.backstageApps);
|
|
320
|
+
if (this.mode === "child") {
|
|
321
|
+
const parent = getParentSentry();
|
|
322
|
+
if (parent) {
|
|
323
|
+
this.parentSentry = parent;
|
|
324
|
+
this.enabled = true;
|
|
325
|
+
if (this.backstageApp && this.parentSentry.Scope) this.backstageScope = createBackstageScope(this.backstageApp, config.globalTags);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (this.mode === "host") markAsHost(this.backstageApp);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Determine the operation mode based on configuration and environment.
|
|
332
|
+
*
|
|
333
|
+
* @param config - Plugin configuration
|
|
334
|
+
* @returns Operation mode ('host', 'child', or 'standalone')
|
|
335
|
+
*/
|
|
336
|
+
static determineMode(config) {
|
|
337
|
+
if (config.isHost) return "host";
|
|
338
|
+
if (config.detectParent !== false && hasParentSentry()) return "child";
|
|
339
|
+
return "standalone";
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Prepare configuration based on operation mode.
|
|
343
|
+
*
|
|
344
|
+
* Adjusts configuration settings based on whether running as host, child, or standalone.
|
|
345
|
+
*
|
|
346
|
+
* @param config - Original plugin configuration
|
|
347
|
+
* @param mode - Determined operation mode
|
|
348
|
+
* @returns Prepared configuration object
|
|
349
|
+
*/
|
|
350
|
+
static prepareConfig(config, mode) {
|
|
351
|
+
const preparedConfig = { ...config };
|
|
352
|
+
if (mode === "child") preparedConfig.enabled = false;
|
|
353
|
+
else if (mode === "host" && config.backstageApps && config.useMultiplexedTransport !== false) {}
|
|
354
|
+
return preparedConfig;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Initialize the plugin
|
|
358
|
+
*/
|
|
359
|
+
async initialize(config) {
|
|
360
|
+
const mergedConfig = {
|
|
361
|
+
...this.microFrontendConfig,
|
|
362
|
+
...config
|
|
363
|
+
};
|
|
364
|
+
if (this.mode === "child") {
|
|
365
|
+
if (this.parentSentry) {
|
|
366
|
+
this.client = this.parentSentry;
|
|
367
|
+
this.initialized = true;
|
|
368
|
+
if (this.backstageApp && mergedConfig.addBackstageContext !== false) this.configureParentSentry();
|
|
369
|
+
}
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (mergedConfig.preventDuplicateInit !== false) try {
|
|
373
|
+
ensureSingleInit();
|
|
374
|
+
} catch (error) {
|
|
375
|
+
logError("Sentry initialization prevented", { error });
|
|
376
|
+
this.enabled = false;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
await super.initialize(mergedConfig);
|
|
380
|
+
if (this.mode === "host" && this.client && mergedConfig.backstageApps) this.setupHostMode(mergedConfig);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Configure parent Sentry instance for child mode
|
|
384
|
+
*/
|
|
385
|
+
configureParentSentry() {
|
|
386
|
+
if (!this.parentSentry || !this.backstageApp) {
|
|
387
|
+
logWarn("[SentryMicroFrontendPlugin] Cannot configure parent Sentry: missing parentSentry or backstageApp");
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
try {
|
|
391
|
+
const processor = (event) => {
|
|
392
|
+
try {
|
|
393
|
+
if (this.shouldProcessEvent(event)) enhanceEventWithBackstageApp(event, this.backstageApp ?? "", {
|
|
394
|
+
mode: this.mode,
|
|
395
|
+
plugin: "SentryMicroFrontendPlugin"
|
|
396
|
+
});
|
|
397
|
+
} catch (error) {
|
|
398
|
+
logError("[SentryMicroFrontendPlugin] Error processing event", {
|
|
399
|
+
error,
|
|
400
|
+
event
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
return event;
|
|
404
|
+
};
|
|
405
|
+
if (typeof this.parentSentry.addEventProcessor === "function") {
|
|
406
|
+
this.parentSentry.addEventProcessor(processor);
|
|
407
|
+
this.eventProcessorCleanup = () => {};
|
|
408
|
+
} else logWarn("[SentryMicroFrontendPlugin] Parent Sentry does not support addEventProcessor");
|
|
409
|
+
} catch (error) {
|
|
410
|
+
logError("[SentryMicroFrontendPlugin] Failed to configure parent Sentry", { error });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Set up host mode with multiplexed transport
|
|
415
|
+
*/
|
|
416
|
+
setupHostMode(config) {
|
|
417
|
+
if (!config.backstageApps || !this.client) {
|
|
418
|
+
logWarn("[SentryMicroFrontendPlugin] Cannot setup host mode: missing backstageApps or client");
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
const transport = createMultiplexedTransport(config.backstageApps, config.fallbackDsn ?? config.dsn, this.client);
|
|
423
|
+
if (transport && typeof this.client.init === "function") {
|
|
424
|
+
const currentOptions = typeof this.client.getOptions === "function" ? this.client.getOptions() : {};
|
|
425
|
+
this.client.init({
|
|
426
|
+
...currentOptions,
|
|
427
|
+
transport,
|
|
428
|
+
beforeSend: createBackstageBeforeSend(this.backstageApp ?? "main", config.beforeSend)
|
|
429
|
+
});
|
|
430
|
+
} else logWarn("[SentryMicroFrontendPlugin] Client does not support init method or transport creation failed");
|
|
431
|
+
} catch (error) {
|
|
432
|
+
logError("[SentryMicroFrontendPlugin] Failed to setup host mode", { error });
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Check if we should process this event
|
|
437
|
+
*/
|
|
438
|
+
shouldProcessEvent(event) {
|
|
439
|
+
if (event.tags?.microFrontendProcessed) return false;
|
|
440
|
+
if (this.backstageApp && event.tags?.backstageApp && event.tags.backstageApp !== this.backstageApp) return false;
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Capture an exception with backstageApp context
|
|
445
|
+
*/
|
|
446
|
+
captureException(error, context) {
|
|
447
|
+
if (!this.enabled) return;
|
|
448
|
+
try {
|
|
449
|
+
if (this.mode === "child" && this.parentSentry && this.backstageScope) if (typeof this.parentSentry.withScope === "function") this.parentSentry.withScope((scope) => {
|
|
450
|
+
try {
|
|
451
|
+
if (this.backstageScope && typeof scope.setTag === "function") {
|
|
452
|
+
scope.setTag("backstageApp", this.backstageApp ?? "unknown");
|
|
453
|
+
scope.setTag("microFrontend", true);
|
|
454
|
+
scope.setContext("microFrontend", {
|
|
455
|
+
backstageApp: this.backstageApp,
|
|
456
|
+
mode: this.mode
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
if (context && typeof scope.setContext === "function") scope.setContext("additional", context);
|
|
460
|
+
if (this.parentSentry && typeof this.parentSentry.captureException === "function") this.parentSentry.captureException(error);
|
|
461
|
+
} catch (scopeError) {
|
|
462
|
+
logError("[SentryMicroFrontendPlugin] Error in scope callback", { error: scopeError });
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
else logWarn("[SentryMicroFrontendPlugin] Parent Sentry does not support withScope");
|
|
466
|
+
else {
|
|
467
|
+
const enhancedContext = {
|
|
468
|
+
...context,
|
|
469
|
+
microFrontend: {
|
|
470
|
+
backstageApp: this.backstageApp,
|
|
471
|
+
mode: this.mode
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
super.captureException(error, enhancedContext);
|
|
475
|
+
}
|
|
476
|
+
} catch (captureError) {
|
|
477
|
+
logError("[SentryMicroFrontendPlugin] Failed to capture exception", { error: captureError });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Capture a message with backstageApp context
|
|
482
|
+
*/
|
|
483
|
+
captureMessage(message, level = "info", context) {
|
|
484
|
+
if (!this.enabled) return;
|
|
485
|
+
try {
|
|
486
|
+
const sentryLevel = mapLogLevelToSentrySeverity(level);
|
|
487
|
+
if (this.mode === "child" && this.parentSentry && this.backstageScope) if (typeof this.parentSentry.withScope === "function") this.parentSentry.withScope((scope) => {
|
|
488
|
+
try {
|
|
489
|
+
if (this.backstageScope && typeof scope.setTag === "function") {
|
|
490
|
+
scope.setTag("backstageApp", this.backstageApp ?? "unknown");
|
|
491
|
+
scope.setTag("microFrontend", true);
|
|
492
|
+
if (typeof scope.setContext === "function") scope.setContext("microFrontend", {
|
|
493
|
+
backstageApp: this.backstageApp,
|
|
494
|
+
mode: this.mode
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
if (context && typeof scope.setContext === "function") scope.setContext("additional", context);
|
|
498
|
+
if (this.parentSentry && typeof this.parentSentry.captureMessage === "function") this.parentSentry.captureMessage(message, sentryLevel);
|
|
499
|
+
} catch (scopeError) {
|
|
500
|
+
logError("[SentryMicroFrontendPlugin] Error in scope callback", { error: scopeError });
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
else logWarn("[SentryMicroFrontendPlugin] Parent Sentry does not support withScope");
|
|
504
|
+
else super.captureMessage(message, level, context);
|
|
505
|
+
} catch (captureError) {
|
|
506
|
+
logError("[SentryMicroFrontendPlugin] Failed to capture message", { error: captureError });
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Get the current operation mode
|
|
511
|
+
*/
|
|
512
|
+
getMode() {
|
|
513
|
+
return this.mode;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Get the current Backstage app identifier
|
|
517
|
+
*/
|
|
518
|
+
getBackstageApp() {
|
|
519
|
+
return this.backstageApp;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* @deprecated Use getBackstageApp instead.
|
|
523
|
+
*/
|
|
524
|
+
getZone() {
|
|
525
|
+
return this.getBackstageApp();
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Get debug information about the plugin state
|
|
529
|
+
*/
|
|
530
|
+
getDebugInfo() {
|
|
531
|
+
return {
|
|
532
|
+
mode: this.mode,
|
|
533
|
+
backstageApp: this.backstageApp,
|
|
534
|
+
enabled: this.enabled,
|
|
535
|
+
initialized: this.initialized,
|
|
536
|
+
hasParentSentry: this.mode === "child" && Boolean(this.parentSentry),
|
|
537
|
+
clientType: this.client ? this.client.constructor.name : "none"
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Clean up the plugin and release resources
|
|
542
|
+
*/
|
|
543
|
+
async cleanup() {
|
|
544
|
+
try {
|
|
545
|
+
if (this.eventProcessorCleanup) {
|
|
546
|
+
this.eventProcessorCleanup();
|
|
547
|
+
this.eventProcessorCleanup = void 0;
|
|
548
|
+
}
|
|
549
|
+
if (this.backstageScope && typeof this.backstageScope.clear === "function") this.backstageScope.clear();
|
|
550
|
+
this.backstageScope = void 0;
|
|
551
|
+
this.parentSentry = void 0;
|
|
552
|
+
await super.cleanup();
|
|
553
|
+
this.initialized = false;
|
|
554
|
+
this.enabled = false;
|
|
555
|
+
logDebug("[SentryMicroFrontendPlugin] Cleanup completed");
|
|
556
|
+
} catch (error) {
|
|
557
|
+
logError("[SentryMicroFrontendPlugin] Error during cleanup", { error });
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Destroy the plugin (alias for cleanup)
|
|
562
|
+
*/
|
|
563
|
+
async destroy() {
|
|
564
|
+
await this.cleanup();
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
/**
|
|
568
|
+
* Factory function to create a Sentry Micro Frontend plugin.
|
|
569
|
+
*
|
|
570
|
+
* Creates a configured SentryMicroFrontendPlugin instance with micro frontend-specific
|
|
571
|
+
* features like multiplexed transport and backstage app routing.
|
|
572
|
+
*
|
|
573
|
+
* @param config - Optional Sentry micro frontend plugin configuration
|
|
574
|
+
* @returns SentryMicroFrontendPlugin instance
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```typescript
|
|
578
|
+
* const sentry = createSentryMicroFrontendPlugin({
|
|
579
|
+
* dsn: 'https://...',
|
|
580
|
+
* backstage: [
|
|
581
|
+
* { name: 'admin', dsn: 'https://admin-dsn...' },
|
|
582
|
+
* { name: 'dashboard', dsn: 'https://dashboard-dsn...' },
|
|
583
|
+
* ],
|
|
584
|
+
* });
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
const createSentryMicroFrontendPlugin = (config) => {
|
|
588
|
+
return new SentryMicroFrontendPlugin(config);
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
//#endregion
|
|
592
|
+
export { isHostEnvironment as a, detectCurrentBackstageApp as i, createSentryMicroFrontendPlugin as n, createMultiplexedTransport as o, createBackstageScope as r, SentryMicroFrontendPlugin as t };
|
|
593
|
+
//# sourceMappingURL=plugin-CLFwRERa.mjs.map
|