@logbrew/react-native 0.1.2 → 0.1.4
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/LogBrewReactNative.podspec +22 -0
- package/README.md +3 -3
- package/android/build.gradle +42 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/co/logbrew/reactnative/FatalRecordStore.java +636 -0
- package/android/src/main/java/co/logbrew/reactnative/FatalStoreModuleImpl.java +225 -0
- package/android/src/main/java/co/logbrew/reactnative/LogBrewReactNativePackage.java +20 -0
- package/android/src/newarch/java/co/logbrew/reactnative/FatalStoreModule.java +39 -0
- package/android/src/oldarch/java/co/logbrew/reactnative/FatalStoreModule.java +41 -0
- package/fatal-replay.cjs +531 -0
- package/global-errors.cjs +51 -3
- package/global-errors.d.cts +72 -4
- package/global-errors.d.ts +72 -4
- package/global-errors.native.js +39 -0
- package/index.native.d.ts +2 -0
- package/index.native.js +3 -0
- package/ios/LBRNFatalRecordStore.h +25 -0
- package/ios/LBRNFatalRecordStore.m +542 -0
- package/ios/LBRNFatalStoreModule.h +4 -0
- package/ios/LBRNFatalStoreModule.mm +147 -0
- package/package.json +33 -4
- package/react-native.config.js +11 -0
- package/src/NativeLogBrewFatalStore.ts +11 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
package co.logbrew.reactnative;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments;
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
5
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
7
|
+
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
|
8
|
+
import com.facebook.react.bridge.ReadableType;
|
|
9
|
+
import com.facebook.react.bridge.WritableArray;
|
|
10
|
+
import com.facebook.react.bridge.WritableMap;
|
|
11
|
+
import java.io.File;
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import java.util.Arrays;
|
|
14
|
+
import java.util.HashSet;
|
|
15
|
+
import java.util.List;
|
|
16
|
+
import java.util.Set;
|
|
17
|
+
|
|
18
|
+
final class FatalStoreModuleImpl {
|
|
19
|
+
static final String NAME = "LogBrewFatalStore";
|
|
20
|
+
|
|
21
|
+
private static final Set<String> RECORD_KEYS =
|
|
22
|
+
new HashSet<>(
|
|
23
|
+
Arrays.asList(
|
|
24
|
+
"schemaVersion",
|
|
25
|
+
"id",
|
|
26
|
+
"timestamp",
|
|
27
|
+
"errorName",
|
|
28
|
+
"stackFrames",
|
|
29
|
+
"droppedRecords",
|
|
30
|
+
"corruptRecords"));
|
|
31
|
+
private static final Set<String> FRAME_KEYS =
|
|
32
|
+
new HashSet<>(Arrays.asList("filename", "line", "column"));
|
|
33
|
+
|
|
34
|
+
private final FatalRecordStore store;
|
|
35
|
+
|
|
36
|
+
FatalStoreModuleImpl(ReactApplicationContext context) {
|
|
37
|
+
File root = context.getNoBackupFilesDir();
|
|
38
|
+
store = root == null ? null : new FatalRecordStore(new File(root, "logbrew-fatal-js"));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
WritableMap writeFatalRecord(ReadableMap input) {
|
|
42
|
+
if (store == null) {
|
|
43
|
+
return status("storage_error");
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
FatalRecordStore.Record record = readRecord(input);
|
|
47
|
+
return record == null ? status("invalid_record") : resultMap(store.write(record));
|
|
48
|
+
} catch (RuntimeException error) {
|
|
49
|
+
return status("storage_error");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
WritableMap readFatalRecord() {
|
|
54
|
+
if (store == null) {
|
|
55
|
+
return status("storage_error");
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return resultMap(store.read());
|
|
59
|
+
} catch (RuntimeException error) {
|
|
60
|
+
return status("storage_error");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
WritableMap acknowledgeFatalRecord(String recordId) {
|
|
65
|
+
if (store == null) {
|
|
66
|
+
return status("storage_error");
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
return resultMap(store.acknowledge(recordId));
|
|
70
|
+
} catch (RuntimeException error) {
|
|
71
|
+
return status("storage_error");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
WritableMap discardFatalRecord() {
|
|
76
|
+
if (store == null) {
|
|
77
|
+
return status("storage_error");
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return resultMap(store.discard());
|
|
81
|
+
} catch (RuntimeException error) {
|
|
82
|
+
return status("storage_error");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private static FatalRecordStore.Record readRecord(ReadableMap input) {
|
|
87
|
+
if (input == null
|
|
88
|
+
|| !hasExactKeys(input, RECORD_KEYS)
|
|
89
|
+
|| !hasType(input, "schemaVersion", ReadableType.Number)
|
|
90
|
+
|| !hasType(input, "id", ReadableType.String)
|
|
91
|
+
|| !hasType(input, "timestamp", ReadableType.String)
|
|
92
|
+
|| !hasType(input, "errorName", ReadableType.String)
|
|
93
|
+
|| !hasType(input, "stackFrames", ReadableType.Array)
|
|
94
|
+
|| !hasType(input, "droppedRecords", ReadableType.Number)
|
|
95
|
+
|| !hasType(input, "corruptRecords", ReadableType.Number)) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
Integer schemaVersion = integer(input, "schemaVersion");
|
|
99
|
+
Integer droppedRecords = integer(input, "droppedRecords");
|
|
100
|
+
Integer corruptRecords = integer(input, "corruptRecords");
|
|
101
|
+
if (schemaVersion == null || droppedRecords == null || corruptRecords == null) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
ReadableArray values = input.getArray("stackFrames");
|
|
106
|
+
if (values == null) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
List<FatalRecordStore.Frame> frames = new ArrayList<>(values.size());
|
|
110
|
+
for (int index = 0; index < values.size(); index += 1) {
|
|
111
|
+
if (values.getType(index) != ReadableType.Map) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
ReadableMap value = values.getMap(index);
|
|
115
|
+
FatalRecordStore.Frame frame = readFrame(value);
|
|
116
|
+
if (frame == null) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
frames.add(frame);
|
|
120
|
+
}
|
|
121
|
+
return new FatalRecordStore.Record(
|
|
122
|
+
schemaVersion,
|
|
123
|
+
input.getString("id"),
|
|
124
|
+
input.getString("timestamp"),
|
|
125
|
+
input.getString("errorName"),
|
|
126
|
+
frames,
|
|
127
|
+
droppedRecords,
|
|
128
|
+
corruptRecords);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private static FatalRecordStore.Frame readFrame(ReadableMap input) {
|
|
132
|
+
if (input == null
|
|
133
|
+
|| !hasExactKeys(input, FRAME_KEYS)
|
|
134
|
+
|| !hasType(input, "filename", ReadableType.String)
|
|
135
|
+
|| !hasType(input, "line", ReadableType.Number)
|
|
136
|
+
|| !hasType(input, "column", ReadableType.Number)) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
Integer line = integer(input, "line");
|
|
140
|
+
Integer column = integer(input, "column");
|
|
141
|
+
String filename = input.getString("filename");
|
|
142
|
+
if (line == null || column == null || filename == null) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
if (filename.startsWith("/")
|
|
146
|
+
&& filename.indexOf('/', 1) < 0
|
|
147
|
+
&& filename.length() > 1) {
|
|
148
|
+
filename = filename.substring(1);
|
|
149
|
+
}
|
|
150
|
+
return new FatalRecordStore.Frame(filename, line, column);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private static boolean hasType(ReadableMap map, String key, ReadableType type) {
|
|
154
|
+
return map.hasKey(key) && !map.isNull(key) && map.getType(key) == type;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private static boolean hasExactKeys(ReadableMap map, Set<String> expected) {
|
|
158
|
+
Set<String> observed = new HashSet<>();
|
|
159
|
+
ReadableMapKeySetIterator iterator = map.keySetIterator();
|
|
160
|
+
while (iterator.hasNextKey()) {
|
|
161
|
+
observed.add(iterator.nextKey());
|
|
162
|
+
}
|
|
163
|
+
return observed.equals(expected);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private static Integer integer(ReadableMap map, String key) {
|
|
167
|
+
double value = map.getDouble(key);
|
|
168
|
+
return Double.isFinite(value)
|
|
169
|
+
&& value >= 0
|
|
170
|
+
&& value <= Integer.MAX_VALUE
|
|
171
|
+
&& value == Math.rint(value)
|
|
172
|
+
? (int) value
|
|
173
|
+
: null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private static WritableMap resultMap(FatalRecordStore.Result result) {
|
|
177
|
+
if (result == null || result.status == null) {
|
|
178
|
+
return status("storage_error");
|
|
179
|
+
}
|
|
180
|
+
WritableMap output = status(result.status);
|
|
181
|
+
if (result.recordId != null) {
|
|
182
|
+
output.putString("recordId", result.recordId);
|
|
183
|
+
}
|
|
184
|
+
if (result.droppedRecords > 0) {
|
|
185
|
+
output.putInt("droppedRecords", result.droppedRecords);
|
|
186
|
+
}
|
|
187
|
+
if (result.corruptRecords > 0) {
|
|
188
|
+
output.putInt("corruptRecords", result.corruptRecords);
|
|
189
|
+
}
|
|
190
|
+
if (result.record != null) {
|
|
191
|
+
output.putMap("record", recordMap(result.record));
|
|
192
|
+
}
|
|
193
|
+
return output;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private static WritableMap recordMap(FatalRecordStore.Record record) {
|
|
197
|
+
WritableMap output = Arguments.createMap();
|
|
198
|
+
output.putInt("schemaVersion", record.schemaVersion);
|
|
199
|
+
output.putString("id", record.id);
|
|
200
|
+
output.putString("timestamp", record.timestamp);
|
|
201
|
+
output.putString("errorName", record.errorName);
|
|
202
|
+
output.putArray("stackFrames", frameMaps(record.stackFrames));
|
|
203
|
+
output.putInt("droppedRecords", record.droppedRecords);
|
|
204
|
+
output.putInt("corruptRecords", record.corruptRecords);
|
|
205
|
+
return output;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private static WritableArray frameMaps(List<FatalRecordStore.Frame> frames) {
|
|
209
|
+
WritableArray output = Arguments.createArray();
|
|
210
|
+
for (FatalRecordStore.Frame frame : frames) {
|
|
211
|
+
WritableMap value = Arguments.createMap();
|
|
212
|
+
value.putString("filename", frame.filename);
|
|
213
|
+
value.putInt("line", frame.line);
|
|
214
|
+
value.putInt("column", frame.column);
|
|
215
|
+
output.pushMap(value);
|
|
216
|
+
}
|
|
217
|
+
return output;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private static WritableMap status(String value) {
|
|
221
|
+
WritableMap output = Arguments.createMap();
|
|
222
|
+
output.putString("status", value);
|
|
223
|
+
return output;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package co.logbrew.reactnative;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage;
|
|
4
|
+
import com.facebook.react.bridge.NativeModule;
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager;
|
|
7
|
+
import java.util.Collections;
|
|
8
|
+
import java.util.List;
|
|
9
|
+
|
|
10
|
+
public final class LogBrewReactNativePackage implements ReactPackage {
|
|
11
|
+
@Override
|
|
12
|
+
public List<NativeModule> createNativeModules(ReactApplicationContext context) {
|
|
13
|
+
return Collections.singletonList(new FatalStoreModule(context));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Override
|
|
17
|
+
public List<ViewManager> createViewManagers(ReactApplicationContext context) {
|
|
18
|
+
return Collections.emptyList();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package co.logbrew.reactnative;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
4
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
5
|
+
import com.facebook.react.bridge.WritableMap;
|
|
6
|
+
|
|
7
|
+
final class FatalStoreModule extends NativeLogBrewFatalStoreSpec {
|
|
8
|
+
private final FatalStoreModuleImpl implementation;
|
|
9
|
+
|
|
10
|
+
FatalStoreModule(ReactApplicationContext context) {
|
|
11
|
+
super(context);
|
|
12
|
+
implementation = new FatalStoreModuleImpl(context);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Override
|
|
16
|
+
public String getName() {
|
|
17
|
+
return FatalStoreModuleImpl.NAME;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Override
|
|
21
|
+
public WritableMap writeFatalRecord(ReadableMap record) {
|
|
22
|
+
return implementation.writeFatalRecord(record);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Override
|
|
26
|
+
public WritableMap readFatalRecord() {
|
|
27
|
+
return implementation.readFatalRecord();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Override
|
|
31
|
+
public WritableMap acknowledgeFatalRecord(String recordId) {
|
|
32
|
+
return implementation.acknowledgeFatalRecord(recordId);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Override
|
|
36
|
+
public WritableMap discardFatalRecord() {
|
|
37
|
+
return implementation.discardFatalRecord();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package co.logbrew.reactnative;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
4
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
5
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
7
|
+
import com.facebook.react.bridge.WritableMap;
|
|
8
|
+
|
|
9
|
+
final class FatalStoreModule extends ReactContextBaseJavaModule {
|
|
10
|
+
private final FatalStoreModuleImpl implementation;
|
|
11
|
+
|
|
12
|
+
FatalStoreModule(ReactApplicationContext context) {
|
|
13
|
+
super(context);
|
|
14
|
+
implementation = new FatalStoreModuleImpl(context);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@Override
|
|
18
|
+
public String getName() {
|
|
19
|
+
return FatalStoreModuleImpl.NAME;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
23
|
+
public WritableMap writeFatalRecord(ReadableMap record) {
|
|
24
|
+
return implementation.writeFatalRecord(record);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
28
|
+
public WritableMap readFatalRecord() {
|
|
29
|
+
return implementation.readFatalRecord();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
33
|
+
public WritableMap acknowledgeFatalRecord(String recordId) {
|
|
34
|
+
return implementation.acknowledgeFatalRecord(recordId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
38
|
+
public WritableMap discardFatalRecord() {
|
|
39
|
+
return implementation.discardFatalRecord();
|
|
40
|
+
}
|
|
41
|
+
}
|