@deeptracer/nextjs 0.2.0 → 0.3.1

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/README.md ADDED
@@ -0,0 +1,269 @@
1
+ # @deeptracer/nextjs
2
+
3
+ [![npm](https://img.shields.io/npm/v/@deeptracer/nextjs?color=blue)](https://www.npmjs.com/package/@deeptracer/nextjs)
4
+
5
+ DeepTracer Next.js integration — automatic server-side error capture with one-file setup. The easiest way to add observability to a Next.js application.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @deeptracer/nextjs
11
+ ```
12
+
13
+ **Peer dependencies:** `next >=14`, `react >=18`, `react-dom >=18`
14
+
15
+ ## Quick Start (1 file, 5 lines)
16
+
17
+ Create `instrumentation.ts` in your project root:
18
+
19
+ ```ts
20
+ import { init } from "@deeptracer/nextjs"
21
+
22
+ export const { register, onRequestError } = init({
23
+ product: "my-app",
24
+ service: "web",
25
+ environment: "production",
26
+ endpoint: "https://deeptracer.example.com",
27
+ apiKey: process.env.DEEPTRACER_API_KEY!,
28
+ })
29
+ ```
30
+
31
+ That's it. All server-side errors are now captured automatically.
32
+
33
+ ## What Gets Captured Automatically
34
+
35
+ With just `instrumentation.ts`, the following are captured without any additional code:
36
+
37
+ - **Server Component errors** — rendering failures in React Server Components
38
+ - **Route Handler errors** — uncaught exceptions in `app/api/**/route.ts`
39
+ - **Middleware errors** — failures in `middleware.ts` / `proxy.ts`
40
+ - **Uncaught exceptions** — `process.on("uncaughtException")` in Node.js runtime
41
+ - **Unhandled rejections** — `process.on("unhandledRejection")` in Node.js runtime
42
+
43
+ ## API Reference (Server)
44
+
45
+ Import from `@deeptracer/nextjs`:
46
+
47
+ ### `init(config)`
48
+
49
+ Initialize DeepTracer for Next.js. Returns `register` and `onRequestError` for direct re-export from `instrumentation.ts`.
50
+
51
+ **Parameters:**
52
+ - `config: NextjsConfig` — extends `LoggerConfig` with:
53
+
54
+ | Field | Type | Default | Description |
55
+ |-------|------|---------|-------------|
56
+ | `captureGlobalErrors` | `boolean` | `true` | Capture uncaught exceptions and unhandled rejections via `process.on` (Node.js runtime only). |
57
+ | `captureConsole` | `boolean` | `false` | Intercept `console.*` calls and forward to DeepTracer. |
58
+
59
+ **Returns:** `{ register, onRequestError, logger }`
60
+
61
+ | Property | Type | Description |
62
+ |----------|------|-------------|
63
+ | `register` | `() => void` | Called by Next.js on server start. Sets up error handlers. |
64
+ | `onRequestError` | `(err, request, context) => Promise<void>` | Called by Next.js on every server-side error. |
65
+ | `logger` | `Logger` | The Logger instance for manual logging, server actions, and route handlers. |
66
+
67
+ ```ts
68
+ // instrumentation.ts
69
+ import { init } from "@deeptracer/nextjs"
70
+
71
+ const deeptracer = init({
72
+ product: "my-app",
73
+ service: "web",
74
+ environment: "production",
75
+ endpoint: "https://deeptracer.example.com",
76
+ apiKey: process.env.DEEPTRACER_API_KEY!,
77
+ })
78
+
79
+ export const { register, onRequestError } = deeptracer
80
+ export const logger = deeptracer.logger
81
+ ```
82
+
83
+ ---
84
+
85
+ ### `withServerAction(logger, name, fn)`
86
+
87
+ Wrap a Next.js Server Action with automatic tracing and error capture. Creates a span and catches errors (re-throws after reporting).
88
+
89
+ ```ts
90
+ // app/actions.ts
91
+ "use server"
92
+ import { withServerAction } from "@deeptracer/nextjs"
93
+ import { logger } from "@/instrumentation"
94
+
95
+ export async function createUser(formData: FormData) {
96
+ return withServerAction(logger, "createUser", async () => {
97
+ const name = formData.get("name") as string
98
+ const user = await db.user.create({ data: { name } })
99
+ return user
100
+ })
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ### `withRouteHandler(logger, name, handler)`
107
+
108
+ Wrap a Next.js Route Handler with automatic tracing and error capture. Creates a request-scoped span and extracts trace context from headers.
109
+
110
+ ```ts
111
+ // app/api/users/route.ts
112
+ import { withRouteHandler } from "@deeptracer/nextjs"
113
+ import { logger } from "@/instrumentation"
114
+
115
+ export const GET = withRouteHandler(logger, "GET /api/users", async (request) => {
116
+ const users = await db.user.findMany()
117
+ return Response.json(users)
118
+ })
119
+
120
+ export const POST = withRouteHandler(logger, "POST /api/users", async (request) => {
121
+ const body = await request.json()
122
+ const user = await db.user.create({ data: body })
123
+ return Response.json(user, { status: 201 })
124
+ })
125
+ ```
126
+
127
+ ---
128
+
129
+ ### Re-exported from @deeptracer/node
130
+
131
+ All exports from `@deeptracer/node` and `@deeptracer/core` are available:
132
+
133
+ - `createLogger`, `Logger`, `captureGlobalErrors`, `captureConsole`, `honoMiddleware`, `expressMiddleware`
134
+ - Types: `LoggerConfig`, `User`, `Breadcrumb`, `BeforeSendEvent`, `Span`, `InactiveSpan`, etc.
135
+ - Constants: `SDK_VERSION`, `SDK_NAME`
136
+
137
+ ## API Reference (Client)
138
+
139
+ Import from `@deeptracer/nextjs/client`:
140
+
141
+ ### `DeepTracerProvider`
142
+
143
+ React context provider for client-side error capture. See [`@deeptracer/react`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/react) for full docs.
144
+
145
+ ```tsx
146
+ // app/layout.tsx
147
+ import { DeepTracerProvider } from "@deeptracer/nextjs/client"
148
+
149
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
150
+ return (
151
+ <html>
152
+ <body>
153
+ <DeepTracerProvider config={{
154
+ product: "my-app",
155
+ service: "web",
156
+ environment: "production",
157
+ endpoint: process.env.NEXT_PUBLIC_DEEPTRACER_ENDPOINT!,
158
+ apiKey: process.env.NEXT_PUBLIC_DEEPTRACER_API_KEY!,
159
+ }}>
160
+ {children}
161
+ </DeepTracerProvider>
162
+ </body>
163
+ </html>
164
+ )
165
+ }
166
+ ```
167
+
168
+ ### `DeepTracerErrorPage`
169
+
170
+ Drop-in error page for `error.tsx` / `global-error.tsx`.
171
+
172
+ ```tsx
173
+ // app/global-error.tsx
174
+ "use client"
175
+ export { DeepTracerErrorPage as default } from "@deeptracer/nextjs/client"
176
+ ```
177
+
178
+ ### Other client exports
179
+
180
+ - `DeepTracerErrorBoundary` — class-based error boundary for wrapping React trees
181
+ - `useLogger()` — hook to access Logger from context
182
+ - `useDeepTracerErrorReporter(error)` — hook for custom error pages
183
+
184
+ ## Full Setup (Server + Client)
185
+
186
+ ### 1. Server-side (required)
187
+
188
+ ```ts
189
+ // instrumentation.ts
190
+ import { init } from "@deeptracer/nextjs"
191
+
192
+ const deeptracer = init({
193
+ product: "my-app",
194
+ service: "web",
195
+ environment: "production",
196
+ endpoint: "https://deeptracer.example.com",
197
+ apiKey: process.env.DEEPTRACER_API_KEY!,
198
+ })
199
+
200
+ export const { register, onRequestError } = deeptracer
201
+ export const logger = deeptracer.logger
202
+ ```
203
+
204
+ ### 2. Client-side provider (optional)
205
+
206
+ ```tsx
207
+ // app/layout.tsx
208
+ import { DeepTracerProvider } from "@deeptracer/nextjs/client"
209
+
210
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
211
+ return (
212
+ <html>
213
+ <body>
214
+ <DeepTracerProvider config={{
215
+ product: "my-app",
216
+ service: "web",
217
+ environment: "production",
218
+ endpoint: process.env.NEXT_PUBLIC_DEEPTRACER_ENDPOINT!,
219
+ apiKey: process.env.NEXT_PUBLIC_DEEPTRACER_API_KEY!,
220
+ }}>
221
+ {children}
222
+ </DeepTracerProvider>
223
+ </body>
224
+ </html>
225
+ )
226
+ }
227
+ ```
228
+
229
+ ### 3. Error boundary (optional)
230
+
231
+ ```tsx
232
+ // app/global-error.tsx
233
+ "use client"
234
+ export { DeepTracerErrorPage as default } from "@deeptracer/nextjs/client"
235
+ ```
236
+
237
+ ## Environment Variables
238
+
239
+ | Variable | Side | Description |
240
+ |----------|------|-------------|
241
+ | `DEEPTRACER_API_KEY` | Server | API key for server-side SDK |
242
+ | `NEXT_PUBLIC_DEEPTRACER_ENDPOINT` | Client | Ingestion endpoint URL |
243
+ | `NEXT_PUBLIC_DEEPTRACER_API_KEY` | Client | API key for client-side SDK |
244
+ | `NEXT_PUBLIC_DEEPTRACER_PRODUCT` | Client | Product name (for zero-config provider) |
245
+ | `NEXT_PUBLIC_DEEPTRACER_SERVICE` | Client | Service name (default: `"web"`) |
246
+ | `NEXT_PUBLIC_DEEPTRACER_ENVIRONMENT` | Client | `"production"` or `"staging"` (default: `"production"`) |
247
+
248
+ ## Monorepo
249
+
250
+ This package is part of the [DeepTracer JavaScript SDK](https://github.com/getdeeptracer/deeptracer-js) monorepo:
251
+
252
+ | Package | Description |
253
+ |---------|-------------|
254
+ | [`@deeptracer/core`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/core) | Zero-dependency shared core |
255
+ | [`@deeptracer/node`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/node) | Node.js/Bun SDK |
256
+ | [`@deeptracer/ai`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/ai) | AI SDK wrappers |
257
+ | [`@deeptracer/browser`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/browser) | Browser SDK |
258
+ | [`@deeptracer/react`](https://github.com/getdeeptracer/deeptracer-js/tree/main/packages/react) | React integration |
259
+ | **`@deeptracer/nextjs`** | Next.js integration (this package) |
260
+
261
+ ## Links
262
+
263
+ - [deeptracer.dev](https://deeptracer.dev) — Homepage
264
+ - [Docs](https://deeptracer.dev/docs) — Documentation
265
+ - [GitHub](https://github.com/getdeeptracer/deeptracer-js) — Source code
266
+
267
+ ## License
268
+
269
+ MIT
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/client.ts
21
+ var client_exports = {};
22
+ __export(client_exports, {
23
+ DeepTracerErrorBoundary: () => import_react.DeepTracerErrorBoundary,
24
+ DeepTracerErrorPage: () => import_react.DeepTracerErrorPage,
25
+ DeepTracerProvider: () => import_react.DeepTracerProvider,
26
+ useDeepTracerErrorReporter: () => import_react.useDeepTracerErrorReporter,
27
+ useLogger: () => import_react.useLogger
28
+ });
29
+ module.exports = __toCommonJS(client_exports);
30
+ var import_react = require("@deeptracer/react");
31
+ // Annotate the CommonJS export names for ESM import in node:
32
+ 0 && (module.exports = {
33
+ DeepTracerErrorBoundary,
34
+ DeepTracerErrorPage,
35
+ DeepTracerProvider,
36
+ useDeepTracerErrorReporter,
37
+ useLogger
38
+ });
@@ -0,0 +1 @@
1
+ export { DeepTracerErrorBoundary, DeepTracerErrorPage, DeepTracerProvider, DeepTracerProviderProps, useDeepTracerErrorReporter, useLogger } from '@deeptracer/react';
@@ -0,0 +1 @@
1
+ export { DeepTracerErrorBoundary, DeepTracerErrorPage, DeepTracerProvider, DeepTracerProviderProps, useDeepTracerErrorReporter, useLogger } from '@deeptracer/react';
package/dist/client.js ADDED
@@ -0,0 +1,15 @@
1
+ // src/client.ts
2
+ import {
3
+ DeepTracerProvider,
4
+ DeepTracerErrorPage,
5
+ DeepTracerErrorBoundary,
6
+ useDeepTracerErrorReporter,
7
+ useLogger
8
+ } from "@deeptracer/react";
9
+ export {
10
+ DeepTracerErrorBoundary,
11
+ DeepTracerErrorPage,
12
+ DeepTracerProvider,
13
+ useDeepTracerErrorReporter,
14
+ useLogger
15
+ };
package/dist/index.cjs CHANGED
@@ -3,6 +3,10 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
6
10
  var __copyProps = (to, from, except, desc) => {
7
11
  if (from && typeof from === "object" || typeof from === "function") {
8
12
  for (let key of __getOwnPropNames(from))
@@ -16,9 +20,146 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
16
20
 
17
21
  // src/index.ts
18
22
  var index_exports = {};
23
+ __export(index_exports, {
24
+ init: () => init,
25
+ withRouteHandler: () => withRouteHandler,
26
+ withServerAction: () => withServerAction
27
+ });
19
28
  module.exports = __toCommonJS(index_exports);
20
29
  __reExport(index_exports, require("@deeptracer/node"), module.exports);
30
+
31
+ // src/init.ts
32
+ var import_core = require("@deeptracer/core");
33
+ function init(config) {
34
+ const logger = (0, import_core.createLogger)(config);
35
+ const shouldCaptureGlobalErrors = config.captureGlobalErrors !== false;
36
+ const shouldCaptureConsole = config.captureConsole === true;
37
+ function register() {
38
+ const runtime = typeof process !== "undefined" ? process.env?.NEXT_RUNTIME : void 0;
39
+ if (runtime === "nodejs") {
40
+ if (shouldCaptureGlobalErrors) {
41
+ process.on("uncaughtException", (error) => {
42
+ logger.captureError(error, {
43
+ severity: "critical",
44
+ context: { source: "uncaughtException", runtime: "nodejs" }
45
+ });
46
+ logger.flush();
47
+ });
48
+ process.on("unhandledRejection", (reason) => {
49
+ logger.captureError(
50
+ reason instanceof Error ? reason : new Error(String(reason)),
51
+ {
52
+ severity: "high",
53
+ context: { source: "unhandledRejection", runtime: "nodejs" }
54
+ }
55
+ );
56
+ logger.flush();
57
+ });
58
+ }
59
+ if (shouldCaptureConsole) {
60
+ const origLog = console.log;
61
+ const origInfo = console.info;
62
+ const origWarn = console.warn;
63
+ const origError = console.error;
64
+ const origDebug = console.debug;
65
+ console.log = (...args) => {
66
+ logger.info(args.map(String).join(" "));
67
+ origLog(...args);
68
+ };
69
+ console.info = (...args) => {
70
+ logger.info(args.map(String).join(" "));
71
+ origInfo(...args);
72
+ };
73
+ console.warn = (...args) => {
74
+ logger.warn(args.map(String).join(" "));
75
+ origWarn(...args);
76
+ };
77
+ console.error = (...args) => {
78
+ logger.error(args.map(String).join(" "));
79
+ origError(...args);
80
+ };
81
+ console.debug = (...args) => {
82
+ logger.debug(args.map(String).join(" "));
83
+ origDebug(...args);
84
+ };
85
+ }
86
+ logger.info("DeepTracer initialized", {
87
+ runtime: "nodejs",
88
+ product: config.product,
89
+ service: config.service
90
+ });
91
+ } else if (runtime === "edge") {
92
+ logger.info("DeepTracer initialized", {
93
+ runtime: "edge",
94
+ product: config.product,
95
+ service: config.service
96
+ });
97
+ }
98
+ }
99
+ async function onRequestError(err, request, context) {
100
+ const reqLogger = logger.withContext(
101
+ `${context.routeType}:${context.routePath}`
102
+ );
103
+ reqLogger.addBreadcrumb({
104
+ type: "http",
105
+ message: `${request.method} ${request.path}`
106
+ });
107
+ reqLogger.captureError(err, {
108
+ severity: "high",
109
+ context: {
110
+ source: "nextjs-onRequestError",
111
+ method: request.method,
112
+ path: request.path,
113
+ routerKind: context.routerKind,
114
+ routePath: context.routePath,
115
+ routeType: context.routeType
116
+ }
117
+ });
118
+ }
119
+ return { register, onRequestError, logger };
120
+ }
121
+
122
+ // src/server-action.ts
123
+ async function withServerAction(logger, name, fn) {
124
+ return logger.startSpan(`server-action:${name}`, async () => {
125
+ try {
126
+ return await fn();
127
+ } catch (error) {
128
+ logger.captureError(error, {
129
+ severity: "high",
130
+ context: { source: "server-action", action: name }
131
+ });
132
+ throw error;
133
+ }
134
+ });
135
+ }
136
+
137
+ // src/route-handler.ts
138
+ function withRouteHandler(logger, name, handler) {
139
+ return async (request) => {
140
+ const reqLogger = logger.forRequest(request);
141
+ return reqLogger.startSpan(`route:${name}`, async () => {
142
+ try {
143
+ return await handler(request);
144
+ } catch (error) {
145
+ reqLogger.captureError(error, {
146
+ severity: "high",
147
+ context: {
148
+ source: "route-handler",
149
+ route: name,
150
+ method: request.method,
151
+ url: request.url
152
+ }
153
+ });
154
+ throw error;
155
+ }
156
+ });
157
+ };
158
+ }
21
159
  // Annotate the CommonJS export names for ESM import in node:
22
160
  0 && (module.exports = {
161
+ init,
162
+ withRouteHandler,
163
+ withServerAction,
23
164
  ...require("@deeptracer/node")
24
165
  });
package/dist/index.d.cts CHANGED
@@ -1 +1,149 @@
1
1
  export * from '@deeptracer/node';
2
+ import { Logger, LoggerConfig } from '@deeptracer/core';
3
+
4
+ /**
5
+ * Configuration for the DeepTracer Next.js integration.
6
+ * Extends the base LoggerConfig with Next.js-specific options.
7
+ */
8
+ interface NextjsConfig extends LoggerConfig {
9
+ /**
10
+ * Automatically capture uncaught exceptions and unhandled rejections
11
+ * via Node.js process events (only in Node.js runtime, not Edge).
12
+ * Default: true
13
+ */
14
+ captureGlobalErrors?: boolean;
15
+ /**
16
+ * Intercept console.log/warn/error/debug calls and forward them to DeepTracer.
17
+ * Default: false (can be noisy in development)
18
+ */
19
+ captureConsole?: boolean;
20
+ }
21
+ /**
22
+ * Return type of `init()`. Destructure `register` and `onRequestError`
23
+ * to re-export them from your `instrumentation.ts` file.
24
+ */
25
+ interface InitResult {
26
+ /**
27
+ * Called by Next.js when the server starts.
28
+ * Sets up global error capture and console interception.
29
+ * Re-export this from your `instrumentation.ts`.
30
+ */
31
+ register: () => void;
32
+ /**
33
+ * Called by Next.js on every server-side error (Server Components,
34
+ * Route Handlers, Middleware). Captures errors and sends them to DeepTracer.
35
+ * Re-export this as `onRequestError` from your `instrumentation.ts`.
36
+ */
37
+ onRequestError: (err: Error, request: {
38
+ path: string;
39
+ method: string;
40
+ headers: Record<string, string>;
41
+ }, context: {
42
+ routerKind: string;
43
+ routePath: string;
44
+ routeType: string;
45
+ }) => Promise<void>;
46
+ /**
47
+ * The DeepTracer Logger instance. Use this for manual logging,
48
+ * error capture, or to pass to `withServerAction` / `withRouteHandler`.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const deeptracer = init({ ... })
53
+ * export const { register, onRequestError } = deeptracer
54
+ * export const logger = deeptracer.logger
55
+ * ```
56
+ */
57
+ logger: Logger;
58
+ }
59
+ /**
60
+ * Initialize DeepTracer for Next.js. Returns `register` and `onRequestError`
61
+ * to be re-exported from your `instrumentation.ts` file.
62
+ *
63
+ * This is the **only setup required** for server-side error capture in Next.js.
64
+ * Every server-side error (Server Components, Route Handlers, Middleware) is
65
+ * automatically captured via Next.js's built-in `onRequestError` hook.
66
+ *
67
+ * @param config - Logger configuration with optional Next.js-specific options
68
+ * @returns Object with `register`, `onRequestError`, and `logger`
69
+ *
70
+ * @example
71
+ * Create `instrumentation.ts` in your project root:
72
+ * ```ts
73
+ * import { init } from "@deeptracer/nextjs"
74
+ *
75
+ * export const { register, onRequestError } = init({
76
+ * product: "my-app",
77
+ * service: "web",
78
+ * environment: "production",
79
+ * endpoint: "https://deeptracer.example.com",
80
+ * apiKey: process.env.DEEPTRACER_API_KEY!,
81
+ * })
82
+ * ```
83
+ *
84
+ * That's it. All server-side errors are now captured automatically.
85
+ */
86
+ declare function init(config: NextjsConfig): InitResult;
87
+
88
+ /**
89
+ * Wrap a Next.js Server Action with automatic tracing and error capture.
90
+ *
91
+ * Creates a span for the action's execution and captures any errors.
92
+ * The original error is always re-thrown so Next.js error handling works normally.
93
+ *
94
+ * @param logger - DeepTracer Logger instance (from `init().logger`)
95
+ * @param name - A descriptive name for the action (e.g., "createUser", "submitForm")
96
+ * @param fn - The async function to execute
97
+ * @returns The result of the server action function
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * // app/actions.ts
102
+ * "use server"
103
+ * import { withServerAction } from "@deeptracer/nextjs"
104
+ * import { logger } from "@/instrumentation"
105
+ *
106
+ * export async function createUser(formData: FormData) {
107
+ * return withServerAction(logger, "createUser", async () => {
108
+ * const name = formData.get("name") as string
109
+ * const user = await db.user.create({ data: { name } })
110
+ * return user
111
+ * })
112
+ * }
113
+ * ```
114
+ */
115
+ declare function withServerAction<T>(logger: Logger, name: string, fn: () => Promise<T>): Promise<T>;
116
+
117
+ /**
118
+ * Wrap a Next.js App Router Route Handler with automatic tracing and error capture.
119
+ *
120
+ * Creates a request-scoped span, extracts trace context from headers,
121
+ * and captures any errors. The original error is re-thrown so Next.js
122
+ * error handling works normally.
123
+ *
124
+ * @param logger - DeepTracer Logger instance (from `init().logger`)
125
+ * @param name - A descriptive name for the route (e.g., "GET /api/users")
126
+ * @param handler - The route handler function
127
+ * @returns A wrapped route handler function
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * // app/api/users/route.ts
132
+ * import { withRouteHandler } from "@deeptracer/nextjs"
133
+ * import { logger } from "@/instrumentation"
134
+ *
135
+ * export const GET = withRouteHandler(logger, "GET /api/users", async (request) => {
136
+ * const users = await db.user.findMany()
137
+ * return Response.json(users)
138
+ * })
139
+ *
140
+ * export const POST = withRouteHandler(logger, "POST /api/users", async (request) => {
141
+ * const body = await request.json()
142
+ * const user = await db.user.create({ data: body })
143
+ * return Response.json(user, { status: 201 })
144
+ * })
145
+ * ```
146
+ */
147
+ declare function withRouteHandler(logger: Logger, name: string, handler: (request: Request) => Promise<Response>): (request: Request) => Promise<Response>;
148
+
149
+ export { type InitResult, type NextjsConfig, init, withRouteHandler, withServerAction };
package/dist/index.d.ts CHANGED
@@ -1 +1,149 @@
1
1
  export * from '@deeptracer/node';
2
+ import { Logger, LoggerConfig } from '@deeptracer/core';
3
+
4
+ /**
5
+ * Configuration for the DeepTracer Next.js integration.
6
+ * Extends the base LoggerConfig with Next.js-specific options.
7
+ */
8
+ interface NextjsConfig extends LoggerConfig {
9
+ /**
10
+ * Automatically capture uncaught exceptions and unhandled rejections
11
+ * via Node.js process events (only in Node.js runtime, not Edge).
12
+ * Default: true
13
+ */
14
+ captureGlobalErrors?: boolean;
15
+ /**
16
+ * Intercept console.log/warn/error/debug calls and forward them to DeepTracer.
17
+ * Default: false (can be noisy in development)
18
+ */
19
+ captureConsole?: boolean;
20
+ }
21
+ /**
22
+ * Return type of `init()`. Destructure `register` and `onRequestError`
23
+ * to re-export them from your `instrumentation.ts` file.
24
+ */
25
+ interface InitResult {
26
+ /**
27
+ * Called by Next.js when the server starts.
28
+ * Sets up global error capture and console interception.
29
+ * Re-export this from your `instrumentation.ts`.
30
+ */
31
+ register: () => void;
32
+ /**
33
+ * Called by Next.js on every server-side error (Server Components,
34
+ * Route Handlers, Middleware). Captures errors and sends them to DeepTracer.
35
+ * Re-export this as `onRequestError` from your `instrumentation.ts`.
36
+ */
37
+ onRequestError: (err: Error, request: {
38
+ path: string;
39
+ method: string;
40
+ headers: Record<string, string>;
41
+ }, context: {
42
+ routerKind: string;
43
+ routePath: string;
44
+ routeType: string;
45
+ }) => Promise<void>;
46
+ /**
47
+ * The DeepTracer Logger instance. Use this for manual logging,
48
+ * error capture, or to pass to `withServerAction` / `withRouteHandler`.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const deeptracer = init({ ... })
53
+ * export const { register, onRequestError } = deeptracer
54
+ * export const logger = deeptracer.logger
55
+ * ```
56
+ */
57
+ logger: Logger;
58
+ }
59
+ /**
60
+ * Initialize DeepTracer for Next.js. Returns `register` and `onRequestError`
61
+ * to be re-exported from your `instrumentation.ts` file.
62
+ *
63
+ * This is the **only setup required** for server-side error capture in Next.js.
64
+ * Every server-side error (Server Components, Route Handlers, Middleware) is
65
+ * automatically captured via Next.js's built-in `onRequestError` hook.
66
+ *
67
+ * @param config - Logger configuration with optional Next.js-specific options
68
+ * @returns Object with `register`, `onRequestError`, and `logger`
69
+ *
70
+ * @example
71
+ * Create `instrumentation.ts` in your project root:
72
+ * ```ts
73
+ * import { init } from "@deeptracer/nextjs"
74
+ *
75
+ * export const { register, onRequestError } = init({
76
+ * product: "my-app",
77
+ * service: "web",
78
+ * environment: "production",
79
+ * endpoint: "https://deeptracer.example.com",
80
+ * apiKey: process.env.DEEPTRACER_API_KEY!,
81
+ * })
82
+ * ```
83
+ *
84
+ * That's it. All server-side errors are now captured automatically.
85
+ */
86
+ declare function init(config: NextjsConfig): InitResult;
87
+
88
+ /**
89
+ * Wrap a Next.js Server Action with automatic tracing and error capture.
90
+ *
91
+ * Creates a span for the action's execution and captures any errors.
92
+ * The original error is always re-thrown so Next.js error handling works normally.
93
+ *
94
+ * @param logger - DeepTracer Logger instance (from `init().logger`)
95
+ * @param name - A descriptive name for the action (e.g., "createUser", "submitForm")
96
+ * @param fn - The async function to execute
97
+ * @returns The result of the server action function
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * // app/actions.ts
102
+ * "use server"
103
+ * import { withServerAction } from "@deeptracer/nextjs"
104
+ * import { logger } from "@/instrumentation"
105
+ *
106
+ * export async function createUser(formData: FormData) {
107
+ * return withServerAction(logger, "createUser", async () => {
108
+ * const name = formData.get("name") as string
109
+ * const user = await db.user.create({ data: { name } })
110
+ * return user
111
+ * })
112
+ * }
113
+ * ```
114
+ */
115
+ declare function withServerAction<T>(logger: Logger, name: string, fn: () => Promise<T>): Promise<T>;
116
+
117
+ /**
118
+ * Wrap a Next.js App Router Route Handler with automatic tracing and error capture.
119
+ *
120
+ * Creates a request-scoped span, extracts trace context from headers,
121
+ * and captures any errors. The original error is re-thrown so Next.js
122
+ * error handling works normally.
123
+ *
124
+ * @param logger - DeepTracer Logger instance (from `init().logger`)
125
+ * @param name - A descriptive name for the route (e.g., "GET /api/users")
126
+ * @param handler - The route handler function
127
+ * @returns A wrapped route handler function
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * // app/api/users/route.ts
132
+ * import { withRouteHandler } from "@deeptracer/nextjs"
133
+ * import { logger } from "@/instrumentation"
134
+ *
135
+ * export const GET = withRouteHandler(logger, "GET /api/users", async (request) => {
136
+ * const users = await db.user.findMany()
137
+ * return Response.json(users)
138
+ * })
139
+ *
140
+ * export const POST = withRouteHandler(logger, "POST /api/users", async (request) => {
141
+ * const body = await request.json()
142
+ * const user = await db.user.create({ data: body })
143
+ * return Response.json(user, { status: 201 })
144
+ * })
145
+ * ```
146
+ */
147
+ declare function withRouteHandler(logger: Logger, name: string, handler: (request: Request) => Promise<Response>): (request: Request) => Promise<Response>;
148
+
149
+ export { type InitResult, type NextjsConfig, init, withRouteHandler, withServerAction };
package/dist/index.js CHANGED
@@ -1,2 +1,136 @@
1
1
  // src/index.ts
2
2
  export * from "@deeptracer/node";
3
+
4
+ // src/init.ts
5
+ import { createLogger } from "@deeptracer/core";
6
+ function init(config) {
7
+ const logger = createLogger(config);
8
+ const shouldCaptureGlobalErrors = config.captureGlobalErrors !== false;
9
+ const shouldCaptureConsole = config.captureConsole === true;
10
+ function register() {
11
+ const runtime = typeof process !== "undefined" ? process.env?.NEXT_RUNTIME : void 0;
12
+ if (runtime === "nodejs") {
13
+ if (shouldCaptureGlobalErrors) {
14
+ process.on("uncaughtException", (error) => {
15
+ logger.captureError(error, {
16
+ severity: "critical",
17
+ context: { source: "uncaughtException", runtime: "nodejs" }
18
+ });
19
+ logger.flush();
20
+ });
21
+ process.on("unhandledRejection", (reason) => {
22
+ logger.captureError(
23
+ reason instanceof Error ? reason : new Error(String(reason)),
24
+ {
25
+ severity: "high",
26
+ context: { source: "unhandledRejection", runtime: "nodejs" }
27
+ }
28
+ );
29
+ logger.flush();
30
+ });
31
+ }
32
+ if (shouldCaptureConsole) {
33
+ const origLog = console.log;
34
+ const origInfo = console.info;
35
+ const origWarn = console.warn;
36
+ const origError = console.error;
37
+ const origDebug = console.debug;
38
+ console.log = (...args) => {
39
+ logger.info(args.map(String).join(" "));
40
+ origLog(...args);
41
+ };
42
+ console.info = (...args) => {
43
+ logger.info(args.map(String).join(" "));
44
+ origInfo(...args);
45
+ };
46
+ console.warn = (...args) => {
47
+ logger.warn(args.map(String).join(" "));
48
+ origWarn(...args);
49
+ };
50
+ console.error = (...args) => {
51
+ logger.error(args.map(String).join(" "));
52
+ origError(...args);
53
+ };
54
+ console.debug = (...args) => {
55
+ logger.debug(args.map(String).join(" "));
56
+ origDebug(...args);
57
+ };
58
+ }
59
+ logger.info("DeepTracer initialized", {
60
+ runtime: "nodejs",
61
+ product: config.product,
62
+ service: config.service
63
+ });
64
+ } else if (runtime === "edge") {
65
+ logger.info("DeepTracer initialized", {
66
+ runtime: "edge",
67
+ product: config.product,
68
+ service: config.service
69
+ });
70
+ }
71
+ }
72
+ async function onRequestError(err, request, context) {
73
+ const reqLogger = logger.withContext(
74
+ `${context.routeType}:${context.routePath}`
75
+ );
76
+ reqLogger.addBreadcrumb({
77
+ type: "http",
78
+ message: `${request.method} ${request.path}`
79
+ });
80
+ reqLogger.captureError(err, {
81
+ severity: "high",
82
+ context: {
83
+ source: "nextjs-onRequestError",
84
+ method: request.method,
85
+ path: request.path,
86
+ routerKind: context.routerKind,
87
+ routePath: context.routePath,
88
+ routeType: context.routeType
89
+ }
90
+ });
91
+ }
92
+ return { register, onRequestError, logger };
93
+ }
94
+
95
+ // src/server-action.ts
96
+ async function withServerAction(logger, name, fn) {
97
+ return logger.startSpan(`server-action:${name}`, async () => {
98
+ try {
99
+ return await fn();
100
+ } catch (error) {
101
+ logger.captureError(error, {
102
+ severity: "high",
103
+ context: { source: "server-action", action: name }
104
+ });
105
+ throw error;
106
+ }
107
+ });
108
+ }
109
+
110
+ // src/route-handler.ts
111
+ function withRouteHandler(logger, name, handler) {
112
+ return async (request) => {
113
+ const reqLogger = logger.forRequest(request);
114
+ return reqLogger.startSpan(`route:${name}`, async () => {
115
+ try {
116
+ return await handler(request);
117
+ } catch (error) {
118
+ reqLogger.captureError(error, {
119
+ severity: "high",
120
+ context: {
121
+ source: "route-handler",
122
+ route: name,
123
+ method: request.method,
124
+ url: request.url
125
+ }
126
+ });
127
+ throw error;
128
+ }
129
+ });
130
+ };
131
+ }
132
+ export {
133
+ init,
134
+ withRouteHandler,
135
+ withServerAction
136
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deeptracer/nextjs",
3
- "version": "0.2.0",
4
- "description": "DeepTracer Next.js integration — server and client instrumentation (coming soon)",
3
+ "version": "0.3.1",
4
+ "description": "DeepTracer Next.js integration — automatic server-side error capture with one-file setup",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
@@ -11,11 +11,16 @@
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js",
13
13
  "require": "./dist/index.cjs"
14
+ },
15
+ "./client": {
16
+ "types": "./dist/client.d.ts",
17
+ "import": "./dist/client.js",
18
+ "require": "./dist/client.cjs"
14
19
  }
15
20
  },
16
21
  "files": ["dist", "README.md"],
17
22
  "sideEffects": false,
18
- "keywords": ["deeptracer", "nextjs", "observability"],
23
+ "keywords": ["deeptracer", "nextjs", "observability", "error-tracking", "instrumentation"],
19
24
  "repository": {
20
25
  "type": "git",
21
26
  "url": "https://github.com/getdeeptracer/deeptracer-js.git",
@@ -23,11 +28,13 @@
23
28
  },
24
29
  "license": "MIT",
25
30
  "dependencies": {
26
- "@deeptracer/node": "0.2.0",
27
- "@deeptracer/react": "0.2.0"
31
+ "@deeptracer/node": "0.3.1",
32
+ "@deeptracer/react": "0.3.1"
28
33
  },
29
34
  "peerDependencies": {
30
- "next": ">=14"
35
+ "next": ">=14",
36
+ "react": ">=18",
37
+ "react-dom": ">=18"
31
38
  },
32
39
  "scripts": {
33
40
  "build": "tsup",