jahiz-tracker 1.0.0
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/dist/index.cjs +359 -0
- package/dist/index.d.cts +166 -0
- package/dist/index.d.ts +166 -0
- package/dist/index.js +328 -0
- package/dist/react/index.cjs +150 -0
- package/dist/react/index.d.cts +93 -0
- package/dist/react/index.d.ts +93 -0
- package/dist/react/index.js +122 -0
- package/package.json +65 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
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
|
+
// index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
JahizErrorBoundary: () => JahizErrorBoundary_default,
|
|
24
|
+
JahizTracker: () => JahizTracker,
|
|
25
|
+
createJahizTracker: () => createJahizTracker,
|
|
26
|
+
getJahizTracker: () => getJahizTracker,
|
|
27
|
+
useJahizTracker: () => useJahizTracker
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// jahiz-tracker.ts
|
|
32
|
+
var JahizTracker = class {
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.user = {};
|
|
35
|
+
this.initialized = false;
|
|
36
|
+
this.config = {
|
|
37
|
+
captureGlobal: true,
|
|
38
|
+
collectDeviceInfo: true,
|
|
39
|
+
...config
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Initialize the tracker. Call once at app startup. */
|
|
43
|
+
init() {
|
|
44
|
+
if (this.initialized) return;
|
|
45
|
+
this.initialized = true;
|
|
46
|
+
if (this.config.captureGlobal && typeof window !== "undefined") {
|
|
47
|
+
window.addEventListener("error", (event) => {
|
|
48
|
+
this.captureError(event.error ?? event.message, {
|
|
49
|
+
metadata: {
|
|
50
|
+
source: "window.onerror",
|
|
51
|
+
filename: event.filename,
|
|
52
|
+
lineno: event.lineno,
|
|
53
|
+
colno: event.colno
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
58
|
+
const error = event.reason instanceof Error ? event.reason : new Error(String(event.reason));
|
|
59
|
+
this.captureError(error, {
|
|
60
|
+
metadata: { source: "unhandledrejection" }
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Set the current user context. Attached to all subsequent reports. */
|
|
66
|
+
setUser(user) {
|
|
67
|
+
this.user = user;
|
|
68
|
+
}
|
|
69
|
+
/** Clear user context (e.g. on logout). */
|
|
70
|
+
clearUser() {
|
|
71
|
+
this.user = {};
|
|
72
|
+
}
|
|
73
|
+
/** Capture an Error object or string message. */
|
|
74
|
+
async captureError(error, options = {}) {
|
|
75
|
+
const isError = error instanceof Error;
|
|
76
|
+
const message = isError ? error.message : String(error);
|
|
77
|
+
const stack = isError ? error.stack : void 0;
|
|
78
|
+
const parsed = stack ? this.parseStack(stack) : {};
|
|
79
|
+
const payload = this.buildPayload({
|
|
80
|
+
error_message: message,
|
|
81
|
+
severity: options.severity ?? "error",
|
|
82
|
+
error_type: isError ? error.name : void 0,
|
|
83
|
+
error_code: options.errorCode,
|
|
84
|
+
stacktrace: stack,
|
|
85
|
+
file_name: parsed.fileName,
|
|
86
|
+
line_number: parsed.lineNumber,
|
|
87
|
+
function_name: parsed.functionName,
|
|
88
|
+
component: options.component,
|
|
89
|
+
context: options.context,
|
|
90
|
+
user: { ...this.user, ...options.user },
|
|
91
|
+
tags: { ...this.config.defaultTags, ...options.tags },
|
|
92
|
+
metadata: options.metadata,
|
|
93
|
+
fingerprint: this.generateFingerprint(
|
|
94
|
+
isError ? error.name : "Error",
|
|
95
|
+
message,
|
|
96
|
+
parsed.fileName
|
|
97
|
+
)
|
|
98
|
+
});
|
|
99
|
+
return this.send(payload);
|
|
100
|
+
}
|
|
101
|
+
/** Report a custom error message (not from a thrown Error). */
|
|
102
|
+
async captureMessage(message, options = {}) {
|
|
103
|
+
const payload = this.buildPayload({
|
|
104
|
+
error_message: message,
|
|
105
|
+
severity: options.severity ?? "info",
|
|
106
|
+
error_code: options.errorCode,
|
|
107
|
+
component: options.component,
|
|
108
|
+
context: options.context,
|
|
109
|
+
user: { ...this.user, ...options.user },
|
|
110
|
+
tags: { ...this.config.defaultTags, ...options.tags },
|
|
111
|
+
metadata: options.metadata
|
|
112
|
+
});
|
|
113
|
+
return this.send(payload);
|
|
114
|
+
}
|
|
115
|
+
/** Wrap an async function so errors are automatically captured. */
|
|
116
|
+
wrap(fn, options = {}) {
|
|
117
|
+
const tracker = this;
|
|
118
|
+
return function(...args) {
|
|
119
|
+
try {
|
|
120
|
+
const result = fn.apply(this, args);
|
|
121
|
+
if (result instanceof Promise) {
|
|
122
|
+
return result.catch((err) => {
|
|
123
|
+
tracker.captureError(err, options);
|
|
124
|
+
throw err;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
} catch (err) {
|
|
129
|
+
tracker.captureError(err, options);
|
|
130
|
+
throw err;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// ─── Internal ────────────────────────────────────────────────────
|
|
135
|
+
buildPayload(partial) {
|
|
136
|
+
const payload = {
|
|
137
|
+
error_message: partial.error_message ?? "Unknown error",
|
|
138
|
+
severity: partial.severity ?? "error",
|
|
139
|
+
...partial,
|
|
140
|
+
app_name: partial.app_name ?? this.config.appName,
|
|
141
|
+
app_version: partial.app_version ?? this.config.appVersion,
|
|
142
|
+
environment: partial.environment ?? this.config.environment,
|
|
143
|
+
service_name: partial.service_name ?? this.config.serviceName,
|
|
144
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
145
|
+
};
|
|
146
|
+
if (this.config.collectDeviceInfo && typeof window !== "undefined") {
|
|
147
|
+
payload.device = this.collectBrowserInfo();
|
|
148
|
+
}
|
|
149
|
+
return payload;
|
|
150
|
+
}
|
|
151
|
+
async send(payload) {
|
|
152
|
+
if (this.config.beforeSend) {
|
|
153
|
+
const result = this.config.beforeSend(payload);
|
|
154
|
+
if (result === false) return null;
|
|
155
|
+
payload = result;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const url = this.config.webhookUrl.replace(/\/$/, "");
|
|
159
|
+
const response = await fetch(`${url}/webhook/error`, {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers: {
|
|
162
|
+
"Content-Type": "application/json",
|
|
163
|
+
"X-Webhook-Secret": this.config.webhookSecret
|
|
164
|
+
},
|
|
165
|
+
body: JSON.stringify(payload)
|
|
166
|
+
});
|
|
167
|
+
if (!response.ok) {
|
|
168
|
+
console.error(
|
|
169
|
+
`[JahizTracker] Webhook returned ${response.status}:`,
|
|
170
|
+
await response.text()
|
|
171
|
+
);
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
return await response.json();
|
|
175
|
+
} catch (err) {
|
|
176
|
+
console.error("[JahizTracker] Failed to send error report:", err);
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
parseStack(stack) {
|
|
181
|
+
const lines = stack.split("\n").filter((l) => l.trim());
|
|
182
|
+
const frameLine = lines[1] ?? lines[0] ?? "";
|
|
183
|
+
const chromeMatch = frameLine.match(
|
|
184
|
+
/at\s+(.+?)\s+\((.+?):(\d+):\d+\)/
|
|
185
|
+
);
|
|
186
|
+
if (chromeMatch) {
|
|
187
|
+
return {
|
|
188
|
+
functionName: chromeMatch[1],
|
|
189
|
+
fileName: chromeMatch[2],
|
|
190
|
+
lineNumber: parseInt(chromeMatch[3], 10)
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const firefoxMatch = frameLine.match(/(.+?)@(.+?):(\d+):\d+/);
|
|
194
|
+
if (firefoxMatch) {
|
|
195
|
+
return {
|
|
196
|
+
functionName: firefoxMatch[1],
|
|
197
|
+
fileName: firefoxMatch[2],
|
|
198
|
+
lineNumber: parseInt(firefoxMatch[3], 10)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
collectBrowserInfo() {
|
|
204
|
+
const nav = typeof navigator !== "undefined" ? navigator : null;
|
|
205
|
+
if (!nav) return {};
|
|
206
|
+
return {
|
|
207
|
+
os: this.getOS(),
|
|
208
|
+
osVersion: nav.userAgent,
|
|
209
|
+
architecture: nav.userAgentData?.platform ?? nav.platform
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
getOS() {
|
|
213
|
+
const ua = navigator.userAgent;
|
|
214
|
+
if (ua.includes("Win")) return "Windows";
|
|
215
|
+
if (ua.includes("Mac")) return "macOS";
|
|
216
|
+
if (ua.includes("Linux")) return "Linux";
|
|
217
|
+
if (ua.includes("Android")) return "Android";
|
|
218
|
+
if (/iPhone|iPad|iPod/.test(ua)) return "iOS";
|
|
219
|
+
return "Unknown";
|
|
220
|
+
}
|
|
221
|
+
generateFingerprint(type, message, fileName) {
|
|
222
|
+
const raw = `${type}:${message}:${fileName ?? ""}`;
|
|
223
|
+
let hash = 0;
|
|
224
|
+
for (let i = 0; i < raw.length; i++) {
|
|
225
|
+
const char = raw.charCodeAt(i);
|
|
226
|
+
hash = (hash << 5) - hash + char;
|
|
227
|
+
hash |= 0;
|
|
228
|
+
}
|
|
229
|
+
return Math.abs(hash).toString(16);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
var instance = null;
|
|
233
|
+
function createJahizTracker(config) {
|
|
234
|
+
instance = new JahizTracker(config);
|
|
235
|
+
instance.init();
|
|
236
|
+
return instance;
|
|
237
|
+
}
|
|
238
|
+
function getJahizTracker() {
|
|
239
|
+
if (!instance) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
"[JahizTracker] Not initialized. Call createJahizTracker() first."
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
return instance;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// react/JahizErrorBoundary.tsx
|
|
248
|
+
var import_react = require("react");
|
|
249
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
250
|
+
var JahizErrorBoundary = class extends import_react.Component {
|
|
251
|
+
constructor(props) {
|
|
252
|
+
super(props);
|
|
253
|
+
this.reset = () => {
|
|
254
|
+
this.setState({ hasError: false, error: null });
|
|
255
|
+
};
|
|
256
|
+
this.state = { hasError: false, error: null };
|
|
257
|
+
}
|
|
258
|
+
static getDerivedStateFromError(error) {
|
|
259
|
+
return { hasError: true, error };
|
|
260
|
+
}
|
|
261
|
+
componentDidCatch(error, errorInfo) {
|
|
262
|
+
const tracker = getJahizTracker();
|
|
263
|
+
tracker.captureError(error, {
|
|
264
|
+
severity: "critical",
|
|
265
|
+
component: this.props.component,
|
|
266
|
+
...this.props.reportOptions,
|
|
267
|
+
metadata: {
|
|
268
|
+
...this.props.reportOptions?.metadata,
|
|
269
|
+
componentStack: errorInfo.componentStack ?? void 0,
|
|
270
|
+
source: "JahizErrorBoundary"
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
this.props.onError?.(error, errorInfo);
|
|
274
|
+
}
|
|
275
|
+
render() {
|
|
276
|
+
if (this.state.hasError && this.state.error) {
|
|
277
|
+
if (typeof this.props.fallback === "function") {
|
|
278
|
+
return this.props.fallback(this.state.error, this.reset);
|
|
279
|
+
}
|
|
280
|
+
if (this.props.fallback) {
|
|
281
|
+
return this.props.fallback;
|
|
282
|
+
}
|
|
283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
284
|
+
"div",
|
|
285
|
+
{
|
|
286
|
+
style: {
|
|
287
|
+
padding: "2rem",
|
|
288
|
+
textAlign: "center",
|
|
289
|
+
fontFamily: "system-ui, sans-serif"
|
|
290
|
+
},
|
|
291
|
+
children: [
|
|
292
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { color: "#dc2626" }, children: "Something went wrong" }),
|
|
293
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { color: "#6b7280" }, children: "The error has been automatically reported." }),
|
|
294
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
295
|
+
"button",
|
|
296
|
+
{
|
|
297
|
+
onClick: this.reset,
|
|
298
|
+
style: {
|
|
299
|
+
marginTop: "1rem",
|
|
300
|
+
padding: "0.5rem 1.5rem",
|
|
301
|
+
borderRadius: "0.375rem",
|
|
302
|
+
border: "1px solid #d1d5db",
|
|
303
|
+
background: "#fff",
|
|
304
|
+
cursor: "pointer",
|
|
305
|
+
fontSize: "0.875rem"
|
|
306
|
+
},
|
|
307
|
+
children: "Try Again"
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
]
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
return this.props.children;
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
var JahizErrorBoundary_default = JahizErrorBoundary;
|
|
318
|
+
|
|
319
|
+
// react/useJahizTracker.ts
|
|
320
|
+
var import_react2 = require("react");
|
|
321
|
+
function useJahizTracker(component) {
|
|
322
|
+
const trackerRef = (0, import_react2.useRef)(getJahizTracker());
|
|
323
|
+
const captureError = (0, import_react2.useCallback)(
|
|
324
|
+
async (error, options = {}) => {
|
|
325
|
+
return trackerRef.current.captureError(error, {
|
|
326
|
+
component,
|
|
327
|
+
...options
|
|
328
|
+
});
|
|
329
|
+
},
|
|
330
|
+
[component]
|
|
331
|
+
);
|
|
332
|
+
const captureMessage = (0, import_react2.useCallback)(
|
|
333
|
+
async (message, options = {}) => {
|
|
334
|
+
return trackerRef.current.captureMessage(message, {
|
|
335
|
+
component,
|
|
336
|
+
...options
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
[component]
|
|
340
|
+
);
|
|
341
|
+
const setUser = (0, import_react2.useCallback)(
|
|
342
|
+
(user) => {
|
|
343
|
+
trackerRef.current.setUser(user);
|
|
344
|
+
},
|
|
345
|
+
[]
|
|
346
|
+
);
|
|
347
|
+
const clearUser = (0, import_react2.useCallback)(() => {
|
|
348
|
+
trackerRef.current.clearUser();
|
|
349
|
+
}, []);
|
|
350
|
+
return { captureError, captureMessage, setUser, clearUser };
|
|
351
|
+
}
|
|
352
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
353
|
+
0 && (module.exports = {
|
|
354
|
+
JahizErrorBoundary,
|
|
355
|
+
JahizTracker,
|
|
356
|
+
createJahizTracker,
|
|
357
|
+
getJahizTracker,
|
|
358
|
+
useJahizTracker
|
|
359
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Component, ReactNode, ErrorInfo } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Jahiz Error Tracker - Core Client
|
|
5
|
+
*
|
|
6
|
+
* Lightweight client for sending error reports to the Jahiz webhook.
|
|
7
|
+
* Framework-agnostic. Works in any JS/TS environment (browser, Node, Deno).
|
|
8
|
+
*/
|
|
9
|
+
type Severity = "critical" | "error" | "warning" | "info";
|
|
10
|
+
interface JahizConfig {
|
|
11
|
+
webhookUrl: string;
|
|
12
|
+
webhookSecret: string;
|
|
13
|
+
appName?: string;
|
|
14
|
+
appVersion?: string;
|
|
15
|
+
environment?: string;
|
|
16
|
+
serviceName?: string;
|
|
17
|
+
/** Automatically capture unhandled errors and promise rejections. Default: true */
|
|
18
|
+
captureGlobal?: boolean;
|
|
19
|
+
/** Collect browser/device info automatically. Default: true */
|
|
20
|
+
collectDeviceInfo?: boolean;
|
|
21
|
+
/** Custom tags applied to every error report */
|
|
22
|
+
defaultTags?: Record<string, string>;
|
|
23
|
+
/** Callback before sending — return false to skip */
|
|
24
|
+
beforeSend?: (payload: ErrorPayload) => ErrorPayload | false;
|
|
25
|
+
}
|
|
26
|
+
interface UserInfo {
|
|
27
|
+
userId?: string;
|
|
28
|
+
username?: string;
|
|
29
|
+
email?: string;
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
ipAddress?: string;
|
|
32
|
+
}
|
|
33
|
+
interface ErrorContext {
|
|
34
|
+
requestUrl?: string;
|
|
35
|
+
requestMethod?: string;
|
|
36
|
+
responseStatus?: number;
|
|
37
|
+
queryParams?: Record<string, string>;
|
|
38
|
+
}
|
|
39
|
+
interface DeviceInfo {
|
|
40
|
+
hostname?: string;
|
|
41
|
+
os?: string;
|
|
42
|
+
osVersion?: string;
|
|
43
|
+
architecture?: string;
|
|
44
|
+
ipAddress?: string;
|
|
45
|
+
}
|
|
46
|
+
interface ErrorPayload {
|
|
47
|
+
error_message: string;
|
|
48
|
+
severity: Severity;
|
|
49
|
+
error_type?: string;
|
|
50
|
+
error_code?: string;
|
|
51
|
+
stacktrace?: string;
|
|
52
|
+
file_name?: string;
|
|
53
|
+
line_number?: number;
|
|
54
|
+
function_name?: string;
|
|
55
|
+
app_name?: string;
|
|
56
|
+
app_version?: string;
|
|
57
|
+
environment?: string;
|
|
58
|
+
service_name?: string;
|
|
59
|
+
component?: string;
|
|
60
|
+
context?: Partial<ErrorContext>;
|
|
61
|
+
user?: Partial<UserInfo>;
|
|
62
|
+
device?: Partial<DeviceInfo>;
|
|
63
|
+
tags?: Record<string, string>;
|
|
64
|
+
metadata?: Record<string, unknown>;
|
|
65
|
+
fingerprint?: string;
|
|
66
|
+
timestamp?: string;
|
|
67
|
+
}
|
|
68
|
+
interface WebhookResponse {
|
|
69
|
+
success: boolean;
|
|
70
|
+
message: string;
|
|
71
|
+
error_id?: string;
|
|
72
|
+
timestamp: string;
|
|
73
|
+
}
|
|
74
|
+
interface ReportOptions {
|
|
75
|
+
severity?: Severity;
|
|
76
|
+
component?: string;
|
|
77
|
+
errorCode?: string;
|
|
78
|
+
context?: Partial<ErrorContext>;
|
|
79
|
+
user?: Partial<UserInfo>;
|
|
80
|
+
tags?: Record<string, string>;
|
|
81
|
+
metadata?: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
declare class JahizTracker {
|
|
84
|
+
private config;
|
|
85
|
+
private user;
|
|
86
|
+
private initialized;
|
|
87
|
+
constructor(config: JahizConfig);
|
|
88
|
+
/** Initialize the tracker. Call once at app startup. */
|
|
89
|
+
init(): void;
|
|
90
|
+
/** Set the current user context. Attached to all subsequent reports. */
|
|
91
|
+
setUser(user: Partial<UserInfo>): void;
|
|
92
|
+
/** Clear user context (e.g. on logout). */
|
|
93
|
+
clearUser(): void;
|
|
94
|
+
/** Capture an Error object or string message. */
|
|
95
|
+
captureError(error: Error | string, options?: ReportOptions): Promise<WebhookResponse | null>;
|
|
96
|
+
/** Report a custom error message (not from a thrown Error). */
|
|
97
|
+
captureMessage(message: string, options?: ReportOptions): Promise<WebhookResponse | null>;
|
|
98
|
+
/** Wrap an async function so errors are automatically captured. */
|
|
99
|
+
wrap<T extends (...args: unknown[]) => unknown>(fn: T, options?: ReportOptions): T;
|
|
100
|
+
private buildPayload;
|
|
101
|
+
private send;
|
|
102
|
+
private parseStack;
|
|
103
|
+
private collectBrowserInfo;
|
|
104
|
+
private getOS;
|
|
105
|
+
private generateFingerprint;
|
|
106
|
+
}
|
|
107
|
+
/** Create and return the singleton tracker instance. */
|
|
108
|
+
declare function createJahizTracker(config: JahizConfig): JahizTracker;
|
|
109
|
+
/** Get the existing tracker instance. Throws if not initialized. */
|
|
110
|
+
declare function getJahizTracker(): JahizTracker;
|
|
111
|
+
|
|
112
|
+
interface Props {
|
|
113
|
+
children: ReactNode;
|
|
114
|
+
/** Component name for error context (e.g. "CheckoutPage") */
|
|
115
|
+
component?: string;
|
|
116
|
+
/** Custom fallback UI when an error is caught */
|
|
117
|
+
fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
|
|
118
|
+
/** Extra options applied to every error captured by this boundary */
|
|
119
|
+
reportOptions?: ReportOptions;
|
|
120
|
+
/** Callback when an error is caught */
|
|
121
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
122
|
+
}
|
|
123
|
+
interface State {
|
|
124
|
+
hasError: boolean;
|
|
125
|
+
error: Error | null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* React Error Boundary that automatically reports caught errors
|
|
129
|
+
* to the Jahiz webhook and shows a fallback UI.
|
|
130
|
+
*
|
|
131
|
+
* Usage:
|
|
132
|
+
* <JahizErrorBoundary component="Dashboard" fallback={<ErrorPage />}>
|
|
133
|
+
* <Dashboard />
|
|
134
|
+
* </JahizErrorBoundary>
|
|
135
|
+
*/
|
|
136
|
+
declare class JahizErrorBoundary extends Component<Props, State> {
|
|
137
|
+
constructor(props: Props);
|
|
138
|
+
static getDerivedStateFromError(error: Error): State;
|
|
139
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
140
|
+
private reset;
|
|
141
|
+
render(): ReactNode;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* React hook for reporting errors from components.
|
|
146
|
+
*
|
|
147
|
+
* Usage:
|
|
148
|
+
* const { captureError, captureMessage } = useJahizTracker("PaymentForm");
|
|
149
|
+
*
|
|
150
|
+
* const handleSubmit = async () => {
|
|
151
|
+
* try {
|
|
152
|
+
* await processPayment();
|
|
153
|
+
* } catch (err) {
|
|
154
|
+
* captureError(err, { severity: "critical", metadata: { orderId } });
|
|
155
|
+
* showErrorToast("Payment failed");
|
|
156
|
+
* }
|
|
157
|
+
* };
|
|
158
|
+
*/
|
|
159
|
+
declare function useJahizTracker(component?: string): {
|
|
160
|
+
captureError: (error: Error | string, options?: ReportOptions) => Promise<WebhookResponse | null>;
|
|
161
|
+
captureMessage: (message: string, options?: ReportOptions) => Promise<WebhookResponse | null>;
|
|
162
|
+
setUser: (user: Partial<UserInfo>) => void;
|
|
163
|
+
clearUser: () => void;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export { type DeviceInfo, type ErrorContext, type ErrorPayload, type JahizConfig, JahizErrorBoundary, JahizTracker, type ReportOptions, type Severity, type UserInfo, type WebhookResponse, createJahizTracker, getJahizTracker, useJahizTracker };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Component, ReactNode, ErrorInfo } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Jahiz Error Tracker - Core Client
|
|
5
|
+
*
|
|
6
|
+
* Lightweight client for sending error reports to the Jahiz webhook.
|
|
7
|
+
* Framework-agnostic. Works in any JS/TS environment (browser, Node, Deno).
|
|
8
|
+
*/
|
|
9
|
+
type Severity = "critical" | "error" | "warning" | "info";
|
|
10
|
+
interface JahizConfig {
|
|
11
|
+
webhookUrl: string;
|
|
12
|
+
webhookSecret: string;
|
|
13
|
+
appName?: string;
|
|
14
|
+
appVersion?: string;
|
|
15
|
+
environment?: string;
|
|
16
|
+
serviceName?: string;
|
|
17
|
+
/** Automatically capture unhandled errors and promise rejections. Default: true */
|
|
18
|
+
captureGlobal?: boolean;
|
|
19
|
+
/** Collect browser/device info automatically. Default: true */
|
|
20
|
+
collectDeviceInfo?: boolean;
|
|
21
|
+
/** Custom tags applied to every error report */
|
|
22
|
+
defaultTags?: Record<string, string>;
|
|
23
|
+
/** Callback before sending — return false to skip */
|
|
24
|
+
beforeSend?: (payload: ErrorPayload) => ErrorPayload | false;
|
|
25
|
+
}
|
|
26
|
+
interface UserInfo {
|
|
27
|
+
userId?: string;
|
|
28
|
+
username?: string;
|
|
29
|
+
email?: string;
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
ipAddress?: string;
|
|
32
|
+
}
|
|
33
|
+
interface ErrorContext {
|
|
34
|
+
requestUrl?: string;
|
|
35
|
+
requestMethod?: string;
|
|
36
|
+
responseStatus?: number;
|
|
37
|
+
queryParams?: Record<string, string>;
|
|
38
|
+
}
|
|
39
|
+
interface DeviceInfo {
|
|
40
|
+
hostname?: string;
|
|
41
|
+
os?: string;
|
|
42
|
+
osVersion?: string;
|
|
43
|
+
architecture?: string;
|
|
44
|
+
ipAddress?: string;
|
|
45
|
+
}
|
|
46
|
+
interface ErrorPayload {
|
|
47
|
+
error_message: string;
|
|
48
|
+
severity: Severity;
|
|
49
|
+
error_type?: string;
|
|
50
|
+
error_code?: string;
|
|
51
|
+
stacktrace?: string;
|
|
52
|
+
file_name?: string;
|
|
53
|
+
line_number?: number;
|
|
54
|
+
function_name?: string;
|
|
55
|
+
app_name?: string;
|
|
56
|
+
app_version?: string;
|
|
57
|
+
environment?: string;
|
|
58
|
+
service_name?: string;
|
|
59
|
+
component?: string;
|
|
60
|
+
context?: Partial<ErrorContext>;
|
|
61
|
+
user?: Partial<UserInfo>;
|
|
62
|
+
device?: Partial<DeviceInfo>;
|
|
63
|
+
tags?: Record<string, string>;
|
|
64
|
+
metadata?: Record<string, unknown>;
|
|
65
|
+
fingerprint?: string;
|
|
66
|
+
timestamp?: string;
|
|
67
|
+
}
|
|
68
|
+
interface WebhookResponse {
|
|
69
|
+
success: boolean;
|
|
70
|
+
message: string;
|
|
71
|
+
error_id?: string;
|
|
72
|
+
timestamp: string;
|
|
73
|
+
}
|
|
74
|
+
interface ReportOptions {
|
|
75
|
+
severity?: Severity;
|
|
76
|
+
component?: string;
|
|
77
|
+
errorCode?: string;
|
|
78
|
+
context?: Partial<ErrorContext>;
|
|
79
|
+
user?: Partial<UserInfo>;
|
|
80
|
+
tags?: Record<string, string>;
|
|
81
|
+
metadata?: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
declare class JahizTracker {
|
|
84
|
+
private config;
|
|
85
|
+
private user;
|
|
86
|
+
private initialized;
|
|
87
|
+
constructor(config: JahizConfig);
|
|
88
|
+
/** Initialize the tracker. Call once at app startup. */
|
|
89
|
+
init(): void;
|
|
90
|
+
/** Set the current user context. Attached to all subsequent reports. */
|
|
91
|
+
setUser(user: Partial<UserInfo>): void;
|
|
92
|
+
/** Clear user context (e.g. on logout). */
|
|
93
|
+
clearUser(): void;
|
|
94
|
+
/** Capture an Error object or string message. */
|
|
95
|
+
captureError(error: Error | string, options?: ReportOptions): Promise<WebhookResponse | null>;
|
|
96
|
+
/** Report a custom error message (not from a thrown Error). */
|
|
97
|
+
captureMessage(message: string, options?: ReportOptions): Promise<WebhookResponse | null>;
|
|
98
|
+
/** Wrap an async function so errors are automatically captured. */
|
|
99
|
+
wrap<T extends (...args: unknown[]) => unknown>(fn: T, options?: ReportOptions): T;
|
|
100
|
+
private buildPayload;
|
|
101
|
+
private send;
|
|
102
|
+
private parseStack;
|
|
103
|
+
private collectBrowserInfo;
|
|
104
|
+
private getOS;
|
|
105
|
+
private generateFingerprint;
|
|
106
|
+
}
|
|
107
|
+
/** Create and return the singleton tracker instance. */
|
|
108
|
+
declare function createJahizTracker(config: JahizConfig): JahizTracker;
|
|
109
|
+
/** Get the existing tracker instance. Throws if not initialized. */
|
|
110
|
+
declare function getJahizTracker(): JahizTracker;
|
|
111
|
+
|
|
112
|
+
interface Props {
|
|
113
|
+
children: ReactNode;
|
|
114
|
+
/** Component name for error context (e.g. "CheckoutPage") */
|
|
115
|
+
component?: string;
|
|
116
|
+
/** Custom fallback UI when an error is caught */
|
|
117
|
+
fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
|
|
118
|
+
/** Extra options applied to every error captured by this boundary */
|
|
119
|
+
reportOptions?: ReportOptions;
|
|
120
|
+
/** Callback when an error is caught */
|
|
121
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
122
|
+
}
|
|
123
|
+
interface State {
|
|
124
|
+
hasError: boolean;
|
|
125
|
+
error: Error | null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* React Error Boundary that automatically reports caught errors
|
|
129
|
+
* to the Jahiz webhook and shows a fallback UI.
|
|
130
|
+
*
|
|
131
|
+
* Usage:
|
|
132
|
+
* <JahizErrorBoundary component="Dashboard" fallback={<ErrorPage />}>
|
|
133
|
+
* <Dashboard />
|
|
134
|
+
* </JahizErrorBoundary>
|
|
135
|
+
*/
|
|
136
|
+
declare class JahizErrorBoundary extends Component<Props, State> {
|
|
137
|
+
constructor(props: Props);
|
|
138
|
+
static getDerivedStateFromError(error: Error): State;
|
|
139
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
140
|
+
private reset;
|
|
141
|
+
render(): ReactNode;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* React hook for reporting errors from components.
|
|
146
|
+
*
|
|
147
|
+
* Usage:
|
|
148
|
+
* const { captureError, captureMessage } = useJahizTracker("PaymentForm");
|
|
149
|
+
*
|
|
150
|
+
* const handleSubmit = async () => {
|
|
151
|
+
* try {
|
|
152
|
+
* await processPayment();
|
|
153
|
+
* } catch (err) {
|
|
154
|
+
* captureError(err, { severity: "critical", metadata: { orderId } });
|
|
155
|
+
* showErrorToast("Payment failed");
|
|
156
|
+
* }
|
|
157
|
+
* };
|
|
158
|
+
*/
|
|
159
|
+
declare function useJahizTracker(component?: string): {
|
|
160
|
+
captureError: (error: Error | string, options?: ReportOptions) => Promise<WebhookResponse | null>;
|
|
161
|
+
captureMessage: (message: string, options?: ReportOptions) => Promise<WebhookResponse | null>;
|
|
162
|
+
setUser: (user: Partial<UserInfo>) => void;
|
|
163
|
+
clearUser: () => void;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export { type DeviceInfo, type ErrorContext, type ErrorPayload, type JahizConfig, JahizErrorBoundary, JahizTracker, type ReportOptions, type Severity, type UserInfo, type WebhookResponse, createJahizTracker, getJahizTracker, useJahizTracker };
|