Complete setup for Node.js, React, Next.js, and browser applications.
# All packages
npm install @honeybadger-io/js @sentry/node @devcycle/nodejs-server-sdk appwrite
# React/Browser
npm install @sentry/react @devcycle/react-client-sdk
# Next.js
npm install @sentry/nextjsimport Honeybadger from '@honeybadger-io/js';
import * as Sentry from '@sentry/node';
import { initializeDevCycle } from '@devcycle/nodejs-server-sdk';
import { Client, Account, Databases } from 'node-appwrite';
// Initialize all services
export async function initServices() {
// Sentry
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
});
// Honeybadger
Honeybadger.configure({
apiKey: process.env.HONEYBADGER_API_KEY,
environment: process.env.NODE_ENV,
});
// DevCycle
const devcycle = await initializeDevCycle(
process.env.DEVCYCLE_SERVER_SDK_KEY
);
// Appwrite
const appwrite = new Client()
.setEndpoint(process.env.APPWRITE_ENDPOINT)
.setProject(process.env.APPWRITE_PROJECT_ID)
.setKey(process.env.APPWRITE_API_KEY);
return {
sentry: Sentry,
honeybadger: Honeybadger,
devcycle,
appwrite: {
client: appwrite,
account: new Account(appwrite),
databases: new Databases(appwrite),
},
};
}import express from 'express';
import * as Sentry from '@sentry/node';
const app = express();
// Sentry request handler (before routes)
app.use(Sentry.Handlers.requestHandler());
// Your routes
app.get('/', (req, res) => {
res.send('Hello World');
});
// Sentry error handler (after routes)
app.use(Sentry.Handlers.errorHandler());
app.listen(3000);import { DevCycleProvider, useVariableValue } from '@devcycle/react-client-sdk';
import * as Sentry from '@sentry/react';
// Initialize Sentry
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration(),
],
tracesSampleRate: 0.1,
replaysSessionSampleRate: 0.1,
});
function App() {
return (
<Sentry.ErrorBoundary fallback={<ErrorFallback />}>
<DevCycleProvider
sdkKey={process.env.REACT_APP_DEVCYCLE_CLIENT_SDK_KEY}
user={{ user_id: getUserId() }}
>
<AppContent />
</DevCycleProvider>
</Sentry.ErrorBoundary>
);
}
function FeatureComponent() {
const showNewFeature = useVariableValue('new-feature', false);
return showNewFeature ? <NewFeature /> : <LegacyFeature />;
}import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1,
});const { withSentryConfig } = require('@sentry/nextjs');
const nextConfig = {
// Your Next.js config
};
module.exports = withSentryConfig(nextConfig, {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
silent: true,
});// types/services.d.ts
import type { DevCycleClient } from '@devcycle/nodejs-server-sdk';
import type { Client } from 'node-appwrite';
export interface Services {
devcycle: DevCycleClient;
appwrite: {
client: Client;
account: Account;
databases: Databases;
};
}
export interface User {
user_id: string;
email?: string;
customData?: Record<string, unknown>;
}# .env.local
# Sentry
SENTRY_DSN=https://key@sentry.io/project
NEXT_PUBLIC_SENTRY_DSN=https://key@sentry.io/project
SENTRY_AUTH_TOKEN=
SENTRY_ORG=
SENTRY_PROJECT=
# Honeybadger
HONEYBADGER_API_KEY=
# DevCycle
DEVCYCLE_SERVER_SDK_KEY=
DEVCYCLE_CLIENT_SDK_KEY=
NEXT_PUBLIC_DEVCYCLE_CLIENT_SDK_KEY=
# Appwrite
APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
APPWRITE_PROJECT_ID=
APPWRITE_API_KEY=import * as Sentry from '@sentry/node';
import Honeybadger from '@honeybadger-io/js';
export function captureError(
error: Error,
context?: Record<string, unknown>
): void {
// Log to console in development
if (process.env.NODE_ENV === 'development') {
console.error(error);
}
// Report to Sentry
Sentry.captureException(error, {
extra: context,
});
// Report critical errors to Honeybadger
if (error.name === 'CriticalError') {
Honeybadger.notify(error, { context });
}
}
// Usage
try {
await riskyOperation();
} catch (error) {
captureError(error, { userId: user.id, action: 'riskyOperation' });
}import { useVariableValue } from '@devcycle/react-client-sdk';
// Hook for feature checks
export function useFeature(key: string, defaultValue = false): boolean {
return useVariableValue(key, defaultValue);
}
// Component usage
function MyComponent() {
const showBeta = useFeature('beta-features');
const maxItems = useVariableValue('max-items', 10);
return (
<div>
{showBeta && <BetaBanner />}
<ItemList max={maxItems} />
</div>
);
}// __mocks__/services.ts
export const mockDevcycle = {
variableValue: jest.fn().mockResolvedValue(false),
};
export const mockSentry = {
captureException: jest.fn(),
};
// test.spec.ts
jest.mock('@devcycle/nodejs-server-sdk', () => ({
initializeDevCycle: () => mockDevcycle,
}));