@od-oneapp/observability 2026.2.1701 → 2026.2.2001-canary.1

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/README.md +6 -6
  3. package/client-next.d.mts +6 -6
  4. package/client-next.mjs +4 -4
  5. package/client.d.mts +3 -3
  6. package/client.mjs +1 -1
  7. package/client.mjs.map +1 -1
  8. package/core-BgKCqXjb.mjs +95 -0
  9. package/core-BgKCqXjb.mjs.map +1 -0
  10. package/env.mjs +1 -1
  11. package/env.mjs.map +1 -1
  12. package/{factory-DkY353r8.mjs → factory-d1469fpz.mjs} +2 -2
  13. package/factory-d1469fpz.mjs.map +1 -0
  14. package/hooks-useObservability.d.mts +1 -1
  15. package/hooks-useObservability.mjs +1 -1
  16. package/hooks-useObservability.mjs.map +1 -1
  17. package/{index-CpcdzWrF.d.mts → index-CktVJJqJ.d.mts} +3 -3
  18. package/{index-CpcdzWrF.d.mts.map → index-CktVJJqJ.d.mts.map} +1 -1
  19. package/index.mjs +1 -1
  20. package/index.mjs.map +1 -1
  21. package/logs-DkncIKEw.mjs +112 -0
  22. package/logs-DkncIKEw.mjs.map +1 -0
  23. package/{manager-BxQqOPEg.d.mts → manager-CONEYB97.d.mts} +2 -2
  24. package/{manager-BxQqOPEg.d.mts.map → manager-CONEYB97.d.mts.map} +1 -1
  25. package/package.json +33 -40
  26. package/{plugin-Bt-ygG1m.d.mts → plugin-81171XQL.d.mts} +4 -4
  27. package/{plugin-Bt-ygG1m.d.mts.map → plugin-81171XQL.d.mts.map} +1 -1
  28. package/{plugin-CaQxviDs.d.mts → plugin-CEOGIJFN.d.mts} +2 -2
  29. package/{plugin-CaQxviDs.d.mts.map → plugin-CEOGIJFN.d.mts.map} +1 -1
  30. package/plugin-CuRZ8qQf.mjs +593 -0
  31. package/plugin-CuRZ8qQf.mjs.map +1 -0
  32. package/{plugin-CP895lBx.mjs → plugin-DApSl5bY.mjs} +2 -2
  33. package/plugin-DApSl5bY.mjs.map +1 -0
  34. package/{plugin-lPdJirTY.mjs → plugin-LhaOv4eq.mjs} +2 -2
  35. package/plugin-LhaOv4eq.mjs.map +1 -0
  36. package/{plugin-Bfq-o3nr.d.mts → plugin-pvH_kv0a.d.mts} +1 -1
  37. package/{plugin-Bfq-o3nr.d.mts.map → plugin-pvH_kv0a.d.mts.map} +1 -1
  38. package/plugins-betterstack-env.mjs +1 -1
  39. package/plugins-betterstack-env.mjs.map +1 -1
  40. package/plugins-betterstack.d.mts +2 -2
  41. package/plugins-betterstack.mjs +1 -1
  42. package/plugins-console.d.mts +1 -1
  43. package/plugins-sentry-env.d.mts +4 -4
  44. package/plugins-sentry-env.mjs +1 -1
  45. package/plugins-sentry-env.mjs.map +1 -1
  46. package/plugins-sentry-microfrontend-env.mjs +1 -1
  47. package/plugins-sentry-microfrontend-env.mjs.map +1 -1
  48. package/plugins-sentry-microfrontend.d.mts +1 -1
  49. package/plugins-sentry-microfrontend.mjs +1 -1
  50. package/plugins-sentry.d.mts +2 -2
  51. package/plugins-sentry.mjs +1 -1
  52. package/server-edge.d.mts +4 -4
  53. package/server-edge.mjs +2 -2
  54. package/server-next.d.mts +6 -6
  55. package/server-next.mjs +4 -4
  56. package/server.d.mts +3 -3
  57. package/server.mjs +1 -1
  58. package/server.mjs.map +1 -1
  59. package/{utils-DjjqCeoW.d.mts → utils-6Gg4fkvH.d.mts} +4 -3
  60. package/utils-6Gg4fkvH.d.mts.map +1 -0
  61. package/factory-DkY353r8.mjs.map +0 -1
  62. package/plugin-CP895lBx.mjs.map +0 -1
  63. package/plugin-CxeJHHeJ.mjs +0 -1195
  64. package/plugin-CxeJHHeJ.mjs.map +0 -1
  65. package/plugin-lPdJirTY.mjs.map +0 -1
  66. package/utils-DjjqCeoW.d.mts.map +0 -1
