@watchforge/browser 0.1.3 → 0.1.5
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/CONFIGURATION_GUIDE.md +271 -10
- package/README.md +157 -1
- package/bin/watchforge.js +284 -0
- package/package.json +38 -5
- package/src/client.js +30 -0
- package/src/express.d.ts +12 -0
- package/src/index.d.ts +41 -0
- package/src/index.js +1 -2
- package/src/next-server.d.ts +26 -0
- package/src/next-server.js +58 -0
- package/src/next.d.ts +11 -0
- package/src/next.js +12 -0
- package/src/react.d.ts +8 -0
- package/src/replay.js +128 -0
- package/src/stacktrace.js +185 -7
- package/src/tracing.d.ts +39 -0
- package/src/transport.js +45 -3
package/CONFIGURATION_GUIDE.md
CHANGED
|
@@ -2,10 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
The WatchForge JavaScript SDK
|
|
5
|
+
The WatchForge JavaScript SDK is one npm package with typed framework entry points for:
|
|
6
|
+
|
|
7
|
+
- **Browser JavaScript** applications
|
|
8
|
+
- **Next.js** App Router applications
|
|
9
|
+
- **React** frontend applications
|
|
6
10
|
- **Node.js** applications
|
|
7
11
|
- **Express.js** web servers
|
|
8
|
-
|
|
12
|
+
|
|
13
|
+
This package intentionally stays unified instead of splitting into separate `watchforge-next-sdk`, `watchforge-node-sdk`, `watchforge-react-sdk`, and `watchforge-express-sdk` packages. The shared package keeps DSN handling, event transport, breadcrumbs, stack traces, source context, and session replay consistent across JavaScript runtimes.
|
|
14
|
+
|
|
15
|
+
## Supported Imports
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// Browser JavaScript, React client, and shared APIs
|
|
19
|
+
import { register, captureException, captureMessage } from "@watchforge/browser";
|
|
20
|
+
|
|
21
|
+
// Next.js App Router client provider
|
|
22
|
+
import { WatchForgeProvider } from "@watchforge/browser/next";
|
|
23
|
+
|
|
24
|
+
// Next.js server route handlers
|
|
25
|
+
import { withWatchForgeRouteHandler } from "@watchforge/browser/next/server";
|
|
26
|
+
|
|
27
|
+
// React error boundary
|
|
28
|
+
import { ErrorBoundary } from "@watchforge/browser/react";
|
|
29
|
+
|
|
30
|
+
// Express middleware
|
|
31
|
+
import {
|
|
32
|
+
expressRequestMiddleware,
|
|
33
|
+
expressMiddleware,
|
|
34
|
+
} from "@watchforge/browser/express";
|
|
35
|
+
|
|
36
|
+
// Explicit Node.js import
|
|
37
|
+
import { register as registerNode } from "@watchforge/browser/node";
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Support Matrix
|
|
41
|
+
|
|
42
|
+
| Runtime / Framework | Entry point | Recommended setup |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| Browser JavaScript | `@watchforge/browser` | Call `register()` once in the main browser bundle |
|
|
45
|
+
| React | `@watchforge/browser` + `@watchforge/browser/react` | Call `register()` once and wrap the app with `ErrorBoundary` |
|
|
46
|
+
| Next.js App Router client | `@watchforge/browser/next` | Use the wizard or render `WatchForgeProvider` from a client component |
|
|
47
|
+
| Next.js App Router server | `@watchforge/browser/next/server` | Wrap route handlers with `withWatchForgeRouteHandler()` |
|
|
48
|
+
| Node.js | `@watchforge/browser/node` | Call `register()` once during process startup |
|
|
49
|
+
| Express.js | `@watchforge/browser/express` | Add request middleware before routes and error middleware after routes |
|
|
9
50
|
|
|
10
51
|
## Installation
|
|
11
52
|
|
|
@@ -64,8 +105,39 @@ npm install ../watchforge-javascript-sdk
|
|
|
64
105
|
```
|
|
65
106
|
|
|
66
107
|
After installation, use it the same way:
|
|
67
|
-
```
|
|
68
|
-
import { register
|
|
108
|
+
```ts
|
|
109
|
+
import { register } from "@watchforge/browser";
|
|
110
|
+
import { ErrorBoundary } from "@watchforge/browser/react";
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Next.js Wizard Setup
|
|
114
|
+
|
|
115
|
+
From your Next.js project root:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx @watchforge/browser -i nextjs --dsn "https://PUBLIC_KEY@dev.watchforges.com/PROJECT_ID" --app-env production
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
With error-triggered Session Replay:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npx @watchforge/browser -i nextjs \
|
|
125
|
+
--dsn "https://PUBLIC_KEY@dev.watchforges.com/PROJECT_ID" \
|
|
126
|
+
--app-env production \
|
|
127
|
+
--replays-on-error 1
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The wizard:
|
|
131
|
+
|
|
132
|
+
1. Installs `@watchforge/browser`
|
|
133
|
+
2. Creates `watchforge.config.ts`
|
|
134
|
+
3. Creates `app/watchforge-init.tsx` (or `src/app/.../watchforge-init.tsx`)
|
|
135
|
+
4. Patches `app/layout.tsx` to render `<WatchForgeInit />`
|
|
136
|
+
|
|
137
|
+
If you only want file generation and no package install:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx @watchforge/browser -i nextjs --dsn "..." --skip-install
|
|
69
141
|
```
|
|
70
142
|
|
|
71
143
|
## Quick Testing
|
|
@@ -158,11 +230,92 @@ See the React setup section below for complete examples.
|
|
|
158
230
|
|
|
159
231
|
## Quick Start
|
|
160
232
|
|
|
233
|
+
### Browser JavaScript
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
import { register } from "@watchforge/browser";
|
|
237
|
+
|
|
238
|
+
register({
|
|
239
|
+
dsn: "https://PUBLIC_KEY@watchforge.io/PROJECT_ID",
|
|
240
|
+
app_env: "production",
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
This captures uncaught browser errors, unhandled promise rejections, breadcrumbs, page context, browser/device/OS details, and performance context.
|
|
245
|
+
|
|
246
|
+
### Next.js App Router
|
|
247
|
+
|
|
248
|
+
Create `watchforge.config.ts` in your project root:
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
export const watchforgeConfig = {
|
|
252
|
+
dsn: "https://PUBLIC_KEY@watchforge.io/PROJECT_ID",
|
|
253
|
+
app_env: "production",
|
|
254
|
+
replaysOnErrorSampleRate: 1,
|
|
255
|
+
maskAllInputs: true,
|
|
256
|
+
};
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Create a client init component beside your frontend layout, for example `src/app/watchforge-init.tsx` or `src/app/(frontend)/watchforge-init.tsx`:
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
"use client";
|
|
263
|
+
|
|
264
|
+
import { WatchForgeProvider } from "@watchforge/browser/next";
|
|
265
|
+
import { watchforgeConfig } from "../watchforge.config";
|
|
266
|
+
|
|
267
|
+
export default function WatchForgeInit() {
|
|
268
|
+
return <WatchForgeProvider options={watchforgeConfig} />;
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Render it once in the matching `layout.tsx`:
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
import WatchForgeInit from "./watchforge-init";
|
|
276
|
+
|
|
277
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
278
|
+
return (
|
|
279
|
+
<html lang="en">
|
|
280
|
+
<body>
|
|
281
|
+
<WatchForgeInit />
|
|
282
|
+
{children}
|
|
283
|
+
</body>
|
|
284
|
+
</html>
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
For route-group projects like `src/app/(frontend)/layout.tsx`, put `watchforge-init.tsx` in that same route group and adjust the config import path if needed.
|
|
290
|
+
|
|
291
|
+
For Next.js route handlers, use the server entry point:
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
// app/api/example/route.ts
|
|
295
|
+
import {
|
|
296
|
+
register,
|
|
297
|
+
withWatchForgeRouteHandler,
|
|
298
|
+
} from "@watchforge/browser/next/server";
|
|
299
|
+
|
|
300
|
+
register({
|
|
301
|
+
dsn: "https://PUBLIC_KEY@watchforge.io/PROJECT_ID",
|
|
302
|
+
app_env: "production",
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
export const GET = withWatchForgeRouteHandler(async () => {
|
|
306
|
+
throw new Error("Next.js API route test error");
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
161
310
|
### 1. Node.js Application
|
|
162
311
|
|
|
163
|
-
```
|
|
312
|
+
```ts
|
|
164
313
|
// app.js
|
|
165
|
-
|
|
314
|
+
import {
|
|
315
|
+
register,
|
|
316
|
+
captureException,
|
|
317
|
+
captureMessage,
|
|
318
|
+
} from "@watchforge/browser/node";
|
|
166
319
|
|
|
167
320
|
// Initialize SDK
|
|
168
321
|
// API URL is automatically derived from DSN host
|
|
@@ -184,10 +337,14 @@ captureMessage("User logged in", "info");
|
|
|
184
337
|
|
|
185
338
|
### 2. Express.js Application
|
|
186
339
|
|
|
187
|
-
```
|
|
340
|
+
```ts
|
|
188
341
|
// server.js
|
|
189
|
-
|
|
190
|
-
|
|
342
|
+
import express from "express";
|
|
343
|
+
import { register } from "@watchforge/browser/node";
|
|
344
|
+
import {
|
|
345
|
+
expressRequestMiddleware,
|
|
346
|
+
expressMiddleware,
|
|
347
|
+
} from "@watchforge/browser/express";
|
|
191
348
|
|
|
192
349
|
const app = express();
|
|
193
350
|
|
|
@@ -710,7 +867,11 @@ try {
|
|
|
710
867
|
```javascript
|
|
711
868
|
// server.js
|
|
712
869
|
const express = require('express');
|
|
713
|
-
const {
|
|
870
|
+
const {
|
|
871
|
+
register,
|
|
872
|
+
expressRequestMiddleware,
|
|
873
|
+
expressMiddleware,
|
|
874
|
+
} = require('@watchforge/browser');
|
|
714
875
|
|
|
715
876
|
const app = express();
|
|
716
877
|
|
|
@@ -719,6 +880,12 @@ register({
|
|
|
719
880
|
app_env: process.env.NODE_ENV,
|
|
720
881
|
});
|
|
721
882
|
|
|
883
|
+
app.use(express.json());
|
|
884
|
+
app.use(expressRequestMiddleware());
|
|
885
|
+
app.use(expressRequestMiddleware());
|
|
886
|
+
|
|
887
|
+
// routes here
|
|
888
|
+
|
|
722
889
|
// Add error handler (must be last middleware)
|
|
723
890
|
app.use(expressMiddleware());
|
|
724
891
|
|
|
@@ -735,6 +902,11 @@ import App from './App';
|
|
|
735
902
|
register({
|
|
736
903
|
dsn: process.env.REACT_APP_WATCHFORGE_DSN,
|
|
737
904
|
app_env: process.env.NODE_ENV,
|
|
905
|
+
// Optional: upload the last 60s of masked browser replay events when an error occurs.
|
|
906
|
+
replaysOnErrorSampleRate: 1.0,
|
|
907
|
+
// Optional: continuously sample full sessions. Keep 0 in production unless you need it.
|
|
908
|
+
replaysSessionSampleRate: 0,
|
|
909
|
+
maskAllInputs: true,
|
|
738
910
|
});
|
|
739
911
|
|
|
740
912
|
ReactDOM.render(
|
|
@@ -745,6 +917,95 @@ ReactDOM.render(
|
|
|
745
917
|
);
|
|
746
918
|
```
|
|
747
919
|
|
|
920
|
+
## Stack Trace Source Context
|
|
921
|
+
|
|
922
|
+
The SDK enriches stack frames with Python-style source context when possible:
|
|
923
|
+
|
|
924
|
+
| Field | Description |
|
|
925
|
+
|-------|-------------|
|
|
926
|
+
| `context_line` | The exact line where the error occurred |
|
|
927
|
+
| `pre_context` | Up to 5 lines before the error |
|
|
928
|
+
| `post_context` | Up to 5 lines after the error |
|
|
929
|
+
|
|
930
|
+
### Node.js / Express
|
|
931
|
+
|
|
932
|
+
For local project files, the SDK reads source from disk and attaches context lines automatically. No extra configuration is required.
|
|
933
|
+
|
|
934
|
+
### Browser (development)
|
|
935
|
+
|
|
936
|
+
In dev builds (Next.js, Vite, etc.), the SDK attempts to fetch same-origin script URLs from the stack trace and slice source lines around the reported line number.
|
|
937
|
+
|
|
938
|
+
Works when stack frames point to readable URLs such as:
|
|
939
|
+
|
|
940
|
+
```txt
|
|
941
|
+
http://localhost:3000/_next/static/chunks/...
|
|
942
|
+
http://localhost:3000/src/App.tsx
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
### Browser (production / minified bundles)
|
|
946
|
+
|
|
947
|
+
Production bundles often report locations like:
|
|
948
|
+
|
|
949
|
+
```txt
|
|
950
|
+
https://your-app.com/_next/static/chunks/app-abc123.js:1:98432
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
The SDK still sends filename, line, and column, but **cannot** show original TypeScript/JSX source without **source maps**.
|
|
954
|
+
|
|
955
|
+
**Current status:** source map upload and symbolication are not yet supported (planned for a future release).
|
|
956
|
+
|
|
957
|
+
**Workarounds today:**
|
|
958
|
+
|
|
959
|
+
1. Test with `npm run dev` / unminified builds to see source lines in WatchForge.
|
|
960
|
+
2. Use `release` in `register()` so issues are grouped by deploy version.
|
|
961
|
+
3. Rely on breadcrumbs and the Browser Event Summary in the dashboard to understand user actions before the error.
|
|
962
|
+
|
|
963
|
+
When source map support ships, you will upload maps during deploy and WatchForge will resolve minified frames back to original files.
|
|
964
|
+
|
|
965
|
+
## Session Replay
|
|
966
|
+
|
|
967
|
+
The browser SDK can record a Sentry-style DOM replay using `rrweb`. Replays are **not videos**; they are masked DOM snapshots and incremental browser events that WatchForge can play back in the Issue Detail page.
|
|
968
|
+
|
|
969
|
+
Enable replay capture when registering the SDK:
|
|
970
|
+
|
|
971
|
+
```javascript
|
|
972
|
+
register({
|
|
973
|
+
dsn: "https://PUBLIC_KEY@dev.watchforges.com/PROJECT_ID",
|
|
974
|
+
app_env: "production",
|
|
975
|
+
replaysOnErrorSampleRate: 1.0,
|
|
976
|
+
replaysSessionSampleRate: 0,
|
|
977
|
+
maskAllInputs: true,
|
|
978
|
+
});
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
Replay behavior:
|
|
982
|
+
|
|
983
|
+
- `replaysOnErrorSampleRate`: records in buffer mode and uploads the last 60 seconds when an error is captured.
|
|
984
|
+
- `replaysSessionSampleRate`: continuously samples full browser sessions.
|
|
985
|
+
- Text/input privacy is handled in the browser before upload.
|
|
986
|
+
- Password, email, tel and text inputs are masked when `maskAllInputs` is true.
|
|
987
|
+
- Elements with `.rr-block` are blocked.
|
|
988
|
+
- Elements with `.rr-ignore` ignore input events.
|
|
989
|
+
- Elements with `.rr-mask` mask text.
|
|
990
|
+
|
|
991
|
+
When an error is captured, the SDK attaches:
|
|
992
|
+
|
|
993
|
+
```json
|
|
994
|
+
{
|
|
995
|
+
"replay_id": "...",
|
|
996
|
+
"session_id": "...",
|
|
997
|
+
"contexts": {
|
|
998
|
+
"replay": {
|
|
999
|
+
"replay_id": "...",
|
|
1000
|
+
"session_id": "...",
|
|
1001
|
+
"sampled": true
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
The dashboard shows the linked replay in the Issue Detail **Session Replay** tab.
|
|
1008
|
+
|
|
748
1009
|
## Test Scripts
|
|
749
1010
|
|
|
750
1011
|
Test scripts are included in the SDK directory:
|
package/README.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# WatchForge JavaScript SDK (`@watchforge/browser`)
|
|
2
2
|
|
|
3
|
-
Browser
|
|
3
|
+
Browser, Next.js, React, Node.js, and Express SDK for WatchForge. **One call to `register()`** turns on automatic error reporting for typical crashes, and framework entry points add richer context where needed.
|
|
4
|
+
|
|
5
|
+
## Runtime Support
|
|
6
|
+
|
|
7
|
+
| Runtime / Framework | Import | What it captures |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Browser JavaScript | `@watchforge/browser` | Uncaught errors, unhandled promise rejections, breadcrumbs, browser/device/page/performance context |
|
|
10
|
+
| React | `@watchforge/browser` + `@watchforge/browser/react` | Browser errors plus React `ErrorBoundary` component stack context |
|
|
11
|
+
| Next.js App Router | `@watchforge/browser/next` | Client-side Next.js errors through a client provider; wizard patches the app layout |
|
|
12
|
+
| Node.js | `@watchforge/browser` or `@watchforge/browser/node` | `uncaughtException`, `unhandledRejection`, Node runtime/server context |
|
|
13
|
+
| Express.js | `@watchforge/browser/express` | Express request errors, request URL/method/headers/body/query, user/IP, route, duration |
|
|
14
|
+
|
|
15
|
+
The package is intentionally shipped as **one npm package** with typed subpath exports instead of separate SDK packages. This keeps DSN setup, replay, stack traces, breadcrumbs, and event transport consistent across JavaScript runtimes.
|
|
4
16
|
|
|
5
17
|
## What this package does *not* require
|
|
6
18
|
|
|
@@ -18,6 +30,150 @@ Browser and Node SDK for WatchForge. **One call to `register()`** turns on autom
|
|
|
18
30
|
npm install @watchforge/browser
|
|
19
31
|
```
|
|
20
32
|
|
|
33
|
+
## Next.js one-line setup
|
|
34
|
+
|
|
35
|
+
For Next.js apps, run the setup wizard from your app root:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @watchforge/browser -i nextjs --dsn "https://PUBLIC_KEY@your-host/PROJECT_ID" --app-env production
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
With Session Replay on errors:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx @watchforge/browser -i nextjs \
|
|
45
|
+
--dsn "https://PUBLIC_KEY@your-host/PROJECT_ID" \
|
|
46
|
+
--app-env production \
|
|
47
|
+
--replays-on-error 1
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The wizard installs `@watchforge/browser`, writes `watchforge.config.ts`, creates a client init component, and patches `app/layout.tsx` or `pages/_app.tsx`.
|
|
51
|
+
|
|
52
|
+
## Framework Imports
|
|
53
|
+
|
|
54
|
+
WatchForge ships as one JavaScript SDK package with typed framework entry points:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// Browser / React client / Node global handlers
|
|
58
|
+
import { register } from "@watchforge/browser";
|
|
59
|
+
|
|
60
|
+
// Next.js App Router client provider
|
|
61
|
+
import { WatchForgeProvider } from "@watchforge/browser/next";
|
|
62
|
+
|
|
63
|
+
// Next.js App Router server route helper
|
|
64
|
+
import { withWatchForgeRouteHandler } from "@watchforge/browser/next/server";
|
|
65
|
+
|
|
66
|
+
// React error boundary
|
|
67
|
+
import { ErrorBoundary } from "@watchforge/browser/react";
|
|
68
|
+
|
|
69
|
+
// Express middleware
|
|
70
|
+
import {
|
|
71
|
+
expressRequestMiddleware,
|
|
72
|
+
expressMiddleware,
|
|
73
|
+
} from "@watchforge/browser/express";
|
|
74
|
+
|
|
75
|
+
// Optional explicit Node import
|
|
76
|
+
import { captureException } from "@watchforge/browser/node";
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Next.js Manual Setup
|
|
80
|
+
|
|
81
|
+
Use the wizard when possible. For manual setup in App Router projects, create a client init component for browser-side errors:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
"use client";
|
|
85
|
+
|
|
86
|
+
import { WatchForgeProvider } from "@watchforge/browser/next";
|
|
87
|
+
import { watchforgeConfig } from "../watchforge.config";
|
|
88
|
+
|
|
89
|
+
export default function WatchForgeInit() {
|
|
90
|
+
return <WatchForgeProvider options={watchforgeConfig} />;
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then render it once in your frontend `layout.tsx`:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import WatchForgeInit from "./watchforge-init";
|
|
98
|
+
|
|
99
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
100
|
+
return (
|
|
101
|
+
<html lang="en">
|
|
102
|
+
<body>
|
|
103
|
+
<WatchForgeInit />
|
|
104
|
+
{children}
|
|
105
|
+
</body>
|
|
106
|
+
</html>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
For route groups, place the init component beside the frontend layout, for example `src/app/(frontend)/watchforge-init.tsx`, and import `watchforge.config.ts` using the correct relative path.
|
|
112
|
+
|
|
113
|
+
For server route handlers, initialize once in server code and wrap handlers:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import {
|
|
117
|
+
register,
|
|
118
|
+
withWatchForgeRouteHandler,
|
|
119
|
+
} from "@watchforge/browser/next/server";
|
|
120
|
+
|
|
121
|
+
register({
|
|
122
|
+
dsn: "https://PUBLIC_KEY@your-host/PROJECT_ID",
|
|
123
|
+
app_env: "production",
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export const GET = withWatchForgeRouteHandler(async () => {
|
|
127
|
+
throw new Error("Next.js route handler test error");
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Express Setup
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import express from "express";
|
|
135
|
+
import { register } from "@watchforge/browser/node";
|
|
136
|
+
import {
|
|
137
|
+
expressRequestMiddleware,
|
|
138
|
+
expressMiddleware,
|
|
139
|
+
} from "@watchforge/browser/express";
|
|
140
|
+
|
|
141
|
+
register({
|
|
142
|
+
dsn: "https://PUBLIC_KEY@your-host/PROJECT_ID",
|
|
143
|
+
app_env: "production",
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const app = express();
|
|
147
|
+
app.use(express.json());
|
|
148
|
+
app.use(expressRequestMiddleware());
|
|
149
|
+
|
|
150
|
+
app.get("/error", () => {
|
|
151
|
+
throw new Error("Express test error");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
app.use(expressMiddleware());
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## React Setup
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { register } from "@watchforge/browser";
|
|
161
|
+
import { ErrorBoundary } from "@watchforge/browser/react";
|
|
162
|
+
|
|
163
|
+
register({
|
|
164
|
+
dsn: "https://PUBLIC_KEY@your-host/PROJECT_ID",
|
|
165
|
+
app_env: "production",
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
export function AppRoot() {
|
|
169
|
+
return (
|
|
170
|
+
<ErrorBoundary fallback={<div>Something went wrong.</div>}>
|
|
171
|
+
<App />
|
|
172
|
+
</ErrorBoundary>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
21
177
|
## Quick start (all most apps need)
|
|
22
178
|
|
|
23
179
|
Call **`register()` once** as early as possible (e.g. app entry / main bundle), with your **DSN** from the WatchForge project settings.
|