Skip to content

Commit a29c98b

Browse files
committed
feat: integrate Sentry monitoring and improve error handling
Web App: - Add Sentry error tracking with performance monitoring and session replay - Configure automatic source maps upload for production builds - Add Sentry Error Boundary for React component error handling - Sync user context with Clerk for better error attribution - Improve session expiration handling with retry logic and user-friendly messages - Add iOS App Store redirect for mobile web visitors Mobile App: - Replace New Relic with Sentry for unified error tracking - Configure Sentry React Native SDK with native crash reporting - Add performance monitoring and automatic session tracking - Update Expo config with Sentry plugin for source maps Infrastructure: - Add Sentry Vite plugin for release management - Configure environment variables for Sentry auth and organization - Enable release tracking with version information - Add source map generation for production builds
1 parent 2f153cd commit a29c98b

14 files changed

Lines changed: 1300 additions & 1223 deletions

File tree

.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ VITE_API_URL=http://localhost:3000/api
1010

1111
# Optional
1212
VITE_APP_NAME=Typelets
13+
14+
# Sentry Error Tracking - Get your DSN from https://sentry.io
15+
VITE_SENTRY_DSN=your_sentry_dsn_here
16+
17+
# Sentry Release Configuration (for source maps upload)
18+
# Get auth token from https://sentry.io/settings/account/api/auth-tokens/
19+
SENTRY_AUTH_TOKEN=your_sentry_auth_token_here
20+
SENTRY_ORG=your_sentry_org
21+
SENTRY_PROJECT=your_sentry_project

