@crashsense/core 1.0.7 → 1.1.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/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +445 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +445 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CrashSenseConfig, CrashSenseCore, RawCrashEvent, ClassificationResult } from '@crashsense/types';
|
|
2
|
-
export { Breadcrumb, CrashAnalysis, CrashCategory, CrashEvent, CrashReport, CrashSenseConfig, CrashSenseCore, CrashSensePlugin, CrashSeverity, DeviceInfo, EventBus, IframeState, PreCrashLevel, ResolvedConfig, StackFrame, SystemState } from '@crashsense/types';
|
|
2
|
+
export { Breadcrumb, CheckpointData, CrashAnalysis, CrashCategory, CrashEvent, CrashReport, CrashSenseConfig, CrashSenseCore, CrashSensePlugin, CrashSeverity, DeviceInfo, EventBus, IframeState, OOMRecoveryReport, OOMSignal, PreCrashLevel, ResolvedConfig, StackFrame, SystemState } from '@crashsense/types';
|
|
3
3
|
|
|
4
4
|
declare function createCrashSense(userConfig: CrashSenseConfig): CrashSenseCore;
|
|
5
5
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CrashSenseConfig, CrashSenseCore, RawCrashEvent, ClassificationResult } from '@crashsense/types';
|
|
2
|
-
export { Breadcrumb, CrashAnalysis, CrashCategory, CrashEvent, CrashReport, CrashSenseConfig, CrashSenseCore, CrashSensePlugin, CrashSeverity, DeviceInfo, EventBus, IframeState, PreCrashLevel, ResolvedConfig, StackFrame, SystemState } from '@crashsense/types';
|
|
2
|
+
export { Breadcrumb, CheckpointData, CrashAnalysis, CrashCategory, CrashEvent, CrashReport, CrashSenseConfig, CrashSenseCore, CrashSensePlugin, CrashSeverity, DeviceInfo, EventBus, IframeState, OOMRecoveryReport, OOMSignal, PreCrashLevel, ResolvedConfig, StackFrame, SystemState } from '@crashsense/types';
|
|
3
3
|
|
|
4
4
|
declare function createCrashSense(userConfig: CrashSenseConfig): CrashSenseCore;
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,12 @@ function resolveConfig(userConfig) {
|
|
|
32
32
|
preCrashMemoryThreshold: userConfig.preCrashMemoryThreshold ?? 0.8,
|
|
33
33
|
piiScrubbing: userConfig.piiScrubbing ?? true,
|
|
34
34
|
debug: userConfig.debug ?? false,
|
|
35
|
-
onCrash: userConfig.onCrash ?? null
|
|
35
|
+
onCrash: userConfig.onCrash ?? null,
|
|
36
|
+
enableOOMRecovery: userConfig.enableOOMRecovery ?? false,
|
|
37
|
+
checkpointInterval: userConfig.checkpointInterval ?? 1e4,
|
|
38
|
+
oomRecoveryThreshold: userConfig.oomRecoveryThreshold ?? 0.3,
|
|
39
|
+
flushEndpoint: userConfig.flushEndpoint ?? null,
|
|
40
|
+
onOOMRecovery: userConfig.onOOMRecovery ?? null
|
|
36
41
|
};
|
|
37
42
|
}
|
|
38
43
|
|
|
@@ -970,6 +975,373 @@ function classifyCrash(event) {
|
|
|
970
975
|
};
|
|
971
976
|
}
|
|
972
977
|
|
|
978
|
+
// src/checkpoint-manager.ts
|
|
979
|
+
var CHECKPOINT_KEY = "__crashsense_checkpoint";
|
|
980
|
+
var CHECKPOINT_VERSION = 1;
|
|
981
|
+
function createCheckpointManager(bus, config, sessionId, deviceInfo, getSystemState, getBreadcrumbs) {
|
|
982
|
+
let intervalId = null;
|
|
983
|
+
let checkpointCount = 0;
|
|
984
|
+
const preCrashWarnings = [];
|
|
985
|
+
let lastMemoryTrend = null;
|
|
986
|
+
function hasSessionStorage() {
|
|
987
|
+
try {
|
|
988
|
+
return typeof sessionStorage !== "undefined" && sessionStorage !== null;
|
|
989
|
+
} catch {
|
|
990
|
+
return false;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
function writeCheckpoint() {
|
|
994
|
+
if (!hasSessionStorage()) return;
|
|
995
|
+
checkpointCount++;
|
|
996
|
+
const systemState = getSystemState();
|
|
997
|
+
if (systemState.memory?.trend) {
|
|
998
|
+
lastMemoryTrend = systemState.memory.trend;
|
|
999
|
+
}
|
|
1000
|
+
const checkpoint = {
|
|
1001
|
+
version: CHECKPOINT_VERSION,
|
|
1002
|
+
timestamp: Date.now(),
|
|
1003
|
+
sessionId,
|
|
1004
|
+
appId: config.appId,
|
|
1005
|
+
url: typeof location !== "undefined" ? location.href : "",
|
|
1006
|
+
breadcrumbs: getBreadcrumbs().slice(-20),
|
|
1007
|
+
systemState,
|
|
1008
|
+
device: deviceInfo,
|
|
1009
|
+
preCrashWarnings: preCrashWarnings.slice(-5),
|
|
1010
|
+
memoryTrend: lastMemoryTrend,
|
|
1011
|
+
checkpointCount
|
|
1012
|
+
};
|
|
1013
|
+
try {
|
|
1014
|
+
sessionStorage.setItem(CHECKPOINT_KEY, JSON.stringify(checkpoint));
|
|
1015
|
+
bus.emit("checkpoint_written", { timestamp: checkpoint.timestamp, sessionId });
|
|
1016
|
+
} catch {
|
|
1017
|
+
try {
|
|
1018
|
+
const minimal = {
|
|
1019
|
+
...checkpoint,
|
|
1020
|
+
breadcrumbs: checkpoint.breadcrumbs.slice(-5),
|
|
1021
|
+
systemState: { memory: systemState.memory }
|
|
1022
|
+
};
|
|
1023
|
+
sessionStorage.setItem(CHECKPOINT_KEY, JSON.stringify(minimal));
|
|
1024
|
+
} catch {
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
bus.on("pre_crash_warning", (data) => {
|
|
1029
|
+
preCrashWarnings.push({
|
|
1030
|
+
level: data.level,
|
|
1031
|
+
reason: data.reason,
|
|
1032
|
+
timestamp: data.timestamp
|
|
1033
|
+
});
|
|
1034
|
+
while (preCrashWarnings.length > 10) {
|
|
1035
|
+
preCrashWarnings.shift();
|
|
1036
|
+
}
|
|
1037
|
+
writeCheckpoint();
|
|
1038
|
+
});
|
|
1039
|
+
bus.on("crash_detected", () => {
|
|
1040
|
+
writeCheckpoint();
|
|
1041
|
+
});
|
|
1042
|
+
return {
|
|
1043
|
+
start() {
|
|
1044
|
+
if (typeof window === "undefined") return;
|
|
1045
|
+
if (!hasSessionStorage()) return;
|
|
1046
|
+
writeCheckpoint();
|
|
1047
|
+
intervalId = setInterval(writeCheckpoint, config.checkpointInterval);
|
|
1048
|
+
},
|
|
1049
|
+
stop() {
|
|
1050
|
+
if (intervalId !== null) {
|
|
1051
|
+
clearInterval(intervalId);
|
|
1052
|
+
intervalId = null;
|
|
1053
|
+
}
|
|
1054
|
+
},
|
|
1055
|
+
/** Force an immediate checkpoint write (used by lifecycle flush) */
|
|
1056
|
+
flush() {
|
|
1057
|
+
writeCheckpoint();
|
|
1058
|
+
},
|
|
1059
|
+
/** Read and remove the stored checkpoint (used by OOM recovery on next load) */
|
|
1060
|
+
static: {
|
|
1061
|
+
readCheckpoint() {
|
|
1062
|
+
try {
|
|
1063
|
+
if (typeof sessionStorage === "undefined") return null;
|
|
1064
|
+
const raw = sessionStorage.getItem(CHECKPOINT_KEY);
|
|
1065
|
+
if (!raw) return null;
|
|
1066
|
+
const data = JSON.parse(raw);
|
|
1067
|
+
if (data.version !== CHECKPOINT_VERSION) return null;
|
|
1068
|
+
return data;
|
|
1069
|
+
} catch {
|
|
1070
|
+
return null;
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
clearCheckpoint() {
|
|
1074
|
+
try {
|
|
1075
|
+
if (typeof sessionStorage !== "undefined") {
|
|
1076
|
+
sessionStorage.removeItem(CHECKPOINT_KEY);
|
|
1077
|
+
}
|
|
1078
|
+
} catch {
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
},
|
|
1082
|
+
/** Clear checkpoint on clean shutdown (destroy) */
|
|
1083
|
+
clearOnDestroy() {
|
|
1084
|
+
try {
|
|
1085
|
+
if (hasSessionStorage()) {
|
|
1086
|
+
sessionStorage.removeItem(CHECKPOINT_KEY);
|
|
1087
|
+
}
|
|
1088
|
+
} catch {
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
function readCheckpoint() {
|
|
1094
|
+
try {
|
|
1095
|
+
if (typeof sessionStorage === "undefined") return null;
|
|
1096
|
+
const raw = sessionStorage.getItem(CHECKPOINT_KEY);
|
|
1097
|
+
if (!raw) return null;
|
|
1098
|
+
const data = JSON.parse(raw);
|
|
1099
|
+
if (data.version !== CHECKPOINT_VERSION) return null;
|
|
1100
|
+
return data;
|
|
1101
|
+
} catch {
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
function clearCheckpoint() {
|
|
1106
|
+
try {
|
|
1107
|
+
if (typeof sessionStorage !== "undefined") {
|
|
1108
|
+
sessionStorage.removeItem(CHECKPOINT_KEY);
|
|
1109
|
+
}
|
|
1110
|
+
} catch {
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
function getNavigationType() {
|
|
1114
|
+
try {
|
|
1115
|
+
if (typeof performance === "undefined") return "unknown";
|
|
1116
|
+
const entries = performance.getEntriesByType("navigation");
|
|
1117
|
+
if (entries.length > 0) {
|
|
1118
|
+
return entries[0].type || "unknown";
|
|
1119
|
+
}
|
|
1120
|
+
} catch {
|
|
1121
|
+
}
|
|
1122
|
+
return "unknown";
|
|
1123
|
+
}
|
|
1124
|
+
function getWasDiscarded() {
|
|
1125
|
+
try {
|
|
1126
|
+
const doc = document;
|
|
1127
|
+
if ("wasDiscarded" in doc) {
|
|
1128
|
+
return doc.wasDiscarded;
|
|
1129
|
+
}
|
|
1130
|
+
} catch {
|
|
1131
|
+
}
|
|
1132
|
+
return void 0;
|
|
1133
|
+
}
|
|
1134
|
+
function detectOOMRecovery(bus, config, currentSessionId) {
|
|
1135
|
+
if (typeof window === "undefined") return null;
|
|
1136
|
+
const checkpoint = readCheckpoint();
|
|
1137
|
+
if (!checkpoint) return null;
|
|
1138
|
+
clearCheckpoint();
|
|
1139
|
+
const now = Date.now();
|
|
1140
|
+
const timeSinceCheckpoint = now - checkpoint.timestamp;
|
|
1141
|
+
const MAX_OOM_AGE = 5 * 60 * 1e3;
|
|
1142
|
+
if (timeSinceCheckpoint > MAX_OOM_AGE) return null;
|
|
1143
|
+
if (checkpoint.appId !== config.appId) return null;
|
|
1144
|
+
const wasDiscarded = getWasDiscarded();
|
|
1145
|
+
const navigationType = getNavigationType();
|
|
1146
|
+
const deviceInfo = utils.collectDeviceInfo();
|
|
1147
|
+
const signals = [];
|
|
1148
|
+
let probability = 0;
|
|
1149
|
+
if (wasDiscarded === true) {
|
|
1150
|
+
probability += 0.45;
|
|
1151
|
+
signals.push({
|
|
1152
|
+
signal: "document_was_discarded",
|
|
1153
|
+
weight: 0.45,
|
|
1154
|
+
evidence: "document.wasDiscarded is true \u2014 OS confirmed tab discard"
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
if (navigationType === "reload" && timeSinceCheckpoint < 3e4) {
|
|
1158
|
+
probability += 0.25;
|
|
1159
|
+
signals.push({
|
|
1160
|
+
signal: "recent_reload",
|
|
1161
|
+
weight: 0.25,
|
|
1162
|
+
evidence: `Page reloaded ${Math.round(timeSinceCheckpoint / 1e3)}s after last checkpoint`
|
|
1163
|
+
});
|
|
1164
|
+
} else if (navigationType === "reload" && timeSinceCheckpoint < 6e4) {
|
|
1165
|
+
probability += 0.15;
|
|
1166
|
+
signals.push({
|
|
1167
|
+
signal: "moderate_reload",
|
|
1168
|
+
weight: 0.15,
|
|
1169
|
+
evidence: `Page reloaded ${Math.round(timeSinceCheckpoint / 1e3)}s after last checkpoint`
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
if (checkpoint.memoryTrend === "growing") {
|
|
1173
|
+
probability += 0.1;
|
|
1174
|
+
signals.push({
|
|
1175
|
+
signal: "memory_growing_trend",
|
|
1176
|
+
weight: 0.1,
|
|
1177
|
+
evidence: "Memory was in growing trend before tab died"
|
|
1178
|
+
});
|
|
1179
|
+
} else if (checkpoint.memoryTrend === "spike") {
|
|
1180
|
+
probability += 0.08;
|
|
1181
|
+
signals.push({
|
|
1182
|
+
signal: "memory_spike",
|
|
1183
|
+
weight: 0.08,
|
|
1184
|
+
evidence: "Memory was spiking before tab died"
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
if (checkpoint.preCrashWarnings.length > 0) {
|
|
1188
|
+
const highestLevel = checkpoint.preCrashWarnings.reduce((max, w) => {
|
|
1189
|
+
const severity = { elevated: 1, critical: 2, imminent: 3 };
|
|
1190
|
+
return (severity[w.level] || 0) > (severity[max.level] || 0) ? w : max;
|
|
1191
|
+
}, checkpoint.preCrashWarnings[0]);
|
|
1192
|
+
if (highestLevel.level === "imminent") {
|
|
1193
|
+
probability += 0.15;
|
|
1194
|
+
signals.push({
|
|
1195
|
+
signal: "pre_crash_warning_imminent",
|
|
1196
|
+
weight: 0.15,
|
|
1197
|
+
evidence: `Pre-crash warning at IMMINENT level: ${highestLevel.reason}`
|
|
1198
|
+
});
|
|
1199
|
+
} else if (highestLevel.level === "critical") {
|
|
1200
|
+
probability += 0.1;
|
|
1201
|
+
signals.push({
|
|
1202
|
+
signal: "pre_crash_warning_critical",
|
|
1203
|
+
weight: 0.1,
|
|
1204
|
+
evidence: `Pre-crash warning at CRITICAL level: ${highestLevel.reason}`
|
|
1205
|
+
});
|
|
1206
|
+
} else {
|
|
1207
|
+
probability += 0.05;
|
|
1208
|
+
signals.push({
|
|
1209
|
+
signal: "pre_crash_warning_elevated",
|
|
1210
|
+
weight: 0.05,
|
|
1211
|
+
evidence: `Pre-crash warning at ELEVATED level: ${highestLevel.reason}`
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
const memUtil = checkpoint.systemState?.memory?.utilizationPercent;
|
|
1216
|
+
if (memUtil !== void 0 && memUtil !== null && memUtil > 85) {
|
|
1217
|
+
probability += 0.1;
|
|
1218
|
+
signals.push({
|
|
1219
|
+
signal: "high_memory_at_checkpoint",
|
|
1220
|
+
weight: 0.1,
|
|
1221
|
+
evidence: `Memory was at ${memUtil}% utilization at last checkpoint`
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
if (checkpoint.device.touchSupport && checkpoint.device.deviceMemory !== null && checkpoint.device.deviceMemory <= 4) {
|
|
1225
|
+
probability += 0.05;
|
|
1226
|
+
signals.push({
|
|
1227
|
+
signal: "mobile_low_memory_device",
|
|
1228
|
+
weight: 0.05,
|
|
1229
|
+
evidence: `Touch device with ${checkpoint.device.deviceMemory}GB RAM \u2014 higher OOM risk`
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
probability = Math.min(probability, 1);
|
|
1233
|
+
if (probability < config.oomRecoveryThreshold) return null;
|
|
1234
|
+
const report = {
|
|
1235
|
+
id: utils.generateId(),
|
|
1236
|
+
type: "oom_recovery",
|
|
1237
|
+
timestamp: now,
|
|
1238
|
+
probability,
|
|
1239
|
+
sessionId: currentSessionId,
|
|
1240
|
+
previousSessionId: checkpoint.sessionId,
|
|
1241
|
+
timeSinceLastCheckpoint: timeSinceCheckpoint,
|
|
1242
|
+
wasDiscarded,
|
|
1243
|
+
navigationType,
|
|
1244
|
+
lastCheckpoint: checkpoint,
|
|
1245
|
+
device: deviceInfo,
|
|
1246
|
+
signals
|
|
1247
|
+
};
|
|
1248
|
+
bus.emit("oom_recovery", { report });
|
|
1249
|
+
if (config.onOOMRecovery) {
|
|
1250
|
+
try {
|
|
1251
|
+
config.onOOMRecovery(report);
|
|
1252
|
+
} catch {
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
if (config.debug) {
|
|
1256
|
+
logOOMRecovery(report);
|
|
1257
|
+
}
|
|
1258
|
+
return report;
|
|
1259
|
+
}
|
|
1260
|
+
function logOOMRecovery(report) {
|
|
1261
|
+
if (typeof console === "undefined") return;
|
|
1262
|
+
const header = `[CrashSense] OOM Recovery Detected (${(report.probability * 100).toFixed(0)}% confidence)`;
|
|
1263
|
+
const details = [
|
|
1264
|
+
`Previous session: ${report.previousSessionId}`,
|
|
1265
|
+
`Time since last checkpoint: ${Math.round(report.timeSinceLastCheckpoint / 1e3)}s`,
|
|
1266
|
+
`Navigation type: ${report.navigationType}`,
|
|
1267
|
+
`document.wasDiscarded: ${report.wasDiscarded}`,
|
|
1268
|
+
`Last URL: ${report.lastCheckpoint.url}`,
|
|
1269
|
+
`Memory trend: ${report.lastCheckpoint.memoryTrend || "unknown"}`,
|
|
1270
|
+
`Pre-crash warnings: ${report.lastCheckpoint.preCrashWarnings.length}`,
|
|
1271
|
+
`Breadcrumbs recovered: ${report.lastCheckpoint.breadcrumbs.length}`
|
|
1272
|
+
];
|
|
1273
|
+
console.groupCollapsed?.(header) ?? console.log(header);
|
|
1274
|
+
for (const d of details) console.log(d);
|
|
1275
|
+
if (report.signals.length > 0) {
|
|
1276
|
+
console.log("Signals:");
|
|
1277
|
+
for (const s of report.signals) {
|
|
1278
|
+
console.log(` - ${s.signal} (${(s.weight * 100).toFixed(0)}%): ${s.evidence}`);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
console.groupEnd?.();
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// src/lifecycle-flush.ts
|
|
1285
|
+
function createLifecycleFlush(bus, config, sessionId, getSystemState, getBreadcrumbs, flushCheckpoint) {
|
|
1286
|
+
let installed = false;
|
|
1287
|
+
function buildFlushPayload(reason) {
|
|
1288
|
+
return JSON.stringify({
|
|
1289
|
+
type: "lifecycle_flush",
|
|
1290
|
+
reason,
|
|
1291
|
+
timestamp: Date.now(),
|
|
1292
|
+
sessionId,
|
|
1293
|
+
appId: config.appId,
|
|
1294
|
+
url: typeof location !== "undefined" ? location.href : "",
|
|
1295
|
+
breadcrumbs: getBreadcrumbs().slice(-10),
|
|
1296
|
+
systemState: getSystemState()
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
function flush(reason) {
|
|
1300
|
+
flushCheckpoint();
|
|
1301
|
+
if (config.flushEndpoint && typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
1302
|
+
try {
|
|
1303
|
+
const payload = buildFlushPayload(reason);
|
|
1304
|
+
navigator.sendBeacon(config.flushEndpoint, payload);
|
|
1305
|
+
} catch {
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
bus.emit("lifecycle_flush", { reason, timestamp: Date.now() });
|
|
1309
|
+
}
|
|
1310
|
+
function handleVisibilityChange() {
|
|
1311
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
1312
|
+
flush("visibilitychange_hidden");
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
function handlePageHide() {
|
|
1316
|
+
flush("pagehide");
|
|
1317
|
+
}
|
|
1318
|
+
function handleFreeze() {
|
|
1319
|
+
flush("freeze");
|
|
1320
|
+
}
|
|
1321
|
+
return {
|
|
1322
|
+
install() {
|
|
1323
|
+
if (typeof window === "undefined") return;
|
|
1324
|
+
if (installed) return;
|
|
1325
|
+
installed = true;
|
|
1326
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
1327
|
+
window.addEventListener("pagehide", handlePageHide, { capture: true });
|
|
1328
|
+
if ("onfreeze" in document) {
|
|
1329
|
+
document.addEventListener("freeze", handleFreeze);
|
|
1330
|
+
}
|
|
1331
|
+
},
|
|
1332
|
+
uninstall() {
|
|
1333
|
+
if (typeof window === "undefined") return;
|
|
1334
|
+
if (!installed) return;
|
|
1335
|
+
installed = false;
|
|
1336
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1337
|
+
window.removeEventListener("pagehide", handlePageHide, { capture: true });
|
|
1338
|
+
if ("onfreeze" in document) {
|
|
1339
|
+
document.removeEventListener("freeze", handleFreeze);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
|
|
973
1345
|
// src/crashsense.ts
|
|
974
1346
|
function createCrashSense(userConfig) {
|
|
975
1347
|
const config = resolveConfig(userConfig);
|
|
@@ -987,6 +1359,34 @@ function createCrashSense(userConfig) {
|
|
|
987
1359
|
const breadcrumbTracker = createBreadcrumbTracker(bus);
|
|
988
1360
|
const iframeTracker = createIframeTracker(bus);
|
|
989
1361
|
const preCrashWarning = createPreCrashWarning(bus, config, memoryMonitor, iframeTracker);
|
|
1362
|
+
const checkpointManager = createCheckpointManager(
|
|
1363
|
+
bus,
|
|
1364
|
+
config,
|
|
1365
|
+
sessionId,
|
|
1366
|
+
deviceInfo,
|
|
1367
|
+
() => ({
|
|
1368
|
+
memory: memoryMonitor.getSnapshot(),
|
|
1369
|
+
cpu: eventLoopMonitor.getCpuSnapshot(),
|
|
1370
|
+
eventLoop: eventLoopMonitor.getEventLoopSnapshot(),
|
|
1371
|
+
network: networkMonitor.getSnapshot(),
|
|
1372
|
+
iframe: config.enableIframeTracking ? iframeTracker.getSnapshot() : void 0
|
|
1373
|
+
}),
|
|
1374
|
+
() => breadcrumbTracker.getBreadcrumbs()
|
|
1375
|
+
);
|
|
1376
|
+
const lifecycleFlush = createLifecycleFlush(
|
|
1377
|
+
bus,
|
|
1378
|
+
config,
|
|
1379
|
+
sessionId,
|
|
1380
|
+
() => ({
|
|
1381
|
+
memory: memoryMonitor.getSnapshot(),
|
|
1382
|
+
cpu: eventLoopMonitor.getCpuSnapshot(),
|
|
1383
|
+
eventLoop: eventLoopMonitor.getEventLoopSnapshot(),
|
|
1384
|
+
network: networkMonitor.getSnapshot(),
|
|
1385
|
+
iframe: config.enableIframeTracking ? iframeTracker.getSnapshot() : void 0
|
|
1386
|
+
}),
|
|
1387
|
+
() => breadcrumbTracker.getBreadcrumbs(),
|
|
1388
|
+
() => checkpointManager.flush()
|
|
1389
|
+
);
|
|
990
1390
|
function buildRawEvent(error, source) {
|
|
991
1391
|
const stack = error.stack ? utils.parseStackTrace(error.stack) : [];
|
|
992
1392
|
return {
|
|
@@ -1135,6 +1535,9 @@ function createCrashSense(userConfig) {
|
|
|
1135
1535
|
data: { level: data.level, memoryUtilization: data.memoryUtilization, iframeCount: data.iframeCount }
|
|
1136
1536
|
});
|
|
1137
1537
|
});
|
|
1538
|
+
if (config.enableOOMRecovery) {
|
|
1539
|
+
detectOOMRecovery(bus, config, sessionId);
|
|
1540
|
+
}
|
|
1138
1541
|
errorInterceptor.install();
|
|
1139
1542
|
breadcrumbTracker.install();
|
|
1140
1543
|
if (config.enableMemoryMonitoring) memoryMonitor.start();
|
|
@@ -1142,6 +1545,10 @@ function createCrashSense(userConfig) {
|
|
|
1142
1545
|
if (config.enableNetworkMonitoring) networkMonitor.start();
|
|
1143
1546
|
if (config.enableIframeTracking) iframeTracker.start();
|
|
1144
1547
|
if (config.enablePreCrashWarning) preCrashWarning.start();
|
|
1548
|
+
if (config.enableOOMRecovery) {
|
|
1549
|
+
checkpointManager.start();
|
|
1550
|
+
lifecycleFlush.install();
|
|
1551
|
+
}
|
|
1145
1552
|
const core = {
|
|
1146
1553
|
get config() {
|
|
1147
1554
|
return config;
|
|
@@ -1157,9 +1564,40 @@ function createCrashSense(userConfig) {
|
|
|
1157
1564
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
1158
1565
|
const rawEvent = buildRawEvent(err, "manual");
|
|
1159
1566
|
if (context) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1567
|
+
const frameworkKeys = /* @__PURE__ */ new Set([
|
|
1568
|
+
"framework",
|
|
1569
|
+
"lifecycleStage",
|
|
1570
|
+
"componentStack",
|
|
1571
|
+
"componentTree",
|
|
1572
|
+
"currentRoute",
|
|
1573
|
+
"storeState",
|
|
1574
|
+
"renderCount",
|
|
1575
|
+
"componentName",
|
|
1576
|
+
"lifecycleInfo"
|
|
1577
|
+
]);
|
|
1578
|
+
const tagEntries = [];
|
|
1579
|
+
for (const [key, value] of Object.entries(context)) {
|
|
1580
|
+
if (key === "framework" && typeof value === "string") {
|
|
1581
|
+
rawEvent.framework.name = value;
|
|
1582
|
+
} else if (key === "lifecycleStage" || key === "lifecycleInfo") {
|
|
1583
|
+
rawEvent.framework.lifecycleStage = String(value);
|
|
1584
|
+
} else if (key === "componentStack" || key === "componentTree") {
|
|
1585
|
+
rawEvent.framework.componentTree = Array.isArray(value) ? value : [String(value)];
|
|
1586
|
+
} else if (key === "currentRoute" && typeof value === "string") {
|
|
1587
|
+
rawEvent.framework.currentRoute = value;
|
|
1588
|
+
} else if (key === "storeState" && typeof value === "object" && value !== null) {
|
|
1589
|
+
rawEvent.framework.storeState = value;
|
|
1590
|
+
} else if (key === "renderCount" && typeof value === "number") {
|
|
1591
|
+
rawEvent.framework.renderCount = value;
|
|
1592
|
+
} else if (key === "componentName") {
|
|
1593
|
+
tagEntries.push([key, String(value)]);
|
|
1594
|
+
} else if (!frameworkKeys.has(key)) {
|
|
1595
|
+
tagEntries.push([key, String(value)]);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
if (tagEntries.length > 0) {
|
|
1599
|
+
rawEvent.meta.tags = { ...rawEvent.meta.tags, ...Object.fromEntries(tagEntries) };
|
|
1600
|
+
}
|
|
1163
1601
|
}
|
|
1164
1602
|
processRawEvent(rawEvent);
|
|
1165
1603
|
},
|
|
@@ -1199,6 +1637,9 @@ function createCrashSense(userConfig) {
|
|
|
1199
1637
|
networkMonitor.stop();
|
|
1200
1638
|
iframeTracker.stop();
|
|
1201
1639
|
preCrashWarning.stop();
|
|
1640
|
+
checkpointManager.stop();
|
|
1641
|
+
checkpointManager.clearOnDestroy();
|
|
1642
|
+
lifecycleFlush.uninstall();
|
|
1202
1643
|
for (const plugin of plugins) {
|
|
1203
1644
|
plugin.teardown();
|
|
1204
1645
|
}
|