reroute-js 0.22.4 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/bin.d.ts +1 -1
- package/cli/bin.js +6 -6
- package/cli/bin.js.map +1 -1
- package/cli/index.d.ts +1 -1
- package/cli/index.js +4 -4
- package/cli/index.js.map +1 -1
- package/cli/src/cli.d.ts +1 -1
- package/cli/src/commands/analyze.d.ts +1 -1
- package/cli/src/commands/build.d.ts +1 -1
- package/cli/src/commands/dev.d.ts +1 -1
- package/cli/src/commands/gen.d.ts +1 -1
- package/cli/src/commands/index.d.ts +1 -1
- package/cli/src/commands/init.d.ts +1 -1
- package/cli/src/commands/lib/assets.d.ts +1 -1
- package/cli/src/commands/lib/bundler.d.ts +1 -1
- package/cli/src/commands/lib/command.d.ts +1 -1
- package/cli/src/commands/lib/env.d.ts +1 -1
- package/cli/src/commands/lib/index.d.ts +1 -1
- package/cli/src/commands/lib/log.d.ts +1 -1
- package/cli/src/commands/lib/markdown/availability.d.ts +1 -1
- package/cli/src/commands/lib/markdown/index.d.ts +1 -1
- package/cli/src/commands/lib/markdown/processor.d.ts +1 -1
- package/cli/src/commands/lib/production.d.ts +1 -1
- package/cli/src/commands/lib/server.d.ts +1 -1
- package/cli/src/commands/lib/streaming/analyzer.d.ts +1 -1
- package/cli/src/commands/lib/streaming/suspense.d.ts +1 -1
- package/cli/src/commands/lib/tailwind.d.ts +1 -1
- package/cli/src/commands/lib/terminal-ui.d.ts +1 -1
- package/cli/src/commands/lib/version.d.ts +1 -1
- package/cli/src/commands/og.d.ts +1 -1
- package/cli/src/commands/start.d.ts +1 -1
- package/cli/src/index.d.ts +1 -1
- package/core/index.d.ts +1 -1
- package/core/index.js +2 -2
- package/core/index.js.map +1 -1
- package/core/src/bundler/hash.d.ts +1 -1
- package/core/src/bundler/index.d.ts +1 -1
- package/core/src/config.d.ts +1 -1
- package/core/src/content/discovery.d.ts +1 -1
- package/core/src/content/index.d.ts +1 -1
- package/core/src/content/metadata.d.ts +1 -1
- package/core/src/index.d.ts +1 -1
- package/core/src/llms/extractor.d.ts +1 -1
- package/core/src/llms/formatter.d.ts +1 -1
- package/core/src/llms/full-generator.d.ts +1 -1
- package/core/src/llms/index-generator.d.ts +1 -1
- package/core/src/llms/index.d.ts +1 -1
- package/core/src/og/discovery.d.ts +1 -1
- package/core/src/og/index.d.ts +1 -1
- package/core/src/og/meta.d.ts +1 -1
- package/core/src/og/render.d.ts +1 -1
- package/core/src/og/types.d.ts +1 -1
- package/core/src/robots/discovery.d.ts +1 -1
- package/core/src/robots/generator.d.ts +1 -1
- package/core/src/robots/index.d.ts +1 -1
- package/core/src/robots/policies.d.ts +1 -1
- package/core/src/rss/discovery.d.ts +1 -1
- package/core/src/rss/generator.d.ts +1 -1
- package/core/src/rss/index.d.ts +1 -1
- package/core/src/sitemap/discovery.d.ts +1 -1
- package/core/src/sitemap/generator.d.ts +1 -1
- package/core/src/sitemap/index.d.ts +1 -1
- package/core/src/ssr/index.d.ts +1 -1
- package/core/src/ssr/lib/cache.d.ts +1 -1
- package/core/src/ssr/lib/collections.d.ts +1 -1
- package/core/src/ssr/lib/compression.d.ts +1 -1
- package/core/src/ssr/lib/compute/content.d.ts +1 -1
- package/core/src/ssr/lib/compute/index.d.ts +1 -1
- package/core/src/ssr/lib/compute/layouts.d.ts +1 -1
- package/core/src/ssr/lib/compute/routes.d.ts +1 -1
- package/core/src/ssr/lib/data.d.ts +1 -1
- package/core/src/ssr/lib/html.d.ts +1 -1
- package/core/src/ssr/lib/imports.d.ts +1 -1
- package/core/src/ssr/lib/index.d.ts +1 -1
- package/core/src/ssr/lib/layouts.d.ts +1 -1
- package/core/src/ssr/lib/metadata.d.ts +1 -1
- package/core/src/ssr/lib/mime.d.ts +1 -1
- package/core/src/ssr/lib/modules.d.ts +1 -1
- package/core/src/ssr/lib/path.d.ts +1 -1
- package/core/src/ssr/lib/preload.d.ts +1 -1
- package/core/src/ssr/lib/scripts/collections.d.ts +1 -1
- package/core/src/ssr/lib/scripts/data.d.ts +1 -1
- package/core/src/ssr/lib/scripts/escape.d.ts +1 -1
- package/core/src/ssr/lib/scripts/feeds.d.ts +1 -1
- package/core/src/ssr/lib/scripts/index.d.ts +1 -1
- package/core/src/ssr/lib/seed.d.ts +1 -1
- package/core/src/ssr/lib/setup.d.ts +1 -1
- package/core/src/ssr/lib/styles.d.ts +1 -1
- package/core/src/ssr/lib/template.d.ts +1 -1
- package/core/src/ssr/lib/types.d.ts +1 -1
- package/core/src/ssr/render.d.ts +1 -1
- package/core/src/ssr/stream.d.ts +1 -1
- package/elysia/index.d.ts +1 -1
- package/elysia/index.js +2 -2
- package/elysia/index.js.map +1 -1
- package/elysia/src/index.d.ts +1 -1
- package/elysia/src/libs/assets.d.ts +1 -1
- package/elysia/src/libs/cache.d.ts +1 -1
- package/elysia/src/libs/caching.d.ts +1 -1
- package/elysia/src/libs/http.d.ts +1 -1
- package/elysia/src/libs/image.d.ts +1 -1
- package/elysia/src/libs/index.d.ts +1 -1
- package/elysia/src/libs/llms.d.ts +1 -1
- package/elysia/src/libs/response.d.ts +1 -1
- package/elysia/src/libs/serving.d.ts +1 -1
- package/elysia/src/plugin.d.ts +1 -1
- package/elysia/src/routes/artifacts.d.ts +1 -1
- package/elysia/src/routes/content.d.ts +1 -1
- package/elysia/src/routes/image.d.ts +1 -1
- package/elysia/src/routes/index.d.ts +1 -1
- package/elysia/src/routes/internal.d.ts +1 -1
- package/elysia/src/routes/llms.d.ts +1 -1
- package/elysia/src/routes/og.d.ts +1 -1
- package/elysia/src/routes/redirects.d.ts +1 -1
- package/elysia/src/routes/robots.d.ts +1 -1
- package/elysia/src/routes/rss.d.ts +1 -1
- package/elysia/src/routes/search.d.ts +1 -1
- package/elysia/src/routes/sitemap.d.ts +1 -1
- package/elysia/src/routes/ssr.d.ts +1 -1
- package/elysia/src/routes/static.d.ts +1 -1
- package/elysia/src/types.d.ts +1 -1
- package/package.json +1 -1
- package/react/index.d.ts +1 -1
- package/react/index.js +368 -34
- package/react/index.js.map +6 -5
- package/react/src/components/ClientOnly.d.ts +1 -1
- package/react/src/components/ContentRoute.d.ts +1 -1
- package/react/src/components/Image.d.ts +1 -1
- package/react/src/components/LazyRoute.d.ts +1 -1
- package/react/src/components/Link.d.ts +1 -1
- package/react/src/components/Markdown.d.ts +1 -1
- package/react/src/components/Outlet.d.ts +1 -1
- package/react/src/components/index.d.ts +1 -1
- package/react/src/hooks/index.d.ts +1 -1
- package/react/src/hooks/useContent.d.ts +1 -1
- package/react/src/hooks/useData.d.ts +1 -1
- package/react/src/hooks/useFeed.d.ts +1 -1
- package/react/src/hooks/useLayoutData.d.ts +1 -1
- package/react/src/hooks/useLlms.d.ts +1 -1
- package/react/src/hooks/useNavigate.d.ts +1 -1
- package/react/src/hooks/useParams.d.ts +1 -1
- package/react/src/hooks/useRouter.d.ts +1 -1
- package/react/src/hooks/useSearch.d.ts +1 -1
- package/react/src/hooks/useSearchParams.d.ts +1 -1
- package/react/src/hooks/useToc.d.ts +1 -1
- package/react/src/index.d.ts +1 -1
- package/react/src/lib/collection.d.ts +1 -1
- package/react/src/lib/content.d.ts +1 -1
- package/react/src/lib/head.d.ts +1 -1
- package/react/src/lib/index.d.ts +1 -1
- package/react/src/lib/lazy-route.d.ts +1 -1
- package/react/src/lib/route-loader.d.ts +1 -1
- package/react/src/providers/ContentProvider.d.ts +1 -1
- package/react/src/providers/RerouteProvider.d.ts +3 -2
- package/react/src/providers/RerouteProvider.d.ts.map +1 -1
- package/react/src/providers/RouterProvider.d.ts +2 -2
- package/react/src/providers/RouterProvider.d.ts.map +1 -1
- package/react/src/providers/index.d.ts +1 -1
- package/react/src/types/any.d.ts +1 -1
- package/react/src/types/index.d.ts +1 -1
- package/react/src/types/router.d.ts +1 -1
- package/telemetry/browser.d.ts +1 -1
- package/telemetry/browser.js +47 -52
- package/telemetry/browser.js.map +4 -5
- package/telemetry/index.d.ts +1 -1
- package/telemetry/index.js +2 -2
- package/telemetry/index.js.map +1 -1
- package/telemetry/react.d.ts +1 -1
- package/telemetry/react.js +90 -76
- package/telemetry/react.js.map +4 -4
- package/telemetry/src/browser/index.d.ts +4 -8
- package/telemetry/src/browser/index.d.ts.map +1 -1
- package/telemetry/src/browser/react.d.ts +1 -1
- package/telemetry/src/browser/react.d.ts.map +1 -1
- package/telemetry/src/server/index.d.ts +1 -1
package/telemetry/browser.js.map
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../packages/telemetry/src/browser/index.ts"
|
|
3
|
+
"sources": ["../../packages/telemetry/src/browser/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { SpanStatusCode, trace } from '@opentelemetry/api';\nimport { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web';\nimport { ZoneContextManager } from '@opentelemetry/context-zone';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport { registerInstrumentations } from '@opentelemetry/instrumentation';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { WebTracerProvider } from '@opentelemetry/sdk-trace-web';\nimport {\n\tATTR_SERVICE_NAME,\n\tATTR_SERVICE_VERSION,\n} from '@opentelemetry/semantic-conventions';\n\nexport interface BrowserTelemetryOptions {\n\t/**\n\t * Service name for browser telemetry\n\t * @default 'reroute-app-browser'\n\t */\n\tserviceName?: string;\n\n\t/**\n\t * Service version\n\t * @default '1.0.0'\n\t */\n\tserviceVersion?: string;\n\n\t/**\n\t * OTLP endpoint URL (use relative URL for same-origin proxy)\n\t * @default '/api/telemetry'\n\t */\n\totlpEndpoint?: string;\n\n\t/**\n\t * API key for authentication (optional)\n\t */\n\tapiKey?: string;\n\n\t/**\n\t * Whether running in production\n\t * @default import.meta.env.PROD\n\t */\n\tisProduction?: boolean;\n\n\t/**\n\t * Enable Web Vitals tracking (LCP, CLS, TTFB, INP)\n\t * @default true\n\t */\n\tenableWebVitals?: boolean;\n\n\t/**\n\t * Enable console.error capture (recommended for production only)\n\t * @default isProduction\n\t */\n\tenableConsoleCapture?: boolean;\n}\n\nconst IS_SERVER = typeof window === 'undefined';\n\nlet isInitialized = false;\nlet tracerProvider: WebTracerProvider | null = null;\n\n/**\n * Initialize browser telemetry\n * Call this once when your app starts (usually in a React provider)\n *\n * @example\n * ```typescript\n * import { initBrowserTelemetry } from 'reroute-js/telemetry/browser';\n *\n * initBrowserTelemetry({\n * serviceName: 'My App Browser',\n * otlpEndpoint: '/api/telemetry', // Same-origin proxy\n * isProduction: true,\n * });\n * ```\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Initialization requires multiple setup steps\nexport function initBrowserTelemetry(options: BrowserTelemetryOptions = {}) {\n\tif (IS_SERVER || isInitialized) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst env =\n\t\t\ttypeof import.meta !== 'undefined' ? import.meta.env : undefined;\n\n\t\tconst SERVICE_NAME = options.serviceName || 'reroute-app-browser';\n\t\tconst SERVICE_VERSION = options.serviceVersion || '1.0.0';\n\t\tconst OTLP_ENDPOINT = options.otlpEndpoint || '/api/telemetry';\n\t\tconst IS_PRODUCTION = options.isProduction ?? env?.PROD ?? false;\n\t\tconst ENABLE_WEB_VITALS = options.enableWebVitals ?? true;\n\t\tconst ENABLE_CONSOLE_CAPTURE =\n\t\t\toptions.enableConsoleCapture ?? IS_PRODUCTION;\n\n\t\tconsole.log(\n\t\t\t`[browser-telemetry] Initializing with endpoint: ${OTLP_ENDPOINT}`,\n\t\t);\n\n\t\t// Configure OTLP exporter\n\t\tconst headers: Record<string, string> = {};\n\t\tconst apiKey = options.apiKey || env?.REROUTE_SIGNOZ_API_KEY;\n\t\tif (apiKey) {\n\t\t\theaders.Authorization = `Bearer ${apiKey}`;\n\t\t}\n\n\t\tconst exporter = new OTLPTraceExporter({\n\t\t\turl: `${OTLP_ENDPOINT}/v1/traces`,\n\t\t\theaders: Object.keys(headers).length > 0 ? headers : undefined,\n\t\t});\n\n\t\t// Create resource\n\t\tconst resource = resourceFromAttributes({\n\t\t\t[ATTR_SERVICE_NAME]: SERVICE_NAME,\n\t\t\t[ATTR_SERVICE_VERSION]: SERVICE_VERSION,\n\t\t\t'deployment.environment': IS_PRODUCTION ? 'production' : 'development',\n\t\t\t'browser.user_agent': navigator.userAgent,\n\t\t\t'browser.language': navigator.language,\n\t\t\t'browser.platform': navigator.platform,\n\t\t\t'screen.width': window.screen.width,\n\t\t\t'screen.height': window.screen.height,\n\t\t});\n\n\t\t// Create span processor\n\t\tconst spanProcessor = new BatchSpanProcessor(exporter, {\n\t\t\tmaxQueueSize: 100,\n\t\t\tmaxExportBatchSize: 10,\n\t\t\tscheduledDelayMillis: 500,\n\t\t});\n\n\t\t// Create tracer provider\n\t\ttracerProvider = new WebTracerProvider({\n\t\t\tresource,\n\t\t\tspanProcessors: [spanProcessor],\n\t\t});\n\n\t\ttracerProvider.register({\n\t\t\tcontextManager: new ZoneContextManager(),\n\t\t});\n\n\t\t// Auto-instrument browser APIs\n\t\tregisterInstrumentations({\n\t\t\tinstrumentations: [\n\t\t\t\tgetWebAutoInstrumentations({\n\t\t\t\t\t'@opentelemetry/instrumentation-document-load': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t},\n\t\t\t\t\t'@opentelemetry/instrumentation-user-interaction': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\teventNames: ['click', 'submit'],\n\t\t\t\t\t},\n\t\t\t\t\t'@opentelemetry/instrumentation-fetch': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tpropagateTraceHeaderCorsUrls: [/.*/],\n\t\t\t\t\t\tclearTimingResources: true,\n\t\t\t\t\t},\n\t\t\t\t\t'@opentelemetry/instrumentation-xml-http-request': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tpropagateTraceHeaderCorsUrls: [/.*/],\n\t\t\t\t\t\tclearTimingResources: true,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t],\n\t\t});\n\n\t\t// Setup error handlers\n\t\tsetupErrorHandlers();\n\n\t\t// Setup Web Vitals\n\t\tif (ENABLE_WEB_VITALS) {\n\t\t\tsetupWebVitals();\n\t\t}\n\n\t\t// Setup console capture (production only)\n\t\tif (ENABLE_CONSOLE_CAPTURE) {\n\t\t\tsetupConsoleCapture();\n\t\t}\n\n\t\t// Track page visibility\n\t\tsetupVisibilityTracking();\n\n\t\tisInitialized = true;\n\t\tconsole.log('[browser-telemetry] Initialized successfully');\n\t} catch (error) {\n\t\tconsole.error('[browser-telemetry] Failed to initialize:', error);\n\t\t// Don't throw - telemetry should never break the app\n\t}\n}\n\nfunction setupErrorHandlers() {\n\tconst tracer = trace.getTracer('error-handler');\n\n\twindow.addEventListener('error', (event) => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.error.uncaught', {\n\t\t\t\tstartTime: Date.now(),\n\t\t\t});\n\n\t\t\tconst stackTrace = event.error?.stack || '';\n\n\t\t\tspan.setStatus({\n\t\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\t\tmessage: event.message,\n\t\t\t});\n\n\t\t\tspan.setAttributes({\n\t\t\t\terror: true,\n\t\t\t\t'error.type': event.error?.name || 'UncaughtError',\n\t\t\t\t'error.message': event.message,\n\t\t\t\t'error.stack': stackTrace,\n\t\t\t\t'error.filename': event.filename || '',\n\t\t\t\t'error.lineno': event.lineno || 0,\n\t\t\t\t'error.colno': event.colno || 0,\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t\t'browser.user_agent': navigator.userAgent,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tif (event.error) {\n\t\t\t\tspan.recordException(event.error);\n\t\t\t\tspan.addEvent('exception', {\n\t\t\t\t\t'exception.type': event.error.name,\n\t\t\t\t\t'exception.message': event.error.message,\n\t\t\t\t\t'exception.stacktrace': stackTrace,\n\t\t\t\t\t'exception.escaped': 'false',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tspan.end();\n\t\t} catch (telemetryError) {\n\t\t\t// Telemetry failed - log but don't break the app\n\t\t\tconsole.error(\n\t\t\t\t'[browser-telemetry] Error tracking failed:',\n\t\t\t\ttelemetryError,\n\t\t\t);\n\t\t}\n\t\tconsole.error(\n\t\t\t'[browser-telemetry] Uncaught error:',\n\t\t\tevent.error || event.message,\n\t\t);\n\t});\n\n\twindow.addEventListener('unhandledrejection', (event) => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.error.unhandled_rejection', {\n\t\t\t\tstartTime: Date.now(),\n\t\t\t});\n\n\t\t\tconst isError = event.reason instanceof Error;\n\t\t\tconst errorMessage = isError\n\t\t\t\t? event.reason.message\n\t\t\t\t: String(event.reason);\n\t\t\tconst errorStack = isError ? event.reason.stack || '' : '';\n\t\t\tconst errorType = isError ? event.reason.name : 'UnhandledRejection';\n\n\t\t\tspan.setStatus({\n\t\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\t\tmessage: errorMessage,\n\t\t\t});\n\n\t\t\tspan.setAttributes({\n\t\t\t\terror: true,\n\t\t\t\t'error.type': errorType,\n\t\t\t\t'error.message': errorMessage,\n\t\t\t\t'error.stack': errorStack,\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t\t'browser.user_agent': navigator.userAgent,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tif (isError) {\n\t\t\t\tspan.recordException(event.reason);\n\t\t\t\tspan.addEvent('exception', {\n\t\t\t\t\t'exception.type': event.reason.name,\n\t\t\t\t\t'exception.message': event.reason.message,\n\t\t\t\t\t'exception.stacktrace': errorStack,\n\t\t\t\t\t'exception.escaped': 'false',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tspan.end();\n\t\t} catch (telemetryError) {\n\t\t\t// Telemetry failed - log but don't break the app\n\t\t\tconsole.error(\n\t\t\t\t'[browser-telemetry] Rejection tracking failed:',\n\t\t\t\ttelemetryError,\n\t\t\t);\n\t\t}\n\t\tconsole.error('[browser-telemetry] Unhandled rejection:', event.reason);\n\t});\n}\n\nasync function setupWebVitals() {\n\ttry {\n\t\tconst { onLCP, onCLS, onTTFB, onINP } = await import('web-vitals');\n\t\tconst tracer = trace.getTracer('web-vitals');\n\n\t\tconst sendToAnalytics = (metric: {\n\t\t\tname: string;\n\t\t\tvalue: number;\n\t\t\trating: string;\n\t\t\tdelta: number;\n\t\t\tid: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst span = tracer.startSpan(`web_vitals.${metric.name}`, {\n\t\t\t\t\tstartTime: Date.now() - metric.value,\n\t\t\t\t});\n\n\t\t\t\tspan.setAttributes({\n\t\t\t\t\t'metric.name': metric.name,\n\t\t\t\t\t'metric.value': metric.value,\n\t\t\t\t\t'metric.rating': metric.rating,\n\t\t\t\t\t'metric.delta': metric.delta,\n\t\t\t\t\t'metric.id': metric.id,\n\t\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t\t});\n\n\t\t\t\tspan.end();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[browser-telemetry] Web Vitals tracking failed:', error);\n\t\t\t}\n\t\t};\n\n\t\tonLCP(sendToAnalytics);\n\t\tonCLS(sendToAnalytics);\n\t\tonTTFB(sendToAnalytics);\n\t\tonINP(sendToAnalytics);\n\n\t\tconsole.log('[browser-telemetry] Web Vitals tracking enabled');\n\t} catch (error) {\n\t\tconsole.warn('[browser-telemetry] Web Vitals not available:', error);\n\t}\n}\n\nfunction setupConsoleCapture() {\n\tconst tracer = trace.getTracer('console');\n\tconst originalError = console.error;\n\n\tconsole.error = (...args: unknown[]) => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.console.error');\n\n\t\t\tspan.setAttributes({\n\t\t\t\t'log.level': 'error',\n\t\t\t\t'log.message': args.map(String).join(' '),\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tspan.end();\n\t\t} catch {\n\t\t\t// Silently fail - don't break console.error\n\t\t}\n\t\toriginalError.apply(console, args);\n\t};\n}\n\nfunction setupVisibilityTracking() {\n\tconst tracer = trace.getTracer('visibility');\n\n\tdocument.addEventListener('visibilitychange', () => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.visibility_change');\n\n\t\t\tspan.setAttributes({\n\t\t\t\t'visibility.state': document.visibilityState,\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tspan.end();\n\t\t} catch {\n\t\t\t// Silently fail - don't break visibility tracking\n\t\t}\n\t});\n}\n\n/**\n * Create a custom span for tracking user interactions\n *\n * @example\n * ```typescript\n * const span = createSpan('user.button_click', { button: 'download' });\n * // ... do something\n * span.end();\n * ```\n */\nexport function createSpan(\n\tname: string,\n\tattributes: Record<string, string | number | boolean> = {},\n) {\n\tif (IS_SERVER || !isInitialized) {\n\t\treturn {\n\t\t\tsetAttributes: () => {},\n\t\t\tsetStatus: () => {},\n\t\t\trecordException: () => {},\n\t\t\tend: () => {},\n\t\t};\n\t}\n\n\ttry {\n\t\tconst tracer = trace.getTracer('custom');\n\t\tconst span = tracer.startSpan(name);\n\n\t\tspan.setAttributes({\n\t\t\t...attributes,\n\t\t\t'browser.url': window.location.href,\n\t\t\t'browser.pathname': window.location.pathname,\n\t\t});\n\n\t\treturn span;\n\t} catch (error) {\n\t\tconsole.error('[browser-telemetry] Failed to create span:', error);\n\t\treturn {\n\t\t\tsetAttributes: () => {},\n\t\t\tsetStatus: () => {},\n\t\t\trecordException: () => {},\n\t\t\tend: () => {},\n\t\t};\n\t}\n}\n\n/**\n * Track a custom event\n *\n * @example\n * ```typescript\n * trackEvent('download_click', { platform: 'mac' });\n * ```\n */\nexport function trackEvent(\n\teventName: string,\n\tattributes: Record<string, string | number | boolean> = {},\n) {\n\tif (IS_SERVER || !isInitialized) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst span = createSpan(`custom.${eventName}`, attributes);\n\t\tspan.end();\n\t} catch (error) {\n\t\tconsole.error('[browser-telemetry] Failed to track event:', error);\n\t}\n}\n\n/**\n * Track an error with context\n *\n * @example\n * ```typescript\n * try {\n * // ... something\n * } catch (error) {\n * trackError(error, { action: 'checkout', step: 'payment' });\n * }\n * ```\n */\nexport function trackError(\n\terror: Error,\n\tcontext: Record<string, string | number | boolean> = {},\n) {\n\tif (IS_SERVER || !isInitialized) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst tracer = trace.getTracer('error-handler');\n\t\tconst span = tracer.startSpan('browser.error.tracked');\n\n\t\tconst stackTrace = error.stack || '';\n\n\t\tspan.setStatus({\n\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\tmessage: error.message,\n\t\t});\n\n\t\tspan.setAttributes({\n\t\t\terror: true,\n\t\t\t'error.type': error.name,\n\t\t\t'error.message': error.message,\n\t\t\t'error.stack': stackTrace,\n\t\t\t...context,\n\t\t\t'browser.url': window.location.href,\n\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t});\n\n\t\tspan.recordException(error);\n\n\t\tspan.addEvent('exception', {\n\t\t\t'exception.type': error.name,\n\t\t\t'exception.message': error.message,\n\t\t\t'exception.stacktrace': stackTrace,\n\t\t\t'exception.escaped': 'false',\n\t\t});\n\n\t\tspan.end();\n\t} catch (telemetryError) {\n\t\tconsole.error('[browser-telemetry] Failed to track error:', telemetryError);\n\t}\n}\n\n/**\n * Gracefully shutdown telemetry\n */\nexport async function shutdownTelemetry() {\n\tif (tracerProvider) {\n\t\tawait tracerProvider.shutdown();\n\t\tisInitialized = false;\n\t\tconsole.log('[browser-telemetry] Shut down successfully');\n\t}\n}\n",
|
|
6
|
-
"export * from './src/browser';\n"
|
|
5
|
+
"/** biome-ignore-all lint/suspicious/noExplicitAny: That's fine */\nexport interface BrowserTelemetryOptions {\n\t/**\n\t * Service name for browser telemetry\n\t * @default 'reroute-app-browser'\n\t */\n\tserviceName?: string;\n\n\t/**\n\t * Service version\n\t * @default '1.0.0'\n\t */\n\tserviceVersion?: string;\n\n\t/**\n\t * OTLP endpoint URL (use relative URL for same-origin proxy)\n\t * @default '/api/telemetry'\n\t */\n\totlpEndpoint?: string;\n\n\t/**\n\t * API key for authentication (optional)\n\t */\n\tapiKey?: string;\n\n\t/**\n\t * Whether running in production\n\t * @default import.meta.env.PROD\n\t */\n\tisProduction?: boolean;\n\n\t/**\n\t * Enable Web Vitals tracking (LCP, CLS, TTFB, INP)\n\t * @default true\n\t */\n\tenableWebVitals?: boolean;\n\n\t/**\n\t * Enable console.error capture (recommended for production only)\n\t * @default isProduction\n\t */\n\tenableConsoleCapture?: boolean;\n}\n\nconst IS_SERVER = typeof window === 'undefined';\n\nlet isInitialized = false;\nlet tracerProvider: any = null;\n\n/**\n * Initialize browser telemetry\n * Call this once when your app starts (usually in a React provider)\n *\n * @example\n * ```typescript\n * import { initBrowserTelemetry } from 'reroute-js/telemetry/browser';\n *\n * initBrowserTelemetry({\n * serviceName: 'My App Browser',\n * otlpEndpoint: '/api/telemetry', // Same-origin proxy\n * isProduction: true,\n * });\n * ```\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Initialization requires multiple setup steps\nexport async function initBrowserTelemetry(\n\toptions: BrowserTelemetryOptions = {},\n) {\n\tif (IS_SERVER || isInitialized) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\t// Lazy load OpenTelemetry modules to prevent SSR execution\n\t\tconst [\n\t\t\t{ getWebAutoInstrumentations },\n\t\t\t{ ZoneContextManager },\n\t\t\t{ OTLPTraceExporter },\n\t\t\t{ registerInstrumentations },\n\t\t\t{ resourceFromAttributes },\n\t\t\t{ BatchSpanProcessor },\n\t\t\t{ WebTracerProvider },\n\t\t\t{ ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION },\n\t\t] = await Promise.all([\n\t\t\timport('@opentelemetry/auto-instrumentations-web'),\n\t\t\timport('@opentelemetry/context-zone'),\n\t\t\timport('@opentelemetry/exporter-trace-otlp-http'),\n\t\t\timport('@opentelemetry/instrumentation'),\n\t\t\timport('@opentelemetry/resources'),\n\t\t\timport('@opentelemetry/sdk-trace-base'),\n\t\t\timport('@opentelemetry/sdk-trace-web'),\n\t\t\timport('@opentelemetry/semantic-conventions'),\n\t\t]);\n\n\t\tconst env =\n\t\t\ttypeof import.meta !== 'undefined' ? import.meta.env : undefined;\n\n\t\tconst SERVICE_NAME = options.serviceName || 'reroute-app-browser';\n\t\tconst SERVICE_VERSION = options.serviceVersion || '1.0.0';\n\t\tconst OTLP_ENDPOINT = options.otlpEndpoint || '/api/telemetry';\n\t\tconst IS_PRODUCTION = options.isProduction ?? env?.PROD ?? false;\n\t\tconst ENABLE_WEB_VITALS = options.enableWebVitals ?? true;\n\t\tconst ENABLE_CONSOLE_CAPTURE =\n\t\t\toptions.enableConsoleCapture ?? IS_PRODUCTION;\n\n\t\tconsole.log(\n\t\t\t`[browser-telemetry] Initializing with endpoint: ${OTLP_ENDPOINT}`,\n\t\t);\n\n\t\t// Configure OTLP exporter\n\t\tconst headers: Record<string, string> = {};\n\t\tconst apiKey = options.apiKey || env?.REROUTE_SIGNOZ_API_KEY;\n\t\tif (apiKey) {\n\t\t\theaders.Authorization = `Bearer ${apiKey}`;\n\t\t}\n\n\t\tconst exporter = new OTLPTraceExporter({\n\t\t\turl: `${OTLP_ENDPOINT}/v1/traces`,\n\t\t\theaders: Object.keys(headers).length > 0 ? headers : undefined,\n\t\t});\n\n\t\t// Create resource\n\t\tconst resource = resourceFromAttributes({\n\t\t\t[ATTR_SERVICE_NAME]: SERVICE_NAME,\n\t\t\t[ATTR_SERVICE_VERSION]: SERVICE_VERSION,\n\t\t\t'deployment.environment': IS_PRODUCTION ? 'production' : 'development',\n\t\t\t'browser.user_agent': navigator.userAgent,\n\t\t\t'browser.language': navigator.language,\n\t\t\t'browser.platform': navigator.platform,\n\t\t\t'screen.width': window.screen.width,\n\t\t\t'screen.height': window.screen.height,\n\t\t});\n\n\t\t// Create span processor\n\t\tconst spanProcessor = new BatchSpanProcessor(exporter, {\n\t\t\tmaxQueueSize: 100,\n\t\t\tmaxExportBatchSize: 10,\n\t\t\tscheduledDelayMillis: 500,\n\t\t});\n\n\t\t// Create tracer provider\n\t\ttracerProvider = new WebTracerProvider({\n\t\t\tresource,\n\t\t\tspanProcessors: [spanProcessor],\n\t\t});\n\n\t\ttracerProvider.register({\n\t\t\tcontextManager: new ZoneContextManager(),\n\t\t});\n\n\t\t// Auto-instrument browser APIs\n\t\tregisterInstrumentations({\n\t\t\tinstrumentations: [\n\t\t\t\tgetWebAutoInstrumentations({\n\t\t\t\t\t'@opentelemetry/instrumentation-document-load': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t},\n\t\t\t\t\t'@opentelemetry/instrumentation-user-interaction': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\teventNames: ['click', 'submit'],\n\t\t\t\t\t},\n\t\t\t\t\t'@opentelemetry/instrumentation-fetch': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tpropagateTraceHeaderCorsUrls: [/.*/],\n\t\t\t\t\t\tclearTimingResources: true,\n\t\t\t\t\t},\n\t\t\t\t\t'@opentelemetry/instrumentation-xml-http-request': {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tpropagateTraceHeaderCorsUrls: [/.*/],\n\t\t\t\t\t\tclearTimingResources: true,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t],\n\t\t});\n\n\t\t// Setup error handlers (async but don't await - let them set up in background)\n\t\tsetupErrorHandlers().catch((err) =>\n\t\t\tconsole.error('[browser-telemetry] Error handler setup failed:', err),\n\t\t);\n\n\t\t// Setup Web Vitals (async but don't await)\n\t\tif (ENABLE_WEB_VITALS) {\n\t\t\tsetupWebVitals().catch((err) =>\n\t\t\t\tconsole.error('[browser-telemetry] Web Vitals setup failed:', err),\n\t\t\t);\n\t\t}\n\n\t\t// Setup console capture (async but don't await)\n\t\tif (ENABLE_CONSOLE_CAPTURE) {\n\t\t\tsetupConsoleCapture().catch((err) =>\n\t\t\t\tconsole.error('[browser-telemetry] Console capture setup failed:', err),\n\t\t\t);\n\t\t}\n\n\t\t// Track page visibility (async but don't await)\n\t\tsetupVisibilityTracking().catch((err) =>\n\t\t\tconsole.error(\n\t\t\t\t'[browser-telemetry] Visibility tracking setup failed:',\n\t\t\t\terr,\n\t\t\t),\n\t\t);\n\n\t\tisInitialized = true;\n\t\tconsole.log('[browser-telemetry] Initialized successfully');\n\t} catch (error) {\n\t\tconsole.error('[browser-telemetry] Failed to initialize:', error);\n\t\t// Don't throw - telemetry should never break the app\n\t}\n}\n\nasync function setupErrorHandlers() {\n\tconst { trace, SpanStatusCode } = await import('@opentelemetry/api');\n\tconst tracer = trace.getTracer('error-handler');\n\n\twindow.addEventListener('error', (event) => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.error.uncaught', {\n\t\t\t\tstartTime: Date.now(),\n\t\t\t});\n\n\t\t\tconst stackTrace = event.error?.stack || '';\n\n\t\t\tspan.setStatus({\n\t\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\t\tmessage: event.message,\n\t\t\t});\n\n\t\t\tspan.setAttributes({\n\t\t\t\terror: true,\n\t\t\t\t'error.type': event.error?.name || 'UncaughtError',\n\t\t\t\t'error.message': event.message,\n\t\t\t\t'error.stack': stackTrace,\n\t\t\t\t'error.filename': event.filename || '',\n\t\t\t\t'error.lineno': event.lineno || 0,\n\t\t\t\t'error.colno': event.colno || 0,\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t\t'browser.user_agent': navigator.userAgent,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tif (event.error) {\n\t\t\t\tspan.recordException(event.error);\n\t\t\t\tspan.addEvent('exception', {\n\t\t\t\t\t'exception.type': event.error.name,\n\t\t\t\t\t'exception.message': event.error.message,\n\t\t\t\t\t'exception.stacktrace': stackTrace,\n\t\t\t\t\t'exception.escaped': 'false',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tspan.end();\n\t\t} catch (telemetryError) {\n\t\t\t// Telemetry failed - log but don't break the app\n\t\t\tconsole.error(\n\t\t\t\t'[browser-telemetry] Error tracking failed:',\n\t\t\t\ttelemetryError,\n\t\t\t);\n\t\t}\n\t\tconsole.error(\n\t\t\t'[browser-telemetry] Uncaught error:',\n\t\t\tevent.error || event.message,\n\t\t);\n\t});\n\n\twindow.addEventListener('unhandledrejection', (event) => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.error.unhandled_rejection', {\n\t\t\t\tstartTime: Date.now(),\n\t\t\t});\n\n\t\t\tconst isError = event.reason instanceof Error;\n\t\t\tconst errorMessage = isError\n\t\t\t\t? event.reason.message\n\t\t\t\t: String(event.reason);\n\t\t\tconst errorStack = isError ? event.reason.stack || '' : '';\n\t\t\tconst errorType = isError ? event.reason.name : 'UnhandledRejection';\n\n\t\t\tspan.setStatus({\n\t\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\t\tmessage: errorMessage,\n\t\t\t});\n\n\t\t\tspan.setAttributes({\n\t\t\t\terror: true,\n\t\t\t\t'error.type': errorType,\n\t\t\t\t'error.message': errorMessage,\n\t\t\t\t'error.stack': errorStack,\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t\t'browser.user_agent': navigator.userAgent,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tif (isError) {\n\t\t\t\tspan.recordException(event.reason);\n\t\t\t\tspan.addEvent('exception', {\n\t\t\t\t\t'exception.type': event.reason.name,\n\t\t\t\t\t'exception.message': event.reason.message,\n\t\t\t\t\t'exception.stacktrace': errorStack,\n\t\t\t\t\t'exception.escaped': 'false',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tspan.end();\n\t\t} catch (telemetryError) {\n\t\t\t// Telemetry failed - log but don't break the app\n\t\t\tconsole.error(\n\t\t\t\t'[browser-telemetry] Rejection tracking failed:',\n\t\t\t\ttelemetryError,\n\t\t\t);\n\t\t}\n\t\tconsole.error('[browser-telemetry] Unhandled rejection:', event.reason);\n\t});\n}\n\nasync function setupWebVitals() {\n\ttry {\n\t\tconst { onLCP, onCLS, onTTFB, onINP } = await import('web-vitals');\n\t\tconst { trace } = await import('@opentelemetry/api');\n\t\tconst tracer = trace.getTracer('web-vitals');\n\n\t\tconst sendToAnalytics = (metric: {\n\t\t\tname: string;\n\t\t\tvalue: number;\n\t\t\trating: string;\n\t\t\tdelta: number;\n\t\t\tid: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst span = tracer.startSpan(`web_vitals.${metric.name}`, {\n\t\t\t\t\tstartTime: Date.now() - metric.value,\n\t\t\t\t});\n\n\t\t\t\tspan.setAttributes({\n\t\t\t\t\t'metric.name': metric.name,\n\t\t\t\t\t'metric.value': metric.value,\n\t\t\t\t\t'metric.rating': metric.rating,\n\t\t\t\t\t'metric.delta': metric.delta,\n\t\t\t\t\t'metric.id': metric.id,\n\t\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t\t});\n\n\t\t\t\tspan.end();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[browser-telemetry] Web Vitals tracking failed:', error);\n\t\t\t}\n\t\t};\n\n\t\tonLCP(sendToAnalytics);\n\t\tonCLS(sendToAnalytics);\n\t\tonTTFB(sendToAnalytics);\n\t\tonINP(sendToAnalytics);\n\n\t\tconsole.log('[browser-telemetry] Web Vitals tracking enabled');\n\t} catch (error) {\n\t\tconsole.warn('[browser-telemetry] Web Vitals not available:', error);\n\t}\n}\n\nasync function setupConsoleCapture() {\n\tconst { trace } = await import('@opentelemetry/api');\n\tconst tracer = trace.getTracer('console');\n\n\t// Store reference to current console.error (which might be a test spy)\n\tconst originalError = console.error;\n\n\t// Don't override if it's already been captured (e.g., in tests)\n\tif ((originalError as any).__telemetry_captured__) {\n\t\treturn;\n\t}\n\n\tconst wrappedError = (...args: unknown[]) => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.console.error');\n\n\t\t\tspan.setAttributes({\n\t\t\t\t'log.level': 'error',\n\t\t\t\t'log.message': args.map(String).join(' '),\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tspan.end();\n\t\t} catch {\n\t\t\t// Silently fail - don't break console.error\n\t\t}\n\t\toriginalError.apply(console, args);\n\t};\n\n\t// Mark as captured\n\t(wrappedError as any).__telemetry_captured__ = true;\n\tconsole.error = wrappedError;\n}\n\nasync function setupVisibilityTracking() {\n\tconst { trace } = await import('@opentelemetry/api');\n\tconst tracer = trace.getTracer('visibility');\n\n\tdocument.addEventListener('visibilitychange', () => {\n\t\ttry {\n\t\t\tconst span = tracer.startSpan('browser.visibility_change');\n\n\t\t\tspan.setAttributes({\n\t\t\t\t'visibility.state': document.visibilityState,\n\t\t\t\t'browser.url': window.location.href,\n\t\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t\t});\n\n\t\t\tspan.end();\n\t\t} catch {\n\t\t\t// Silently fail - don't break visibility tracking\n\t\t}\n\t});\n}\n\n/**\n * Create a custom span for tracking user interactions\n *\n * @example\n * ```typescript\n * const span = createSpan('user.button_click', { button: 'download' });\n * // ... do something\n * span.end();\n * ```\n */\nexport function createSpan(\n\tname: string,\n\tattributes: Record<string, string | number | boolean> = {},\n) {\n\tif (IS_SERVER || !isInitialized) {\n\t\treturn {\n\t\t\tsetAttributes: () => {},\n\t\t\tsetStatus: () => {},\n\t\t\trecordException: () => {},\n\t\t\tend: () => {},\n\t\t};\n\t}\n\n\ttry {\n\t\t// Use globalThis cache to avoid repeated imports\n\t\tconst trace =\n\t\t\t(globalThis as any).__OTEL_TRACE__ || require('@opentelemetry/api').trace;\n\t\tif (!(globalThis as any).__OTEL_TRACE__) {\n\t\t\t(globalThis as any).__OTEL_TRACE__ = trace;\n\t\t}\n\t\tconst tracer = trace.getTracer('custom');\n\t\tconst span = tracer.startSpan(name);\n\n\t\tspan.setAttributes({\n\t\t\t...attributes,\n\t\t\t'browser.url': window.location.href,\n\t\t\t'browser.pathname': window.location.pathname,\n\t\t});\n\n\t\treturn span;\n\t} catch (error) {\n\t\tconsole.error('[browser-telemetry] Failed to create span:', error);\n\t\treturn {\n\t\t\tsetAttributes: () => {},\n\t\t\tsetStatus: () => {},\n\t\t\trecordException: () => {},\n\t\t\tend: () => {},\n\t\t};\n\t}\n}\n\n/**\n * Track a custom event\n *\n * @example\n * ```typescript\n * trackEvent('download_click', { platform: 'mac' });\n * ```\n */\nexport function trackEvent(\n\teventName: string,\n\tattributes: Record<string, string | number | boolean> = {},\n) {\n\tif (IS_SERVER || !isInitialized) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst span = createSpan(`custom.${eventName}`, attributes);\n\t\tspan.end();\n\t} catch (error) {\n\t\tconsole.error('[browser-telemetry] Failed to track event:', error);\n\t}\n}\n\n/**\n * Track an error with context\n *\n * @example\n * ```typescript\n * try {\n * // ... something\n * } catch (error) {\n * trackError(error, { action: 'checkout', step: 'payment' });\n * }\n * ```\n */\nexport function trackError(\n\terror: Error,\n\tcontext: Record<string, string | number | boolean> = {},\n) {\n\tif (IS_SERVER || !isInitialized) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst { trace, SpanStatusCode } = require('@opentelemetry/api');\n\t\tconst tracer = trace.getTracer('error-handler');\n\t\tconst span = tracer.startSpan('browser.error.tracked');\n\n\t\tconst stackTrace = error.stack || '';\n\n\t\tspan.setStatus({\n\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\tmessage: error.message,\n\t\t});\n\n\t\tspan.setAttributes({\n\t\t\terror: true,\n\t\t\t'error.type': error.name,\n\t\t\t'error.message': error.message,\n\t\t\t'error.stack': stackTrace,\n\t\t\t...context,\n\t\t\t'browser.url': window.location.href,\n\t\t\t'browser.pathname': window.location.pathname,\n\t\t\t'browser.timestamp': new Date().toISOString(),\n\t\t});\n\n\t\tspan.recordException(error);\n\n\t\tspan.addEvent('exception', {\n\t\t\t'exception.type': error.name,\n\t\t\t'exception.message': error.message,\n\t\t\t'exception.stacktrace': stackTrace,\n\t\t\t'exception.escaped': 'false',\n\t\t});\n\n\t\tspan.end();\n\t} catch (telemetryError) {\n\t\tconsole.error('[browser-telemetry] Failed to track error:', telemetryError);\n\t}\n}\n\n/**\n * Gracefully shutdown telemetry\n */\nexport async function shutdownTelemetry() {\n\tif (tracerProvider) {\n\t\tawait tracerProvider.shutdown();\n\t\tisInitialized = false;\n\t\tconsole.log('[browser-telemetry] Shut down successfully');\n\t}\n}\n"
|
|
7
6
|
],
|
|
8
|
-
"mappings": "
|
|
9
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "04111BFC19F6778764756E2164756E21",
|
|
10
9
|
"names": []
|
|
11
10
|
}
|
package/telemetry/index.d.ts
CHANGED
package/telemetry/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* reroute-js v0.
|
|
2
|
+
* reroute-js v0.23.0
|
|
3
3
|
*
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright 2025 stewones <hi@stewan.io>
|
|
@@ -506,4 +506,4 @@ export {
|
|
|
506
506
|
telemetry
|
|
507
507
|
};
|
|
508
508
|
|
|
509
|
-
//# debugId=
|
|
509
|
+
//# debugId=1B4D6904ACC7910E64756E2164756E21
|
package/telemetry/index.js.map
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
"import os from 'node:os';\nimport { opentelemetry } from '@elysiajs/opentelemetry';\nimport {\n\ttype Counter,\n\ttype Histogram,\n\tmetrics,\n\tSpanStatusCode,\n\ttrace,\n\ttype UpDownCounter,\n} from '@opentelemetry/api';\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs';\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport {\n\tBatchLogRecordProcessor,\n\tLoggerProvider,\n} from '@opentelemetry/sdk-logs';\nimport {\n\tMeterProvider,\n\tPeriodicExportingMetricReader,\n} from '@opentelemetry/sdk-metrics';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-node';\nimport {\n\tATTR_SERVICE_NAME,\n\tATTR_SERVICE_VERSION,\n} from '@opentelemetry/semantic-conventions';\nimport { ATTR_HOST_NAME } from '@opentelemetry/semantic-conventions/incubating';\nimport type { Elysia } from 'elysia';\n\nexport interface ServerTelemetryOptions {\n\t/**\n\t * Service name for telemetry\n\t * @default 'reroute-app'\n\t */\n\tserviceName?: string;\n\n\t/**\n\t * Service version\n\t * @default process.env.npm_package_version || '1.0.0'\n\t */\n\tserviceVersion?: string;\n\n\t/**\n\t * OTLP endpoint URL\n\t * @default process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318'\n\t */\n\totlpEndpoint?: string;\n\n\t/**\n\t * API key for authentication (optional, only needed for SigNoz Cloud)\n\t */\n\tapiKey?: string;\n\n\t/**\n\t * Whether running in production\n\t * @default process.env.NODE_ENV === 'production'\n\t */\n\tisProduction?: boolean;\n\n\t/**\n\t * Enable system metrics (CPU, memory, connections)\n\t * @default true\n\t */\n\tenableSystemMetrics?: boolean;\n\n\t/**\n\t * Metric export interval in milliseconds\n\t * @default 5000\n\t */\n\tmetricsInterval?: number;\n\n\t/**\n\t * Enable browser telemetry proxy\n\t * Creates /api/telemetry/* endpoints to forward browser traces\n\t * This avoids CORS issues and ad blockers\n\t * @default false\n\t */\n\tproxy?: boolean;\n\n\t/**\n\t * Enable verbose logging for proxy\n\t * @default false\n\t */\n\tproxyVerbose?: boolean;\n}\n\n// Helper to extract error details\nfunction getErrorDetails(error: unknown): {\n\tname: string;\n\tmessage: string;\n\tstack: string;\n} {\n\tif (error instanceof Error) {\n\t\treturn {\n\t\t\tname: error.name,\n\t\t\tmessage: error.message,\n\t\t\tstack: error.stack || '',\n\t\t};\n\t}\n\n\tif (typeof error === 'object' && error !== null) {\n\t\tconst err = error as Record<string, unknown>;\n\t\treturn {\n\t\t\tname: String(err.name || err.code || 'UnknownError'),\n\t\t\tmessage: String(err.message || err.error || JSON.stringify(error)),\n\t\t\tstack: String(err.stack || ''),\n\t\t};\n\t}\n\n\treturn {\n\t\tname: 'UnknownError',\n\t\tmessage: String(error),\n\t\tstack: '',\n\t};\n}\n\n/**\n * Server-side telemetry plugin for Elysia\n *\n * Automatically captures:\n * - HTTP requests and responses\n * - Errors with full stack traces\n * - System metrics (CPU, memory)\n * - Request/response sizes\n * - Active connections\n *\n * @example\n * ```typescript\n * import { Elysia } from 'elysia';\n * import { telemetry } from 'reroute-js/telemetry/server';\n *\n * new Elysia()\n * .use(telemetry({\n * serviceName: 'My App',\n * isProduction: true,\n * }))\n * .listen(3000);\n * ```\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Telemetry middleware initialization\nexport function telemetry(options: ServerTelemetryOptions = {}) {\n\tconst SERVICE_NAME = options.serviceName || 'reroute-app';\n\tconst SERVICE_VERSION =\n\t\toptions.serviceVersion || process.env.npm_package_version || '1.0.0';\n\tconst OTLP_ENDPOINT =\n\t\toptions.otlpEndpoint ||\n\t\tprocess.env.OTEL_EXPORTER_OTLP_ENDPOINT ||\n\t\t'http://localhost:4318';\n\tconst IS_PRODUCTION =\n\t\toptions.isProduction ?? process.env.NODE_ENV === 'production';\n\tconst ENABLE_SYSTEM_METRICS = options.enableSystemMetrics ?? true;\n\tconst METRICS_INTERVAL = options.metricsInterval ?? 5000;\n\tconst ENABLE_PROXY = options.proxy ?? false;\n\tconst PROXY_VERBOSE = options.proxyVerbose ?? false;\n\n\tconsole.log(`[telemetry] Initializing with endpoint: ${OTLP_ENDPOINT}`);\n\tif (ENABLE_PROXY) {\n\t\tconsole.log(\n\t\t\t'[telemetry] Browser telemetry proxy enabled at /api/telemetry/*',\n\t\t);\n\t}\n\n\t// Secure headers for API authentication (optional)\n\tconst otlpHeaders: Record<string, string> = {};\n\tif (options.apiKey || process.env.SIGNOZ_API_KEY) {\n\t\totlpHeaders.Authorization = `Bearer ${options.apiKey || process.env.SIGNOZ_API_KEY}`;\n\t}\n\n\t// Configure OTLP exporters with timeouts\n\tconst traceExporter = new OTLPTraceExporter({\n\t\turl: `${OTLP_ENDPOINT}/v1/traces`,\n\t\theaders: Object.keys(otlpHeaders).length > 0 ? otlpHeaders : undefined,\n\t\ttimeoutMillis: 5000, // 5 second timeout\n\t});\n\n\tconst logExporter = new OTLPLogExporter({\n\t\turl: `${OTLP_ENDPOINT}/v1/logs`,\n\t\theaders: Object.keys(otlpHeaders).length > 0 ? otlpHeaders : undefined,\n\t\ttimeoutMillis: 5000, // 5 second timeout\n\t});\n\n\tconst metricExporter = new OTLPMetricExporter({\n\t\turl: `${OTLP_ENDPOINT}/v1/metrics`,\n\t\theaders: Object.keys(otlpHeaders).length > 0 ? otlpHeaders : undefined,\n\t\ttimeoutMillis: 5000, // 5 second timeout\n\t});\n\n\t// Create resource with service information\n\t// In Docker, prefer env var over os.hostname() (which returns container ID)\n\tconst HOSTNAME =\n\t\tprocess.env.OTEL_RESOURCE_ATTRIBUTES?.match(/host\\.name=([^,]+)/)?.[1] ||\n\t\tprocess.env.HOSTNAME ||\n\t\tos.hostname();\n\n\tconst resource = resourceFromAttributes({\n\t\t[ATTR_SERVICE_NAME]: SERVICE_NAME,\n\t\t[ATTR_SERVICE_VERSION]: SERVICE_VERSION,\n\t\t[ATTR_HOST_NAME]: HOSTNAME,\n\t});\n\n\t// Set up Logs with error handling\n\tlet logger: ReturnType<LoggerProvider['getLogger']> | null = null;\n\ttry {\n\t\tconst loggerProvider = new LoggerProvider({\n\t\t\tresource,\n\t\t\tprocessors: [new BatchLogRecordProcessor(logExporter)],\n\t\t});\n\t\tlogs.setGlobalLoggerProvider(loggerProvider);\n\t\tlogger = loggerProvider.getLogger(SERVICE_NAME, SERVICE_VERSION);\n\t} catch (error) {\n\t\tconsole.error('[telemetry] Failed to initialize logger:', error);\n\t}\n\n\t// Set up Metrics with error handling\n\tlet meter: ReturnType<MeterProvider['getMeter']> | null = null;\n\ttry {\n\t\tconst meterProvider = new MeterProvider({\n\t\t\tresource,\n\t\t\treaders: [\n\t\t\t\tnew PeriodicExportingMetricReader({\n\t\t\t\t\texporter: metricExporter,\n\t\t\t\t\texportIntervalMillis: METRICS_INTERVAL,\n\t\t\t\t}),\n\t\t\t],\n\t\t});\n\t\tmetrics.setGlobalMeterProvider(meterProvider);\n\t\tmeter = meterProvider.getMeter(SERVICE_NAME, SERVICE_VERSION);\n\t} catch (error) {\n\t\tconsole.error('[telemetry] Failed to initialize meter:', error);\n\t}\n\n\t// Create HTTP metrics with null checks\n\tlet httpRequestCounter: Counter | null = null;\n\tlet httpRequestDuration: Histogram | null = null;\n\tlet httpErrorCounter: Counter | null = null;\n\tlet httpActiveRequests: UpDownCounter | null = null;\n\tlet activeConnections: UpDownCounter | null = null;\n\n\tif (meter) {\n\t\ttry {\n\t\t\thttpRequestCounter = meter.createCounter('http.server.request.count', {\n\t\t\t\tdescription: 'Total HTTP requests',\n\t\t\t\tunit: 'requests',\n\t\t\t});\n\n\t\t\thttpRequestDuration = meter.createHistogram(\n\t\t\t\t'http.server.request.duration',\n\t\t\t\t{\n\t\t\t\t\tdescription: 'HTTP request duration',\n\t\t\t\t\tunit: 'milliseconds',\n\t\t\t\t},\n\t\t\t);\n\n\t\t\thttpErrorCounter = meter.createCounter('http.server.error.count', {\n\t\t\t\tdescription: 'Total HTTP errors',\n\t\t\t\tunit: 'errors',\n\t\t\t});\n\n\t\t\thttpActiveRequests = meter.createUpDownCounter(\n\t\t\t\t'http.server.active_requests',\n\t\t\t\t{\n\t\t\t\t\tdescription: 'Active HTTP requests',\n\t\t\t\t\tunit: 'requests',\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tactiveConnections = meter.createUpDownCounter('app.connections.active', {\n\t\t\t\tdescription: 'Active connections',\n\t\t\t\tunit: 'connections',\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error('[telemetry] Failed to create HTTP metrics:', error);\n\t\t}\n\t}\n\n\t// Create system metrics (optional) with error handling\n\tif (ENABLE_SYSTEM_METRICS && meter) {\n\t\ttry {\n\t\t\t// Reuse HOSTNAME from resource (already computed above)\n\n\t\t\tconst memoryUsage = meter.createObservableGauge('app.memory.usage', {\n\t\t\t\tdescription: 'Process memory usage',\n\t\t\t\tunit: 'bytes',\n\t\t\t});\n\n\t\t\tmemoryUsage.addCallback((result) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst usage = process.memoryUsage();\n\t\t\t\t\tresult.observe(usage.heapUsed, {\n\t\t\t\t\t\ttype: 'heap',\n\t\t\t\t\t\t'host.name': HOSTNAME,\n\t\t\t\t\t});\n\t\t\t\t\tresult.observe(usage.rss, { type: 'rss', 'host.name': HOSTNAME });\n\t\t\t\t\tresult.observe(usage.external, {\n\t\t\t\t\t\ttype: 'external',\n\t\t\t\t\t\t'host.name': HOSTNAME,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[telemetry] Memory usage callback failed:', error);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst systemCpuUsage = meter.createObservableGauge(\n\t\t\t\t'system.cpu.utilization',\n\t\t\t\t{\n\t\t\t\t\tdescription: 'System CPU utilization',\n\t\t\t\t\tunit: '1',\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tsystemCpuUsage.addCallback((result) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst cpus = os.cpus();\n\t\t\t\t\tlet totalIdle = 0;\n\t\t\t\t\tlet totalTick = 0;\n\n\t\t\t\t\tcpus.forEach((cpu) => {\n\t\t\t\t\t\tconst times = cpu.times;\n\t\t\t\t\t\ttotalIdle += times.idle;\n\t\t\t\t\t\ttotalTick +=\n\t\t\t\t\t\t\ttimes.user + times.nice + times.sys + times.idle + times.irq;\n\t\t\t\t\t});\n\n\t\t\t\t\tconst usage = 1 - totalIdle / totalTick;\n\t\t\t\t\tresult.observe(usage, {\n\t\t\t\t\t\t'service.name': SERVICE_NAME,\n\t\t\t\t\t\t'host.name': HOSTNAME,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[telemetry] CPU usage callback failed:', error);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst systemMemoryUsage = meter.createObservableGauge(\n\t\t\t\t'system.memory.utilization',\n\t\t\t\t{\n\t\t\t\t\tdescription: 'System memory utilization',\n\t\t\t\t\tunit: '1',\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tsystemMemoryUsage.addCallback((result) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst totalMem = os.totalmem();\n\t\t\t\t\tconst freeMem = os.freemem();\n\t\t\t\t\tconst usage = (totalMem - freeMem) / totalMem;\n\n\t\t\t\t\tresult.observe(usage, {\n\t\t\t\t\t\t'service.name': SERVICE_NAME,\n\t\t\t\t\t\t'host.name': HOSTNAME,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[telemetry] System memory callback failed:', error);\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error('[telemetry] Failed to create system metrics:', error);\n\t\t}\n\t}\n\n\t// Graceful shutdown with error handling\n\tconst shutdown = async () => {\n\t\tconsole.log('[telemetry] Shutting down...');\n\t\ttry {\n\t\t\t// Note: We can't reference loggerProvider/meterProvider here since they're in try blocks\n\t\t\t// The providers will be cleaned up automatically\n\t\t\tawait logs.disable();\n\t\t} catch (error) {\n\t\t\tconsole.error('[telemetry] Shutdown error:', error);\n\t\t}\n\t};\n\n\tprocess.on('SIGTERM', async () => {\n\t\tawait shutdown();\n\t\tprocess.exit(0);\n\t});\n\n\treturn (app: Elysia) => {\n\t\tapp = app\n\t\t\t.use(\n\t\t\t\topentelemetry({\n\t\t\t\t\tserviceName: SERVICE_NAME,\n\t\t\t\t\tspanProcessors: [new BatchSpanProcessor(traceExporter)],\n\t\t\t\t}),\n\t\t\t)\n\t\t\t// Track incoming requests\n\t\t\t.onBeforeHandle(function trackIncomingRequest({ request, store }) {\n\t\t\t\tconst startTime = Date.now();\n\t\t\t\tconst url = new URL(request.url);\n\t\t\t\tconst route = url.pathname;\n\n\t\t\t\t(store as Record<string, unknown>).startTime = startTime;\n\t\t\t\t(store as Record<string, unknown>).route = route;\n\n\t\t\t\t// Track active requests - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tactiveConnections?.add(1);\n\t\t\t\t\thttpActiveRequests?.add(1, {\n\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\troute,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[telemetry] Failed to track active requests:', error);\n\t\t\t\t}\n\n\t\t\t\t// Log incoming request - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tlogger?.emit({\n\t\t\t\t\t\tseverityNumber: SeverityNumber.INFO,\n\t\t\t\t\t\tseverityText: 'INFO',\n\t\t\t\t\t\tbody: `→ ${request.method} ${route}`,\n\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t\t'url.full': request.url,\n\t\t\t\t\t\t\t'http.route': route,\n\t\t\t\t\t\t\t'url.scheme': url.protocol.replace(':', ''),\n\t\t\t\t\t\t\t'server.address': url.host,\n\t\t\t\t\t\t\t'service.name': SERVICE_NAME,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[telemetry] Failed to log incoming request:', error);\n\t\t\t\t}\n\n\t\t\t\t// Increment request counter - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\thttpRequestCounter?.add(1, {\n\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t'http.route': route,\n\t\t\t\t\t\t'url.scheme': url.protocol.replace(':', ''),\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'[telemetry] Failed to increment request counter:',\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})\n\t\t\t// Handle errors with full context\n\t\t\t// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Error handling with context\n\t\t\t.onError(function handleRequestError({ error, request, set, store }) {\n\t\t\t\tconst errorDetails = getErrorDetails(error);\n\t\t\t\tconst duration =\n\t\t\t\t\tDate.now() -\n\t\t\t\t\t(((store as Record<string, unknown>).startTime as number) ||\n\t\t\t\t\t\tDate.now());\n\n\t\t\t\t// Record exception in span - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tconst currentSpan = trace.getActiveSpan();\n\t\t\t\t\tif (currentSpan) {\n\t\t\t\t\t\tconst errorObj =\n\t\t\t\t\t\t\terror instanceof Error ? error : new Error(errorDetails.message);\n\n\t\t\t\t\t\tcurrentSpan.recordException(errorObj);\n\t\t\t\t\t\tcurrentSpan.setStatus({\n\t\t\t\t\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\t\t\t\t\tmessage: `${errorDetails.name}: ${errorDetails.message}`,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tcurrentSpan.setAttributes({\n\t\t\t\t\t\t\terror: true,\n\t\t\t\t\t\t\t'error.type': errorDetails.name,\n\t\t\t\t\t\t\t'error.message': errorDetails.message,\n\t\t\t\t\t\t\t'error.stack': errorDetails.stack,\n\t\t\t\t\t\t\t'http.request.url': request.url,\n\t\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t\t'http.response.status_code':\n\t\t\t\t\t\t\t\ttypeof set.status === 'number' ? set.status : 500,\n\t\t\t\t\t\t\t'service.name': SERVICE_NAME,\n\t\t\t\t\t\t\t'service.version': SERVICE_VERSION,\n\t\t\t\t\t\t\t'deployment.environment': IS_PRODUCTION\n\t\t\t\t\t\t\t\t? 'production'\n\t\t\t\t\t\t\t\t: 'development',\n\t\t\t\t\t\t\t'error.timestamp': new Date().toISOString(),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tcurrentSpan.addEvent('exception', {\n\t\t\t\t\t\t\t'exception.type': errorDetails.name,\n\t\t\t\t\t\t\t'exception.message': errorDetails.message,\n\t\t\t\t\t\t\t'exception.stacktrace': errorDetails.stack,\n\t\t\t\t\t\t\t'exception.escaped': 'false',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (spanError) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'[telemetry] Failed to record exception in span:',\n\t\t\t\t\t\tspanError,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Log error - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tlogger?.emit({\n\t\t\t\t\t\tseverityNumber: SeverityNumber.ERROR,\n\t\t\t\t\t\tseverityText: 'ERROR',\n\t\t\t\t\t\tbody: `${errorDetails.name}: ${errorDetails.message}`,\n\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t'error.type': errorDetails.name,\n\t\t\t\t\t\t\t'error.message': errorDetails.message,\n\t\t\t\t\t\t\t'error.stack': errorDetails.stack,\n\t\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t\t'url.full': request.url,\n\t\t\t\t\t\t\t'http.response.status_code':\n\t\t\t\t\t\t\t\ttypeof set.status === 'number' ? set.status : 500,\n\t\t\t\t\t\t\t'service.name': SERVICE_NAME,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch (logError) {\n\t\t\t\t\tconsole.error('[telemetry] Failed to log error:', logError);\n\t\t\t\t}\n\n\t\t\t\t// Increment error counter - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tconst statusCode = typeof set.status === 'number' ? set.status : 500;\n\t\t\t\t\thttpErrorCounter?.add(1, {\n\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t'http.response.status_code': statusCode,\n\t\t\t\t\t\t'error.type': errorDetails.name,\n\t\t\t\t\t});\n\n\t\t\t\t\thttpRequestDuration?.record(duration, {\n\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t'http.response.status_code': statusCode,\n\t\t\t\t\t\terror: true,\n\t\t\t\t\t});\n\t\t\t\t} catch (metricsError) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'[telemetry] Failed to record error metrics:',\n\t\t\t\t\t\tmetricsError,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})\n\t\t\t// Record response metrics\n\t\t\t// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Response metrics recording\n\t\t\t.onAfterResponse(function recordResponseMetrics({ request, set, store }) {\n\t\t\t\tconst statusCode = typeof set.status === 'number' ? set.status : 200;\n\t\t\t\tconst duration =\n\t\t\t\t\tDate.now() -\n\t\t\t\t\t(((store as Record<string, unknown>).startTime as number) ||\n\t\t\t\t\t\tDate.now());\n\t\t\t\tconst route =\n\t\t\t\t\t((store as Record<string, unknown>).route as string) ||\n\t\t\t\t\tnew URL(request.url).pathname;\n\t\t\t\tconst url = new URL(request.url);\n\n\t\t\t\t// Decrement active requests - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tactiveConnections?.add(-1);\n\t\t\t\t\thttpActiveRequests?.add(-1, {\n\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\troute,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'[telemetry] Failed to decrement active requests:',\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Set span attributes - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tconst currentSpan = trace.getActiveSpan();\n\t\t\t\t\tif (currentSpan) {\n\t\t\t\t\t\tcurrentSpan.setAttributes({\n\t\t\t\t\t\t\t'http.response.status_code': statusCode,\n\t\t\t\t\t\t\t'http.request.url': request.url,\n\t\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t\t'http.route': route,\n\t\t\t\t\t\t\t'http.duration_ms': duration,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (statusCode >= 400) {\n\t\t\t\t\t\t\tcurrentSpan.setStatus({\n\t\t\t\t\t\t\t\tcode: SpanStatusCode.ERROR,\n\t\t\t\t\t\t\t\tmessage: `HTTP ${statusCode}`,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tcurrentSpan.setAttribute('error', true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (spanError) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'[telemetry] Failed to set span attributes:',\n\t\t\t\t\t\tspanError,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Log response - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\tconst isError = statusCode >= 400;\n\t\t\t\t\tlogger?.emit({\n\t\t\t\t\t\tseverityNumber: isError\n\t\t\t\t\t\t\t? SeverityNumber.ERROR\n\t\t\t\t\t\t\t: SeverityNumber.INFO,\n\t\t\t\t\t\tseverityText: isError ? 'ERROR' : 'INFO',\n\t\t\t\t\t\tbody: `← ${request.method} ${route} → ${statusCode} (${duration}ms)`,\n\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t\t'url.full': request.url,\n\t\t\t\t\t\t\t'http.route': route,\n\t\t\t\t\t\t\t'http.response.status_code': statusCode,\n\t\t\t\t\t\t\t'http.duration_ms': duration,\n\t\t\t\t\t\t\t'url.scheme': url.protocol.replace(':', ''),\n\t\t\t\t\t\t\t'server.address': url.host,\n\t\t\t\t\t\t\t'service.name': SERVICE_NAME,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch (logError) {\n\t\t\t\t\tconsole.error('[telemetry] Failed to log response:', logError);\n\t\t\t\t}\n\n\t\t\t\t// Record metrics - wrapped in try/catch to prevent blocking\n\t\t\t\ttry {\n\t\t\t\t\thttpRequestDuration?.record(duration, {\n\t\t\t\t\t\t'http.request.method': request.method,\n\t\t\t\t\t\t'http.route': route,\n\t\t\t\t\t\t'http.response.status_code': statusCode,\n\t\t\t\t\t\t'url.scheme': url.protocol.replace(':', ''),\n\t\t\t\t\t});\n\t\t\t\t} catch (metricsError) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'[telemetry] Failed to record request duration:',\n\t\t\t\t\t\tmetricsError,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Optionally add browser telemetry proxy\n\t\tif (ENABLE_PROXY) {\n\t\t\tconst API_KEY = options.apiKey || process.env.SIGNOZ_API_KEY;\n\n\t\t\tapp\n\t\t\t\t.post(\n\t\t\t\t\t'/api/telemetry/v1/traces',\n\t\t\t\t\t// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Traces endpoint handler\n\t\t\t\t\tasync function forwardBrowserTraces({ body }) {\n\t\t\t\t\t\tconst headers: Record<string, string> = {\n\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (API_KEY) {\n\t\t\t\t\t\t\theaders.Authorization = `Bearer ${API_KEY}`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Create an AbortController for timeout\n\t\t\t\t\t\t\tconst controller = new AbortController();\n\t\t\t\t\t\t\tconst timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout\n\n\t\t\t\t\t\t\tconst response = await fetch(`${OTLP_ENDPOINT}/v1/traces`, {\n\t\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tclearTimeout(timeoutId);\n\n\t\t\t\t\t\t\tif (PROXY_VERBOSE) {\n\t\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t\t`[telemetry-proxy] Traces forwarded: ${response.status}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t`[telemetry-proxy] OTLP error: ${response.status} ${response.statusText}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t// Return 200 to browser even if backend fails - don't block user experience\n\t\t\t\t\t\t\t\treturn new Response(null, { status: 200 });\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn new Response(null, { status: 200 });\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t'[telemetry-proxy] Failed to forward traces:',\n\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t// Return 200 to browser even on error - don't block user experience\n\t\t\t\t\t\t\treturn new Response(null, { status: 200 });\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.post(\n\t\t\t\t\t'/api/telemetry/v1/metrics',\n\t\t\t\t\tasync function forwardBrowserMetrics({ body }) {\n\t\t\t\t\t\tconst headers: Record<string, string> = {\n\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (API_KEY) {\n\t\t\t\t\t\t\theaders.Authorization = `Bearer ${API_KEY}`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Create an AbortController for timeout\n\t\t\t\t\t\t\tconst controller = new AbortController();\n\t\t\t\t\t\t\tconst timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout\n\n\t\t\t\t\t\t\tconst response = await fetch(`${OTLP_ENDPOINT}/v1/metrics`, {\n\t\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tclearTimeout(timeoutId);\n\n\t\t\t\t\t\t\tif (PROXY_VERBOSE && !response.ok) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t`[telemetry-proxy] OTLP error: ${response.status}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Return 200 to browser even if backend fails - don't block user experience\n\t\t\t\t\t\t\treturn new Response(null, { status: 200 });\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t'[telemetry-proxy] Failed to forward metrics:',\n\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t// Return 200 to browser even on error - don't block user experience\n\t\t\t\t\t\t\treturn new Response(null, { status: 200 });\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.post(\n\t\t\t\t\t'/api/telemetry/v1/logs',\n\t\t\t\t\tasync function forwardBrowserLogs({ body }) {\n\t\t\t\t\t\tconst headers: Record<string, string> = {\n\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (API_KEY) {\n\t\t\t\t\t\t\theaders.Authorization = `Bearer ${API_KEY}`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Create an AbortController for timeout\n\t\t\t\t\t\t\tconst controller = new AbortController();\n\t\t\t\t\t\t\tconst timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout\n\n\t\t\t\t\t\t\tconst response = await fetch(`${OTLP_ENDPOINT}/v1/logs`, {\n\t\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tclearTimeout(timeoutId);\n\n\t\t\t\t\t\t\tif (PROXY_VERBOSE && !response.ok) {\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t`[telemetry-proxy] OTLP logs error: ${response.status}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Return 200 to browser even if backend fails - don't block user experience\n\t\t\t\t\t\t\treturn new Response(null, { status: 200 });\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconsole.error('[telemetry-proxy] Failed to forward logs:', error);\n\t\t\t\t\t\t\t// Return 200 to browser even on error - don't block user experience\n\t\t\t\t\t\t\treturn new Response(null, { status: 200 });\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.get('/api/telemetry/health', function telemetryHealthCheck() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'ok',\n\t\t\t\t\t\totlpEndpoint: OTLP_ENDPOINT,\n\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t}\n\n\t\treturn app;\n\t};\n}\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
8
|
+
"debugId": "1B4D6904ACC7910E64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/telemetry/react.d.ts
CHANGED
package/telemetry/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* reroute-js v0.
|
|
2
|
+
* reroute-js v0.23.0
|
|
3
3
|
*
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright 2025 stewones <hi@stewan.io>
|
|
@@ -42,23 +42,30 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
// packages/telemetry/src/browser/index.ts
|
|
45
|
-
|
|
46
|
-
import { getWebAutoInstrumentations } from "@opentelemetry/auto-instrumentations-web";
|
|
47
|
-
import { ZoneContextManager } from "@opentelemetry/context-zone";
|
|
48
|
-
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
49
|
-
import { registerInstrumentations } from "@opentelemetry/instrumentation";
|
|
50
|
-
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
51
|
-
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
52
|
-
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
|
|
53
|
-
import {
|
|
54
|
-
ATTR_SERVICE_NAME,
|
|
55
|
-
ATTR_SERVICE_VERSION
|
|
56
|
-
} from "@opentelemetry/semantic-conventions";
|
|
57
|
-
function initBrowserTelemetry(options = {}) {
|
|
45
|
+
async function initBrowserTelemetry(options = {}) {
|
|
58
46
|
if (IS_SERVER || isInitialized) {
|
|
59
47
|
return;
|
|
60
48
|
}
|
|
61
49
|
try {
|
|
50
|
+
const [
|
|
51
|
+
{ getWebAutoInstrumentations },
|
|
52
|
+
{ ZoneContextManager },
|
|
53
|
+
{ OTLPTraceExporter },
|
|
54
|
+
{ registerInstrumentations },
|
|
55
|
+
{ resourceFromAttributes },
|
|
56
|
+
{ BatchSpanProcessor },
|
|
57
|
+
{ WebTracerProvider },
|
|
58
|
+
{ ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION }
|
|
59
|
+
] = await Promise.all([
|
|
60
|
+
import("@opentelemetry/auto-instrumentations-web"),
|
|
61
|
+
import("@opentelemetry/context-zone"),
|
|
62
|
+
import("@opentelemetry/exporter-trace-otlp-http"),
|
|
63
|
+
import("@opentelemetry/instrumentation"),
|
|
64
|
+
import("@opentelemetry/resources"),
|
|
65
|
+
import("@opentelemetry/sdk-trace-base"),
|
|
66
|
+
import("@opentelemetry/sdk-trace-web"),
|
|
67
|
+
import("@opentelemetry/semantic-conventions")
|
|
68
|
+
]);
|
|
62
69
|
const env = typeof import.meta !== "undefined" ? import.meta.env : undefined;
|
|
63
70
|
const SERVICE_NAME = options.serviceName || "reroute-app-browser";
|
|
64
71
|
const SERVICE_VERSION = options.serviceVersion || "1.0.0";
|
|
@@ -121,21 +128,22 @@ function initBrowserTelemetry(options = {}) {
|
|
|
121
128
|
})
|
|
122
129
|
]
|
|
123
130
|
});
|
|
124
|
-
setupErrorHandlers();
|
|
131
|
+
setupErrorHandlers().catch((err) => console.error("[browser-telemetry] Error handler setup failed:", err));
|
|
125
132
|
if (ENABLE_WEB_VITALS) {
|
|
126
|
-
setupWebVitals();
|
|
133
|
+
setupWebVitals().catch((err) => console.error("[browser-telemetry] Web Vitals setup failed:", err));
|
|
127
134
|
}
|
|
128
135
|
if (ENABLE_CONSOLE_CAPTURE) {
|
|
129
|
-
setupConsoleCapture();
|
|
136
|
+
setupConsoleCapture().catch((err) => console.error("[browser-telemetry] Console capture setup failed:", err));
|
|
130
137
|
}
|
|
131
|
-
setupVisibilityTracking();
|
|
138
|
+
setupVisibilityTracking().catch((err) => console.error("[browser-telemetry] Visibility tracking setup failed:", err));
|
|
132
139
|
isInitialized = true;
|
|
133
140
|
console.log("[browser-telemetry] Initialized successfully");
|
|
134
141
|
} catch (error) {
|
|
135
142
|
console.error("[browser-telemetry] Failed to initialize:", error);
|
|
136
143
|
}
|
|
137
144
|
}
|
|
138
|
-
function setupErrorHandlers() {
|
|
145
|
+
async function setupErrorHandlers() {
|
|
146
|
+
const { trace, SpanStatusCode } = await import("@opentelemetry/api");
|
|
139
147
|
const tracer = trace.getTracer("error-handler");
|
|
140
148
|
window.addEventListener("error", (event) => {
|
|
141
149
|
try {
|
|
@@ -217,6 +225,7 @@ function setupErrorHandlers() {
|
|
|
217
225
|
async function setupWebVitals() {
|
|
218
226
|
try {
|
|
219
227
|
const { onLCP, onCLS, onTTFB, onINP } = await import("web-vitals");
|
|
228
|
+
const { trace } = await import("@opentelemetry/api");
|
|
220
229
|
const tracer = trace.getTracer("web-vitals");
|
|
221
230
|
const sendToAnalytics = (metric) => {
|
|
222
231
|
try {
|
|
@@ -246,10 +255,14 @@ async function setupWebVitals() {
|
|
|
246
255
|
console.warn("[browser-telemetry] Web Vitals not available:", error);
|
|
247
256
|
}
|
|
248
257
|
}
|
|
249
|
-
function setupConsoleCapture() {
|
|
258
|
+
async function setupConsoleCapture() {
|
|
259
|
+
const { trace } = await import("@opentelemetry/api");
|
|
250
260
|
const tracer = trace.getTracer("console");
|
|
251
261
|
const originalError = console.error;
|
|
252
|
-
|
|
262
|
+
if (originalError.__telemetry_captured__) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const wrappedError = (...args) => {
|
|
253
266
|
try {
|
|
254
267
|
const span = tracer.startSpan("browser.console.error");
|
|
255
268
|
span.setAttributes({
|
|
@@ -262,8 +275,11 @@ function setupConsoleCapture() {
|
|
|
262
275
|
} catch {}
|
|
263
276
|
originalError.apply(console, args);
|
|
264
277
|
};
|
|
278
|
+
wrappedError.__telemetry_captured__ = true;
|
|
279
|
+
console.error = wrappedError;
|
|
265
280
|
}
|
|
266
|
-
function setupVisibilityTracking() {
|
|
281
|
+
async function setupVisibilityTracking() {
|
|
282
|
+
const { trace } = await import("@opentelemetry/api");
|
|
267
283
|
const tracer = trace.getTracer("visibility");
|
|
268
284
|
document.addEventListener("visibilitychange", () => {
|
|
269
285
|
try {
|
|
@@ -287,6 +303,10 @@ function createSpan(name, attributes = {}) {
|
|
|
287
303
|
};
|
|
288
304
|
}
|
|
289
305
|
try {
|
|
306
|
+
const trace = globalThis.__OTEL_TRACE__ || __require("@opentelemetry/api").trace;
|
|
307
|
+
if (!globalThis.__OTEL_TRACE__) {
|
|
308
|
+
globalThis.__OTEL_TRACE__ = trace;
|
|
309
|
+
}
|
|
290
310
|
const tracer = trace.getTracer("custom");
|
|
291
311
|
const span = tracer.startSpan(name);
|
|
292
312
|
span.setAttributes({
|
|
@@ -321,6 +341,7 @@ function trackError(error, context = {}) {
|
|
|
321
341
|
return;
|
|
322
342
|
}
|
|
323
343
|
try {
|
|
344
|
+
const { trace, SpanStatusCode } = __require("@opentelemetry/api");
|
|
324
345
|
const tracer = trace.getTracer("error-handler");
|
|
325
346
|
const span = tracer.startSpan("browser.error.tracked");
|
|
326
347
|
const stackTrace = error.stack || "";
|
|
@@ -378,7 +399,6 @@ var init_browser2 = __esm(() => {
|
|
|
378
399
|
// packages/telemetry/src/browser/react.tsx
|
|
379
400
|
import {
|
|
380
401
|
createContext,
|
|
381
|
-
useCallback,
|
|
382
402
|
useContext,
|
|
383
403
|
useEffect,
|
|
384
404
|
useMemo,
|
|
@@ -386,20 +406,16 @@ import {
|
|
|
386
406
|
} from "react";
|
|
387
407
|
import { jsx } from "react/jsx-runtime";
|
|
388
408
|
var IS_SERVER2 = typeof window === "undefined";
|
|
389
|
-
var
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
return null;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
return telemetryModule;
|
|
409
|
+
var noopSpan = {
|
|
410
|
+
setAttributes: () => {},
|
|
411
|
+
setStatus: () => {},
|
|
412
|
+
recordException: () => {},
|
|
413
|
+
end: () => {}
|
|
414
|
+
};
|
|
415
|
+
var noopContext = {
|
|
416
|
+
createCustomSpan: () => noopSpan,
|
|
417
|
+
trackCustomEvent: () => {},
|
|
418
|
+
trackCustomError: () => {}
|
|
403
419
|
};
|
|
404
420
|
var TelemetryContext = createContext(null);
|
|
405
421
|
function TelemetryProvider({
|
|
@@ -412,8 +428,9 @@ function TelemetryProvider({
|
|
|
412
428
|
enableWebVitals,
|
|
413
429
|
enableConsoleCapture
|
|
414
430
|
}) {
|
|
415
|
-
const [
|
|
416
|
-
const
|
|
431
|
+
const [telemetryReady, setTelemetryReady] = useState(false);
|
|
432
|
+
const [telemetryAPI, setTelemetryAPI] = useState(null);
|
|
433
|
+
const memoizedOptions = useMemo(() => ({
|
|
417
434
|
serviceName,
|
|
418
435
|
serviceVersion,
|
|
419
436
|
otlpEndpoint,
|
|
@@ -431,47 +448,44 @@ function TelemetryProvider({
|
|
|
431
448
|
enableConsoleCapture
|
|
432
449
|
]);
|
|
433
450
|
useEffect(() => {
|
|
434
|
-
|
|
435
|
-
}, []);
|
|
436
|
-
useEffect(() => {
|
|
437
|
-
if (IS_SERVER2 || !isMounted || typeof window === "undefined")
|
|
451
|
+
if (IS_SERVER2) {
|
|
438
452
|
return;
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
453
|
+
}
|
|
454
|
+
Promise.resolve().then(() => (init_browser2(), exports_browser)).then((module) => {
|
|
455
|
+
module.initBrowserTelemetry(memoizedOptions);
|
|
456
|
+
setTelemetryAPI(module);
|
|
457
|
+
setTelemetryReady(true);
|
|
458
|
+
console.debug("[TelemetryProvider] Browser telemetry initialized");
|
|
444
459
|
}).catch((error) => {
|
|
445
|
-
console.
|
|
460
|
+
console.warn("[TelemetryProvider] Failed to load telemetry:", error);
|
|
446
461
|
});
|
|
447
|
-
}, [
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const trackCustomError = useCallback((error, context) => {
|
|
465
|
-
if (telemetryModule) {
|
|
466
|
-
telemetryModule.trackError(error, context);
|
|
462
|
+
}, [memoizedOptions]);
|
|
463
|
+
const contextValue = useMemo(() => ({
|
|
464
|
+
createCustomSpan: (name, attributes) => {
|
|
465
|
+
if (telemetryReady && telemetryAPI) {
|
|
466
|
+
return telemetryAPI.createSpan(name, attributes);
|
|
467
|
+
}
|
|
468
|
+
return noopSpan;
|
|
469
|
+
},
|
|
470
|
+
trackCustomEvent: (eventName, attributes) => {
|
|
471
|
+
if (telemetryReady && telemetryAPI) {
|
|
472
|
+
telemetryAPI.trackEvent(eventName, attributes);
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
trackCustomError: (error, context) => {
|
|
476
|
+
if (telemetryReady && telemetryAPI) {
|
|
477
|
+
telemetryAPI.trackError(error, context);
|
|
478
|
+
}
|
|
467
479
|
}
|
|
468
|
-
}, []);
|
|
480
|
+
}), [telemetryReady, telemetryAPI]);
|
|
481
|
+
if (IS_SERVER2) {
|
|
482
|
+
return /* @__PURE__ */ jsx(TelemetryContext.Provider, {
|
|
483
|
+
value: noopContext,
|
|
484
|
+
children
|
|
485
|
+
});
|
|
486
|
+
}
|
|
469
487
|
return /* @__PURE__ */ jsx(TelemetryContext.Provider, {
|
|
470
|
-
value:
|
|
471
|
-
createCustomSpan,
|
|
472
|
-
trackCustomEvent,
|
|
473
|
-
trackCustomError
|
|
474
|
-
},
|
|
488
|
+
value: contextValue,
|
|
475
489
|
children
|
|
476
490
|
});
|
|
477
491
|
}
|
|
@@ -487,4 +501,4 @@ export {
|
|
|
487
501
|
TelemetryProvider
|
|
488
502
|
};
|
|
489
503
|
|
|
490
|
-
//# debugId=
|
|
504
|
+
//# debugId=8F2F63864506980F64756E2164756E21
|