apps/mobile/v1/app.json

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,6 @@
88
"scheme": "typelets",
99
"userInterfaceStyle": "automatic",
1010
"description": "Secure, encrypted note-taking app with seamless sync across all your devices. Organize your thoughts with folders, encrypt sensitive content, and access your notes anywhere. Your data, your privacy.",
11-
"keywords": [
12-
"notes",
13-
"notepad",
14-
"encrypted",
15-
"secure",
16-
"sync",
17-
"productivity",
18-
"writing",
19-
"journal",
20-
"documents",
21-
"typelets"
22-
],
23-
"privacy": "public",
24-
"privacyPolicyUrl": "https://app.typelets.com/privacy",
2511
"platforms": [
2612
"ios",
2713
"android"
@@ -48,7 +34,6 @@
4834
"monochromeImage": "./assets/images/android-icon-monochrome.png"
4935
},
5036
"edgeToEdgeEnabled": true,
51-
"predictiveBackGestureEnabled": false,
5237
"permissions": [
5338
"INTERNET",
5439
"ACCESS_NETWORK_STATE"
@@ -60,7 +45,7 @@
6045
},
6146
"plugins": [
6247
"expo-router",
63-
"newrelic-react-native-agent",
48+
"@sentry/react-native/expo",
6449
[
6550
"expo-splash-screen",
6651
{
@@ -86,7 +71,6 @@
8671
"runtimeVersion": {
8772
"policy": "appVersion"
8873
},
89-
"owner": "typelets",
90-
"category": "productivity"
74+
"owner": "typelets"
9175
}
9276
}

apps/mobile/v1/index.js

Lines changed: 35 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,40 @@
1+
import 'expo-router/entry';
2+
13
import { Platform } from 'react-native';
4+
import * as Sentry from '@sentry/react-native';
5+
import Constants from 'expo-constants';
26
import { APP_VERSION } from './src/constants/version';
37

4-
// Initialize New Relic with error handling
5-
try {
6-
const NewRelicModule = require('newrelic-react-native-agent');
7-
const NewRelic = NewRelicModule.default || NewRelicModule;
8-
9-
if (NewRelic && NewRelic.startAgent) {
10-
let appToken;
11-
12-
if (Platform.OS === 'ios') {
13-
appToken = 'AAc3e01a8a8dfd3e2fef5e493052472740f6b4efab-NRMA';
14-
} else {
15-
appToken = 'AA29e5cbf5c69abe369e2ceed761a18688dbc00d91-NRMA';
16-
}
17-
18-
const agentConfiguration = {
19-
// Android Specific
20-
// Optional: Enable or disable collection of event data.
21-
analyticsEventEnabled: true,
22-
23-
// Optional: Enable or disable crash reporting.
24-
crashReportingEnabled: true,
25-
26-
// Optional: Enable or disable interaction tracing. Trace instrumentation still occurs, but no traces are harvested.
27-
// This will disable default and custom interactions.
28-
interactionTracingEnabled: true,
29-
30-
// Optional: Enable or disable reporting successful HTTP requests to the MobileRequest event type.
31-
networkRequestEnabled: true,
32-
33-
// Optional: Enable or disable reporting network and HTTP request errors to the MobileRequestError event type.
34-
networkErrorRequestEnabled: true,
35-
36-
// Optional: Enable or disable capture of HTTP response bodies for HTTP error traces, and MobileRequestError events.
37-
httpResponseBodyCaptureEnabled: true,
38-
39-
// Optional: Enable or disable agent logging.
40-
loggingEnabled: true,
41-
42-
// Optional: Specifies the log level. Omit this field for the default log level.
43-
// Options include: ERROR (least verbose), WARNING, INFO, VERBOSE, AUDIT (most verbose).
44-
logLevel: NewRelic.LogLevel.INFO,
45-
46-
// iOS Specific
47-
// Optional: Enable/Disable automatic instrumentation of WebViews
48-
webViewInstrumentation: true,
49-
50-
// Optional: Set a specific collector address for sending data. Omit this field for default address.
51-
// collectorAddress: "",
52-
53-
// Optional: Set a specific crash collector address for sending crashes. Omit this field for default address.
54-
// crashCollectorAddress: ""
55-
};
56-
57-
NewRelic.startAgent(appToken, agentConfiguration);
58-
NewRelic.setJSAppVersion(APP_VERSION);
59-
60-
if (__DEV__) {
61-
console.log('[New Relic] Agent started successfully with version:', APP_VERSION);
62-
console.log('[New Relic] Platform:', Platform.OS);
63-
}
64-
65-
// Send initialization log to NewRelic
66-
if (NewRelic.logInfo) {
67-
NewRelic.logInfo('NewRelic agent initialized', {
68-
platform: Platform.OS,
69-
version: APP_VERSION,
70-
timestamp: new Date().toISOString(),
71-
});
72-
}
73-
} else {
74-
console.warn('[New Relic] Agent module loaded but startAgent not available');
8+
// Initialize Sentry for error tracking and performance monitoring
9+
const SENTRY_DSN = Constants.expoConfig?.extra?.sentryDsn || process.env.EXPO_PUBLIC_SENTRY_DSN;
10+
11+
if (SENTRY_DSN) {
12+
Sentry.init({
13+
dsn: SENTRY_DSN,
14+
// Performance Monitoring
15+
tracesSampleRate: __DEV__ ? 1.0 : 0.1, // 100% in dev, 10% in prod
16+
// Environment
17+
environment: __DEV__ ? 'development' : 'production',
18+
// Release tracking
19+
release: `typelets-mobile@${APP_VERSION}`,
20+
dist: APP_VERSION,
21+
// Enable native crash handling
22+
enableNative: true,
23+
// Enable automatic session tracking
24+
enableAutoSessionTracking: true,
25+
// Session timeout (30 minutes = 1,800,000ms)
26+
sessionTrackingIntervalMillis: 1800000,
27+
// Enable native profiling (iOS)
28+
enableNativeProfiling: Platform.OS === 'ios',
29+
// Enable automatic performance tracing
30+
enableAutoPerformanceTracing: true,
31+
});
32+
33+
if (__DEV__) {
34+
console.log('[Sentry] Agent started successfully');
35+
console.log('[Sentry] Platform:', Platform.OS);
36+
console.log('[Sentry] Version:', APP_VERSION);
7537
}
76-
} catch (error) {
77-
console.warn('[New Relic] Failed to initialize:', error.message);
38+
} else {
39+
console.warn('[Sentry] DSN not found - Sentry will not be initialized');
7840
}
79-
80-
import 'expo-router/entry';

0 commit comments

Comments
 (0)