er0-l0gmachine
v1.0.0
Published
Frontend error monitoring package with OpenTelemetry integration and secure authentication (JWT/SSO)
Maintainers
Readme
Frontend Error Monitoring SDK
A comprehensive TypeScript npm package for frontend error monitoring with OpenTelemetry integration, secure authentication (JWT/SSO), and real-time observability features inspired by Grafana Faro Web SDK.
🚀 Features
Core Monitoring
- Error Tracking: Automatic capture of JavaScript errors, unhandled promise rejections, and console errors
- OpenTelemetry Tracing: Full distributed tracing support with auto-instrumentations
- Performance Monitoring: Web Vitals, resource timing, and custom metrics
- Session Tracking: User session management with interaction tracking
- Breadcrumbs: Detailed debugging context with customizable breadcrumb trails
Security & Authentication
- JWT Authentication: Secure endpoint authentication with automatic token validation
- SSO Integration: Support for Okta, Auth0, Azure AD, and custom providers
- Token Management: Automatic token refresh and expiration handling
- Custom Token Providers: Flexible authentication with custom token logic
Advanced Features
- CORS Support: Configurable trace header propagation for cross-origin requests
- Batch Processing: Efficient data transmission with configurable batching
- Real-time Monitoring: Live error reporting and performance metrics
- Custom Instrumentation: Extensible architecture for custom monitoring needs
📦 Installation
npm install frontend-error-monitoring🔧 Quick Start
Basic Setup with JWT Authentication
import { createMonitoring } from 'frontend-error-monitoring';
const monitoring = await createMonitoring({
endpoint: 'https://your-monitoring-api.com/api/v1',
app: {
name: 'my-webapp',
version: '1.2.0',
environment: 'production'
},
auth: {
jwt: 'your-jwt-token-here'
},
tracing: {
enabled: true,
sampleRate: 0.1, // Sample 10% of traces
propagateTraceHeaderCorsUrls: [
'https://api.example.com',
/https:\/\/.*\.example\.com/
]
},
errorTracking: {
enabled: true,
captureUnhandledRejections: true,
captureConsoleErrors: true
},
performance: {
enabled: true,
webVitals: true,
resourceTiming: true
}
});
// The SDK is now monitoring your application!SSO Authentication Examples
Okta Integration
const monitoring = await createMonitoring({
endpoint: 'https://monitoring.company.com/api',
app: {
name: 'corporate-dashboard',
version: '2.0.0'
},
auth: {
sso: {
provider: 'okta',
clientId: 'your-okta-client-id',
domain: 'https://your-company.okta.com',
config: {
scope: 'openid profile email'
}
}
}
});Auth0 Integration
const monitoring = await createMonitoring({
endpoint: 'https://api.myapp.com/monitoring',
app: {
name: 'mobile-app-web',
version: '1.0.0'
},
auth: {
sso: {
provider: 'auth0',
clientId: 'your-auth0-client-id',
domain: 'https://your-tenant.auth0.com',
config: {
audience: 'https://api.myapp.com',
clientSecret: 'your-client-secret'
}
}
}
});Azure AD Integration
const monitoring = await createMonitoring({
endpoint: 'https://monitoring.enterprise.com/api',
app: {
name: 'enterprise-app',
version: '3.0.0'
},
auth: {
sso: {
provider: 'azure-ad',
clientId: 'your-azure-client-id',
domain: 'https://login.microsoftonline.com/your-tenant-id',
config: {
clientSecret: 'your-client-secret',
scope: 'https://graph.microsoft.com/.default'
}
}
}
});📖 Usage Examples
Error Tracking
// Manual error capture
try {
throw new Error('Something went wrong!');
} catch (error) {
monitoring.captureError(error, {
component: 'user-profile',
action: 'save-profile',
userId: '12345'
});
}
// Exception with severity level
monitoring.captureException(new Error('Critical error'), 'error');
// Add debugging breadcrumbs
monitoring.addBreadcrumb('User clicked save button', 'ui', 'info', {
button_id: 'save-btn',
form_data: { name: 'John', email: '[email protected]' }
});Custom Tracing
// Start a custom trace
const span = monitoring.startSpan('database-query', {
query_type: 'user_lookup',
table: 'users',
user_id: '12345'
});
// Perform operation
const result = await fetchUserData('12345');
span?.end();
// Or use the convenience method
const result = monitoring.withSpan('api-call', async () => {
return await fetch('/api/data');
}, {
endpoint: '/api/data',
method: 'GET'
});Performance Monitoring
// Send custom metrics
await monitoring.sendMetric('page_load_time', 1250, 'ms', {
page: 'dashboard',
user_type: 'premium'
});
// Monitor operation performance
const startTime = performance.now();
await performComplexOperation();
const duration = performance.now() - startTime;
await monitoring.sendMetric('operation_duration', duration, 'ms', {
operation: 'data_processing',
complexity: 'high'
});User Context & Events
// Set user context
monitoring.setUser('[email protected]', {
role: 'admin',
department: 'engineering',
subscription: 'enterprise'
});
// Add custom context
monitoring.setContext('feature_flag', 'new-ui-enabled');
monitoring.setContext('ab_test_variant', 'variant-b');
// Send custom events
await monitoring.sendEvent('user_action', {
action: 'button_click',
component: 'navigation',
feature: 'export_data'
});⚙️ Configuration Options
Complete Configuration Interface
interface ErrorMonitoringConfig {
// Required
endpoint: string;
app: {
name: string;
version?: string;
environment?: string;
};
// Authentication
auth?: {
jwt?: string;
sso?: {
provider: 'okta' | 'auth0' | 'azure-ad';
clientId: string;
domain: string;
config?: Record<string, any>;
};
tokenProvider?: () => Promise<string> | string;
};
// Tracing
tracing?: {
enabled?: boolean;
sampleRate?: number;
propagateTraceHeaderCorsUrls?: (string | RegExp)[];
exporter?: {
headers?: Record<string, string>;
timeout?: number;
};
};
// Error Tracking
errorTracking?: {
enabled?: boolean;
captureUnhandledRejections?: boolean;
captureConsoleErrors?: boolean;
maxBreadcrumbs?: number;
};
// Performance
performance?: {
enabled?: boolean;
webVitals?: boolean;
resourceTiming?: boolean;
};
// Session
session?: {
enabled?: boolean;
timeout?: number;
trackInteractions?: boolean;
};
debug?: boolean;
}Default Values
{
tracing: {
enabled: true,
sampleRate: 1.0,
propagateTraceHeaderCorsUrls: []
},
errorTracking: {
enabled: true,
captureUnhandledRejections: true,
captureConsoleErrors: false,
maxBreadcrumbs: 100
},
performance: {
enabled: true,
webVitals: true,
resourceTiming: false
},
session: {
enabled: true,
timeout: 30,
trackInteractions: true
},
debug: false
}🔐 Endpoint Verification & Security
How Endpoint Verification Works
The SDK verifies endpoints through multi-layered authentication that ensures your monitoring data reaches only authorized servers:
1. Token-Based Authentication
Every request includes an Authorization header:
Authorization: Bearer your-jwt-token
// or
Authorization: Bearer sso-generated-token2. Endpoint Health Monitoring
// Verify endpoint connectivity and authentication
const health = await monitoring.verifyEndpoint();
console.log(health.status); // 'healthy' | 'unhealthy' | 'unauthorized'
// Test with actual data
const test = await monitoring.testEndpoint();
if (test.success) {
console.log(`Endpoint verified in ${test.responseTime}ms`);
}
// Validate auth configuration
const validation = monitoring.validateAuthConfig();
if (!validation.valid) {
console.error('Auth errors:', validation.errors);
}3. Continuous Monitoring
// Start periodic health checks (every 60 seconds)
monitoring.startEndpointMonitoring(60000);
// Stop monitoring
monitoring.stopEndpointMonitoring();4. Backend Verification Requirements
Your backend must validate the authentication token:
// Express.js example
app.post('/api/v1/errors', authenticateToken, (req, res) => {
if (!req.user) {
return res.status(401).json({ error: 'Invalid token' });
}
// Process authenticated monitoring data
const { errors, session, app } = req.body;
console.log(`Received ${errors.length} errors from ${app.name}`);
res.json({ success: true });
});
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}5. Security Features
- ✅ Automatic token validation and expiration checking
- ✅ Token refresh for SSO providers
- ✅ HTTPS-only communication
- ✅ CORS header propagation for authenticated cross-origin requests
- ✅ Request signing with JWT/SSO tokens
- ✅ Endpoint health monitoring with authentication testing
🔐 Authentication Details
JWT Token Format
The SDK expects JWT tokens in standard format. Tokens are automatically validated for expiration and refreshed when needed.
SSO Provider Requirements
| Provider | Required Config | Optional Config |
|----------|----------------|-----------------|
| Okta | clientId, domain | scope, audience |
| Auth0 | clientId, domain, clientSecret, audience | scope |
| Azure AD | clientId, domain, clientSecret | scope |
Custom Token Provider
For custom authentication flows:
auth: {
tokenProvider: async () => {
// Your custom logic to get token
const response = await fetch('/api/auth/token', {
method: 'POST',
credentials: 'include'
});
const data = await response.json();
return data.access_token;
}
}📊 API Endpoints
The SDK sends data to these endpoint paths:
POST /errors- Error events and exceptionsPOST /traces- OpenTelemetry trace dataPOST /metrics- Performance metricsPOST /events- Custom application events
Request Format
All requests include authentication headers and follow this structure:
{
"data": [...], // Event/error/metric data
"session": {
"id": "session-id",
"userId": "user-id",
"startTime": 1699123456789
},
"app": {
"name": "my-app",
"version": "1.0.0",
"environment": "production"
},
"trace": {
"traceId": "trace-id",
"spanId": "span-id"
}
}🧪 Testing
Unit Tests
npm testWatch Mode
npm run test:watchType Checking
npm run type-checkLinting
npm run lint
npm run lint:fix🏗️ Building
Development Build
npm run build:watchProduction Build
npm run buildThe build generates multiple formats:
dist/index.js- CommonJSdist/index.esm.js- ES Modulesdist/index.umd.js- UMD (Universal)
🌐 Browser Support
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
📋 API Reference
Core Methods
createMonitoring(config: ErrorMonitoringConfig): Promise<FrontendErrorMonitoring>
Creates and initializes a monitoring instance.
captureError(error: Error, context?: Record<string, any>): void
Manually capture an error with optional context.
captureException(error: Error, level?: 'debug' | 'info' | 'warning' | 'error'): void
Capture an exception with severity level.
startSpan(name: string, attributes?: Record<string, any>): Span
Start a new OpenTelemetry span.
withSpan<T>(name: string, fn: () => T, attributes?: Record<string, any>): T
Execute a function within a span context.
addBreadcrumb(message: string, category?: string, level?: string, data?: Record<string, any>): void
Add a debugging breadcrumb.
setUser(userId: string, userData?: Record<string, any>): void
Set user context for error tracking.
setContext(key: string, value: any): void
Add custom context to all future events.
sendEvent(name: string, data?: Record<string, any>): Promise<void>
Send a custom application event.
sendMetric(name: string, value: number, unit?: string, tags?: Record<string, string>): Promise<void>
Send a performance metric.
getSession(): SessionData
Get current session information.
flush(): Promise<void>
Flush all pending data immediately.
shutdown(): Promise<void>
Shutdown the SDK and clean up resources.
Endpoint Verification Methods
verifyEndpoint(): Promise<EndpointHealth>
Verify endpoint connectivity and authentication status.
const health = await monitoring.verifyEndpoint();
// Returns: { status: 'healthy' | 'unhealthy' | 'unauthorized', responseTime: number, timestamp: number, error?: string }testEndpoint(): Promise<{ success: boolean; error?: string; responseTime: number }>
Test endpoint with sample monitoring data.
const result = await monitoring.testEndpoint();
if (result.success) {
console.log(`Endpoint working: ${result.responseTime}ms`);
} else {
console.error(`Endpoint failed: ${result.error}`);
}validateAuthConfig(): { valid: boolean; errors: string[] }
Validate the authentication configuration.
const validation = monitoring.validateAuthConfig();
if (!validation.valid) {
console.error('Config errors:', validation.errors);
}startEndpointMonitoring(intervalMs?: number): void
Start periodic endpoint health monitoring (default: 60 seconds).
monitoring.startEndpointMonitoring(30000); // Check every 30 secondsstopEndpointMonitoring(): void
Stop periodic endpoint health monitoring.
monitoring.stopEndpointMonitoring();🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run the test suite
- Submit a pull request
📄 License
MIT License - see LICENSE file for details.
🔗 Related Projects
💬 Support
For questions, issues, or contributions:
- Create an issue on GitHub
- Check the examples directory
- Review the API documentation
Built with ❤️ for better frontend observability and secure error monitoring.
