react-native-stallion 2.3.0-alpha.5 → 2.3.0-alpha.7
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/android/build.gradle +0 -8
- package/android/src/main/cpp/CMakeLists.txt +6 -0
- package/android/src/main/cpp/stallion_signal_handler.cpp +35 -6
- package/android/src/main/java/com/stallion/utils/StallionExceptionHandler.java +87 -31
- package/ios/main/StallionExceptionHandler.mm +197 -111
- package/ios/main/StallionSlotManager.m +1 -1
- package/ios/main/StallionStateManager.m +29 -0
- package/package.json +1 -1
- package/src/main/utils/ErrorBoundary.js +15 -7
- package/src/main/utils/ErrorBoundary.js.map +1 -1
- package/types/main/utils/ErrorBoundary.d.ts +1 -0
- package/types/main/utils/ErrorBoundary.d.ts.map +1 -1
package/android/build.gradle
CHANGED
|
@@ -103,11 +103,3 @@ dependencies {
|
|
|
103
103
|
//noinspection GradleDynamicVersion
|
|
104
104
|
implementation "com.facebook.react:react-native:+"
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
if (isNewArchitectureEnabled()) {
|
|
108
|
-
react {
|
|
109
|
-
jsRootDir = file("../src/")
|
|
110
|
-
libraryName = "Stallion"
|
|
111
|
-
codegenJavaPackageName = "com.stallion"
|
|
112
|
-
}
|
|
113
|
-
}
|
|
@@ -17,3 +17,9 @@ target_link_libraries(
|
|
|
17
17
|
stallion-crash
|
|
18
18
|
${log-lib}
|
|
19
19
|
)
|
|
20
|
+
|
|
21
|
+
# Fix for 16KB page size compatibility (required for Android 15+)
|
|
22
|
+
# This ensures LOAD segments are aligned at 16KB boundaries
|
|
23
|
+
set_target_properties(stallion-crash PROPERTIES
|
|
24
|
+
LINK_FLAGS "-Wl,-z,max-page-size=16384"
|
|
25
|
+
)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
static char g_marker_path[512];
|
|
9
9
|
static char g_mount_marker_path[512];
|
|
10
|
+
static struct sigaction g_previous_handlers[32]; // Store previous handlers for chaining
|
|
10
11
|
|
|
11
12
|
// Async-signal-safe function to check if mount marker exists
|
|
12
13
|
static int is_mounted() {
|
|
@@ -36,11 +37,28 @@ static void write_crash_marker_json(int signal, int mounted) {
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
static void stallion_signal_handler(int sig) {
|
|
40
|
+
static void stallion_signal_handler(int sig, siginfo_t *info, void *context) {
|
|
40
41
|
// Read mount state at crash time (async-signal-safe)
|
|
41
42
|
int mounted = is_mounted();
|
|
42
43
|
// Write JSON marker with crash info and autoRollback flag
|
|
43
44
|
write_crash_marker_json(sig, mounted);
|
|
45
|
+
|
|
46
|
+
// Chain to previous handler if it exists and is valid (bubble up)
|
|
47
|
+
if (sig >= 0 && sig < 32) {
|
|
48
|
+
struct sigaction *prev = &g_previous_handlers[sig];
|
|
49
|
+
if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN && prev->sa_handler != NULL) {
|
|
50
|
+
// Prevent infinite loop - don't call ourselves
|
|
51
|
+
if (prev->sa_sigaction != stallion_signal_handler) {
|
|
52
|
+
if (prev->sa_flags & SA_SIGINFO) {
|
|
53
|
+
prev->sa_sigaction(sig, info, context);
|
|
54
|
+
} else if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN) {
|
|
55
|
+
prev->sa_handler(sig);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Restore default and raise to proceed with crash
|
|
44
62
|
signal(sig, SIG_DFL);
|
|
45
63
|
raise(sig);
|
|
46
64
|
}
|
|
@@ -54,9 +72,20 @@ Java_com_stallion_utils_StallionExceptionHandler_initNativeSignalHandler(
|
|
|
54
72
|
snprintf(g_mount_marker_path, sizeof(g_mount_marker_path), "%s/%s", path, "stallion_mount.marker");
|
|
55
73
|
env->ReleaseStringUTFChars(filesDir, path);
|
|
56
74
|
|
|
57
|
-
signal
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
// Use sigaction instead of signal for better handler chaining
|
|
76
|
+
struct sigaction action;
|
|
77
|
+
sigemptyset(&action.sa_mask);
|
|
78
|
+
action.sa_flags = SA_SIGINFO;
|
|
79
|
+
action.sa_sigaction = stallion_signal_handler;
|
|
80
|
+
|
|
81
|
+
int signals[] = {SIGABRT, SIGSEGV, SIGILL, SIGBUS, SIGFPE};
|
|
82
|
+
int signalCount = sizeof(signals) / sizeof(signals[0]);
|
|
83
|
+
|
|
84
|
+
for (int i = 0; i < signalCount; i++) {
|
|
85
|
+
int sig = signals[i];
|
|
86
|
+
// Store previous handler before installing ours (for chaining)
|
|
87
|
+
sigaction(sig, NULL, &g_previous_handlers[sig]);
|
|
88
|
+
// Now install our handler
|
|
89
|
+
sigaction(sig, &action, NULL);
|
|
90
|
+
}
|
|
62
91
|
}
|
|
@@ -9,51 +9,61 @@ import com.stallion.storage.StallionStateManager;
|
|
|
9
9
|
|
|
10
10
|
import org.json.JSONObject;
|
|
11
11
|
|
|
12
|
+
import java.util.concurrent.atomic.AtomicBoolean;
|
|
13
|
+
|
|
12
14
|
public class StallionExceptionHandler {
|
|
13
15
|
|
|
14
16
|
private static Thread.UncaughtExceptionHandler _androidUncaughtExceptionHandler;
|
|
15
17
|
private static Thread _exceptionThread;
|
|
16
18
|
private static Throwable _exceptionThrowable;
|
|
17
|
-
private static
|
|
18
|
-
private static
|
|
19
|
-
private static
|
|
19
|
+
private static final AtomicBoolean isErrorBoundaryInitialized = new AtomicBoolean(false);
|
|
20
|
+
private static final AtomicBoolean isNativeSignalsInitialized = new AtomicBoolean(false);
|
|
21
|
+
private static final AtomicBoolean hasProcessedNativeCrashMarker = new AtomicBoolean(false);
|
|
22
|
+
private static final AtomicBoolean isRollbackPerformed = new AtomicBoolean(false);
|
|
20
23
|
|
|
21
24
|
public static void initErrorBoundary() {
|
|
22
|
-
|
|
25
|
+
// Use compareAndSet to atomically check and set initialization flag
|
|
26
|
+
if (!isErrorBoundaryInitialized.compareAndSet(false, true)) {
|
|
23
27
|
return; // Prevent multiple initializations
|
|
24
28
|
}
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
// Reset rollback flag when initializing exception handler
|
|
31
|
+
isRollbackPerformed.set(false);
|
|
26
32
|
|
|
27
33
|
_androidUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
|
28
34
|
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
|
29
35
|
_exceptionThread = thread;
|
|
30
36
|
_exceptionThrowable = throwable;
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
try {
|
|
39
|
+
// Safely trim the stack trace string
|
|
40
|
+
String stackTraceString = Log.getStackTraceString(throwable);
|
|
41
|
+
stackTraceString = stackTraceString.length() > 900
|
|
42
|
+
? stackTraceString.substring(0, 900) + "..."
|
|
43
|
+
: stackTraceString;
|
|
37
44
|
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
StallionStateManager stateManager = StallionStateManager.getInstance();
|
|
46
|
+
StallionMetaConstants.SwitchState switchState = stateManager.stallionMeta.getSwitchState();
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
if (switchState == StallionMetaConstants.SwitchState.PROD) {
|
|
49
|
+
handleProdState(stackTraceString, stateManager);
|
|
50
|
+
} else if (switchState == StallionMetaConstants.SwitchState.STAGE) {
|
|
51
|
+
handleStageState(stackTraceString, stateManager);
|
|
52
|
+
} else {
|
|
53
|
+
continueExceptionFlow();
|
|
54
|
+
}
|
|
55
|
+
} catch (Exception e) {
|
|
56
|
+
// If anything goes wrong in our handler, ensure we still chain to previous handler
|
|
46
57
|
continueExceptionFlow();
|
|
47
58
|
}
|
|
48
59
|
});
|
|
49
60
|
|
|
50
61
|
// Initialize native signal handler once and process any prior crash marker
|
|
51
62
|
try {
|
|
52
|
-
if (
|
|
63
|
+
if (isNativeSignalsInitialized.compareAndSet(false, true)) {
|
|
53
64
|
System.loadLibrary("stallion-crash");
|
|
54
65
|
String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory();
|
|
55
66
|
initNativeSignalHandler(filesDir);
|
|
56
|
-
isNativeSignalsInitialized = true;
|
|
57
67
|
}
|
|
58
68
|
processNativeCrashMarkerIfPresent();
|
|
59
69
|
} catch (Throwable ignored) {}
|
|
@@ -78,14 +88,30 @@ public class StallionExceptionHandler {
|
|
|
78
88
|
boolean isAutoRollback = !stateManager.getIsMounted();
|
|
79
89
|
String currentHash = stateManager.stallionMeta.getHashAtCurrentProdSlot();
|
|
80
90
|
|
|
81
|
-
//
|
|
82
|
-
|
|
91
|
+
// Only prevent multiple executions for auto rollback cases
|
|
92
|
+
// Launch crashes (when mounted) can continue to be registered
|
|
93
|
+
if (isAutoRollback) {
|
|
94
|
+
// Use compareAndSet to atomically check and set the flag
|
|
95
|
+
if (!isRollbackPerformed.compareAndSet(false, true)) {
|
|
96
|
+
// Flag was already true, skip duplicate rollback
|
|
97
|
+
continueExceptionFlow();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Emit exception event (wrap in try-catch to ensure chaining happens)
|
|
103
|
+
try {
|
|
104
|
+
emitException(stackTraceString, currentHash, isAutoRollback, true);
|
|
105
|
+
} catch (Exception ignored) { }
|
|
83
106
|
|
|
84
107
|
// Perform rollback if auto-rollback is enabled
|
|
85
108
|
if (isAutoRollback) {
|
|
86
|
-
|
|
109
|
+
try {
|
|
110
|
+
StallionSlotManager.rollbackProd(true, stackTraceString);
|
|
111
|
+
} catch (Exception ignored) { }
|
|
87
112
|
}
|
|
88
113
|
|
|
114
|
+
// Always chain to previous handler, even if rollback or emit failed
|
|
89
115
|
continueExceptionFlow();
|
|
90
116
|
}
|
|
91
117
|
|
|
@@ -93,13 +119,29 @@ public class StallionExceptionHandler {
|
|
|
93
119
|
boolean isAutoRollback = !stateManager.getIsMounted();
|
|
94
120
|
String currentStageHash = stateManager.stallionMeta.getStageNewHash();
|
|
95
121
|
|
|
96
|
-
//
|
|
97
|
-
|
|
122
|
+
// Only prevent multiple executions for auto rollback cases
|
|
123
|
+
// Launch crashes (when mounted) can continue to be registered
|
|
124
|
+
if (isAutoRollback) {
|
|
125
|
+
// Use compareAndSet to atomically check and set the flag
|
|
126
|
+
if (!isRollbackPerformed.compareAndSet(false, true)) {
|
|
127
|
+
// Flag was already true, skip duplicate rollback
|
|
128
|
+
continueExceptionFlow();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Emit exception event (wrap in try-catch to ensure chaining happens)
|
|
134
|
+
try {
|
|
135
|
+
emitException(stackTraceString, currentStageHash, isAutoRollback, false);
|
|
136
|
+
} catch (Exception ignored) { }
|
|
98
137
|
|
|
99
138
|
if(isAutoRollback) {
|
|
100
|
-
|
|
139
|
+
try {
|
|
140
|
+
StallionSlotManager.rollbackStage();
|
|
141
|
+
} catch (Exception ignored) { }
|
|
101
142
|
}
|
|
102
143
|
|
|
144
|
+
// Always chain to previous handler, even if rollback or emit failed
|
|
103
145
|
continueExceptionFlow();
|
|
104
146
|
}
|
|
105
147
|
|
|
@@ -111,7 +153,7 @@ public class StallionExceptionHandler {
|
|
|
111
153
|
|
|
112
154
|
private static void processNativeCrashMarkerIfPresent() {
|
|
113
155
|
try {
|
|
114
|
-
if (hasProcessedNativeCrashMarker) { return; }
|
|
156
|
+
if (hasProcessedNativeCrashMarker.get()) { return; }
|
|
115
157
|
String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory();
|
|
116
158
|
java.io.File marker = new java.io.File(filesDir + "/stallion_crash.marker");
|
|
117
159
|
if (marker.exists()) {
|
|
@@ -149,22 +191,36 @@ public class StallionExceptionHandler {
|
|
|
149
191
|
if (switchState == StallionMetaConstants.SwitchState.PROD) {
|
|
150
192
|
String currentHash = stateManager.stallionMeta.getHashAtCurrentProdSlot();
|
|
151
193
|
// Use isAutoRollback from previous crash, not current session state
|
|
152
|
-
|
|
194
|
+
try {
|
|
195
|
+
emitException(stackTraceString, currentHash, isAutoRollback, true);
|
|
196
|
+
} catch (Exception ignored) { }
|
|
153
197
|
if (isAutoRollback) {
|
|
154
|
-
|
|
198
|
+
// Only prevent multiple executions for auto rollback cases
|
|
199
|
+
if (isRollbackPerformed.compareAndSet(false, true)) {
|
|
200
|
+
try {
|
|
201
|
+
StallionSlotManager.rollbackProd(true, stackTraceString);
|
|
202
|
+
} catch (Exception ignored) { }
|
|
203
|
+
}
|
|
155
204
|
}
|
|
156
205
|
} else if (switchState == StallionMetaConstants.SwitchState.STAGE) {
|
|
157
206
|
String currentStageHash = stateManager.stallionMeta.getStageNewHash();
|
|
158
207
|
// Use isAutoRollback from previous crash, not current session state
|
|
159
|
-
|
|
208
|
+
try {
|
|
209
|
+
emitException(stackTraceString, currentStageHash, isAutoRollback, false);
|
|
210
|
+
} catch (Exception ignored) { }
|
|
160
211
|
if (isAutoRollback) {
|
|
161
|
-
|
|
212
|
+
// Only prevent multiple executions for auto rollback cases
|
|
213
|
+
if (isRollbackPerformed.compareAndSet(false, true)) {
|
|
214
|
+
try {
|
|
215
|
+
StallionSlotManager.rollbackStage();
|
|
216
|
+
} catch (Exception ignored) { }
|
|
217
|
+
}
|
|
162
218
|
}
|
|
163
219
|
}
|
|
164
220
|
|
|
165
221
|
// delete marker
|
|
166
222
|
StallionFileManager.deleteFileOrFolderSilently(marker);
|
|
167
|
-
hasProcessedNativeCrashMarker
|
|
223
|
+
hasProcessedNativeCrashMarker.set(true);
|
|
168
224
|
}
|
|
169
225
|
} catch (Exception ignored) {}
|
|
170
226
|
}
|
|
@@ -12,57 +12,55 @@
|
|
|
12
12
|
#import "StallionMeta.h"
|
|
13
13
|
#import "StallionMetaConstants.h"
|
|
14
14
|
#import "StallionObjConstants.h"
|
|
15
|
+
#import "StallionFileManager.h"
|
|
15
16
|
#import <signal.h>
|
|
16
|
-
#import <
|
|
17
|
+
#import <unistd.h>
|
|
18
|
+
#import <fcntl.h>
|
|
17
19
|
#import <React/RCTLog.h>
|
|
18
20
|
#import <React/RCTUtils.h>
|
|
19
|
-
#include <
|
|
20
|
-
#include <cxxabi.h>
|
|
21
|
-
#include <string>
|
|
21
|
+
#include <atomic>
|
|
22
22
|
|
|
23
23
|
// Forward declarations
|
|
24
24
|
void handleException(NSException *exception);
|
|
25
25
|
void handleSignal(int signal, siginfo_t *info, void *context);
|
|
26
26
|
static void performStallionRollback(NSString *errorString);
|
|
27
27
|
static void setupSignalHandlers(void);
|
|
28
|
-
void
|
|
28
|
+
static void processNativeCrashMarkerIfPresent(void);
|
|
29
|
+
|
|
30
|
+
// Async-signal-safe crash marker storage
|
|
31
|
+
static char g_marker_path[512];
|
|
32
|
+
static char g_mount_marker_path[512];
|
|
29
33
|
|
|
30
34
|
@implementation StallionExceptionHandler
|
|
31
35
|
|
|
32
36
|
NSUncaughtExceptionHandler *_defaultExceptionHandler;
|
|
33
|
-
std::
|
|
34
|
-
|
|
35
|
-
static
|
|
36
|
-
static
|
|
37
|
+
static std::atomic<bool> exceptionAlertDismissed(false);
|
|
38
|
+
static std::atomic<bool> exceptionAlertShowing(false);
|
|
39
|
+
static std::atomic<bool> rollbackPerformed(false);
|
|
40
|
+
static std::atomic<bool> hasProcessedNativeCrashMarker(false);
|
|
37
41
|
static struct sigaction _previousHandlers[32]; // Store previous handlers for chaining
|
|
38
42
|
|
|
39
43
|
+ (void)initExceptionHandler {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Setup signal handlers using sigaction with chaining
|
|
62
|
-
setupSignalHandlers();
|
|
63
|
-
|
|
64
|
-
// Initialize JavaScript exception handler
|
|
65
|
-
[self initJavaScriptExceptionHandler];
|
|
44
|
+
static dispatch_once_t onceToken;
|
|
45
|
+
dispatch_once(&onceToken, ^{
|
|
46
|
+
// Reset rollback flag when initializing exception handler
|
|
47
|
+
[self resetRollbackFlag];
|
|
48
|
+
|
|
49
|
+
// Store and set Objective-C exception handler
|
|
50
|
+
if (!_defaultExceptionHandler) {
|
|
51
|
+
_defaultExceptionHandler = NSGetUncaughtExceptionHandler();
|
|
52
|
+
}
|
|
53
|
+
NSSetUncaughtExceptionHandler(&handleException);
|
|
54
|
+
|
|
55
|
+
// Setup signal handlers using sigaction with chaining
|
|
56
|
+
setupSignalHandlers();
|
|
57
|
+
|
|
58
|
+
// Initialize JavaScript exception handler
|
|
59
|
+
[self initJavaScriptExceptionHandler];
|
|
60
|
+
|
|
61
|
+
// Process any crash marker from previous session
|
|
62
|
+
processNativeCrashMarkerIfPresent();
|
|
63
|
+
});
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
+ (void)initJavaScriptExceptionHandler {
|
|
@@ -77,7 +75,7 @@ static struct sigaction _previousHandlers[32]; // Store previous handlers for ch
|
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
+ (void)resetRollbackFlag {
|
|
80
|
-
rollbackPerformed
|
|
78
|
+
rollbackPerformed.store(false);
|
|
81
79
|
}
|
|
82
80
|
|
|
83
81
|
@end
|
|
@@ -93,14 +91,13 @@ static void performStallionRollback(NSString *errorString) {
|
|
|
93
91
|
|
|
94
92
|
// Only prevent multiple executions for auto rollback cases
|
|
95
93
|
// Launch crashes (when mounted) can continue to be registered
|
|
96
|
-
if (rollbackPerformed && isAutoRollback) {
|
|
97
|
-
NSLog(@"Auto rollback already performed, skipping duplicate rollback attempt");
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Set rollback flag only for auto rollback cases
|
|
102
94
|
if (isAutoRollback) {
|
|
103
|
-
|
|
95
|
+
// Use compare-and-swap to atomically check and set the flag
|
|
96
|
+
bool expected = false;
|
|
97
|
+
if (!rollbackPerformed.compare_exchange_strong(expected, true)) {
|
|
98
|
+
// Flag was already true, skip duplicate rollback
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
104
101
|
}
|
|
105
102
|
|
|
106
103
|
if (errorString.length > 900) {
|
|
@@ -121,19 +118,24 @@ static void performStallionRollback(NSString *errorString) {
|
|
|
121
118
|
}
|
|
122
119
|
|
|
123
120
|
} else if (meta.switchState == SwitchStateStage) {
|
|
121
|
+
NSString *currentStageHash = meta.stageNewHash ?: @"";
|
|
124
122
|
|
|
125
|
-
|
|
126
|
-
[StallionSlotManager rollbackStage];
|
|
127
|
-
}
|
|
128
|
-
|
|
123
|
+
// Emit exception event before rollback (consistent with PROD and Android)
|
|
129
124
|
[[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_stage_event
|
|
130
125
|
eventPayload:@{
|
|
131
126
|
@"meta": errorString,
|
|
132
|
-
StallionObjConstants.release_hash_key:
|
|
127
|
+
StallionObjConstants.release_hash_key: currentStageHash,
|
|
133
128
|
StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false"
|
|
134
129
|
}];
|
|
130
|
+
|
|
131
|
+
if(isAutoRollback) {
|
|
132
|
+
[StallionSlotManager rollbackStage];
|
|
133
|
+
}
|
|
135
134
|
|
|
136
|
-
if(
|
|
135
|
+
// Check if alert is already showing (atomic check to prevent duplicates)
|
|
136
|
+
bool expectedShowing = false;
|
|
137
|
+
if (exceptionAlertShowing.compare_exchange_strong(expectedShowing, true)) {
|
|
138
|
+
// We successfully claimed the right to show the alert
|
|
137
139
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Stallion Exception Handler"
|
|
138
140
|
message:[NSString stringWithFormat:@"%@\n%@",
|
|
139
141
|
@"A crash occurred in the app. Build was rolled back. Check crash report below. Continue crash to invoke other exception handlers. \n \n",
|
|
@@ -143,7 +145,8 @@ static void performStallionRollback(NSString *errorString) {
|
|
|
143
145
|
[alert addAction:[UIAlertAction actionWithTitle:@"Continue Crash"
|
|
144
146
|
style:UIAlertActionStyleDefault
|
|
145
147
|
handler:^(UIAlertAction *action) {
|
|
146
|
-
|
|
148
|
+
// Set flag to true only when button is pressed
|
|
149
|
+
exceptionAlertDismissed.store(true);
|
|
147
150
|
}]];
|
|
148
151
|
|
|
149
152
|
UIApplication *app = [UIApplication sharedApplication];
|
|
@@ -153,7 +156,8 @@ static void performStallionRollback(NSString *errorString) {
|
|
|
153
156
|
[rootViewController presentViewController:alert animated:YES completion:nil];
|
|
154
157
|
});
|
|
155
158
|
|
|
156
|
-
|
|
159
|
+
// Wait for user to press the button (exceptionAlertDismissed becomes true)
|
|
160
|
+
while (!exceptionAlertDismissed.load()) {
|
|
157
161
|
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
|
158
162
|
}
|
|
159
163
|
}
|
|
@@ -162,10 +166,47 @@ static void performStallionRollback(NSString *errorString) {
|
|
|
162
166
|
|
|
163
167
|
#pragma mark - Signal Handler Setup
|
|
164
168
|
|
|
169
|
+
// Async-signal-safe function to check if mount marker exists
|
|
170
|
+
static int is_mounted_safe(void) {
|
|
171
|
+
int fd = open(g_mount_marker_path, O_RDONLY);
|
|
172
|
+
if (fd >= 0) {
|
|
173
|
+
close(fd);
|
|
174
|
+
return 1; // Mounted
|
|
175
|
+
}
|
|
176
|
+
return 0; // Not mounted
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Async-signal-safe JSON writing (minimal JSON for crash marker)
|
|
180
|
+
static void write_crash_marker_json_safe(int signal, int mounted) {
|
|
181
|
+
int fd = open(g_marker_path, O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
|
182
|
+
if (fd >= 0) {
|
|
183
|
+
// Write JSON: {"signal":X,"isAutoRollback":true/false,"crashLog":"signal=X\n"}
|
|
184
|
+
// isAutoRollback = !mounted (auto rollback if not mounted)
|
|
185
|
+
int autoRollback = !mounted;
|
|
186
|
+
char json[512];
|
|
187
|
+
int len = snprintf(json, sizeof(json),
|
|
188
|
+
"{\"signal\":%d,\"isAutoRollback\":%s,\"crashLog\":\"signal=%d\\n\"}",
|
|
189
|
+
signal, autoRollback ? "true" : "false", signal);
|
|
190
|
+
if (len > 0 && len < (int)sizeof(json)) {
|
|
191
|
+
(void)write(fd, json, len);
|
|
192
|
+
}
|
|
193
|
+
close(fd);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
165
197
|
static void setupSignalHandlers(void) {
|
|
198
|
+
// Initialize marker paths from StallionStateManager
|
|
199
|
+
StallionStateManager *stateManager = [StallionStateManager sharedInstance];
|
|
200
|
+
NSString *filesDir = stateManager.stallionConfig.filesDirectory;
|
|
201
|
+
if (filesDir) {
|
|
202
|
+
const char *path = [filesDir UTF8String];
|
|
203
|
+
snprintf(g_marker_path, sizeof(g_marker_path), "%s/%s", path, "stallion_crash.marker");
|
|
204
|
+
snprintf(g_mount_marker_path, sizeof(g_mount_marker_path), "%s/%s", path, "stallion_mount.marker");
|
|
205
|
+
}
|
|
206
|
+
|
|
166
207
|
struct sigaction action;
|
|
167
208
|
sigemptyset(&action.sa_mask);
|
|
168
|
-
action.sa_flags = SA_SIGINFO
|
|
209
|
+
action.sa_flags = SA_SIGINFO;
|
|
169
210
|
action.sa_sigaction = handleSignal;
|
|
170
211
|
|
|
171
212
|
// List of signals to catch - comprehensive coverage
|
|
@@ -206,28 +247,15 @@ void handleException(NSException *exception) {
|
|
|
206
247
|
}
|
|
207
248
|
|
|
208
249
|
void handleSignal(int signalVal, siginfo_t *info, void *context) {
|
|
209
|
-
void *callstack[128];
|
|
210
|
-
int frames = backtrace(callstack, 128);
|
|
211
|
-
char **symbols = backtrace_symbols(callstack, frames);
|
|
212
250
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
[stackTrace appendFormat:@"Fault Address: %p\n", info->si_addr];
|
|
220
|
-
}
|
|
251
|
+
if (!rollbackPerformed.load()) {
|
|
252
|
+
// Async-signal-safe operations only
|
|
253
|
+
// Read mount state at crash time (async-signal-safe)
|
|
254
|
+
int mounted = is_mounted_safe();
|
|
255
|
+
// Write JSON marker with crash info and autoRollback flag
|
|
256
|
+
write_crash_marker_json_safe(signalVal, mounted);
|
|
221
257
|
}
|
|
222
258
|
|
|
223
|
-
[stackTrace appendString:@"Stack trace:\n"];
|
|
224
|
-
for (int i = 0; i < frames; ++i) {
|
|
225
|
-
[stackTrace appendFormat:@"%s\n", symbols[i]];
|
|
226
|
-
}
|
|
227
|
-
free(symbols);
|
|
228
|
-
|
|
229
|
-
performStallionRollback(stackTrace);
|
|
230
|
-
|
|
231
259
|
// Chain to previous handler if it exists and is valid (bubble up)
|
|
232
260
|
if (signalVal >= 0 && signalVal < 32) {
|
|
233
261
|
struct sigaction *prev = &_previousHandlers[signalVal];
|
|
@@ -248,46 +276,104 @@ void handleSignal(int signalVal, siginfo_t *info, void *context) {
|
|
|
248
276
|
raise(signalVal);
|
|
249
277
|
}
|
|
250
278
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
std::rethrow_exception(ex);
|
|
258
|
-
} catch (const std::exception &e) {
|
|
259
|
-
const char *name = abi::__cxa_demangle(typeid(e).name(), 0, 0, 0);
|
|
260
|
-
errorString = [NSString stringWithFormat:@"C++ Exception: %s - %s",
|
|
261
|
-
name ? name : typeid(e).name(), e.what()];
|
|
262
|
-
if (name) free((void*)name);
|
|
263
|
-
} catch (const std::string &s) {
|
|
264
|
-
errorString = [NSString stringWithFormat:@"C++ Exception (string): %s", s.c_str()];
|
|
265
|
-
} catch (const char *s) {
|
|
266
|
-
errorString = [NSString stringWithFormat:@"C++ Exception (char*): %s", s];
|
|
267
|
-
} catch (...) {
|
|
268
|
-
errorString = @"C++ Exception: Unknown type";
|
|
279
|
+
#pragma mark - Crash Marker Processing
|
|
280
|
+
|
|
281
|
+
static void processNativeCrashMarkerIfPresent(void) {
|
|
282
|
+
@try {
|
|
283
|
+
if (hasProcessedNativeCrashMarker.load()) {
|
|
284
|
+
return;
|
|
269
285
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
286
|
+
|
|
287
|
+
StallionStateManager *stateManager = [StallionStateManager sharedInstance];
|
|
288
|
+
NSString *filesDir = stateManager.stallionConfig.filesDirectory;
|
|
289
|
+
NSString *markerPath = [NSString stringWithFormat:@"%@/stallion_crash.marker", filesDir];
|
|
290
|
+
|
|
291
|
+
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
292
|
+
if ([fileManager fileExistsAtPath:markerPath]) {
|
|
293
|
+
NSError *error = nil;
|
|
294
|
+
NSString *jsonContent = [NSString stringWithContentsOfFile:markerPath
|
|
295
|
+
encoding:NSUTF8StringEncoding
|
|
296
|
+
error:&error];
|
|
297
|
+
|
|
298
|
+
if (jsonContent && !error) {
|
|
299
|
+
NSString *stackTraceString = @"";
|
|
300
|
+
BOOL isAutoRollback = NO;
|
|
301
|
+
|
|
302
|
+
@try {
|
|
303
|
+
// Parse JSON from previous crash
|
|
304
|
+
NSData *jsonData = [jsonContent dataUsingEncoding:NSUTF8StringEncoding];
|
|
305
|
+
NSDictionary *crashMarker = [NSJSONSerialization JSONObjectWithData:jsonData
|
|
306
|
+
options:0
|
|
307
|
+
error:&error];
|
|
308
|
+
if (crashMarker && !error) {
|
|
309
|
+
// Extract crash log and autoRollback flag from marker
|
|
310
|
+
stackTraceString = crashMarker[@"crashLog"] ?: @"";
|
|
311
|
+
// Use the autoRollback flag that was determined at crash time (previous session)
|
|
312
|
+
isAutoRollback = [crashMarker[@"isAutoRollback"] boolValue];
|
|
313
|
+
}
|
|
314
|
+
} @catch (NSException *e) {
|
|
315
|
+
// Fallback for old format (non-JSON)
|
|
316
|
+
stackTraceString = jsonContent;
|
|
317
|
+
// Default to true for old format (conservative approach)
|
|
318
|
+
isAutoRollback = YES;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (stackTraceString.length > 900) {
|
|
322
|
+
stackTraceString = [stackTraceString substringToIndex:900];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
StallionMeta *meta = stateManager.stallionMeta;
|
|
326
|
+
SwitchState switchState = meta.switchState;
|
|
327
|
+
|
|
328
|
+
if (switchState == SwitchStateProd) {
|
|
329
|
+
NSString *currentHash = [meta getActiveReleaseHash] ?: @"";
|
|
330
|
+
// Use isAutoRollback from previous crash, not current session state
|
|
331
|
+
@try {
|
|
332
|
+
[[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_prod_event
|
|
333
|
+
eventPayload:@{
|
|
334
|
+
@"meta": stackTraceString,
|
|
335
|
+
StallionObjConstants.release_hash_key: currentHash,
|
|
336
|
+
StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false"
|
|
337
|
+
}];
|
|
338
|
+
} @catch (NSException *e) { }
|
|
339
|
+
|
|
340
|
+
if (isAutoRollback) {
|
|
341
|
+
// Only prevent multiple executions for auto rollback cases
|
|
342
|
+
bool expected = false;
|
|
343
|
+
if (rollbackPerformed.compare_exchange_strong(expected, true)) {
|
|
344
|
+
@try {
|
|
345
|
+
[StallionSlotManager rollbackProdWithAutoRollback:YES errorString:stackTraceString];
|
|
346
|
+
} @catch (NSException *e) { }
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
} else if (switchState == SwitchStateStage) {
|
|
350
|
+
NSString *currentStageHash = meta.stageNewHash ?: @"";
|
|
351
|
+
// Use isAutoRollback from previous crash, not current session state
|
|
352
|
+
@try {
|
|
353
|
+
[[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_stage_event
|
|
354
|
+
eventPayload:@{
|
|
355
|
+
@"meta": stackTraceString,
|
|
356
|
+
StallionObjConstants.release_hash_key: currentStageHash,
|
|
357
|
+
StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false"
|
|
358
|
+
}];
|
|
359
|
+
} @catch (NSException *e) { }
|
|
360
|
+
|
|
361
|
+
if (isAutoRollback) {
|
|
362
|
+
// Only prevent multiple executions for auto rollback cases
|
|
363
|
+
bool expected = false;
|
|
364
|
+
if (rollbackPerformed.compare_exchange_strong(expected, true)) {
|
|
365
|
+
@try {
|
|
366
|
+
[StallionSlotManager rollbackStage];
|
|
367
|
+
} @catch (NSException *e) { }
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Delete marker
|
|
373
|
+
[StallionFileManager deleteFileOrFolderSilently:markerPath];
|
|
374
|
+
hasProcessedNativeCrashMarker.store(true);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
} @catch (NSException *e) { }
|
|
292
378
|
}
|
|
293
379
|
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
NSString *newSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.new_folder_slot];
|
|
75
75
|
NSString *stableSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.stable_folder_slot];
|
|
76
76
|
|
|
77
|
-
[StallionFileManager
|
|
77
|
+
[StallionFileManager moveFileFrom:newSlotPath to:stableSlotPath];
|
|
78
78
|
|
|
79
79
|
NSString *newReleaseHash = stateManager.stallionMeta.prodNewHash;
|
|
80
80
|
[stateManager.stallionMeta setProdStableHash:newReleaseHash];
|
|
@@ -44,6 +44,9 @@ static StallionStateManager *_instance = nil;
|
|
|
44
44
|
_isMounted = NO;
|
|
45
45
|
_pendingReleaseUrl = @"";
|
|
46
46
|
_pendingReleaseHash = @"";
|
|
47
|
+
|
|
48
|
+
// Reset mount state on initialization (ensures mount marker file is deleted for new session)
|
|
49
|
+
[self setIsMounted:NO];
|
|
47
50
|
}
|
|
48
51
|
return self;
|
|
49
52
|
}
|
|
@@ -70,6 +73,32 @@ static StallionStateManager *_instance = nil;
|
|
|
70
73
|
[self syncStallionMeta];
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
- (void)setIsMounted:(BOOL)isMounted {
|
|
77
|
+
_isMounted = isMounted;
|
|
78
|
+
// Write mount state to a simple file that signal handler can read (async-signal-safe)
|
|
79
|
+
NSString *filesDir = self.stallionConfig.filesDirectory;
|
|
80
|
+
NSString *mountMarkerPath = [NSString stringWithFormat:@"%@/stallion_mount.marker", filesDir];
|
|
81
|
+
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
82
|
+
|
|
83
|
+
if (isMounted) {
|
|
84
|
+
// Create file to indicate mounted (file existence = mounted)
|
|
85
|
+
@try {
|
|
86
|
+
[fileManager createFileAtPath:mountMarkerPath contents:nil attributes:nil];
|
|
87
|
+
} @catch (NSException *e) {
|
|
88
|
+
// Silently ignore errors
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
// Delete file to indicate not mounted (no file = not mounted)
|
|
92
|
+
@try {
|
|
93
|
+
if ([fileManager fileExistsAtPath:mountMarkerPath]) {
|
|
94
|
+
[fileManager removeItemAtPath:mountMarkerPath error:nil];
|
|
95
|
+
}
|
|
96
|
+
} @catch (NSException *e) {
|
|
97
|
+
// Silently ignore errors
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
73
102
|
#pragma mark - Local Storage Methods
|
|
74
103
|
|
|
75
104
|
- (NSString *)getStringForKey:(NSString *)key defaultValue:(NSString *)defaultValue {
|
package/package.json
CHANGED
|
@@ -11,7 +11,8 @@ class ErrorBoundary extends Component {
|
|
|
11
11
|
constructor(props) {
|
|
12
12
|
super(props);
|
|
13
13
|
this.state = {
|
|
14
|
-
errorText: null
|
|
14
|
+
errorText: null,
|
|
15
|
+
originalError: null
|
|
15
16
|
};
|
|
16
17
|
this.continueCrash = this.continueCrash.bind(this);
|
|
17
18
|
}
|
|
@@ -40,11 +41,6 @@ class ErrorBoundary extends Component {
|
|
|
40
41
|
// Mark that a crash has occurred
|
|
41
42
|
setCrashOccurred();
|
|
42
43
|
|
|
43
|
-
// Always populate state with error information
|
|
44
|
-
this.setState({
|
|
45
|
-
errorText: errorString
|
|
46
|
-
});
|
|
47
|
-
|
|
48
44
|
// Get meta to determine behavior
|
|
49
45
|
const meta = await getStallionMetaNative();
|
|
50
46
|
|
|
@@ -53,10 +49,22 @@ class ErrorBoundary extends Component {
|
|
|
53
49
|
requestAnimationFrame(() => {
|
|
54
50
|
throw error;
|
|
55
51
|
});
|
|
52
|
+
} else {
|
|
53
|
+
// Store both error string and original error for STAGE mode
|
|
54
|
+
this.setState({
|
|
55
|
+
errorText: errorString,
|
|
56
|
+
originalError: error
|
|
57
|
+
});
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
continueCrash() {
|
|
59
|
-
throw
|
|
61
|
+
// Re-throw original error if available to preserve full context (stack trace, name, etc.)
|
|
62
|
+
// Fallback to new error with error text if original is not available
|
|
63
|
+
if (this.state.originalError) {
|
|
64
|
+
throw this.state.originalError;
|
|
65
|
+
} else {
|
|
66
|
+
throw new Error(this.state.errorText || '');
|
|
67
|
+
}
|
|
60
68
|
}
|
|
61
69
|
render() {
|
|
62
70
|
if (this.state.errorText) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Component","View","StyleSheet","Text","ScrollView","SafeAreaView","Header","ButtonFullWidth","getStallionMetaNative","setCrashOccurred","HEADER_TITLE","STALLION_EB_BTN_TXT","STALLION_EB_INFO","STD_MARGIN","COLORS","SWITCH_STATES","ErrorBoundary","constructor","props","state","errorText","continueCrash","bind","componentDidCatch","error","errorInfo","errorParts","name","push","message","cause","String","stack","componentStack","errorString","length","join","console","
|
|
1
|
+
{"version":3,"names":["React","Component","View","StyleSheet","Text","ScrollView","SafeAreaView","Header","ButtonFullWidth","getStallionMetaNative","setCrashOccurred","HEADER_TITLE","STALLION_EB_BTN_TXT","STALLION_EB_INFO","STD_MARGIN","COLORS","SWITCH_STATES","ErrorBoundary","constructor","props","state","errorText","originalError","continueCrash","bind","componentDidCatch","error","errorInfo","errorParts","name","push","message","cause","String","stack","componentStack","errorString","length","join","console","meta","switchState","STAGE","requestAnimationFrame","setState","Error","render","createElement","style","styles","ebContainer","title","ebContentContainer","ebInfoTextContainer","ebInfoText","buttonText","onPress","ebScrollContainer","contentContainerStyle","ebScrollContentContainer","ebErrorText","children","create","flex","flexDirection","justifyContent","alignItems","paddingHorizontal","width","marginVertical","flexGrow","textAlign","backgroundColor","black7","color","white"],"sourceRoot":"../../../../src","sources":["main/utils/ErrorBoundary.tsx"],"mappings":"AAAA,OAAOA,KAAK,IAAIC,SAAS,QAAQ,OAAO;AACxC,SAASC,IAAI,EAAEC,UAAU,EAAEC,IAAI,EAAEC,UAAU,EAAEC,YAAY,QAAQ,cAAc;AAE/E,OAAOC,MAAM,MAAM,6BAA6B;AAChD,OAAOC,eAAe,MAAM,sCAAsC;AAElE,SAASC,qBAAqB,QAAQ,uBAAuB;AAC7D,SAASC,gBAAgB,QAAQ,cAAc;AAC/C,SACEC,YAAY,EACZC,mBAAmB,EACnBC,gBAAgB,EAChBC,UAAU,QACL,2BAA2B;AAClC,SAASC,MAAM,QAAQ,qBAAqB;AAC5C,SAASC,aAAa,QAAQ,wBAAwB;AAQtD,MAAMC,aAAa,SAAShB,SAAS,CAGnC;EACAiB,WAAWA,CAACC,KAA0B,EAAE;IACtC,KAAK,CAACA,KAAK,CAAC;IACZ,IAAI,CAACC,KAAK,GAAG;MACXC,SAAS,EAAE,IAAI;MACfC,aAAa,EAAE;IACjB,CAAC;IACD,IAAI,CAACC,aAAa,GAAG,IAAI,CAACA,aAAa,CAACC,IAAI,CAAC,IAAI,CAAC;EACpD;EAEA,MAAMC,iBAAiBA,CACrBC,KAAY,EACZC,SAA2B,EACZ;IACf;IACA,MAAMC,UAAoB,GAAG,EAAE;IAE/B,IAAIF,KAAK,CAACG,IAAI,EAAE;MACdD,UAAU,CAACE,IAAI,CAAE,eAAcJ,KAAK,CAACG,IAAK,EAAC,CAAC;IAC9C;IACA,IAAIH,KAAK,CAACK,OAAO,EAAE;MACjBH,UAAU,CAACE,IAAI,CAAE,YAAWJ,KAAK,CAACK,OAAQ,EAAC,CAAC;IAC9C;IACA,IAAIL,KAAK,CAACM,KAAK,EAAE;MACfJ,UAAU,CAACE,IAAI,CAAE,UAASG,MAAM,CAACP,KAAK,CAACM,KAAK,CAAE,EAAC,CAAC;IAClD;IACA,IAAIN,KAAK,CAACQ,KAAK,EAAE;MACfN,UAAU,CAACE,IAAI,CAAE,mBAAkBJ,KAAK,CAACQ,KAAM,EAAC,CAAC;IACnD;IACA,IAAIP,SAAS,aAATA,SAAS,eAATA,SAAS,CAAEQ,cAAc,EAAE;MAC7BP,UAAU,CAACE,IAAI,CAAE,uBAAsBH,SAAS,CAACQ,cAAe,EAAC,CAAC;IACpE;IAEA,MAAMC,WAAmB,GACvBR,UAAU,CAACS,MAAM,GAAG,CAAC,GACjBT,UAAU,CAACU,IAAI,CAAC,MAAM,CAAC,GACtB,kBAAiBL,MAAM,CAACP,KAAK,CAAE,EAAC;IAEvCa,OAAO,CAACb,KAAK,CAAC,iCAAiC,EAAEA,KAAK,CAAC;IACvDa,OAAO,CAACb,KAAK,CAAC,aAAa,EAAEC,SAAS,CAAC;;IAEvC;IACAjB,gBAAgB,CAAC,CAAC;;IAElB;IACA,MAAM8B,IAAI,GAAG,MAAM/B,qBAAqB,CAAC,CAAC;;IAE1C;IACA,IAAI+B,IAAI,CAACC,WAAW,KAAKzB,aAAa,CAAC0B,KAAK,EAAE;MAC5CC,qBAAqB,CAAC,MAAM;QAC1B,MAAMjB,KAAK;MACb,CAAC,CAAC;IACJ,CAAC,MAAM;MACL;MACA,IAAI,CAACkB,QAAQ,CAAC;QACZvB,SAAS,EAAEe,WAAW;QACtBd,aAAa,EAAEI;MACjB,CAAC,CAAC;IACJ;EACF;EAEAH,aAAaA,CAAA,EAAG;IACd;IACA;IACA,IAAI,IAAI,CAACH,KAAK,CAACE,aAAa,EAAE;MAC5B,MAAM,IAAI,CAACF,KAAK,CAACE,aAAa;IAChC,CAAC,MAAM;MACL,MAAM,IAAIuB,KAAK,CAAC,IAAI,CAACzB,KAAK,CAACC,SAAS,IAAI,EAAE,CAAC;IAC7C;EACF;EACAyB,MAAMA,CAAA,EAAG;IACP,IAAI,IAAI,CAAC1B,KAAK,CAACC,SAAS,EAAE;MACxB,oBACErB,KAAA,CAAA+C,aAAA,CAACzC,YAAY;QAAC0C,KAAK,EAAEC,MAAM,CAACC;MAAY,gBACtClD,KAAA,CAAA+C,aAAA,CAACxC,MAAM;QAAC4C,KAAK,EAAExC;MAAa,CAAE,CAAC,eAC/BX,KAAA,CAAA+C,aAAA,CAAC7C,IAAI;QAAC8C,KAAK,EAAEC,MAAM,CAACG;MAAmB,gBACrCpD,KAAA,CAAA+C,aAAA,CAAC7C,IAAI;QAAC8C,KAAK,EAAEC,MAAM,CAACI;MAAoB,gBACtCrD,KAAA,CAAA+C,aAAA,CAAC3C,IAAI;QAAC4C,KAAK,EAAEC,MAAM,CAACK;MAAW,GAAEzC,gBAAuB,CAAC,eACzDb,KAAA,CAAA+C,aAAA,CAACvC,eAAe;QACd+C,UAAU,EAAE3C,mBAAoB;QAChC4C,OAAO,EAAE,IAAI,CAACjC;MAAc,CAC7B,CACG,CAAC,eACPvB,KAAA,CAAA+C,aAAA,CAAC1C,UAAU;QACT2C,KAAK,EAAEC,MAAM,CAACQ,iBAAkB;QAChCC,qBAAqB,EAAET,MAAM,CAACU;MAAyB,gBAEvD3D,KAAA,CAAA+C,aAAA,CAAC3C,IAAI;QAAC4C,KAAK,EAAEC,MAAM,CAACW;MAAY,GAAE,IAAI,CAACxC,KAAK,CAACC,SAAgB,CACnD,CACR,CACM,CAAC;IAEnB;IACA,OAAO,IAAI,CAACF,KAAK,CAAC0C,QAAQ;EAC5B;AACF;AAEA,eAAe5C,aAAa;AAE5B,MAAMgC,MAAM,GAAG9C,UAAU,CAAC2D,MAAM,CAAC;EAC/BZ,WAAW,EAAE;IACXa,IAAI,EAAE,CAAC;IACPC,aAAa,EAAE,QAAQ;IACvBC,cAAc,EAAE,YAAY;IAC5BC,UAAU,EAAE;EACd,CAAC;EACDd,kBAAkB,EAAE;IAClBW,IAAI,EAAE,CAAC;IACPI,iBAAiB,EAAErD,UAAU;IAC7BsD,KAAK,EAAE;EACT,CAAC;EACDf,mBAAmB,EAAE;IACnBa,UAAU,EAAE,QAAQ;IACpBD,cAAc,EAAE,QAAQ;IACxBI,cAAc,EAAEvD;EAClB,CAAC;EACD6C,wBAAwB,EAAE;IACxBW,QAAQ,EAAE;EACZ,CAAC;EACDhB,UAAU,EAAE;IACViB,SAAS,EAAE,QAAQ;IACnBF,cAAc,EAAEvD;EAClB,CAAC;EACD2C,iBAAiB,EAAE;IACjBM,IAAI,EAAE,CAAC;IACPS,eAAe,EAAEzD,MAAM,CAAC0D;EAC1B,CAAC;EACDb,WAAW,EAAE;IACXc,KAAK,EAAE3D,MAAM,CAAC4D;EAChB;AACF,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../../../src/main/utils/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiBzC,UAAU,mBAAmB;CAAG;AAChC,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../../../src/main/utils/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiBzC,UAAU,mBAAmB;CAAG;AAChC,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CAC9B;AAED,cAAM,aAAc,SAAQ,SAAS,CACnC,mBAAmB,EACnB,mBAAmB,CACpB;gBACa,KAAK,EAAE,mBAAmB;IAShC,iBAAiB,CACrB,KAAK,EAAE,KAAK,EACZ,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,GAC1B,OAAO,CAAC,IAAI,CAAC;IAgDhB,aAAa;IASb,MAAM;CAyBP;AAED,eAAe,aAAa,CAAC"}
|