@scalable-labs/sentinel
v0.5.3
Published
Frontend error monitoring and tracking client with local storage, Microsoft Teams integration, and visual error viewer
Maintainers
Readme
@scalable-labs/sentinel
⚠️ Pre-1.0 Notice: This package is currently in active development and has not reached v1.0 yet. APIs may change and stability is not guaranteed. Use in production at your own risk. We welcome feedback and contributions!
Frontend error monitoring client for Sentinel by Scalable Labs. Automatically captures and reports failed API requests with support for local storage, Microsoft Teams integration, and visual error tracking.
🔗 Related Projects
- Backend Service: sentinel-server
- Website: sentinel-website
Note: This repository (
sentineljs) contains the source code for the npm package published as@scalable-labs/sentinel.
Installation
npm install @scalable-labs/sentinelQuick Start
Local Mode with UI (No Backend Required)
Perfect for development or when you want to track errors locally without a backend:
import { createSentinel } from '@scalable-labs/sentinel';
const sentinel = createSentinel({
mode: 'local', // Store errors in browser IndexedDB
showUI: true, // Show floating error viewer button
uiPosition: 'bottom-right',
teamMapping: {
'/api/users': 'platform',
'/api/orders': 'commerce',
'/api/products': 'catalog',
},
teamsChannelUrl: 'https://teams.microsoft.com/l/channel/...',
captureHeaders: ['x-correlation-id', 'x-request-id'],
getUserName: () => getCurrentUser()?.email,
});
// Errors are automatically captured and stored locally
// Click the ⚠️ button to view, copy, or send to TeamsRemote Mode (With Sentinel Backend)
import { createSentinel } from '@scalable-labs/sentinel';
const sentinel = createSentinel({
mode: 'remote',
backendUrl: 'https://sentinel.yourcompany.com',
apiKey: 'your-api-key',
enabled: process.env.NODE_ENV === 'production',
teamMapping: {
'/api/users': 'platform',
'/api/orders': 'commerce',
},
getUserName: () => getCurrentUser()?.username,
});
// Fetch interceptor is automatically installed!
// All failed requests will be batched and sent to backendConfiguration
| Option | Type | Required | Default | Description |
| ------------------ | ----------------------------- | --------------- | --------------- | ---------------------------------------------- |
| mode | 'local' \| 'remote' | No | 'local' | Operating mode |
| teamMapping | Record<string, string> | Yes | - | Map endpoints to teams |
| enabled | boolean | No | true | Enable/disable reporting |
| backendUrl | string | Yes (remote) | - | Sentinel backend URL (remote mode only) |
| apiKey | string | Yes (remote) | - | API key for backend (remote mode only) |
| showUI | boolean | No | false | Show visual error viewer (local mode only) |
| uiPosition | 'bottom-right' \| ... | No | 'bottom-right'| Position of UI button |
| teamsChannelUrl | string | No | - | Microsoft Teams channel URL for notifications |
| captureHeaders | string[] | No | - | HTTP headers to capture from responses |
| getUserName | () => string \| undefined | No | undefined | Function to get current username |
| batchSize | number | No | 50 | Batch size (remote mode) |
| batchInterval | number | No | 10000 | Batch interval in ms (remote mode) |
| defaultTeam | string | No | 'unknown' | Team for unmapped endpoints |
| dbName | string | No | 'sentinel' | IndexedDB database name (local mode) |
| maxLocalErrors | number | No | 1000 | Max errors to store locally |
Features
🎯 Automatic Error Detection
Automatically captures failed HTTP requests (status >= 400) or network errors.
📦 Two Operating Modes
Local Mode:
- Stores errors in browser IndexedDB
- No backend required
- Perfect for development
- View errors in built-in UI
- Export as JSON
- Send to Microsoft Teams
Remote Mode:
- Sends errors to Sentinel backend
- Batched transmission
- Prometheus metrics
- Teams webhook alerts
🎨 Visual Error Viewer (Local Mode)
When showUI: true, a floating button (⚠️) appears to:
- View all tracked errors grouped by team
- Copy individual errors in JSON format
- Copy all errors in JSON format
- Send all errors to Microsoft Teams
- Clear all tracked errors
- Refresh error list
📊 Microsoft Teams Integration
Send errors directly to a Teams channel:
teamsChannelUrl: 'https://teams.microsoft.com/l/channel/19%3a...thread.tacv2/General?groupId=...&tenantId=...'Errors are formatted as JSON with team tags for easy tracking. All errors are sent to the configured channel.
📋 Header Capture
Capture specific headers from HTTP responses for distributed tracing:
captureHeaders: ['x-correlation-id', 'x-request-id', 'x-trace-id']Headers are included in error reports for debugging.
🏷️ Team Mapping
Map endpoints to teams using exact match, prefix matching, full URLs, or regex:
teamMapping: {
// Path-based matching
'/api/users': 'platform', // Exact: /api/users
'/api/users/': 'platform', // Prefix: /api/users/123, /api/users/456
'/api/orders': 'commerce', // Prefix: /api/orders/...
// Full URL matching
'https://api.example.com/users': 'platform', // Exact hostname match
'https://api.example.[tld]/users': 'platform', // TLD variation: matches .com, .dk, .co.uk, etc.
'https://payments.stripe.[tld]/': 'payments', // TLD variation with path prefix
// Regex patterns
'/^\\/api\\/products\\/\\d+$/': 'catalog', // Regex: /api/products/123
'/^\\/api\\/payments/': 'payments', // Regex: starts with /api/payments
}Matching Priority:
- Exact match - checked first
- Prefix/URL/Regex - checked in order (first match wins)
- Default team - if no match found
Pattern Types:
Path patterns: String starting with
/(but not ending with/for regex)- Exact:
/api/usersmatches only/api/users - Prefix:
/api/users/matches/api/users/123,/api/users/456/profile, etc.
- Exact:
Full URL patterns: String starting with
http://orhttps://- Exact hostname:
https://api.example.com/usersmatches onlyapi.example.com - TLD variation:
https://api.example.[tld]/usersmatches:https://api.example.com/usershttps://api.example.dk/usershttps://api.example.co.uk/users
- Use
[tld]placeholder in hostname to enable TLD variation - Path must match (prefix matching on path)
- Exact hostname:
Regex patterns: String starting and ending with
/- Pattern between slashes is used as the regex
- Example:
/^\\/api\\/v\\d+\\/users/matches/api/v1/users,/api/v2/users, etc. - Invalid regex patterns are skipped with a warning
Combined Example:
teamMapping: {
// Path patterns
'/api/users': 'platform', // Exact match
'/api/users/': 'platform', // Prefix match
// Full URL patterns (exact hostname)
'https://api.internal.com/data': 'backend', // Internal API
'https://payment-gateway.company.com/': 'payments', // Payment service
// Full URL patterns (with TLD variation)
'https://api.example.[tld]/products': 'catalog', // Multi-region product API
'https://cdn.assets.[tld]/images': 'media', // Multi-region CDN
// Regex patterns for paths
'/^\\/api\\/orders\\/\\d+$/': 'commerce', // /api/orders/123
'/^\\/api\\/v[12]\\/users/': 'platform', // /api/v1/users, /api/v2/users
// Regex patterns for full URLs
'/^https:\\/\\/.*\\.stripe\\.com\\/.*$/': 'payments', // Any Stripe subdomain
'/^https:\\/\\/[a-z0-9-]+\\.cloudfront\\.net\\/.*$/': 'cdn', // CloudFront URLs
}This configuration will match:
Path patterns:
/api/users→platform(exact)/api/users/123→platform(prefix)
Full URL patterns (exact):
https://api.internal.com/data→backendhttps://payment-gateway.company.com/checkout→payments
Full URL patterns (TLD variation):
https://api.example.com/products→cataloghttps://api.example.dk/products→cataloghttps://api.example.co.uk/products/item→cataloghttps://cdn.assets.com/images/logo.png→mediahttps://cdn.assets.fr/images/logo.png→media
Regex patterns (paths):
/api/orders/456→commerce/api/v1/users→platform/api/v2/users/search→platform
Regex patterns (full URLs):
https://payments.stripe.com/v1/charges→paymentshttps://connect.stripe.com/oauth→paymentshttps://d1234567890.cloudfront.net/assets/app.js→cdn
👤 Optional User Tracking
Track which users experience errors:
getUserName: () => {
const user = localStorage.getItem('user');
return user ? JSON.parse(user).username : undefined;
}🔐 Environment-based Toggling
Enable/disable based on environment:
enabled: process.env.NODE_ENV === 'production'
// or
enabled: process.env.SENTINEL_ENABLED === 'true'🛡️ Graceful Failure
If the Sentinel backend is unavailable, errors are logged to console but don't break your app.
Advanced Usage
Axios Integration
import axios from 'axios';
import { SentinelClient, installAxiosInterceptor } from '@scalable-labs/sentinel';
const sentinel = new SentinelClient({
mode: 'remote',
backendUrl: 'https://sentinel.yourcompany.com',
apiKey: 'your-api-key',
teamMapping: { '/api/users': 'platform' },
});
installAxiosInterceptor(axios, sentinel);Manual Error Reporting
import { SentinelClient } from '@scalable-labs/sentinel';
const sentinel = new SentinelClient({
mode: 'local',
teamMapping: { '/api/users': 'platform' },
});
// Manually report an error with headers
try {
const response = await fetch('/api/users/123');
if (!response.ok) {
const payload = await response.text();
const headers = {
'x-correlation-id': response.headers.get('x-correlation-id') || '',
};
sentinel.reportError('/api/users/123', 'GET', response.status, payload, headers);
}
} catch (error) {
sentinel.reportError('/api/users/123', 'GET', 0, 'Network error');
}Export Local Errors
const sentinel = createSentinel({ mode: 'local', teamMapping: {...} });
// Get all errors as array
const errors = await sentinel.getLocalErrors();
// Export as JSON string
const json = await sentinel.exportLocalErrors();
console.log(json);
// Clear all errors
await sentinel.clearLocalErrors();Manual Flush (Remote Mode)
Force send all queued errors immediately:
window.addEventListener('beforeunload', () => {
sentinel.flush();
});Examples
React App with Local Mode
// src/sentinel.ts
import { createSentinel } from '@scalable-labs/sentinel';
export const sentinel = createSentinel({
mode: 'local',
showUI: true,
uiPosition: 'bottom-right',
teamMapping: {
'/api/auth': 'platform',
'/api/users': 'platform',
'/api/products': 'catalog',
},
teamsChannelUrl: 'https://teams.microsoft.com/l/channel/...',
captureHeaders: ['x-correlation-id', 'x-request-id'],
getUserName: () => {
const userStr = localStorage.getItem('user');
return userStr ? JSON.parse(userStr).email : undefined;
},
});
// src/main.tsx
import { sentinel } from './sentinel';
// Sentinel is now monitoring all fetch requests!Next.js App with Remote Mode
// lib/sentinel.ts
import { createSentinel } from '@scalable-labs/sentinel';
export const sentinel = createSentinel({
mode: 'remote',
backendUrl: process.env.NEXT_PUBLIC_SENTINEL_URL!,
apiKey: process.env.NEXT_PUBLIC_SENTINEL_API_KEY!,
enabled: process.env.NODE_ENV === 'production',
teamMapping: {
'/api/auth': 'platform',
'/api/blog': 'content',
'/api/products': 'ecommerce',
},
captureHeaders: ['x-trace-id'],
getUserName: () => {
if (typeof window !== 'undefined') {
return sessionStorage.getItem('username') || undefined;
}
},
});
// app/layout.tsx or pages/_app.tsx
import { sentinel } from '@/lib/sentinel';
// Auto-monitoring enabled!Development
# Install dependencies
npm install
# Build
npm run build
# Watch mode
npm run watch
# Run tests
npm test
# Lint
npm run lint
# Format
npm run formatPublishing
This package is published to npm as @scalable-labs/sentinel.
npm publish --access publicLicense
MIT
Contributing
Contributions welcome! Please open an issue or PR on GitHub.
