usetraceforge 0.1.4 → 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/README.md +39 -9
- package/dist/express.d.ts +6 -0
- package/dist/express.js +27 -0
- package/dist/index.js +41 -1
- package/dist/next.d.ts +1 -0
- package/dist/next.js +20 -0
- package/dist/react.d.ts +18 -0
- package/dist/react.js +33 -0
- package/package.json +25 -3
package/README.md
CHANGED
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
#
|
|
1
|
+
# usetraceforge
|
|
2
2
|
|
|
3
3
|
TraceForge JavaScript SDK for sending errors to your TraceForge backend.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install
|
|
8
|
+
npm install usetraceforge
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Local pack test
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
cd packages/sdk
|
|
15
|
+
npm run build
|
|
15
16
|
npm pack
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
Then in any local app:
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
|
-
npm install /path/to/
|
|
22
|
+
npm install /path/to/usetraceforge-0.1.4.tgz
|
|
22
23
|
```
|
|
23
24
|
|
|
24
|
-
##
|
|
25
|
+
## Frontend setup
|
|
25
26
|
```ts
|
|
26
|
-
import TraceForge from "
|
|
27
|
+
import TraceForge from "usetraceforge";
|
|
27
28
|
|
|
28
29
|
TraceForge.init({
|
|
29
30
|
apiKey: "YOUR_PROJECT_API_KEY",
|
|
30
31
|
endpoint: "http://localhost:3001/ingest",
|
|
31
32
|
autoCapture: true,
|
|
32
|
-
environment: "
|
|
33
|
+
environment: "production",
|
|
33
34
|
release: "web@1.0.0"
|
|
34
35
|
});
|
|
35
36
|
|
|
@@ -42,6 +43,37 @@ try {
|
|
|
42
43
|
}
|
|
43
44
|
```
|
|
44
45
|
|
|
46
|
+
## Backend setup
|
|
47
|
+
```ts
|
|
48
|
+
import express from "express";
|
|
49
|
+
import TraceForge from "usetraceforge";
|
|
50
|
+
|
|
51
|
+
TraceForge.init({
|
|
52
|
+
apiKey: process.env.TRACEFORGE_API_KEY!,
|
|
53
|
+
endpoint: process.env.TRACEFORGE_INGEST_URL,
|
|
54
|
+
environment: process.env.TRACEFORGE_ENV || "production",
|
|
55
|
+
release: process.env.TRACEFORGE_RELEASE || "api@1.0.0"
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const app = express();
|
|
59
|
+
|
|
60
|
+
app.use((error: unknown, _req, res, _next) => {
|
|
61
|
+
TraceForge.captureException(error, {
|
|
62
|
+
payload: { route: "express-error-handler" }
|
|
63
|
+
}).catch(() => undefined);
|
|
64
|
+
|
|
65
|
+
res.status(500).json({ error: "Internal server error" });
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Environment variables
|
|
70
|
+
```env
|
|
71
|
+
TRACEFORGE_INGEST_URL=http://localhost:3001/ingest
|
|
72
|
+
TRACEFORGE_API_KEY=YOUR_PROJECT_API_KEY
|
|
73
|
+
TRACEFORGE_ENV=production
|
|
74
|
+
TRACEFORGE_RELEASE=web@1.0.0
|
|
75
|
+
```
|
|
76
|
+
|
|
45
77
|
## Options
|
|
46
78
|
- `autoCapture`: Listen to `window.onerror` and `window.onunhandledrejection`.
|
|
47
79
|
- `ignoreErrors`: Array of strings or regex to skip noisy errors.
|
|
@@ -61,7 +93,5 @@ npm publish --access public
|
|
|
61
93
|
After publish, consumers can install it with:
|
|
62
94
|
|
|
63
95
|
```bash
|
|
64
|
-
npm install
|
|
96
|
+
npm install usetraceforge
|
|
65
97
|
```
|
|
66
|
-
|
|
67
|
-
If the unscoped npm name is unavailable, publish under a scoped package name and update the install line to match.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
/**
|
|
3
|
+
* Express middleware to catch unhandled errors and report them to TraceForge.
|
|
4
|
+
* Ensure this is added AFTER all your routes and controllers, but BEFORE your custom error handler.
|
|
5
|
+
*/
|
|
6
|
+
export declare const TraceForgeErrorHandler: (error: Error, req: Request, res: Response, next: NextFunction) => void;
|
package/dist/express.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import TraceForge from "./index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Express middleware to catch unhandled errors and report them to TraceForge.
|
|
4
|
+
* Ensure this is added AFTER all your routes and controllers, but BEFORE your custom error handler.
|
|
5
|
+
*/
|
|
6
|
+
export const TraceForgeErrorHandler = (error, req, res, next) => {
|
|
7
|
+
TraceForge.captureException(error, {
|
|
8
|
+
environment: "node",
|
|
9
|
+
tags: {
|
|
10
|
+
method: req.method,
|
|
11
|
+
url: req.url,
|
|
12
|
+
path: req.path,
|
|
13
|
+
ip: req.ip || "Unknown"
|
|
14
|
+
},
|
|
15
|
+
payload: {
|
|
16
|
+
query: req.query,
|
|
17
|
+
body: req.body,
|
|
18
|
+
headers: {
|
|
19
|
+
...req.headers,
|
|
20
|
+
authorization: req.headers.authorization ? "[REDACTED]" : undefined,
|
|
21
|
+
cookie: req.headers.cookie ? "[REDACTED]" : undefined
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}).catch(() => undefined);
|
|
25
|
+
// Pass the error to the next error handler
|
|
26
|
+
next(error);
|
|
27
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
let config = null;
|
|
2
2
|
let autoCaptureInitialized = false;
|
|
3
|
+
let setupHandshakeSent = false;
|
|
3
4
|
const defaultEndpoint = "http://localhost:3001/ingest";
|
|
5
|
+
const getIngestEndpoint = () => config?.endpoint || defaultEndpoint;
|
|
6
|
+
const getSetupEndpoint = () => {
|
|
7
|
+
const endpoint = getIngestEndpoint();
|
|
8
|
+
const normalized = endpoint.replace(/\/+$/, "");
|
|
9
|
+
if (normalized.endsWith("/setup")) {
|
|
10
|
+
return normalized;
|
|
11
|
+
}
|
|
12
|
+
return `${normalized}/setup`;
|
|
13
|
+
};
|
|
4
14
|
const ensureConfig = () => {
|
|
5
15
|
if (!config) {
|
|
6
16
|
throw new Error("TraceForge not initialized. Call TraceForge.init({ apiKey }) first.");
|
|
@@ -52,7 +62,7 @@ const sendEvent = async (event) => {
|
|
|
52
62
|
if (!processed) {
|
|
53
63
|
return;
|
|
54
64
|
}
|
|
55
|
-
await fetch(
|
|
65
|
+
await fetch(getIngestEndpoint(), {
|
|
56
66
|
method: "POST",
|
|
57
67
|
headers: {
|
|
58
68
|
"Content-Type": "application/json",
|
|
@@ -66,6 +76,29 @@ const capture = async (error, extras) => {
|
|
|
66
76
|
const event = buildEvent(error, extras);
|
|
67
77
|
await sendEvent(event);
|
|
68
78
|
};
|
|
79
|
+
const sendSetupHandshake = async () => {
|
|
80
|
+
if (!config?.apiKey || setupHandshakeSent) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
setupHandshakeSent = true;
|
|
84
|
+
try {
|
|
85
|
+
await fetch(getSetupEndpoint(), {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/json",
|
|
89
|
+
"X-Traceforge-Key": config.apiKey
|
|
90
|
+
},
|
|
91
|
+
body: JSON.stringify({
|
|
92
|
+
environment: config.environment,
|
|
93
|
+
release: config.release,
|
|
94
|
+
tags: config.tags
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
setupHandshakeSent = false;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
69
102
|
const setupAutoCapture = () => {
|
|
70
103
|
if (autoCaptureInitialized)
|
|
71
104
|
return;
|
|
@@ -88,11 +121,18 @@ const setupAutoCapture = () => {
|
|
|
88
121
|
};
|
|
89
122
|
const TraceForge = {
|
|
90
123
|
init: (options) => {
|
|
124
|
+
const previousApiKey = config?.apiKey ?? null;
|
|
125
|
+
const previousEndpoint = config?.endpoint ?? defaultEndpoint;
|
|
91
126
|
config = {
|
|
92
127
|
endpoint: defaultEndpoint,
|
|
93
128
|
autoCapture: false,
|
|
94
129
|
...options
|
|
95
130
|
};
|
|
131
|
+
const currentEndpoint = config.endpoint || defaultEndpoint;
|
|
132
|
+
if (previousApiKey !== config.apiKey || previousEndpoint !== currentEndpoint) {
|
|
133
|
+
setupHandshakeSent = false;
|
|
134
|
+
}
|
|
135
|
+
void sendSetupHandshake();
|
|
96
136
|
if (config.autoCapture) {
|
|
97
137
|
setupAutoCapture();
|
|
98
138
|
}
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function withTraceForge(handler: Function): (...args: any[]) => Promise<any>;
|
package/dist/next.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import TraceForge from "./index.js";
|
|
2
|
+
// A wrapper for Next.js API Routes (App Router or Pages Router)
|
|
3
|
+
export function withTraceForge(handler) {
|
|
4
|
+
return async function (...args) {
|
|
5
|
+
try {
|
|
6
|
+
return await handler(...args);
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
// Catch Next.js serverless API errors
|
|
10
|
+
await TraceForge.captureException(error, {
|
|
11
|
+
environment: "node",
|
|
12
|
+
tags: {
|
|
13
|
+
runtime: "nextjs-api"
|
|
14
|
+
}
|
|
15
|
+
}).catch(() => undefined);
|
|
16
|
+
// Re-throw so Next.js can handle the 500 response natively
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { Component, ErrorInfo, ReactNode } from "react";
|
|
2
|
+
interface Props {
|
|
3
|
+
children?: ReactNode;
|
|
4
|
+
fallback?: ReactNode | ((error: Error) => ReactNode);
|
|
5
|
+
environment?: string;
|
|
6
|
+
release?: string;
|
|
7
|
+
}
|
|
8
|
+
interface State {
|
|
9
|
+
hasError: boolean;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
}
|
|
12
|
+
export declare class TraceForgeErrorBoundary extends Component<Props, State> {
|
|
13
|
+
state: State;
|
|
14
|
+
static getDerivedStateFromError(error: Error): State;
|
|
15
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
16
|
+
render(): React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Component } from "react";
|
|
2
|
+
import TraceForge from "./index.js";
|
|
3
|
+
export class TraceForgeErrorBoundary extends Component {
|
|
4
|
+
state = {
|
|
5
|
+
hasError: false,
|
|
6
|
+
error: null
|
|
7
|
+
};
|
|
8
|
+
static getDerivedStateFromError(error) {
|
|
9
|
+
return { hasError: true, error };
|
|
10
|
+
}
|
|
11
|
+
componentDidCatch(error, errorInfo) {
|
|
12
|
+
TraceForge.captureException(error, {
|
|
13
|
+
environment: this.props.environment || "browser",
|
|
14
|
+
release: this.props.release,
|
|
15
|
+
tags: {
|
|
16
|
+
componentStack: errorInfo.componentStack || "Unknown"
|
|
17
|
+
}
|
|
18
|
+
}).catch(() => undefined);
|
|
19
|
+
}
|
|
20
|
+
render() {
|
|
21
|
+
if (this.state.hasError && this.state.error) {
|
|
22
|
+
if (typeof this.props.fallback === "function") {
|
|
23
|
+
return this.props.fallback(this.state.error);
|
|
24
|
+
}
|
|
25
|
+
if (this.props.fallback) {
|
|
26
|
+
return this.props.fallback;
|
|
27
|
+
}
|
|
28
|
+
// Default fallback if nothing is provided
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return this.props.children;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usetraceforge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "TraceForge JavaScript SDK for sending errors to a TraceForge ingest endpoint.",
|
|
6
6
|
"type": "module",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "https://github.com/khushalp2004/TraceForge.git",
|
|
12
|
+
"url": "git+https://github.com/khushalp2004/TraceForge.git",
|
|
13
13
|
"directory": "packages/sdk"
|
|
14
14
|
},
|
|
15
15
|
"homepage": "https://usetraceforge.com/docs",
|
|
@@ -28,6 +28,18 @@
|
|
|
28
28
|
".": {
|
|
29
29
|
"types": "./dist/index.d.ts",
|
|
30
30
|
"import": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./react": {
|
|
33
|
+
"types": "./dist/react.d.ts",
|
|
34
|
+
"import": "./dist/react.js"
|
|
35
|
+
},
|
|
36
|
+
"./express": {
|
|
37
|
+
"types": "./dist/express.d.ts",
|
|
38
|
+
"import": "./dist/express.js"
|
|
39
|
+
},
|
|
40
|
+
"./next": {
|
|
41
|
+
"types": "./dist/next.d.ts",
|
|
42
|
+
"import": "./dist/next.js"
|
|
31
43
|
}
|
|
32
44
|
},
|
|
33
45
|
"files": [
|
|
@@ -47,6 +59,16 @@
|
|
|
47
59
|
"dependencies": {},
|
|
48
60
|
"devDependencies": {
|
|
49
61
|
"typescript": "^5.5.4",
|
|
50
|
-
"tsx": "^4.16.2"
|
|
62
|
+
"tsx": "^4.16.2",
|
|
63
|
+
"@types/react": "^18.2.0",
|
|
64
|
+
"@types/express": "^4.17.21"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"react": ">=16.8.0",
|
|
68
|
+
"express": ">=4.0.0"
|
|
69
|
+
},
|
|
70
|
+
"peerDependenciesMeta": {
|
|
71
|
+
"react": { "optional": true },
|
|
72
|
+
"express": { "optional": true }
|
|
51
73
|
}
|
|
52
74
|
}
|