@expo/metro-runtime 3.0.1 → 3.0.2
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/build/LoadingView.d.ts +6 -0
- package/build/LoadingView.d.ts.map +1 -1
- package/build/LoadingView.js +9 -3
- package/build/LoadingView.js.map +1 -1
- package/build/async-require/fetchAsync.d.ts +6 -0
- package/build/async-require/fetchAsync.d.ts.map +1 -1
- package/build/async-require/fetchAsync.js +1 -2
- package/build/async-require/fetchAsync.js.map +1 -1
- package/build/async-require/fetchThenEval.d.ts +1 -6
- package/build/async-require/fetchThenEval.d.ts.map +1 -1
- package/build/async-require/fetchThenEval.js +2 -32
- package/build/async-require/fetchThenEval.js.map +1 -1
- package/build/async-require/fetchThenEval.web.js +1 -1
- package/build/async-require/fetchThenEval.web.js.map +1 -1
- package/build/async-require/fetchThenEvalJs.d.ts +7 -0
- package/build/async-require/fetchThenEvalJs.d.ts.map +1 -0
- package/build/async-require/fetchThenEvalJs.js +36 -0
- package/build/async-require/fetchThenEvalJs.js.map +1 -0
- package/build/async-require/index.native.d.ts +7 -0
- package/build/async-require/index.native.d.ts.map +1 -0
- package/build/async-require/index.native.js +14 -0
- package/build/async-require/index.native.js.map +1 -0
- package/build/effects.d.ts +0 -1
- package/build/effects.js +1 -6
- package/build/effects.js.map +1 -1
- package/build/error-overlay/Data/parseLogBoxLog.d.ts.map +1 -1
- package/build/error-overlay/Data/parseLogBoxLog.js +1 -2
- package/build/error-overlay/Data/parseLogBoxLog.js.map +1 -1
- package/build/error-overlay/LogBox.web.d.ts.map +1 -1
- package/build/error-overlay/LogBox.web.js +1 -2
- package/build/error-overlay/LogBox.web.js.map +1 -1
- package/build/error-overlay/index.d.ts.map +1 -1
- package/build/error-overlay/index.js +1 -0
- package/build/error-overlay/index.js.map +1 -1
- package/build/getDevServer.d.ts.map +1 -1
- package/build/getDevServer.js +2 -6
- package/build/getDevServer.js.map +1 -1
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +10 -8
- package/build/index.js.map +1 -1
- package/build/setupHMR.js +21 -24
- package/build/setupHMR.js.map +1 -1
- package/package.json +5 -2
- package/src/HMRClient.native.ts +3 -0
- package/src/HMRClient.ts +316 -0
- package/src/LoadingView.native.ts +3 -0
- package/src/LoadingView.ts +24 -0
- package/src/__mocks__/LoadingView.ts +4 -0
- package/src/async-require/buildAsyncRequire.ts +34 -0
- package/src/async-require/buildUrlForBundle.native.ts +28 -0
- package/src/async-require/buildUrlForBundle.ts +18 -0
- package/src/async-require/fetchAsync.native.ts +72 -0
- package/src/async-require/fetchAsync.ts +19 -0
- package/src/async-require/fetchThenEval.ts +1 -0
- package/src/async-require/fetchThenEval.web.ts +70 -0
- package/src/async-require/fetchThenEvalJs.ts +39 -0
- package/src/async-require/index.native.ts +15 -0
- package/src/async-require/index.ts +10 -0
- package/src/async-require/loadBundle.ts +46 -0
- package/src/effects.native.ts +0 -0
- package/src/effects.ts +11 -0
- package/src/error-overlay/Data/LogBoxData.tsx +438 -0
- package/src/error-overlay/Data/LogBoxLog.ts +221 -0
- package/src/error-overlay/Data/LogBoxSymbolication.tsx +64 -0
- package/src/error-overlay/Data/LogContext.tsx +41 -0
- package/src/error-overlay/Data/parseLogBoxLog.tsx +342 -0
- package/src/error-overlay/ErrorOverlay.tsx +191 -0
- package/src/error-overlay/LogBox.ts +51 -0
- package/src/error-overlay/LogBox.web.ts +174 -0
- package/src/error-overlay/UI/AnsiHighlight.tsx +96 -0
- package/src/error-overlay/UI/LogBoxButton.tsx +63 -0
- package/src/error-overlay/UI/LogBoxMessage.tsx +73 -0
- package/src/error-overlay/UI/LogBoxStyle.ts +64 -0
- package/src/error-overlay/UI/constants.ts +7 -0
- package/src/error-overlay/formatProjectFilePath.ts +38 -0
- package/src/error-overlay/index.tsx +34 -0
- package/src/error-overlay/modules/ExceptionsManager/index.native.ts +4 -0
- package/src/error-overlay/modules/ExceptionsManager/index.ts +82 -0
- package/src/error-overlay/modules/NativeLogBox/index.native.ts +3 -0
- package/src/error-overlay/modules/NativeLogBox/index.tsx +27 -0
- package/src/error-overlay/modules/openFileInEditor/index.native.ts +3 -0
- package/src/error-overlay/modules/openFileInEditor/index.ts +16 -0
- package/src/error-overlay/modules/parseErrorStack/index.ts +26 -0
- package/src/error-overlay/modules/parseErrorStack/parseHermesStack.ts +3 -0
- package/src/error-overlay/modules/stringifySafe/index.ts +115 -0
- package/src/error-overlay/modules/symbolicateStackTrace/index.native.ts +3 -0
- package/src/error-overlay/modules/symbolicateStackTrace/index.ts +39 -0
- package/src/error-overlay/overlay/LogBoxInspectorCodeFrame.tsx +102 -0
- package/src/error-overlay/overlay/LogBoxInspectorFooter.tsx +111 -0
- package/src/error-overlay/overlay/LogBoxInspectorHeader.tsx +167 -0
- package/src/error-overlay/overlay/LogBoxInspectorMessageHeader.tsx +116 -0
- package/src/error-overlay/overlay/LogBoxInspectorSection.tsx +52 -0
- package/src/error-overlay/overlay/LogBoxInspectorSourceMapStatus.tsx +125 -0
- package/src/error-overlay/overlay/LogBoxInspectorStackFrame.tsx +89 -0
- package/src/error-overlay/overlay/LogBoxInspectorStackFrames.tsx +201 -0
- package/src/error-overlay/toast/ErrorToast.tsx +167 -0
- package/src/error-overlay/toast/ErrorToastContainer.tsx +9 -0
- package/src/error-overlay/toast/ErrorToastContainer.web.tsx +92 -0
- package/src/error-overlay/toast/ErrorToastMessage.tsx +28 -0
- package/src/error-overlay/useRejectionHandler.ts +61 -0
- package/src/getDevServer.native.ts +3 -0
- package/src/getDevServer.ts +34 -0
- package/src/index.ts +12 -0
- package/src/location/Location.native.ts +201 -0
- package/src/location/Location.ts +3 -0
- package/src/location/install.native.ts +90 -0
- package/src/location/install.ts +0 -0
- package/src/messageSocket.ts +25 -0
- package/src/setupFastRefresh.ts +30 -0
- package/src/setupHMR.ts +28 -0
- package/src/symbolicate.ts +6 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 650 Industries.
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useState } from 'react';
|
|
9
|
+
import { StyleSheet, Text, View } from 'react-native';
|
|
10
|
+
|
|
11
|
+
import { LogBoxInspectorSection } from './LogBoxInspectorSection';
|
|
12
|
+
import { LogBoxInspectorSourceMapStatus } from './LogBoxInspectorSourceMapStatus';
|
|
13
|
+
import { LogBoxInspectorStackFrame } from './LogBoxInspectorStackFrame';
|
|
14
|
+
import type { StackType } from '../Data/LogBoxLog';
|
|
15
|
+
import type { Stack } from '../Data/LogBoxSymbolication';
|
|
16
|
+
import { useSelectedLog } from '../Data/LogContext';
|
|
17
|
+
import { LogBoxButton } from '../UI/LogBoxButton';
|
|
18
|
+
import * as LogBoxStyle from '../UI/LogBoxStyle';
|
|
19
|
+
import openFileInEditor from '../modules/openFileInEditor';
|
|
20
|
+
|
|
21
|
+
type Props = {
|
|
22
|
+
type: StackType;
|
|
23
|
+
onRetry: () => void;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function getCollapseMessage(stackFrames: Stack, collapsed: boolean): string {
|
|
27
|
+
if (stackFrames.length === 0) {
|
|
28
|
+
return 'No frames to show';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const collapsedCount = stackFrames.reduce((count, { collapse }) => {
|
|
32
|
+
if (collapse === true) {
|
|
33
|
+
return count + 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return count;
|
|
37
|
+
}, 0);
|
|
38
|
+
|
|
39
|
+
if (collapsedCount === 0) {
|
|
40
|
+
return 'Showing all frames';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const framePlural = `frame${collapsedCount > 1 ? 's' : ''}`;
|
|
44
|
+
if (collapsedCount === stackFrames.length) {
|
|
45
|
+
return collapsed
|
|
46
|
+
? `See${collapsedCount > 1 ? ' all ' : ' '}${collapsedCount} collapsed ${framePlural}`
|
|
47
|
+
: `Collapse${collapsedCount > 1 ? ' all ' : ' '}${collapsedCount} ${framePlural}`;
|
|
48
|
+
} else {
|
|
49
|
+
return collapsed
|
|
50
|
+
? `See ${collapsedCount} more ${framePlural}`
|
|
51
|
+
: `Collapse ${collapsedCount} ${framePlural}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function LogBoxInspectorStackFrames({ onRetry, type }: Props) {
|
|
56
|
+
const log = useSelectedLog();
|
|
57
|
+
|
|
58
|
+
const [collapsed, setCollapsed] = useState(() => {
|
|
59
|
+
// Only collapse frames initially if some frames are not collapsed.
|
|
60
|
+
return log.getAvailableStack(type)?.some(({ collapse }) => !collapse);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function getStackList() {
|
|
64
|
+
if (collapsed === true) {
|
|
65
|
+
return log.getAvailableStack(type)?.filter(({ collapse }) => !collapse);
|
|
66
|
+
} else {
|
|
67
|
+
return log.getAvailableStack(type);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (log.getAvailableStack(type)?.length === 0) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<LogBoxInspectorSection
|
|
77
|
+
heading={type === 'component' ? 'Component Stack' : 'Call Stack'}
|
|
78
|
+
action={
|
|
79
|
+
<LogBoxInspectorSourceMapStatus
|
|
80
|
+
onPress={log.symbolicated[type].status === 'FAILED' ? onRetry : null}
|
|
81
|
+
status={log.symbolicated[type].status}
|
|
82
|
+
/>
|
|
83
|
+
}>
|
|
84
|
+
{log.symbolicated[type].status !== 'COMPLETE' && (
|
|
85
|
+
<View style={stackStyles.hintBox}>
|
|
86
|
+
<Text style={stackStyles.hintText}>
|
|
87
|
+
This call stack is not symbolicated. Some features are unavailable such as viewing the
|
|
88
|
+
function name or tapping to open files.
|
|
89
|
+
</Text>
|
|
90
|
+
</View>
|
|
91
|
+
)}
|
|
92
|
+
<StackFrameList list={getStackList()!} status={log.symbolicated[type].status} />
|
|
93
|
+
<StackFrameFooter
|
|
94
|
+
onPress={() => setCollapsed(!collapsed)}
|
|
95
|
+
message={getCollapseMessage(log.getAvailableStack(type)!, !!collapsed)}
|
|
96
|
+
/>
|
|
97
|
+
</LogBoxInspectorSection>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function StackFrameList({
|
|
102
|
+
list,
|
|
103
|
+
status,
|
|
104
|
+
}: {
|
|
105
|
+
list: Stack;
|
|
106
|
+
status: 'NONE' | 'PENDING' | 'COMPLETE' | 'FAILED';
|
|
107
|
+
}): any {
|
|
108
|
+
return list.map((frame, index) => {
|
|
109
|
+
const { file, lineNumber } = frame;
|
|
110
|
+
return (
|
|
111
|
+
<LogBoxInspectorStackFrame
|
|
112
|
+
key={index}
|
|
113
|
+
frame={frame}
|
|
114
|
+
onPress={
|
|
115
|
+
status === 'COMPLETE' && file != null && lineNumber != null
|
|
116
|
+
? () => openFileInEditor(file, lineNumber)
|
|
117
|
+
: undefined
|
|
118
|
+
}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function StackFrameFooter({ message, onPress }: { message: string; onPress: () => void }) {
|
|
125
|
+
return (
|
|
126
|
+
<View style={stackStyles.collapseContainer}>
|
|
127
|
+
<LogBoxButton
|
|
128
|
+
backgroundColor={{
|
|
129
|
+
default: 'transparent',
|
|
130
|
+
pressed: LogBoxStyle.getBackgroundColor(1),
|
|
131
|
+
}}
|
|
132
|
+
onPress={onPress}
|
|
133
|
+
style={stackStyles.collapseButton}>
|
|
134
|
+
<Text style={stackStyles.collapse}>{message}</Text>
|
|
135
|
+
</LogBoxButton>
|
|
136
|
+
</View>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const stackStyles = StyleSheet.create({
|
|
141
|
+
section: {
|
|
142
|
+
marginTop: 15,
|
|
143
|
+
},
|
|
144
|
+
heading: {
|
|
145
|
+
alignItems: 'center',
|
|
146
|
+
flexDirection: 'row',
|
|
147
|
+
paddingHorizontal: 12,
|
|
148
|
+
marginBottom: 10,
|
|
149
|
+
},
|
|
150
|
+
headingText: {
|
|
151
|
+
color: LogBoxStyle.getTextColor(1),
|
|
152
|
+
flex: 1,
|
|
153
|
+
fontSize: 20,
|
|
154
|
+
fontWeight: '600',
|
|
155
|
+
includeFontPadding: false,
|
|
156
|
+
lineHeight: 20,
|
|
157
|
+
},
|
|
158
|
+
body: {
|
|
159
|
+
paddingBottom: 10,
|
|
160
|
+
},
|
|
161
|
+
bodyText: {
|
|
162
|
+
color: LogBoxStyle.getTextColor(1),
|
|
163
|
+
fontSize: 14,
|
|
164
|
+
includeFontPadding: false,
|
|
165
|
+
lineHeight: 18,
|
|
166
|
+
fontWeight: '500',
|
|
167
|
+
paddingHorizontal: 27,
|
|
168
|
+
},
|
|
169
|
+
hintText: {
|
|
170
|
+
color: LogBoxStyle.getTextColor(0.7),
|
|
171
|
+
fontSize: 13,
|
|
172
|
+
includeFontPadding: false,
|
|
173
|
+
lineHeight: 18,
|
|
174
|
+
fontWeight: '400',
|
|
175
|
+
marginHorizontal: 10,
|
|
176
|
+
},
|
|
177
|
+
hintBox: {
|
|
178
|
+
backgroundColor: LogBoxStyle.getBackgroundColor(),
|
|
179
|
+
marginHorizontal: 10,
|
|
180
|
+
paddingHorizontal: 5,
|
|
181
|
+
paddingVertical: 10,
|
|
182
|
+
borderRadius: 5,
|
|
183
|
+
marginBottom: 5,
|
|
184
|
+
},
|
|
185
|
+
collapseContainer: {
|
|
186
|
+
marginLeft: 15,
|
|
187
|
+
flexDirection: 'row',
|
|
188
|
+
},
|
|
189
|
+
collapseButton: {
|
|
190
|
+
borderRadius: 5,
|
|
191
|
+
},
|
|
192
|
+
collapse: {
|
|
193
|
+
color: LogBoxStyle.getTextColor(0.7),
|
|
194
|
+
fontSize: 12,
|
|
195
|
+
fontWeight: '300',
|
|
196
|
+
lineHeight: 20,
|
|
197
|
+
marginTop: 0,
|
|
198
|
+
paddingHorizontal: 10,
|
|
199
|
+
paddingVertical: 5,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 650 Industries.
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useEffect } from 'react';
|
|
9
|
+
import { Image, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
10
|
+
|
|
11
|
+
import { ErrorToastMessage } from './ErrorToastMessage';
|
|
12
|
+
import * as LogBoxData from '../Data/LogBoxData';
|
|
13
|
+
import { LogBoxLog } from '../Data/LogBoxLog';
|
|
14
|
+
import * as LogBoxStyle from '../UI/LogBoxStyle';
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
log: LogBoxLog;
|
|
18
|
+
totalLogCount: number;
|
|
19
|
+
level: 'warn' | 'error';
|
|
20
|
+
onPressOpen: () => void;
|
|
21
|
+
onPressDismiss: () => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function useSymbolicatedLog(log: LogBoxLog) {
|
|
25
|
+
// Eagerly symbolicate so the stack is available when pressing to inspect.
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
LogBoxData.symbolicateLogLazy('stack', log);
|
|
28
|
+
LogBoxData.symbolicateLogLazy('component', log);
|
|
29
|
+
}, [log]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function ErrorToast(props: Props) {
|
|
33
|
+
const { totalLogCount, level, log } = props;
|
|
34
|
+
|
|
35
|
+
useSymbolicatedLog(log);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<View style={toastStyles.container}>
|
|
39
|
+
<Pressable style={{ flex: 1 }} onPress={props.onPressOpen}>
|
|
40
|
+
{({
|
|
41
|
+
/** @ts-expect-error: react-native types are broken. */
|
|
42
|
+
hovered,
|
|
43
|
+
pressed,
|
|
44
|
+
}) => (
|
|
45
|
+
<View
|
|
46
|
+
style={[
|
|
47
|
+
toastStyles.press,
|
|
48
|
+
{
|
|
49
|
+
// @ts-expect-error: web-only type
|
|
50
|
+
transitionDuration: '150ms',
|
|
51
|
+
backgroundColor: pressed
|
|
52
|
+
? '#323232'
|
|
53
|
+
: hovered
|
|
54
|
+
? '#111111'
|
|
55
|
+
: LogBoxStyle.getBackgroundColor(),
|
|
56
|
+
},
|
|
57
|
+
]}>
|
|
58
|
+
<Count count={totalLogCount} level={level} />
|
|
59
|
+
<ErrorToastMessage message={log.message} />
|
|
60
|
+
<Dismiss onPress={props.onPressDismiss} />
|
|
61
|
+
</View>
|
|
62
|
+
)}
|
|
63
|
+
</Pressable>
|
|
64
|
+
</View>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function Count({ count, level }: { count: number; level: Props['level'] }) {
|
|
69
|
+
return (
|
|
70
|
+
<View style={[countStyles.inside, countStyles[level]]}>
|
|
71
|
+
<Text style={countStyles.text}>{count <= 1 ? '!' : count}</Text>
|
|
72
|
+
</View>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function Dismiss({ onPress }: { onPress: () => void }) {
|
|
77
|
+
return (
|
|
78
|
+
<Pressable
|
|
79
|
+
style={{
|
|
80
|
+
marginLeft: 5,
|
|
81
|
+
}}
|
|
82
|
+
hitSlop={{
|
|
83
|
+
top: 12,
|
|
84
|
+
right: 10,
|
|
85
|
+
bottom: 12,
|
|
86
|
+
left: 10,
|
|
87
|
+
}}
|
|
88
|
+
onPress={onPress}>
|
|
89
|
+
{({
|
|
90
|
+
/** @ts-expect-error: react-native types are broken. */
|
|
91
|
+
hovered,
|
|
92
|
+
pressed,
|
|
93
|
+
}) => (
|
|
94
|
+
<View
|
|
95
|
+
style={[dismissStyles.press, hovered && { opacity: 0.8 }, pressed && { opacity: 0.5 }]}>
|
|
96
|
+
<Image
|
|
97
|
+
source={require('@expo/metro-runtime/assets/close.png')}
|
|
98
|
+
style={dismissStyles.image}
|
|
99
|
+
/>
|
|
100
|
+
</View>
|
|
101
|
+
)}
|
|
102
|
+
</Pressable>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const countStyles = StyleSheet.create({
|
|
107
|
+
warn: {
|
|
108
|
+
backgroundColor: LogBoxStyle.getWarningColor(1),
|
|
109
|
+
},
|
|
110
|
+
error: {
|
|
111
|
+
backgroundColor: LogBoxStyle.getErrorColor(1),
|
|
112
|
+
},
|
|
113
|
+
log: {
|
|
114
|
+
backgroundColor: LogBoxStyle.getLogColor(1),
|
|
115
|
+
},
|
|
116
|
+
inside: {
|
|
117
|
+
marginRight: 8,
|
|
118
|
+
minWidth: 22,
|
|
119
|
+
aspectRatio: 1,
|
|
120
|
+
paddingHorizontal: 4,
|
|
121
|
+
borderRadius: 11,
|
|
122
|
+
justifyContent: 'center',
|
|
123
|
+
alignItems: 'center',
|
|
124
|
+
},
|
|
125
|
+
text: {
|
|
126
|
+
color: LogBoxStyle.getTextColor(1),
|
|
127
|
+
fontSize: 14,
|
|
128
|
+
lineHeight: 18,
|
|
129
|
+
textAlign: 'center',
|
|
130
|
+
fontWeight: '600',
|
|
131
|
+
textShadow: `0px 0px 3px ${LogBoxStyle.getBackgroundColor(0.8)}`,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const dismissStyles = StyleSheet.create({
|
|
136
|
+
press: {
|
|
137
|
+
backgroundColor: '#323232',
|
|
138
|
+
height: 20,
|
|
139
|
+
width: 20,
|
|
140
|
+
borderRadius: 25,
|
|
141
|
+
alignItems: 'center',
|
|
142
|
+
justifyContent: 'center',
|
|
143
|
+
},
|
|
144
|
+
image: {
|
|
145
|
+
height: 8,
|
|
146
|
+
width: 8,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const toastStyles = StyleSheet.create({
|
|
151
|
+
container: {
|
|
152
|
+
height: 48,
|
|
153
|
+
justifyContent: 'center',
|
|
154
|
+
marginBottom: 4,
|
|
155
|
+
},
|
|
156
|
+
press: {
|
|
157
|
+
borderWidth: 1,
|
|
158
|
+
borderRadius: 8,
|
|
159
|
+
overflow: 'hidden',
|
|
160
|
+
flexDirection: 'row',
|
|
161
|
+
alignItems: 'center',
|
|
162
|
+
borderColor: '#323232',
|
|
163
|
+
backgroundColor: LogBoxStyle.getBackgroundColor(),
|
|
164
|
+
flex: 1,
|
|
165
|
+
paddingHorizontal: 12,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 650 Industries.
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useCallback, useMemo } from 'react';
|
|
9
|
+
import { StyleSheet, View } from 'react-native';
|
|
10
|
+
|
|
11
|
+
import { ErrorToast } from './ErrorToast';
|
|
12
|
+
import * as LogBoxData from '../Data/LogBoxData';
|
|
13
|
+
import { LogBoxLog } from '../Data/LogBoxLog';
|
|
14
|
+
import { useLogs } from '../Data/LogContext';
|
|
15
|
+
import { useRejectionHandler } from '../useRejectionHandler';
|
|
16
|
+
|
|
17
|
+
export function ErrorToastContainer() {
|
|
18
|
+
useRejectionHandler();
|
|
19
|
+
const { logs, isDisabled } = useLogs();
|
|
20
|
+
if (!logs.length || isDisabled) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return <ErrorToastStack logs={logs} />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function ErrorToastStack({ logs }: { logs: LogBoxLog[] }) {
|
|
27
|
+
const onDismissWarns = useCallback(() => {
|
|
28
|
+
LogBoxData.clearWarnings();
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
const onDismissErrors = useCallback(() => {
|
|
32
|
+
LogBoxData.clearErrors();
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
const setSelectedLog = useCallback((index: number): void => {
|
|
36
|
+
LogBoxData.setSelectedLog(index);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
function openLog(log: LogBoxLog) {
|
|
40
|
+
let index = logs.length - 1;
|
|
41
|
+
|
|
42
|
+
// Stop at zero because if we don't find any log, we'll open the first log.
|
|
43
|
+
while (index > 0 && logs[index] !== log) {
|
|
44
|
+
index -= 1;
|
|
45
|
+
}
|
|
46
|
+
setSelectedLog(index);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const warnings = useMemo(() => logs.filter((log) => log.level === 'warn'), [logs]);
|
|
50
|
+
|
|
51
|
+
const errors = useMemo(
|
|
52
|
+
() => logs.filter((log) => log.level === 'error' || log.level === 'fatal'),
|
|
53
|
+
[logs]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<View style={styles.list}>
|
|
58
|
+
{warnings.length > 0 && (
|
|
59
|
+
<ErrorToast
|
|
60
|
+
log={warnings[warnings.length - 1]}
|
|
61
|
+
level="warn"
|
|
62
|
+
totalLogCount={warnings.length}
|
|
63
|
+
onPressOpen={() => openLog(warnings[warnings.length - 1])}
|
|
64
|
+
onPressDismiss={onDismissWarns}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
|
|
68
|
+
{errors.length > 0 && (
|
|
69
|
+
<ErrorToast
|
|
70
|
+
log={errors[errors.length - 1]}
|
|
71
|
+
level="error"
|
|
72
|
+
totalLogCount={errors.length}
|
|
73
|
+
onPressOpen={() => openLog(errors[errors.length - 1])}
|
|
74
|
+
onPressDismiss={onDismissErrors}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</View>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const styles = StyleSheet.create({
|
|
82
|
+
list: {
|
|
83
|
+
bottom: 6,
|
|
84
|
+
left: 10,
|
|
85
|
+
right: 10,
|
|
86
|
+
maxWidth: 320,
|
|
87
|
+
// @ts-expect-error
|
|
88
|
+
position: 'fixed',
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export default LogBoxData.withSubscription(ErrorToastContainer);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet, Text } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { Message as MessageType } from '../Data/parseLogBoxLog';
|
|
5
|
+
import { LogBoxMessage } from '../UI/LogBoxMessage';
|
|
6
|
+
import * as LogBoxStyle from '../UI/LogBoxStyle';
|
|
7
|
+
|
|
8
|
+
export function ErrorToastMessage({ message }: { message?: MessageType }) {
|
|
9
|
+
return (
|
|
10
|
+
<Text numberOfLines={1} style={styles.text}>
|
|
11
|
+
{message && <LogBoxMessage plaintext message={message} style={styles.substitutionText} />}
|
|
12
|
+
</Text>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const styles = StyleSheet.create({
|
|
17
|
+
text: {
|
|
18
|
+
userSelect: 'none',
|
|
19
|
+
paddingLeft: 8,
|
|
20
|
+
color: LogBoxStyle.getTextColor(1),
|
|
21
|
+
flex: 1,
|
|
22
|
+
fontSize: 14,
|
|
23
|
+
lineHeight: 22,
|
|
24
|
+
},
|
|
25
|
+
substitutionText: {
|
|
26
|
+
color: LogBoxStyle.getTextColor(0.6),
|
|
27
|
+
},
|
|
28
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import ExceptionsManager from './modules/ExceptionsManager';
|
|
4
|
+
|
|
5
|
+
function useStackTraceLimit(limit: number) {
|
|
6
|
+
const current = React.useRef(0);
|
|
7
|
+
React.useEffect(() => {
|
|
8
|
+
try {
|
|
9
|
+
// @ts-expect-error: StackTraceLimit is not defined in the Error type
|
|
10
|
+
const currentLimit = Error.stackTraceLimit;
|
|
11
|
+
// @ts-expect-error: StackTraceLimit is not defined in the Error type
|
|
12
|
+
Error.stackTraceLimit = limit;
|
|
13
|
+
current.current = currentLimit;
|
|
14
|
+
} catch {}
|
|
15
|
+
return () => {
|
|
16
|
+
try {
|
|
17
|
+
// @ts-expect-error: StackTraceLimit is not defined in the Error type
|
|
18
|
+
Error.stackTraceLimit = current.current;
|
|
19
|
+
} catch {}
|
|
20
|
+
};
|
|
21
|
+
}, [limit]);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useRejectionHandler() {
|
|
25
|
+
const hasError = React.useRef(false);
|
|
26
|
+
|
|
27
|
+
useStackTraceLimit(35);
|
|
28
|
+
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
function onUnhandledError(ev: ErrorEvent) {
|
|
31
|
+
hasError.current = true;
|
|
32
|
+
|
|
33
|
+
const error = ev?.error;
|
|
34
|
+
if (!error || !(error instanceof Error) || typeof error.stack !== 'string') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
ExceptionsManager.handleException(error);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function onUnhandledRejection(ev: PromiseRejectionEvent) {
|
|
42
|
+
hasError.current = true;
|
|
43
|
+
|
|
44
|
+
const reason = ev?.reason;
|
|
45
|
+
if (!reason || !(reason instanceof Error) || typeof reason.stack !== 'string') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
ExceptionsManager.handleException(reason);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
window.addEventListener('unhandledrejection', onUnhandledRejection);
|
|
53
|
+
window.addEventListener('error', onUnhandledError);
|
|
54
|
+
return () => {
|
|
55
|
+
window.removeEventListener('error', onUnhandledError);
|
|
56
|
+
window.removeEventListener('unhandledrejection', onUnhandledRejection);
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
return hasError;
|
|
61
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import qs from 'qs';
|
|
2
|
+
|
|
3
|
+
const getDevServer = () => {
|
|
4
|
+
// Disable for SSR
|
|
5
|
+
if (typeof window === 'undefined') {
|
|
6
|
+
return {
|
|
7
|
+
bundleLoadedFromServer: true,
|
|
8
|
+
fullBundleUrl: '',
|
|
9
|
+
url: '',
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
// The bundle is always loaded from a server in the browser.
|
|
15
|
+
bundleLoadedFromServer: true,
|
|
16
|
+
|
|
17
|
+
/** URL but ensures that platform query param is added. */
|
|
18
|
+
get fullBundleUrl() {
|
|
19
|
+
if (document?.currentScript && 'src' in document.currentScript) {
|
|
20
|
+
return document.currentScript.src;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const url = window.location.toString();
|
|
24
|
+
const query = qs.parse(url);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
location.origin + location.pathname + '?' + qs.stringify({ ...query, platform: 'web' })
|
|
28
|
+
);
|
|
29
|
+
},
|
|
30
|
+
url: location.origin + location.pathname,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default getDevServer;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2023 650 Industries.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import './location/install';
|
|
9
|
+
// IMPORT POSITION MATTERS FOR FAST REFRESH ON WEB
|
|
10
|
+
import './effects';
|
|
11
|
+
// vvv EVERYTHING ELSE vvv
|
|
12
|
+
import './async-require';
|