@mortada50/error-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.
Files changed (2) hide show
  1. package/index.js +93 -0
  2. package/package.json +15 -0
package/index.js ADDED
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+
3
+ let _config = null;
4
+
5
+ export function init(config) {
6
+ // config: { apiKey, serverUrl, appVersion, userId }
7
+ _config = config;
8
+
9
+ // Global JS error handler
10
+ const prevHandler = global.ErrorUtils?.getGlobalHandler?.();
11
+ global.ErrorUtils?.setGlobalHandler?.((error, isFatal) => {
12
+ _send({
13
+ level: isFatal ? "fatal" : "error",
14
+ message: error?.message || String(error),
15
+ stack: error?.stack || "",
16
+ context: { fatal: isFatal },
17
+ });
18
+ prevHandler?.(error, isFatal);
19
+ });
20
+
21
+ // Unhandled promise rejections
22
+ const originalHandler = global.onunhandledrejection;
23
+ global.onunhandledrejection = (event) => {
24
+ const reason = event?.reason;
25
+ _send({
26
+ level: "error",
27
+ message:
28
+ reason?.message || String(reason) || "Unhandled Promise Rejection",
29
+ stack: reason?.stack || "",
30
+ context: {},
31
+ });
32
+ originalHandler?.(event);
33
+ };
34
+ }
35
+
36
+ export function captureError(error, context = {}) {
37
+ if (!_config) return;
38
+ _send({
39
+ level: "error",
40
+ message: error?.message || String(error),
41
+ stack: error?.stack || "",
42
+ context,
43
+ });
44
+ }
45
+
46
+ export function captureMessage(message, level = "info", context = {}) {
47
+ if (!_config) return;
48
+ _send({ level, message, stack: "", context });
49
+ }
50
+
51
+ async function _send(payload) {
52
+ if (!_config) return;
53
+ try {
54
+ // Lazy imports to avoid crashing if expo-device not installed
55
+ let deviceModel = "unknown";
56
+ let osVersion = "unknown";
57
+ let platform = "unknown";
58
+ try {
59
+ const Device = require("expo-device");
60
+ const { Platform } = require("react-native");
61
+ deviceModel = Device.modelName || "unknown";
62
+ osVersion = Device.osVersion || "unknown";
63
+ platform = Platform.OS || "unknown";
64
+ } catch (_) {}
65
+
66
+ const body = {
67
+ level: payload.level,
68
+ message: payload.message,
69
+ stack: payload.stack,
70
+ context: {
71
+ ...payload.context,
72
+ appVersion: _config.appVersion || "unknown",
73
+ userId: _config.userId || null,
74
+ platform,
75
+ deviceModel,
76
+ osVersion,
77
+ route: "unknown", // Override by passing route in context
78
+ },
79
+ };
80
+
81
+ await fetch(`${_config.serverUrl}/api/errors`, {
82
+ method: "POST",
83
+ headers: {
84
+ "Content-Type": "application/json",
85
+ "x-api-key": _config.apiKey,
86
+ },
87
+ body: JSON.stringify(body),
88
+ });
89
+ } catch (err) {
90
+ // Silently fail — never let the error tracker crash the app
91
+ if (__DEV__) console.warn("[ErrorTracker] Failed to send error:", err);
92
+ }
93
+ }
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@mortada50/error-tracker",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "",
8
+ "license": "ISC",
9
+ "author": "mortada_altaj",
10
+ "type": "commonjs",
11
+ "main": "index.js",
12
+ "scripts": {
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ }
15
+ }