@@ -1,1195 +0,0 @@
1
- import { createEnv } from "@t3-oss/env-core";
2
- import { z } from "zod/v4";
3
- import { logDebug, logError, logWarn } from "@od-oneapp/shared/logs";
4
-
5
- //#region src/plugins/sentry-microfrontend/multiplexed-transport.ts
6
- /**
7
- * @fileoverview Multiplexed transport utilities for Sentry Micro Frontend Plugin
8
- * Multiplexed transport utilities for Sentry Micro Frontend Plugin
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
- function createMultiplexedTransport(backstage, fallbackDsn, sentryClient) {
22
- const Sentry = sentryClient !== void 0 ? sentryClient : typeof globalThis !== "undefined" ? globalThis.Sentry : null;
23
- if (!Sentry?.makeMultiplexedTransport || !Sentry.makeFetchTransport) {
24
- logWarn("Sentry multiplexed transport not available");
25
- return;
26
- }
27
- return Sentry.makeMultiplexedTransport(Sentry.makeFetchTransport, (args) => {
28
- const event = args.getEvent();
29
- if (!event) return [];
30
- const backstageApp = event.tags?.backstageApp ?? event.extra?.backstageApp ?? event.contexts?.microFrontend?.backstageApp;
31
- if (backstageApp) {
32
- const backstageAppConfig = backstage.find((z) => z.name === backstageApp);
33
- if (backstageAppConfig?.dsn) {
34
- const envelope = [{
35
- dsn: backstageAppConfig.dsn,
36
- release: backstageAppConfig.release ?? event.release
37
- }];
38
- if (backstageAppConfig.tags && event.tags) Object.assign(event.tags, backstageAppConfig.tags);
39
- return envelope;
40
- }
41
- }
42
- if (fallbackDsn) return [{ dsn: fallbackDsn }];
43
- return [];
44
- });
45
- }
46
- /**
47
- * Enhance an event with Backstage app information before sending.
48
- *
49
- * Adds backstageApp tags, context, and extra data to a Sentry event.
50
- * This ensures events are properly tagged for micro frontend routing.
51
- *
52
- * @param event - Sentry event to enhance
53
- * @param backstageApp - Name of the backstage app
54
- * @param additionalContext - Optional additional context to add
55
- * @returns Enhanced event with backstageApp information
56
- */
57
- function enhanceEventWithBackstageApp(event, backstageApp, additionalContext) {
58
- event.tags ??= {};
59
- event.tags.backstageApp = backstageApp;
60
- event.tags.microFrontend = true;
61
- event.contexts ??= {};
62
- event.contexts.microFrontend = {
63
- backstageApp,
64
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
65
- ...additionalContext
66
- };
67
- event.extra ??= {};
68
- event.extra.backstageApp = backstageApp;
69
- return event;
70
- }
71
- /**
72
- * Create a beforeSend hook that adds backstageApp information.
73
- *
74
- * Creates a Sentry beforeSend hook that enhances events with backstageApp information
75
- * before they are sent. Can wrap an existing beforeSend hook.
76
- *
77
- * @param backstageApp - Name of the backstage app
78
- * @param originalBeforeSend - Optional original beforeSend hook to wrap
79
- * @returns beforeSend hook function
80
- */
81
- function createBackstageBeforeSend(backstageApp, originalBeforeSend) {
82
- return (event, hint) => {
83
- enhanceEventWithBackstageApp(event, backstageApp);
84
- if (originalBeforeSend) return originalBeforeSend(event, hint);
85
- return event;
86
- };
87
- }
88
-
89
- //#endregion
90
- //#region ../../integrations/sentry/src/observability-plugin/env.ts
91
- /**
92
- * @fileoverview Sentry-specific environment configuration
93
- * Sentry-specific environment configuration
94
- * Apps can extend this configuration to inherit Sentry environment variables
95
- */
96
- const env = createEnv({
97
- server: {
98
- SENTRY_DSN: z.string().url().optional(),
99
- SENTRY_AUTH_TOKEN: z.string().optional(),
100
- SENTRY_ORG: z.string().optional(),
101
- SENTRY_PROJECT: z.string().optional(),
102
- SENTRY_ENVIRONMENT: z.enum([
103
- "development",
104
- "preview",
105
- "production"
106
- ]).optional(),
107
- SENTRY_RELEASE: z.string().optional(),
108
- SENTRY_TRACES_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),
109
- SENTRY_PROFILES_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),
110
- SENTRY_REPLAYS_SESSION_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),
111
- SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),
112
- SENTRY_DEBUG: z.string().optional().transform((val) => val === "true").default(false)
113
- },
114
- clientPrefix: "NEXT_PUBLIC_",
115
- client: {
116
- NEXT_PUBLIC_SENTRY_DSN: z.string().url().optional(),
117
- NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.enum([
118
- "development",
119
- "preview",
120
- "production"
121
- ]).optional(),
122
- NEXT_PUBLIC_SENTRY_RELEASE: z.string().optional()
123
- },
124
- runtimeEnv: process.env,
125
- emptyStringAsUndefined: true,
126
- onInvalidAccess: (variable) => {
127
- if ([
128
- "nodeType",
129
- "$$typeof",
130
- "constructor",
131
- "prototype",
132
- "toJSON",
133
- "then"
134
- ].includes(variable)) return;
135
- const message = `❌ Attempted to access a server-side environment variable on the client: ${variable}`;
136
- if (Boolean(process.env.VITEST) || Boolean(process.env.VITEST_WORKER_ID) || Boolean(globalThis.vi) || Boolean(globalThis.vitest)) {
137
- logWarn(message);
138
- return;
139
- }
140
- throw new Error(message);
141
- },
142
- onValidationError: (error) => {
143
- logWarn("Sentry environment validation failed", { error });
144
- }
145
- });
146
- /**
147
- * Safe environment access for non-Next.js contexts.
148
- *
149
- * Provides fallback environment variable access for Node.js, workers, and test environments
150
- * where the validated env object may not be available. Returns fallback values with proper
151
- * type coercion and defaults.
152
- *
153
- * @returns Environment object with Sentry configuration values
154
- */
155
- function safeEnv() {
156
- if (env) return env;
157
- return {
158
- SENTRY_DSN: process.env.SENTRY_DSN ?? "",
159
- SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN ?? "",
160
- SENTRY_ORG: process.env.SENTRY_ORG ?? "",
161
- SENTRY_PROJECT: process.env.SENTRY_PROJECT ?? "",
162
- SENTRY_ENVIRONMENT: process.env.SENTRY_ENVIRONMENT ?? "development",
163
- SENTRY_RELEASE: process.env.SENTRY_RELEASE ?? "",
164
- SENTRY_TRACES_SAMPLE_RATE: Number(process.env.SENTRY_TRACES_SAMPLE_RATE) || 1,
165
- SENTRY_PROFILES_SAMPLE_RATE: Number(process.env.SENTRY_PROFILES_SAMPLE_RATE) ?? 0,
166
- SENTRY_REPLAYS_SESSION_SAMPLE_RATE: Number(process.env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE) || 0,
167
- SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE: Number(process.env.SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE) || 1,
168
- SENTRY_DEBUG: process.env.SENTRY_DEBUG === "true",
169
- NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN ?? "",
170
- NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT ?? "development",
171
- NEXT_PUBLIC_SENTRY_RELEASE: process.env.NEXT_PUBLIC_SENTRY_RELEASE ?? ""
172
- };
173
- }
174
-
175
- //#endregion
176
- //#region ../../integrations/sentry/src/observability-plugin/plugin.ts
177
- /**
178
- * @fileoverview Sentry plugin implementation
179
- * Sentry plugin implementation
180
- */
181
- /**
182
- * Detect if code is running in a browser environment
183
- */
184
- function isBrowser() {
185
- const g = globalThis;
186
- return typeof globalThis !== "undefined" && "window" in globalThis && typeof g.window?.document !== "undefined" && typeof g.window?.navigator !== "undefined";
187
- }
188
- /**
189
- * Default log filter function that filters out noisy development logs.
190
- * Filters out:
191
- * - Next.js Fast Refresh messages
192
- * - HMR (Hot Module Replacement) messages
193
- * - Prisma query logs (server-only)
194
- * - Prisma engine/info logs
195
- * - SQL queries matching Prisma's format
196
- *
197
- * Handles ANSI color codes, console formatting (%c, %s), and CSS styling.
198
- *
199
- * @param log - The log entry from Sentry
200
- * @param isServer - Whether this is running on the server (defaults to true)
201
- * @returns The log entry if it should be sent, or null to filter it out
202
- */
203
- function defaultBeforeSendLog(log, isServer = true) {
204
- const logObj = log;
205
- const messageToCheck = logObj.message ?? logObj.formatted ?? "";
206
- if (!messageToCheck) return log;
207
- const messageWithoutAnsi = String(messageToCheck).replace(/\u001b\[[0-9;]*m/g, "").replace(/%[csdfiO]/g, "").replace(/background:[^;]+;?/g, "").replace(/color:[^;]+;?/g, "").replace(/border-radius:[^;]+;?/g, "").replace(/light-dark\([^)]+\)/g, "").replace(/rgba?\([^)]+\)/g, "").replace(/#[0-9a-fA-F]{3,8}/g, "").toLowerCase();
208
- if (messageWithoutAnsi.includes("[fast refresh]") || messageWithoutAnsi.includes("[hmr]")) return null;
209
- if (isServer) {
210
- if (messageWithoutAnsi.includes("prisma:query") || messageWithoutAnsi.includes("prisma:engine") || messageWithoutAnsi.includes("prisma:info") || messageWithoutAnsi.includes("select") && messageWithoutAnsi.includes("from") && (messageWithoutAnsi.includes("\"public\".") || messageWithoutAnsi.includes("public."))) return null;
211
- }
212
- return log;
213
- }
214
- /**
215
- * Sentry plugin implementation
216
- */
217
- /**
218
- * Sentry plugin implementation.
219
- *
220
- * Integrates Sentry error tracking and performance monitoring into the observability system.
221
- * Auto-detects the appropriate Sentry package (@sentry/node, @sentry/browser, @sentry/nextjs)
222
- * based on the runtime environment.
223
- */
224
- var SentryPlugin = class {
225
- name = "sentry";
226
- enabled;
227
- client;
228
- initialized = false;
229
- sentryPackage;
230
- config;
231
- /**
232
- * Create a new SentryPlugin instance.
233
- *
234
- * @param config - Sentry plugin configuration
235
- */
236
- constructor(config = {}) {
237
- this.config = config;
238
- const env = safeEnv();
239
- const hasDSN = config.dsn ?? env.SENTRY_DSN ?? env.NEXT_PUBLIC_SENTRY_DSN;
240
- this.enabled = config.enabled ?? Boolean(hasDSN);
241
- this.sentryPackage = config.sentryPackage ?? this.detectSentryPackage();
242
- }
243
- /**
244
- * Detect which Sentry package to use based on the runtime environment.
245
- *
246
- * @returns Package name ('@sentry/node', '@sentry/browser', or '@sentry/nextjs')
247
- */
248
- detectSentryPackage() {
249
- if (isBrowser()) return "@sentry/browser";
250
- else if (process.env.NEXT_RUNTIME === "edge") return "@sentry/nextjs";
251
- else if (process.env.NEXT_RUNTIME) return "@sentry/nextjs";
252
- else return "@sentry/node";
253
- }
254
- getClient() {
255
- return this.client;
256
- }
257
- /**
258
- * Get safe environment access (for testing/mocking).
259
- *
260
- * @returns Environment configuration object
261
- */
262
- getSafeEnv() {
263
- return safeEnv();
264
- }
265
- async initialize(config) {
266
- if (this.initialized || !this.enabled) return;
267
- const env = safeEnv();
268
- const mergedConfig = {
269
- ...this.config,
270
- ...config
271
- };
272
- const dsn = mergedConfig.dsn ?? env.SENTRY_DSN ?? env.NEXT_PUBLIC_SENTRY_DSN;
273
- if (!dsn) {
274
- logWarn("Sentry plugin: No DSN provided, skipping initialization");
275
- this.enabled = false;
276
- return;
277
- }
278
- try {
279
- this.client = await import(
280
- /* webpackIgnore: true */
281
- this.sentryPackage
282
- );
283
- if (this.client && this.enabled) {
284
- let { integrations } = mergedConfig;
285
- if (!integrations && this.client.browserTracingIntegration) {
286
- integrations = [];
287
- if (mergedConfig.tracesSampleRate !== void 0 || env.SENTRY_TRACES_SAMPLE_RATE !== void 0) integrations.push(this.client.browserTracingIntegration());
288
- if (this.client.replayIntegration && (mergedConfig.replaysSessionSampleRate !== void 0 || env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE !== void 0)) integrations.push(this.client.replayIntegration());
289
- if (this.client.profilesIntegration && (mergedConfig.profilesSampleRate !== void 0 || env.SENTRY_PROFILES_SAMPLE_RATE !== void 0)) integrations.push(this.client.profilesIntegration());
290
- }
291
- const enableLogs = mergedConfig.enableLogs ?? true;
292
- if (enableLogs && this.client.consoleLoggingIntegration) {
293
- const consoleLoggingConfig = mergedConfig.consoleLoggingIntegration || { levels: [
294
- "log",
295
- "warn",
296
- "error"
297
- ] };
298
- if (!integrations) integrations = [];
299
- integrations.push(this.client.consoleLoggingIntegration(consoleLoggingConfig));
300
- }
301
- this.client.init({
302
- dsn,
303
- environment: mergedConfig.environment ?? env.SENTRY_ENVIRONMENT ?? "development",
304
- release: mergedConfig.release ?? env.SENTRY_RELEASE,
305
- debug: mergedConfig.debug ?? env.SENTRY_DEBUG,
306
- enableLogs,
307
- tracesSampleRate: mergedConfig.tracesSampleRate ?? env.SENTRY_TRACES_SAMPLE_RATE,
308
- profilesSampleRate: mergedConfig.profilesSampleRate ?? env.SENTRY_PROFILES_SAMPLE_RATE,
309
- replaysSessionSampleRate: mergedConfig.replaysSessionSampleRate ?? env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE,
310
- replaysOnErrorSampleRate: mergedConfig.replaysOnErrorSampleRate ?? env.SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE,
311
- integrations,
312
- beforeSend: mergedConfig.beforeSend,
313
- beforeSendTransaction: mergedConfig.beforeSendTransaction,
314
- beforeSendLog: mergedConfig.beforeSendLog || (enableLogs ? (log) => defaultBeforeSendLog(log, !isBrowser()) : void 0),
315
- tracePropagationTargets: mergedConfig.tracePropagationTargets,
316
- initialScope: mergedConfig.initialScope,
317
- maxBreadcrumbs: mergedConfig.maxBreadcrumbs,
318
- attachStacktrace: mergedConfig.attachStacktrace,
319
- autoSessionTracking: mergedConfig.autoSessionTracking
320
- });
321
- this.initialized = true;
322
- }
323
- } catch (error) {
324
- logError(`Failed to import Sentry package '${this.sentryPackage}'`, { error });
325
- this.enabled = false;
326
- }
327
- }
328
- async shutdown() {
329
- if (this.client && this.initialized) {
330
- if (this.client.close) await this.client.close();
331
- else if (this.client.flush) await this.client.flush();
332
- this.initialized = false;
333
- }
334
- }
335
- /**
336
- * Clean up the plugin (alias for shutdown)
337
- */
338
- async cleanup() {
339
- await this.shutdown();
340
- }
341
- captureException(error, context) {
342
- if (!this.enabled || !this.client) return;
343
- if (typeof this.client.captureException !== "function") {
344
- logError("[Sentry Fallback] Exception", { error });
345
- return;
346
- }
347
- try {
348
- this.client.captureException(error, context);
349
- } catch (captureError) {
350
- logWarn("[Sentry Plugin] Failed to capture exception", { error: captureError });
351
- logError("[Sentry Fallback] Exception", { error });
352
- }
353
- }
354
- captureMessage(message, level = "info", context) {
355
- if (!this.enabled || !this.client) return;
356
- if (this.client.logger) try {
357
- const attributes = context ? context.extra ?? context : void 0;
358
- switch (level) {
359
- case "debug":
360
- this.client.logger.debug(message, attributes);
361
- return;
362
- case "info":
363
- this.client.logger.info(message, attributes);
364
- return;
365
- case "warning":
366
- this.client.logger.warn(message, attributes);
367
- return;
368
- case "error":
369
- this.client.logger.error(message, attributes);
370
- return;
371
- }
372
- } catch (error) {
373
- logWarn("[Sentry Plugin] Failed to log via logger", { error });
374
- }
375
- if (typeof this.client.captureMessage !== "function") {
376
- if (level === "error") logError(`[Sentry Fallback] ${message}`);
377
- else if (level === "warning") logWarn(`[Sentry Fallback] ${message}`);
378
- else logDebug(`[Sentry Fallback] ${message}`);
379
- return;
380
- }
381
- const sentryLevel = level === "warning" ? "warning" : level === "error" ? "error" : level === "debug" ? "debug" : "info";
382
- try {
383
- const captureContext = context ? {
384
- level: sentryLevel,
385
- extra: context.extra ?? context,
386
- tags: context.tags
387
- } : sentryLevel;
388
- this.client.captureMessage(message, captureContext);
389
- } catch (error) {
390
- logWarn("[Sentry Plugin] Failed to capture message", { error });
391
- if (level === "error") logError(`[Sentry Fallback] ${message}`);
392
- else if (level === "warning") logWarn(`[Sentry Fallback] ${message}`);
393
- else logDebug(`[Sentry Fallback] ${message}`);
394
- }
395
- }
396
- setUser(user) {
397
- if (!this.enabled || !this.client) return;
398
- this.client.setUser(user);
399
- }
400
- addBreadcrumb(breadcrumb) {
401
- if (!this.enabled || !this.client) return;
402
- this.client.addBreadcrumb({
403
- ...breadcrumb,
404
- timestamp: breadcrumb.timestamp ?? Date.now() / 1e3
405
- });
406
- }
407
- withScope(callback) {
408
- if (!this.enabled || !this.client) return;
409
- this.client.withScope(callback);
410
- }
411
- /**
412
- * Start a new transaction
413
- */
414
- startTransaction(context, customSamplingContext) {
415
- if (!this.enabled || !this.client) return void 0;
416
- if (this.client.startTransaction) return this.client.startTransaction(context, customSamplingContext);
417
- logWarn("startTransaction not available in this Sentry version");
418
- }
419
- /**
420
- * Start a new span
421
- */
422
- startSpan(context) {
423
- if (!this.enabled || !this.client) return void 0;
424
- if (this.client.startSpan) return this.client.startSpan(context);
425
- const transaction = this.getActiveTransaction();
426
- if (transaction?.startChild) return transaction.startChild(context);
427
- }
428
- /**
429
- * Get the currently active transaction
430
- */
431
- getActiveTransaction() {
432
- if (!this.enabled || !this.client) return void 0;
433
- if (this.client.getActiveTransaction) return this.client.getActiveTransaction();
434
- if (this.client.getCurrentScope) {
435
- const scope = this.client.getCurrentScope();
436
- if (scope?.getTransaction) return scope.getTransaction();
437
- }
438
- }
439
- /**
440
- * Configure the current scope
441
- */
442
- configureScope(callback) {
443
- if (!this.enabled || !this.client) return;
444
- if (this.client.configureScope) this.client.configureScope(callback);
445
- else if (this.client.withScope) this.client.withScope(callback);
446
- }
447
- /**
448
- * Get the current hub instance
449
- */
450
- getCurrentHub() {
451
- if (!this.enabled || !this.client) return void 0;
452
- if (this.client.getCurrentHub) return this.client.getCurrentHub();
453
- }
454
- /**
455
- * Set a measurement on the active transaction
456
- */
457
- setMeasurement(name, value, unit) {
458
- if (!this.enabled || !this.client) return;
459
- const transaction = this.getActiveTransaction();
460
- if (transaction?.setMeasurement) transaction.setMeasurement(name, value, unit);
461
- }
462
- /**
463
- * Add performance entries as breadcrumbs and measurements
464
- */
465
- addPerformanceEntries(entries) {
466
- if (!this.enabled || !this.client) return;
467
- const transaction = this.getActiveTransaction();
468
- entries.forEach((entry) => {
469
- this.addBreadcrumb({
470
- category: "performance",
471
- message: `${entry.entryType}: ${entry.name}`,
472
- data: {
473
- name: entry.name,
474
- duration: entry.duration,
475
- startTime: entry.startTime,
476
- ...entry.entryType === "navigation" && {
477
- transferSize: entry.transferSize,
478
- encodedBodySize: entry.encodedBodySize,
479
- decodedBodySize: entry.decodedBodySize
480
- },
481
- ...entry.entryType === "resource" && {
482
- initiatorType: entry.initiatorType,
483
- transferSize: entry.transferSize
484
- }
485
- }
486
- });
487
- if (transaction && entry.entryType === "navigation") {
488
- const navEntry = entry;
489
- const fetchStart = navEntry.fetchStart ?? 0;
490
- if (navEntry.responseStart !== void 0) this.setMeasurement("fcp", navEntry.responseStart - fetchStart, "millisecond");
491
- if (navEntry.domInteractive !== void 0) this.setMeasurement("dom_interactive", navEntry.domInteractive - fetchStart, "millisecond");
492
- if (navEntry.domComplete !== void 0) this.setMeasurement("dom_complete", navEntry.domComplete - fetchStart, "millisecond");
493
- if (navEntry.loadEventEnd !== void 0) this.setMeasurement("load_event_end", navEntry.loadEventEnd - fetchStart, "millisecond");
494
- }
495
- });
496
- }
497
- /**
498
- * Record a Web Vital measurement
499
- */
500
- recordWebVital(name, value, options) {
501
- if (!this.enabled || !this.client) return;
502
- const { unit = "millisecond", rating } = options ?? {};
503
- const transaction = this.getActiveTransaction();
504
- if (transaction) {
505
- transaction.setMeasurement(name.toLowerCase(), value, unit);
506
- if (rating) transaction.setTag(`webvital.${name.toLowerCase()}.rating`, rating);
507
- this.client.captureMessage(`Web Vital: ${name}`, {
508
- level: "info",
509
- tags: {
510
- "webvital.name": name,
511
- "webvital.value": value,
512
- "webvital.unit": unit,
513
- ...rating && { "webvital.rating": rating }
514
- },
515
- contexts: { trace: {
516
- trace_id: transaction.traceId,
517
- span_id: transaction.spanId
518
- } }
519
- });
520
- }
521
- }
522
- /**
523
- * Create a custom performance mark
524
- */
525
- mark(name, options) {
526
- if (!this.enabled) return;
527
- if (typeof performance !== "undefined" && performance.mark) performance.mark(name, options);
528
- this.addBreadcrumb({
529
- category: "performance.mark",
530
- message: name,
531
- data: options?.detail,
532
- timestamp: Date.now() / 1e3
533
- });
534
- }
535
- /**
536
- * Create a custom performance measure
537
- */
538
- measure(name, startMarkOrOptions, endMark) {
539
- if (!this.enabled) return;
540
- if (typeof performance !== "undefined" && performance.measure) {
541
- if (typeof startMarkOrOptions === "string") performance.measure(name, startMarkOrOptions, endMark);
542
- else if (startMarkOrOptions) performance.measure(name, startMarkOrOptions);
543
- else performance.measure(name);
544
- const measures = performance.getEntriesByName(name, "measure");
545
- const measure = measures[measures.length - 1];
546
- if (measure) {
547
- this.setMeasurement(name, measure.duration, "millisecond");
548
- this.addBreadcrumb({
549
- category: "performance.measure",
550
- message: name,
551
- data: {
552
- duration: measure.duration,
553
- startTime: measure.startTime
554
- },
555
- timestamp: measure.startTime / 1e3
556
- });
557
- }
558
- }
559
- }
560
- /**
561
- * Log a trace message using Sentry.logger (if available).
562
- * Falls back to captureMessage if logger is not available.
563
- *
564
- * @param message - Trace message to log
565
- * @param attributes - Optional attributes to include with the log
566
- */
567
- logTrace(message, attributes) {
568
- if (!this.enabled || !this.client) return;
569
- if (this.client.logger?.trace) try {
570
- this.client.logger.trace(message, attributes);
571
- return;
572
- } catch (error) {
573
- logWarn("[Sentry Plugin] Failed to log trace", { error });
574
- }
575
- this.captureMessage(message, "debug", attributes);
576
- }
577
- /**
578
- * Log a debug message using Sentry.logger (if available).
579
- * Falls back to captureMessage if logger is not available.
580
- *
581
- * @param message - Debug message to log
582
- * @param attributes - Optional attributes to include with the log
583
- */
584
- logDebug(message, attributes) {
585
- if (!this.enabled || !this.client) return;
586
- if (this.client.logger?.debug) try {
587
- this.client.logger.debug(message, attributes);
588
- return;
589
- } catch (error) {
590
- logWarn("[Sentry Plugin] Failed to log debug", { error });
591
- }
592
- this.captureMessage(message, "debug", attributes);
593
- }
594
- /**
595
- * Log an info message using Sentry.logger (if available).
596
- * Falls back to captureMessage if logger is not available.
597
- *
598
- * @param message - Info message to log
599
- * @param attributes - Optional attributes to include with the log
600
- */
601
- logInfo(message, attributes) {
602
- if (!this.enabled || !this.client) return;
603
- if (this.client.logger?.info) try {
604
- this.client.logger.info(message, attributes);
605
- return;
606
- } catch (error) {
607
- logWarn("[Sentry Plugin] Failed to log info", { error });
608
- }
609
- this.captureMessage(message, "info", attributes);
610
- }
611
- /**
612
- * Log a warning message using Sentry.logger (if available).
613
- * Falls back to captureMessage if logger is not available.
614
- *
615
- * @param message - Warning message to log
616
- * @param attributes - Optional attributes to include with the log
617
- */
618
- logWarn(message, attributes) {
619
- if (!this.enabled || !this.client) return;
620
- if (this.client.logger?.warn) try {
621
- this.client.logger.warn(message, attributes);
622
- return;
623
- } catch (error) {
624
- logWarn("[Sentry Plugin] Failed to log warn", { error });
625
- }
626
- this.captureMessage(message, "warning", attributes);
627
- }
628
- /**
629
- * Log an error message using Sentry.logger (if available).
630
- * Falls back to captureMessage if logger is not available.
631
- *
632
- * @param message - Error message to log
633
- * @param attributes - Optional attributes to include with the log
634
- */
635
- logError(message, attributes) {
636
- if (!this.enabled || !this.client) return;
637
- if (this.client.logger?.error) try {
638
- this.client.logger.error(message, attributes);
639
- return;
640
- } catch (error) {
641
- logWarn("[Sentry Plugin] Failed to log error", { error });
642
- }
643
- this.captureMessage(message, "error", attributes);
644
- }
645
- /**
646
- * Log a fatal message using Sentry.logger (if available).
647
- * Falls back to captureMessage if logger is not available.
648
- *
649
- * @param message - Fatal message to log
650
- * @param attributes - Optional attributes to include with the log
651
- */
652
- logFatal(message, attributes) {
653
- if (!this.enabled || !this.client) return;
654
- if (this.client.logger?.fatal) try {
655
- this.client.logger.fatal(message, attributes);
656
- return;
657
- } catch (error) {
658
- logWarn("[Sentry Plugin] Failed to log fatal", { error });
659
- }
660
- this.captureMessage(message, "error", attributes);
661
- }
662
- /**
663
- * Get the Sentry.logger instance if available.
664
- * This allows direct access to Sentry.logger APIs including fmt.
665
- *
666
- * @returns Sentry.logger instance or undefined if not available
667
- *
668
- * @example
669
- * ```typescript
670
- * const logger = sentryPlugin.getLogger();
671
- * if (logger) {
672
- * logger.info(logger.fmt`User ${user.id} logged in`);
673
- * }
674
- * ```
675
- */
676
- getLogger() {
677
- if (!this.enabled || !this.client) return void 0;
678
- return this.client.logger;
679
- }
680
- async flush(timeout) {
681
- if (!this.enabled || !this.client || !this.client.flush) return true;
682
- try {
683
- return await this.client.flush(timeout);
684
- } catch (_error) {
685
- return false;
686
- }
687
- }
688
- };
689
-
690
- //#endregion
691
- //#region src/plugins/sentry-microfrontend/sentry-types.ts
692
- /**
693
- * Map LogLevel to Sentry Severity.
694
- *
695
- * Converts the observability package's LogLevel to Sentry's SeverityLevel format.
696
- *
697
- * @param level - Log level from observability package
698
- * @returns Corresponding Sentry severity level
699
- */
700
- function mapLogLevelToSentrySeverity(level) {
701
- switch (level) {
702
- case "error": return "error";
703
- case "warning": return "warning";
704
- case "info": return "info";
705
- case "debug": return "debug";
706
- default: return "info";
707
- }
708
- }
709
-
710
- //#endregion
711
- //#region src/plugins/sentry-microfrontend/utils.ts
712
- /**
713
- * @fileoverview Utility functions for Sentry Micro Frontend Plugin
714
- * Utility functions for Sentry Micro Frontend Plugin
715
- */
716
- /**
717
- * Detect the current micro frontend backstageApp based on URL path.
718
- *
719
- * Analyzes the current URL pathname to determine which micro frontend application
720
- * is active. Supports custom path patterns and falls back to default patterns.
721
- *
722
- * @param customPatterns - Optional array of custom backstage app configurations with path patterns
723
- * @returns Detected backstage app name, or undefined if not detected
724
- *
725
- * @example
726
- * ```typescript
727
- * const app = detectCurrentBackstageApp([
728
- * { name: 'admin', pathPatterns: ['/admin', '/manage'] },
729
- * { name: 'dashboard', pathPatterns: [/^\/dashboard/] }
730
- * ]);
731
- * // Returns: 'admin' if pathname starts with '/admin' or '/manage'
732
- * ```
733
- */
734
- function detectCurrentBackstageApp(customPatterns) {
735
- if (typeof globalThis === "undefined" || !globalThis.location) {
736
- if (typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BASE_PATH) return process.env.NEXT_PUBLIC_BASE_PATH.replace("/", "");
737
- return;
738
- }
739
- const path = globalThis.location?.pathname;
740
- if (!path) return;
741
- if (customPatterns) {
742
- for (const config of customPatterns) if (config.pathPatterns) {
743
- for (const pattern of config.pathPatterns) if (typeof pattern === "string" && path.startsWith(pattern)) return config.name;
744
- else if (pattern instanceof RegExp && pattern.test(path)) return config.name;
745
- }
746
- }
747
- if (path.startsWith("/admin")) return "admin";
748
- if (path.startsWith("/dashboard")) return "dashboard";
749
- if (path.startsWith("/settings")) return "settings";
750
- if (globalThis.__SENTRY_MICRO_FRONTEND_APP__) return globalThis.__SENTRY_MICRO_FRONTEND_APP__;
751
- if (globalThis.__SENTRY_MICRO_FRONTEND_ZONE__) return globalThis.__SENTRY_MICRO_FRONTEND_ZONE__;
752
- return "main";
753
- }
754
- /**
755
- * Check if running in a host environment.
756
- *
757
- * Determines whether the current application is acting as a host for micro frontends
758
- * or as a child micro frontend. Checks for explicit host markers and Sentry initialization state.
759
- *
760
- * @returns True if running as host, false if child or standalone
761
- */
762
- function isHostEnvironment() {
763
- if (typeof globalThis === "undefined") return false;
764
- if (globalThis.__SENTRY_MICRO_FRONTEND_HOST__) return true;
765
- if (globalThis.Sentry && typeof globalThis.Sentry.getCurrentHub === "function") return false;
766
- return false;
767
- }
768
- /**
769
- * Create a Sentry scope with backstageApp-specific context.
770
- *
771
- * Creates a new Sentry scope configured with micro frontend tags and context.
772
- * Includes backstageApp tag, microFrontend context, and any additional tags provided.
773
- *
774
- * @param backstageApp - Name of the backstage app
775
- * @param additionalTags - Optional additional tags to set on the scope
776
- * @returns Sentry scope instance, or null if Sentry is not available
777
- */
778
- function createBackstageScope(backstageApp, additionalTags) {
779
- if (typeof globalThis === "undefined" || !globalThis.Sentry) return null;
780
- const { Sentry } = globalThis;
781
- if (!Sentry.Scope || typeof Sentry.Scope !== "function") return null;
782
- try {
783
- const scope = new Sentry.Scope();
784
- scope.setTag("backstageApp", backstageApp);
785
- scope.setTag("microFrontend", true);
786
- scope.setContext("microFrontend", {
787
- backstageApp,
788
- isHost: globalThis.__SENTRY_MICRO_FRONTEND_HOST__ ?? false,
789
- url: globalThis.location?.href ?? void 0
790
- });
791
- if (additionalTags) Object.entries(additionalTags).forEach(([key, value]) => {
792
- scope.setTag(key, value);
793
- });
794
- return scope;
795
- } catch (error) {
796
- logError("[SentryMicroFrontendPlugin] Failed to create Backstage scope", { error });
797
- return null;
798
- }
799
- }
800
- /**
801
- * Check if Sentry is already initialized by a parent application.
802
- *
803
- * Verifies whether a parent Sentry instance exists in the global scope.
804
- * Used to determine if the current micro frontend should use the parent's Sentry
805
- * or initialize its own instance.
806
- *
807
- * @returns True if parent Sentry is available, false otherwise
808
- */
809
- function hasParentSentry() {
810
- if (typeof globalThis === "undefined") return false;
811
- const { Sentry } = globalThis;
812
- if (!Sentry) return false;
813
- return [
814
- "captureException",
815
- "captureMessage",
816
- "withScope"
817
- ].every((method) => typeof Sentry[method] === "function");
818
- }
819
- /**
820
- * Get the parent Sentry instance if available.
821
- *
822
- * Returns the global Sentry instance if it exists and has been initialized
823
- * by a parent application. Returns null if no parent Sentry is available.
824
- *
825
- * @returns Parent Sentry SDK instance, or null if not available
826
- */
827
- function getParentSentry() {
828
- if (hasParentSentry()) return globalThis.Sentry;
829
- return null;
830
- }
831
- /**
832
- * Mark the current environment as a host.
833
- *
834
- * Sets global flags indicating that this application is acting as a host
835
- * for micro frontends. This affects how Sentry events are routed and tagged.
836
- *
837
- * @param backstageApp - Optional backstage app name to set
838
- */
839
- function markAsHost(backstageApp) {
840
- if (typeof globalThis !== "undefined") {
841
- globalThis.__SENTRY_MICRO_FRONTEND_HOST__ = true;
842
- if (backstageApp) {
843
- globalThis.__SENTRY_MICRO_FRONTEND_APP__ = backstageApp;
844
- globalThis.__SENTRY_MICRO_FRONTEND_ZONE__ = backstageApp;
845
- }
846
- }
847
- }
848
- /**
849
- * Ensure only one Sentry initialization happens (thread-safe).
850
- *
851
- * Prevents multiple Sentry initializations using global state tracking.
852
- * Uses timestamps and unique IDs to detect concurrent initialization attempts.
853
- * Throws an error if Sentry is already initialized or if concurrent initialization is detected.
854
- *
855
- * @throws Error if Sentry is already initialized or concurrent initialization detected
856
- */
857
- function ensureSingleInit() {
858
- const initKey = "__SENTRY_INIT_STATE__";
859
- const now = Date.now();
860
- if (typeof globalThis !== "undefined") {
861
- const globalState = globalThis[initKey];
862
- if (globalState) {
863
- const { status, timestamp, id } = globalState;
864
- if (status === "initialized") throw new Error("Sentry has already been initialized! Use hasParentSentry() to check before initializing.");
865
- if (status === "initializing" && now - timestamp < 5e3) throw new Error(`Sentry initialization already in progress (started ${now - timestamp}ms ago by ${id})`);
866
- }
867
- const initId = `${now}-${Math.random().toString(36).substr(2, 9)}`;
868
- globalThis[initKey] = {
869
- status: "initializing",
870
- timestamp: now,
871
- id: initId
872
- };
873
- if (globalThis[initKey].id !== initId) throw new Error("Concurrent Sentry initialization detected");
874
- globalThis[initKey] = {
875
- status: "initialized",
876
- timestamp: now,
877
- id: initId
878
- };
879
- globalThis.__SENTRY_INITIALIZED__ = true;
880
- }
881
- }
882
-
883
- //#endregion
884
- //#region src/plugins/sentry-microfrontend/plugin.ts
885
- /**
886
- * @fileoverview Sentry Micro Frontend Plugin
887
- * Sentry Micro Frontend Plugin
888
- *
889
- * Extends the base Sentry plugin with micro frontend-specific functionality
890
- */
891
- /**
892
- * Sentry plugin optimized for micro frontend architectures
893
- */
894
- /**
895
- * Sentry plugin optimized for micro frontend architectures.
896
- *
897
- * Extends SentryPlugin with micro frontend-specific features:
898
- * - Host/child/standalone mode detection
899
- * - Multiplexed transport for routing events to different Sentry projects
900
- * - Backstage app context management
901
- * - Parent Sentry instance detection and reuse
902
- */
903
- var SentryMicroFrontendPlugin = class SentryMicroFrontendPlugin extends SentryPlugin {
904
- mode;
905
- backstageApp;
906
- parentSentry;
907
- backstageScope;
908
- microFrontendConfig;
909
- eventProcessorCleanup;
910
- /**
911
- * Create a new SentryMicroFrontendPlugin instance.
912
- *
913
- * @param config - Sentry micro frontend plugin configuration
914
- */
915
- constructor(config = {}) {
916
- const mode = SentryMicroFrontendPlugin.determineMode(config);
917
- const baseConfig = SentryMicroFrontendPlugin.prepareConfig(config, mode);
918
- super(baseConfig);
919
- this.mode = mode;
920
- this.microFrontendConfig = config;
921
- this.backstageApp = config.backstageApp ?? detectCurrentBackstageApp(config.backstageApps);
922
- if (this.mode === "child") {
923
- const parent = getParentSentry();
924
- if (parent) {
925
- this.parentSentry = parent;
926
- this.enabled = true;
927
- if (this.backstageApp && this.parentSentry.Scope) this.backstageScope = createBackstageScope(this.backstageApp, config.globalTags);
928
- }
929
- }
930
- if (this.mode === "host") markAsHost(this.backstageApp);
931
- }
932
- /**
933
- * Determine the operation mode based on configuration and environment.
934
- *
935
- * @param config - Plugin configuration
936
- * @returns Operation mode ('host', 'child', or 'standalone')
937
- */
938
- static determineMode(config) {
939
- if (config.isHost) return "host";
940
- if (config.detectParent !== false && hasParentSentry()) return "child";
941
- return "standalone";
942
- }
943
- /**
944
- * Prepare configuration based on operation mode.
945
- *
946
- * Adjusts configuration settings based on whether running as host, child, or standalone.
947
- *
948
- * @param config - Original plugin configuration
949
- * @param mode - Determined operation mode
950
- * @returns Prepared configuration object
951
- */
952
- static prepareConfig(config, mode) {
953
- const preparedConfig = { ...config };
954
- if (mode === "child") preparedConfig.enabled = false;
955
- else if (mode === "host" && config.backstageApps && config.useMultiplexedTransport !== false) {}
956
- return preparedConfig;
957
- }
958
- /**
959
- * Initialize the plugin
960
- */
961
- async initialize(config) {
962
- const mergedConfig = {
963
- ...this.microFrontendConfig,
964
- ...config
965
- };
966
- if (this.mode === "child") {
967
- if (this.parentSentry) {
968
- this.client = this.parentSentry;
969
- this.initialized = true;
970
- if (this.backstageApp && mergedConfig.addBackstageContext !== false) this.configureParentSentry();
971
- }
972
- return;
973
- }
974
- if (mergedConfig.preventDuplicateInit !== false) try {
975
- ensureSingleInit();
976
- } catch (error) {
977
- logError("Sentry initialization prevented", { error });
978
- this.enabled = false;
979
- return;
980
- }
981
- await super.initialize(mergedConfig);
982
- if (this.mode === "host" && this.client && mergedConfig.backstageApps) this.setupHostMode(mergedConfig);
983
- }
984
- /**
985
- * Configure parent Sentry instance for child mode
986
- */
987
- configureParentSentry() {
988
- if (!this.parentSentry || !this.backstageApp) {
989
- logWarn("[SentryMicroFrontendPlugin] Cannot configure parent Sentry: missing parentSentry or backstageApp");
990
- return;
991
- }
992
- try {
993
- const processor = (event) => {
994
- try {
995
- if (this.shouldProcessEvent(event)) enhanceEventWithBackstageApp(event, this.backstageApp ?? "", {
996
- mode: this.mode,
997
- plugin: "SentryMicroFrontendPlugin"
998
- });
999
- } catch (error) {
1000
- logError("[SentryMicroFrontendPlugin] Error processing event", {
1001
- error,
1002
- event
1003
- });
1004
- }
1005
- return event;
1006
- };
1007
- if (typeof this.parentSentry.addEventProcessor === "function") {
1008
- this.parentSentry.addEventProcessor(processor);
1009
- this.eventProcessorCleanup = () => {};
1010
- } else logWarn("[SentryMicroFrontendPlugin] Parent Sentry does not support addEventProcessor");
1011
- } catch (error) {
1012
- logError("[SentryMicroFrontendPlugin] Failed to configure parent Sentry", { error });
1013
- }
1014
- }
1015
- /**
1016
- * Set up host mode with multiplexed transport
1017
- */
1018
- setupHostMode(config) {
1019
- if (!config.backstageApps || !this.client) {
1020
- logWarn("[SentryMicroFrontendPlugin] Cannot setup host mode: missing backstageApps or client");
1021
- return;
1022
- }
1023
- try {
1024
- const transport = createMultiplexedTransport(config.backstageApps, config.fallbackDsn ?? config.dsn, this.client);
1025
- if (transport && typeof this.client.init === "function") {
1026
- const currentOptions = typeof this.client.getOptions === "function" ? this.client.getOptions() : {};
1027
- this.client.init({
1028
- ...currentOptions,
1029
- transport,
1030
- beforeSend: createBackstageBeforeSend(this.backstageApp ?? "main", config.beforeSend)
1031
- });
1032
- } else logWarn("[SentryMicroFrontendPlugin] Client does not support init method or transport creation failed");
1033
- } catch (error) {
1034
- logError("[SentryMicroFrontendPlugin] Failed to setup host mode", { error });
1035
- }
1036
- }
1037
- /**
1038
- * Check if we should process this event
1039
- */
1040
- shouldProcessEvent(event) {
1041
- if (event.tags?.microFrontendProcessed) return false;
1042
- if (this.backstageApp && event.tags?.backstageApp && event.tags.backstageApp !== this.backstageApp) return false;
1043
- return true;
1044
- }
1045
- /**
1046
- * Capture an exception with backstageApp context
1047
- */
1048
- captureException(error, context) {
1049
- if (!this.enabled) return;
1050
- try {
1051
- if (this.mode === "child" && this.parentSentry && this.backstageScope) if (typeof this.parentSentry.withScope === "function") this.parentSentry.withScope((scope) => {
1052
- try {
1053
- if (this.backstageScope && typeof scope.setTag === "function") {
1054
- scope.setTag("backstageApp", this.backstageApp ?? "unknown");
1055
- scope.setTag("microFrontend", true);
1056
- scope.setContext("microFrontend", {
1057
- backstageApp: this.backstageApp,
1058
- mode: this.mode
1059
- });
1060
- }
1061
- if (context && typeof scope.setContext === "function") scope.setContext("additional", context);
1062
- if (this.parentSentry && typeof this.parentSentry.captureException === "function") this.parentSentry.captureException(error);
1063
- } catch (scopeError) {
1064
- logError("[SentryMicroFrontendPlugin] Error in scope callback", { error: scopeError });
1065
- }
1066
- });
1067
- else logWarn("[SentryMicroFrontendPlugin] Parent Sentry does not support withScope");
1068
- else {
1069
- const enhancedContext = {
1070
- ...context,
1071
- microFrontend: {
1072
- backstageApp: this.backstageApp,
1073
- mode: this.mode
1074
- }
1075
- };
1076
- super.captureException(error, enhancedContext);
1077
- }
1078
- } catch (captureError) {
1079
- logError("[SentryMicroFrontendPlugin] Failed to capture exception", { error: captureError });
1080
- }
1081
- }
1082
- /**
1083
- * Capture a message with backstageApp context
1084
- */
1085
- captureMessage(message, level = "info", context) {
1086
- if (!this.enabled) return;
1087
- try {
1088
- const sentryLevel = mapLogLevelToSentrySeverity(level);
1089
- if (this.mode === "child" && this.parentSentry && this.backstageScope) if (typeof this.parentSentry.withScope === "function") this.parentSentry.withScope((scope) => {
1090
- try {
1091
- if (this.backstageScope && typeof scope.setTag === "function") {
1092
- scope.setTag("backstageApp", this.backstageApp ?? "unknown");
1093
- scope.setTag("microFrontend", true);
1094
- if (typeof scope.setContext === "function") scope.setContext("microFrontend", {
1095
- backstageApp: this.backstageApp,
1096
- mode: this.mode
1097
- });
1098
- }
1099
- if (context && typeof scope.setContext === "function") scope.setContext("additional", context);
1100
- if (this.parentSentry && typeof this.parentSentry.captureMessage === "function") this.parentSentry.captureMessage(message, sentryLevel);
1101
- } catch (scopeError) {
1102
- logError("[SentryMicroFrontendPlugin] Error in scope callback", { error: scopeError });
1103
- }
1104
- });
1105
- else logWarn("[SentryMicroFrontendPlugin] Parent Sentry does not support withScope");
1106
- else super.captureMessage(message, level, context);
1107
- } catch (captureError) {
1108
- logError("[SentryMicroFrontendPlugin] Failed to capture message", { error: captureError });
1109
- }
1110
- }
1111
- /**
1112
- * Get the current operation mode
1113
- */
1114
- getMode() {
1115
- return this.mode;
1116
- }
1117
- /**
1118
- * Get the current Backstage app identifier
1119
- */
1120
- getBackstageApp() {
1121
- return this.backstageApp;
1122
- }
1123
- /**
1124
- * @deprecated Use getBackstageApp instead.
1125
- */
1126
- getZone() {
1127
- return this.getBackstageApp();
1128
- }
1129
- /**
1130
- * Get debug information about the plugin state
1131
- */
1132
- getDebugInfo() {
1133
- return {
1134
- mode: this.mode,
1135
- backstageApp: this.backstageApp,
1136
- enabled: this.enabled,
1137
- initialized: this.initialized,
1138
- hasParentSentry: this.mode === "child" && Boolean(this.parentSentry),
1139
- clientType: this.client ? this.client.constructor.name : "none"
1140
- };
1141
- }
1142
- /**
1143
- * Clean up the plugin and release resources
1144
- */
1145
- async cleanup() {
1146
- try {
1147
- if (this.eventProcessorCleanup) {
1148
- this.eventProcessorCleanup();
1149
- this.eventProcessorCleanup = void 0;
1150
- }
1151
- if (this.backstageScope && typeof this.backstageScope.clear === "function") this.backstageScope.clear();
1152
- this.backstageScope = void 0;
1153
- this.parentSentry = void 0;
1154
- await super.cleanup();
1155
- this.initialized = false;
1156
- this.enabled = false;
1157
- logDebug("[SentryMicroFrontendPlugin] Cleanup completed");
1158
- } catch (error) {
1159
- logError("[SentryMicroFrontendPlugin] Error during cleanup", { error });
1160
- }
1161
- }
1162
- /**
1163
- * Destroy the plugin (alias for cleanup)
1164
- */
1165
- async destroy() {
1166
- await this.cleanup();
1167
- }
1168
- };
1169
- /**
1170
- * Factory function to create a Sentry Micro Frontend plugin.
1171
- *
1172
- * Creates a configured SentryMicroFrontendPlugin instance with micro frontend-specific
1173
- * features like multiplexed transport and backstage app routing.
1174
- *
1175
- * @param config - Optional Sentry micro frontend plugin configuration
1176
- * @returns SentryMicroFrontendPlugin instance
1177
- *
1178
- * @example
1179
- * ```typescript
1180
- * const sentry = createSentryMicroFrontendPlugin({
1181
- * dsn: 'https://...',
1182
- * backstage: [
1183
- * { name: 'admin', dsn: 'https://admin-dsn...' },
1184
- * { name: 'dashboard', dsn: 'https://dashboard-dsn...' },
1185
- * ],
1186
- * });
1187
- * ```
1188
- */
1189
- const createSentryMicroFrontendPlugin = (config) => {
1190
- return new SentryMicroFrontendPlugin(config);
1191
- };
1192
-
1193
- //#endregion
1194
- export { isHostEnvironment as a, detectCurrentBackstageApp as i, createSentryMicroFrontendPlugin as n, createMultiplexedTransport as o, createBackstageScope as r, SentryMicroFrontendPlugin as t };
1195
- //# sourceMappingURL=plugin-CxeJHHeJ.mjs.map