dreaction-react-native 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/ConfigDialog.d.ts +9 -0
- package/lib/components/ConfigDialog.d.ts.map +1 -0
- package/lib/components/ConfigDialog.js +83 -0
- package/lib/components/DraggableBall.d.ts +3 -0
- package/lib/components/DraggableBall.d.ts.map +1 -0
- package/lib/components/DraggableBall.js +136 -0
- package/lib/dreaction.d.ts +29 -0
- package/lib/dreaction.d.ts.map +1 -0
- package/lib/dreaction.js +134 -0
- package/lib/helpers/getHost.d.ts +9 -0
- package/lib/helpers/getHost.d.ts.map +1 -0
- package/lib/helpers/getHost.js +31 -0
- package/lib/helpers/getReactNativeDimensions.d.ts +3 -0
- package/lib/helpers/getReactNativeDimensions.d.ts.map +1 -0
- package/lib/helpers/getReactNativeDimensions.js +18 -0
- package/lib/helpers/getReactNativeDimensions.test.d.ts +2 -0
- package/lib/helpers/getReactNativeDimensions.test.d.ts.map +1 -0
- package/lib/helpers/getReactNativeDimensions.test.js +20 -0
- package/lib/helpers/getReactNativeDimensionsWithDimensions.d.ts +12 -0
- package/lib/helpers/getReactNativeDimensionsWithDimensions.d.ts.map +1 -0
- package/lib/helpers/getReactNativeDimensionsWithDimensions.js +31 -0
- package/lib/helpers/getReactNativePlatformConstants.d.ts +13 -0
- package/lib/helpers/getReactNativePlatformConstants.d.ts.map +1 -0
- package/lib/helpers/getReactNativePlatformConstants.js +37 -0
- package/lib/helpers/getReactNativeVersion.d.ts +2 -0
- package/lib/helpers/getReactNativeVersion.d.ts.map +1 -0
- package/lib/helpers/getReactNativeVersion.js +8 -0
- package/lib/helpers/getReactNativeVersion.test.d.ts +2 -0
- package/lib/helpers/getReactNativeVersion.test.d.ts.map +1 -0
- package/lib/helpers/getReactNativeVersion.test.js +19 -0
- package/lib/helpers/getReactNativeVersionWithModules.d.ts +3 -0
- package/lib/helpers/getReactNativeVersionWithModules.d.ts.map +1 -0
- package/lib/helpers/getReactNativeVersionWithModules.js +32 -0
- package/lib/helpers/parseErrorStack.d.ts +5 -0
- package/lib/helpers/parseErrorStack.d.ts.map +1 -0
- package/lib/helpers/parseErrorStack.js +2 -0
- package/lib/helpers/parseURL.d.ts +9 -0
- package/lib/helpers/parseURL.d.ts.map +1 -0
- package/lib/helpers/parseURL.js +21 -0
- package/lib/helpers/parseURL.test.d.ts +2 -0
- package/lib/helpers/parseURL.test.d.ts.map +1 -0
- package/lib/helpers/parseURL.test.js +61 -0
- package/lib/helpers/symbolicateStackTrace.d.ts +18 -0
- package/lib/helpers/symbolicateStackTrace.d.ts.map +1 -0
- package/lib/helpers/symbolicateStackTrace.js +2 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +20 -0
- package/lib/plugins/asyncStorage.d.ts +12 -0
- package/lib/plugins/asyncStorage.d.ts.map +1 -0
- package/lib/plugins/asyncStorage.js +173 -0
- package/lib/plugins/devTools.d.ts +3 -0
- package/lib/plugins/devTools.d.ts.map +1 -0
- package/lib/plugins/devTools.js +24 -0
- package/lib/plugins/networking.d.ts +10 -0
- package/lib/plugins/networking.d.ts.map +1 -0
- package/lib/plugins/networking.js +139 -0
- package/lib/plugins/openInEditor.d.ts +9 -0
- package/lib/plugins/openInEditor.d.ts.map +1 -0
- package/lib/plugins/openInEditor.js +21 -0
- package/lib/plugins/overlay/index.d.ts +3 -0
- package/lib/plugins/overlay/index.d.ts.map +1 -0
- package/lib/plugins/overlay/index.js +29 -0
- package/lib/plugins/overlay/overlay.d.ts +161 -0
- package/lib/plugins/overlay/overlay.d.ts.map +1 -0
- package/lib/plugins/overlay/overlay.js +99 -0
- package/lib/plugins/storybook/index.d.ts +6 -0
- package/lib/plugins/storybook/index.d.ts.map +1 -0
- package/lib/plugins/storybook/index.js +27 -0
- package/lib/plugins/storybook/storybook.d.ts +22 -0
- package/lib/plugins/storybook/storybook.d.ts.map +1 -0
- package/lib/plugins/storybook/storybook.js +31 -0
- package/lib/plugins/trackGlobalErrors.d.ts +32 -0
- package/lib/plugins/trackGlobalErrors.d.ts.map +1 -0
- package/lib/plugins/trackGlobalErrors.js +100 -0
- package/lib/plugins/trackGlobalLogs.d.ts +9 -0
- package/lib/plugins/trackGlobalLogs.d.ts.map +1 -0
- package/lib/plugins/trackGlobalLogs.js +31 -0
- package/package.json +29 -0
- package/src/components/ConfigDialog.tsx +79 -0
- package/src/components/DraggableBall.tsx +139 -0
- package/src/dreaction.ts +221 -0
- package/src/helpers/getHost.ts +30 -0
- package/src/helpers/getReactNativeDimensions.ts +20 -0
- package/src/helpers/getReactNativeDimensionsWithDimensions.ts +45 -0
- package/src/helpers/getReactNativePlatformConstants.ts +52 -0
- package/src/helpers/getReactNativeVersion.ts +6 -0
- package/src/helpers/getReactNativeVersionWithModules.ts +37 -0
- package/src/helpers/parseErrorStack.ts +13 -0
- package/src/helpers/parseURL.ts +19 -0
- package/src/helpers/symbolicateStackTrace.ts +28 -0
- package/src/index.ts +6 -0
- package/src/plugins/asyncStorage.ts +222 -0
- package/src/plugins/devTools.ts +30 -0
- package/src/plugins/networking.ts +172 -0
- package/src/plugins/openInEditor.ts +30 -0
- package/src/plugins/trackGlobalErrors.ts +156 -0
- package/src/plugins/trackGlobalLogs.ts +42 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import type { DReactionCore, Plugin } from 'dreaction-client-core';
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
import type { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
|
|
4
|
+
export interface AsyncStorageOptions {
|
|
5
|
+
ignore?: string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const PLUGIN_DEFAULTS: AsyncStorageOptions = {
|
|
9
|
+
ignore: [],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const asyncStorage =
|
|
13
|
+
(options?: AsyncStorageOptions) => (reactotron: DReactionCore) => {
|
|
14
|
+
// setup configuration
|
|
15
|
+
const config = Object.assign({}, PLUGIN_DEFAULTS, options || {});
|
|
16
|
+
const ignore = config.ignore || PLUGIN_DEFAULTS.ignore;
|
|
17
|
+
|
|
18
|
+
let swizzSetItem: AsyncStorageStatic['setItem'];
|
|
19
|
+
let swizzRemoveItem: AsyncStorageStatic['removeItem'];
|
|
20
|
+
let swizzMergeItem: AsyncStorageStatic['mergeItem'];
|
|
21
|
+
let swizzClear: AsyncStorageStatic['clear'];
|
|
22
|
+
let swizzMultiSet: AsyncStorageStatic['multiSet'];
|
|
23
|
+
let swizzMultiRemove: AsyncStorageStatic['multiRemove'];
|
|
24
|
+
let swizzMultiMerge: AsyncStorageStatic['multiMerge'];
|
|
25
|
+
let isSwizzled = false;
|
|
26
|
+
|
|
27
|
+
const sendToReactotron = (action: string, data?: any) => {
|
|
28
|
+
reactotron.send('asyncStorage.mutation', { action, data });
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const setItem: AsyncStorageStatic['setItem'] = async (
|
|
32
|
+
key: string,
|
|
33
|
+
value: any,
|
|
34
|
+
callback: any
|
|
35
|
+
) => {
|
|
36
|
+
try {
|
|
37
|
+
if (ignore!.indexOf(key) < 0) {
|
|
38
|
+
sendToReactotron('setItem', { key, value });
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {}
|
|
41
|
+
return swizzSetItem(key, value, callback);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const removeItem: AsyncStorageStatic['removeItem'] = async (
|
|
45
|
+
key: string,
|
|
46
|
+
callback: any
|
|
47
|
+
) => {
|
|
48
|
+
try {
|
|
49
|
+
if (ignore!.indexOf(key) < 0) {
|
|
50
|
+
sendToReactotron('removeItem', { key });
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {}
|
|
53
|
+
return swizzRemoveItem(key, callback);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const mergeItem: AsyncStorageStatic['mergeItem'] = async (
|
|
57
|
+
key: string,
|
|
58
|
+
value: any,
|
|
59
|
+
callback: any
|
|
60
|
+
) => {
|
|
61
|
+
try {
|
|
62
|
+
if (ignore!.indexOf(key) < 0) {
|
|
63
|
+
sendToReactotron('mergeItem', { key, value });
|
|
64
|
+
}
|
|
65
|
+
} catch (e) {}
|
|
66
|
+
return swizzMergeItem(key, value, callback);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const clear: AsyncStorageStatic['clear'] = async (callback: any) => {
|
|
70
|
+
try {
|
|
71
|
+
sendToReactotron('clear');
|
|
72
|
+
} catch (e) {}
|
|
73
|
+
return swizzClear(callback);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const multiSet: AsyncStorageStatic['multiSet'] = async (
|
|
77
|
+
pairs: any,
|
|
78
|
+
callback: any
|
|
79
|
+
) => {
|
|
80
|
+
try {
|
|
81
|
+
const shippablePairs = (pairs || []).filter(
|
|
82
|
+
(pair: any) => pair && pair[0] && ignore!.indexOf(pair[0]) < 0
|
|
83
|
+
);
|
|
84
|
+
if (shippablePairs.length > 0) {
|
|
85
|
+
sendToReactotron('multiSet', { pairs: shippablePairs });
|
|
86
|
+
}
|
|
87
|
+
} catch (e) {}
|
|
88
|
+
return swizzMultiSet(pairs, callback);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const multiRemove: AsyncStorageStatic['multiRemove'] = async (
|
|
92
|
+
keys: any,
|
|
93
|
+
callback: any
|
|
94
|
+
) => {
|
|
95
|
+
try {
|
|
96
|
+
const shippableKeys = (keys || []).filter(
|
|
97
|
+
(key: any) => ignore!.indexOf(key) < 0
|
|
98
|
+
);
|
|
99
|
+
if (shippableKeys.length > 0) {
|
|
100
|
+
sendToReactotron('multiRemove', { keys: shippableKeys });
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {}
|
|
103
|
+
return swizzMultiRemove(keys, callback);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const multiMerge: AsyncStorageStatic['multiMerge'] = async (
|
|
107
|
+
pairs: any,
|
|
108
|
+
callback: any
|
|
109
|
+
) => {
|
|
110
|
+
try {
|
|
111
|
+
const shippablePairs = (pairs || []).filter(
|
|
112
|
+
(pair: any) => pair && pair[0] && ignore!.indexOf(pair[0]) < 0
|
|
113
|
+
);
|
|
114
|
+
if (shippablePairs.length > 0) {
|
|
115
|
+
sendToReactotron('multiMerge', { pairs: shippablePairs });
|
|
116
|
+
}
|
|
117
|
+
} catch (e) {}
|
|
118
|
+
return swizzMultiMerge(pairs, callback);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Hijacks the AsyncStorage API.
|
|
123
|
+
*/
|
|
124
|
+
const trackAsyncStorage = () => {
|
|
125
|
+
if (isSwizzled) return;
|
|
126
|
+
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
128
|
+
// @ts-ignore: reactotron-apis
|
|
129
|
+
swizzSetItem = reactotron.asyncStorageHandler.setItem;
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
131
|
+
// @ts-ignore: reactotron-apis
|
|
132
|
+
reactotron.asyncStorageHandler.setItem = setItem;
|
|
133
|
+
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
135
|
+
// @ts-ignore: reactotron-apis
|
|
136
|
+
swizzRemoveItem = reactotron.asyncStorageHandler.removeItem;
|
|
137
|
+
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
139
|
+
// @ts-ignore: reactotron-apis
|
|
140
|
+
reactotron.asyncStorageHandler.removeItem = removeItem;
|
|
141
|
+
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
143
|
+
// @ts-ignore: reactotron-apis
|
|
144
|
+
swizzMergeItem = reactotron.asyncStorageHandler.mergeItem;
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
146
|
+
// @ts-ignore: reactotron-apis
|
|
147
|
+
reactotron.asyncStorageHandler.mergeItem = mergeItem;
|
|
148
|
+
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
150
|
+
// @ts-ignore: reactotron-apis
|
|
151
|
+
swizzClear = reactotron.asyncStorageHandler.clear;
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
153
|
+
// @ts-ignore: reactotron-apis
|
|
154
|
+
reactotron.asyncStorageHandler.clear = clear;
|
|
155
|
+
|
|
156
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
157
|
+
// @ts-ignore: reactotron-apis
|
|
158
|
+
swizzMultiSet = reactotron.asyncStorageHandler.multiSet;
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
160
|
+
// @ts-ignore: reactotron-apis
|
|
161
|
+
reactotron.asyncStorageHandler.multiSet = multiSet;
|
|
162
|
+
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
164
|
+
// @ts-ignore: reactotron-apis
|
|
165
|
+
swizzMultiRemove = reactotron.asyncStorageHandler.multiRemove;
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
167
|
+
// @ts-ignore: reactotron-apis
|
|
168
|
+
reactotron.asyncStorageHandler.multiRemove = multiRemove;
|
|
169
|
+
|
|
170
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
171
|
+
// @ts-ignore: reactotron-apis
|
|
172
|
+
swizzMultiMerge = reactotron.asyncStorageHandler.multiMerge;
|
|
173
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
174
|
+
// @ts-ignore: reactotron-apis
|
|
175
|
+
reactotron.asyncStorageHandler.multiMerge = multiMerge;
|
|
176
|
+
|
|
177
|
+
isSwizzled = true;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const untrackAsyncStorage = () => {
|
|
181
|
+
if (!isSwizzled) return;
|
|
182
|
+
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
184
|
+
// @ts-ignore: reactotron-apis
|
|
185
|
+
reactotron.asyncStorageHandler.setItem = swizzSetItem;
|
|
186
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
187
|
+
// @ts-ignore: reactotron-apis
|
|
188
|
+
reactotron.asyncStorageHandler.removeItem = swizzRemoveItem;
|
|
189
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
190
|
+
// @ts-ignore: reactotron-apis
|
|
191
|
+
reactotron.asyncStorageHandler.mergeItem = swizzMergeItem;
|
|
192
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
193
|
+
// @ts-ignore: reactotron-apis
|
|
194
|
+
reactotron.asyncStorageHandler.clear = swizzClear;
|
|
195
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
196
|
+
// @ts-ignore: reactotron-apis
|
|
197
|
+
reactotron.asyncStorageHandler.multiSet = swizzMultiSet;
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
199
|
+
// @ts-ignore: reactotron-apis
|
|
200
|
+
reactotron.asyncStorageHandler.multiRemove = swizzMultiRemove;
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
202
|
+
// @ts-ignore: reactotron-apis
|
|
203
|
+
reactotron.asyncStorageHandler.multiMerge = swizzMultiMerge;
|
|
204
|
+
|
|
205
|
+
isSwizzled = false;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
209
|
+
// @ts-ignore: reactotron-apis
|
|
210
|
+
if (reactotron.asyncStorageHandler) {
|
|
211
|
+
trackAsyncStorage();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
features: {
|
|
216
|
+
trackAsyncStorage,
|
|
217
|
+
untrackAsyncStorage,
|
|
218
|
+
},
|
|
219
|
+
} satisfies Plugin<DReactionCore>;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export default asyncStorage;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import type { DReactionCore, Plugin } from 'dreaction-client-core';
|
|
3
|
+
|
|
4
|
+
let DevMenu = { show: () => {}, reload: () => {} };
|
|
5
|
+
if (Platform.OS === 'ios') {
|
|
6
|
+
DevMenu = require('react-native/Libraries/NativeModules/specs/NativeDevMenu');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const devTools: any = () => () => {
|
|
10
|
+
return {
|
|
11
|
+
onCommand: (command) => {
|
|
12
|
+
if (
|
|
13
|
+
command.type !== 'devtools.open' &&
|
|
14
|
+
command.type !== 'devtools.reload'
|
|
15
|
+
) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (command.type === 'devtools.open') {
|
|
20
|
+
DevMenu.show();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (command.type === 'devtools.reload') {
|
|
24
|
+
DevMenu.reload();
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
} satisfies Plugin<DReactionCore>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default devTools;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import XHRInterceptor from 'react-native/Libraries/Network/XHRInterceptor';
|
|
3
|
+
import type { DReactionCore, Plugin } from 'dreaction-client-core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Don't include the response bodies for images by default.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_CONTENT_TYPES_RX = /^(image)\/.*$/i;
|
|
9
|
+
|
|
10
|
+
export interface NetworkingOptions {
|
|
11
|
+
ignoreContentTypes?: RegExp;
|
|
12
|
+
ignoreUrls?: RegExp;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DEFAULTS: NetworkingOptions = {};
|
|
16
|
+
|
|
17
|
+
const networking =
|
|
18
|
+
(pluginConfig: NetworkingOptions = {}) =>
|
|
19
|
+
(reactotron: DReactionCore) => {
|
|
20
|
+
const options = Object.assign({}, DEFAULTS, pluginConfig);
|
|
21
|
+
|
|
22
|
+
// a RegExp to suppress adding the body cuz it costs a lot to serialize
|
|
23
|
+
const ignoreContentTypes =
|
|
24
|
+
options.ignoreContentTypes || DEFAULT_CONTENT_TYPES_RX;
|
|
25
|
+
|
|
26
|
+
// a XHR call tracker
|
|
27
|
+
let reactotronCounter = 1000;
|
|
28
|
+
|
|
29
|
+
// a temporary cache to hold requests so we can match up the data
|
|
30
|
+
const requestCache = {};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fires when we talk to the server.
|
|
34
|
+
*
|
|
35
|
+
* @param {*} data - The data sent to the server.
|
|
36
|
+
* @param {*} instance - The XMLHTTPRequest instance.
|
|
37
|
+
*/
|
|
38
|
+
function onSend(data: any, xhr: any) {
|
|
39
|
+
if (options.ignoreUrls && options.ignoreUrls.test(xhr._url)) {
|
|
40
|
+
xhr._skipReactotron = true;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// bump the counter
|
|
45
|
+
reactotronCounter++;
|
|
46
|
+
|
|
47
|
+
// tag
|
|
48
|
+
xhr._trackingName = reactotronCounter;
|
|
49
|
+
|
|
50
|
+
// cache
|
|
51
|
+
(requestCache as any)[reactotronCounter] = {
|
|
52
|
+
data,
|
|
53
|
+
xhr,
|
|
54
|
+
stopTimer: reactotron.startTimer(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Fires when the server gives us a response.
|
|
60
|
+
*
|
|
61
|
+
* @param {number} status - The HTTP response status.
|
|
62
|
+
* @param {boolean} timeout - Did we timeout?
|
|
63
|
+
* @param {*} response - The response data.
|
|
64
|
+
* @param {string} url - The URL we talked to.
|
|
65
|
+
* @param {*} type - Not sure.
|
|
66
|
+
* @param {*} xhr - The XMLHttpRequest instance.
|
|
67
|
+
*/
|
|
68
|
+
function onResponse(
|
|
69
|
+
status: any,
|
|
70
|
+
timeout: any,
|
|
71
|
+
response: any,
|
|
72
|
+
url: any,
|
|
73
|
+
type: any,
|
|
74
|
+
xhr: any
|
|
75
|
+
) {
|
|
76
|
+
if (xhr._skipReactotron) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let params = null;
|
|
81
|
+
const queryParamIdx = url ? url.indexOf('?') : -1;
|
|
82
|
+
if (queryParamIdx > -1) {
|
|
83
|
+
params = {};
|
|
84
|
+
url
|
|
85
|
+
.substr(queryParamIdx + 1)
|
|
86
|
+
.split('&')
|
|
87
|
+
.forEach((pair: any) => {
|
|
88
|
+
const [key, value] = pair.split('=');
|
|
89
|
+
if (key && value !== undefined) {
|
|
90
|
+
params[key] = decodeURIComponent(value.replace(/\+/g, ' '));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// fetch and clear the request data from the cache
|
|
96
|
+
const rid = xhr._trackingName;
|
|
97
|
+
const cachedRequest = (requestCache as any)[rid] || { xhr };
|
|
98
|
+
(requestCache as any)[rid] = null;
|
|
99
|
+
|
|
100
|
+
// assemble the request object
|
|
101
|
+
const { data, stopTimer } = cachedRequest;
|
|
102
|
+
const tronRequest = {
|
|
103
|
+
url: url || cachedRequest.xhr._url,
|
|
104
|
+
method: xhr._method || null,
|
|
105
|
+
data,
|
|
106
|
+
headers: xhr._headers || null,
|
|
107
|
+
params,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// what type of content is this?
|
|
111
|
+
const contentType =
|
|
112
|
+
(xhr.responseHeaders && xhr.responseHeaders['content-type']) ||
|
|
113
|
+
(xhr.responseHeaders && xhr.responseHeaders['Content-Type']) ||
|
|
114
|
+
'';
|
|
115
|
+
|
|
116
|
+
const sendResponse = (responseBodyText: string) => {
|
|
117
|
+
let body = `~~~ skipped ~~~`;
|
|
118
|
+
if (responseBodyText) {
|
|
119
|
+
try {
|
|
120
|
+
// all i am saying, is give JSON a chance...
|
|
121
|
+
body = JSON.parse(responseBodyText);
|
|
122
|
+
} catch (boom) {
|
|
123
|
+
body = response;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const tronResponse = {
|
|
127
|
+
body,
|
|
128
|
+
status,
|
|
129
|
+
headers: xhr.responseHeaders || null,
|
|
130
|
+
};
|
|
131
|
+
(reactotron as any).apiResponse(
|
|
132
|
+
tronRequest,
|
|
133
|
+
tronResponse,
|
|
134
|
+
stopTimer ? stopTimer() : null
|
|
135
|
+
); // TODO: Fix
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// can we use the real response?
|
|
139
|
+
const useRealResponse =
|
|
140
|
+
(typeof response === 'string' || typeof response === 'object') &&
|
|
141
|
+
!ignoreContentTypes.test(contentType || '');
|
|
142
|
+
|
|
143
|
+
// prepare the right body to send
|
|
144
|
+
if (useRealResponse) {
|
|
145
|
+
if (type === 'blob' && typeof FileReader !== 'undefined' && response) {
|
|
146
|
+
// Disable reason: FileReader should be in global scope since RN 0.54
|
|
147
|
+
// eslint-disable-next-line no-undef
|
|
148
|
+
const bReader = new FileReader();
|
|
149
|
+
const brListener = () => {
|
|
150
|
+
sendResponse(String(bReader.result));
|
|
151
|
+
bReader.removeEventListener('loadend', brListener);
|
|
152
|
+
};
|
|
153
|
+
bReader.addEventListener('loadend', brListener);
|
|
154
|
+
bReader.readAsText(response);
|
|
155
|
+
} else {
|
|
156
|
+
sendResponse(response);
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
sendResponse('');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
onConnect: () => {
|
|
165
|
+
// register our monkey-patch
|
|
166
|
+
XHRInterceptor.setSendCallback(onSend);
|
|
167
|
+
XHRInterceptor.setResponseCallback(onResponse);
|
|
168
|
+
XHRInterceptor.enableInterception();
|
|
169
|
+
},
|
|
170
|
+
} satisfies Plugin<DReactionCore>;
|
|
171
|
+
};
|
|
172
|
+
export default networking;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DReactionCore, Plugin } from 'dreaction-client-core';
|
|
2
|
+
import type { Command } from 'dreaction-protocol';
|
|
3
|
+
|
|
4
|
+
export interface OpenInEditorOptions {
|
|
5
|
+
url?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const DEFAULTS: OpenInEditorOptions = {
|
|
9
|
+
url: 'http://localhost:8081',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const openInEditor =
|
|
13
|
+
(pluginConfig: OpenInEditorOptions = {}) =>
|
|
14
|
+
() => {
|
|
15
|
+
const options = Object.assign({}, DEFAULTS, pluginConfig);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
onCommand: (command: Command) => {
|
|
19
|
+
if (command.type !== 'editor.open') return;
|
|
20
|
+
const { payload } = command;
|
|
21
|
+
const { file, lineNumber } = payload;
|
|
22
|
+
const url = `${options.url}/open-stack-frame`;
|
|
23
|
+
const body = { file, lineNumber: lineNumber || 1 };
|
|
24
|
+
const method = 'POST';
|
|
25
|
+
|
|
26
|
+
fetch(url, { method, body: JSON.stringify(body) });
|
|
27
|
+
},
|
|
28
|
+
} satisfies Plugin<DReactionCore>;
|
|
29
|
+
};
|
|
30
|
+
export default openInEditor;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides a global error handler to report errors..
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
InferFeatures,
|
|
6
|
+
LoggerPlugin,
|
|
7
|
+
DReactionCore,
|
|
8
|
+
assertHasLoggerPlugin,
|
|
9
|
+
Plugin,
|
|
10
|
+
} from 'dreaction-client-core';
|
|
11
|
+
import _LogBox, {
|
|
12
|
+
LogBoxStatic as LogBoxStaticPublic,
|
|
13
|
+
// eslint-disable-next-line import/default, import/namespace
|
|
14
|
+
} from 'react-native/Libraries/LogBox/LogBox';
|
|
15
|
+
// eslint-disable-next-line import/namespace
|
|
16
|
+
// import type { ExtendedExceptionData } from 'react-native/Libraries/LogBox/Data/parseLogBoxLog';
|
|
17
|
+
import type { SymbolicateStackTraceFn } from '../helpers/symbolicateStackTrace';
|
|
18
|
+
import type { ParseErrorStackFn } from '../helpers/parseErrorStack';
|
|
19
|
+
|
|
20
|
+
interface LogBoxStaticPrivate extends LogBoxStaticPublic {
|
|
21
|
+
/**
|
|
22
|
+
* @see https://github.com/facebook/react-native/blob/v0.72.1/packages/react-native/Libraries/LogBox/LogBox.js#L29
|
|
23
|
+
*/
|
|
24
|
+
// addException: (error: ExtendedExceptionData) => void;
|
|
25
|
+
addException: (error: any) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const LogBox = _LogBox as unknown as LogBoxStaticPrivate;
|
|
29
|
+
|
|
30
|
+
// a few functions to help source map errors -- these seem to be not available immediately
|
|
31
|
+
// so we're lazy loading.
|
|
32
|
+
let parseErrorStack: ParseErrorStackFn;
|
|
33
|
+
let symbolicateStackTrace: SymbolicateStackTraceFn;
|
|
34
|
+
|
|
35
|
+
export interface ErrorStackFrame {
|
|
36
|
+
fileName: string;
|
|
37
|
+
functionName: string;
|
|
38
|
+
lineNumber: number;
|
|
39
|
+
columnNumber?: number | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface TrackGlobalErrorsOptions {
|
|
43
|
+
veto?: (frame: ErrorStackFrame) => boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// defaults
|
|
47
|
+
const PLUGIN_DEFAULTS: TrackGlobalErrorsOptions = {
|
|
48
|
+
veto: undefined,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const objectifyError = (error: Error) => {
|
|
52
|
+
const objectifiedError = {} as Record<string, unknown>;
|
|
53
|
+
Object.getOwnPropertyNames(error).forEach((key) => {
|
|
54
|
+
objectifiedError[key] = (error as any)[key];
|
|
55
|
+
});
|
|
56
|
+
return objectifiedError;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// const reactNativeFrameFinder = frame => contains('/node_modules/react-native/', frame.fileName)
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Track global errors and send them to Reactotron logger.
|
|
63
|
+
*/
|
|
64
|
+
const trackGlobalErrors =
|
|
65
|
+
(options?: TrackGlobalErrorsOptions) => (reactotron: DReactionCore) => {
|
|
66
|
+
// make sure we have the logger plugin
|
|
67
|
+
assertHasLoggerPlugin(reactotron);
|
|
68
|
+
const client = reactotron as DReactionCore &
|
|
69
|
+
InferFeatures<DReactionCore, LoggerPlugin>;
|
|
70
|
+
|
|
71
|
+
// setup configuration
|
|
72
|
+
const config = Object.assign({}, PLUGIN_DEFAULTS, options || {});
|
|
73
|
+
|
|
74
|
+
// manually fire an error
|
|
75
|
+
function reportError(error: Parameters<typeof LogBox.addException>[0]) {
|
|
76
|
+
try {
|
|
77
|
+
parseErrorStack =
|
|
78
|
+
parseErrorStack ||
|
|
79
|
+
require('react-native/Libraries/Core/Devtools/parseErrorStack');
|
|
80
|
+
symbolicateStackTrace =
|
|
81
|
+
symbolicateStackTrace ||
|
|
82
|
+
require('react-native/Libraries/Core/Devtools/symbolicateStackTrace');
|
|
83
|
+
} catch (e) {
|
|
84
|
+
client.error(
|
|
85
|
+
'Unable to load "react-native/Libraries/Core/Devtools/parseErrorStack" or "react-native/Libraries/Core/Devtools/symbolicateStackTrace"',
|
|
86
|
+
[]
|
|
87
|
+
);
|
|
88
|
+
client.debug(objectifyError(e as Error));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!parseErrorStack || !symbolicateStackTrace) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let parsedStacktrace: ReturnType<typeof parseErrorStack>;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
// parseErrorStack arg type is wrong, it's expecting an array, a string, or a hermes error data, https://github.com/facebook/react-native/blob/v0.72.1/packages/react-native/Libraries/Core/Devtools/parseErrorStack.js#L41
|
|
100
|
+
parsedStacktrace = parseErrorStack(error.stack);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
client.error('Unable to parse stack trace from error object', []);
|
|
103
|
+
client.debug(objectifyError(e as Error));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
symbolicateStackTrace(parsedStacktrace)
|
|
108
|
+
.then((symbolicatedStackTrace) => {
|
|
109
|
+
let prettyStackFrames = symbolicatedStackTrace.stack.map(
|
|
110
|
+
(stackFrame) => ({
|
|
111
|
+
fileName: stackFrame.file,
|
|
112
|
+
functionName: stackFrame.methodName,
|
|
113
|
+
lineNumber: stackFrame.lineNumber,
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
// does the dev want us to keep each frame?
|
|
117
|
+
if (config.veto) {
|
|
118
|
+
prettyStackFrames = prettyStackFrames.filter((frame) =>
|
|
119
|
+
config?.veto?.(frame)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
client.error(error.message, prettyStackFrames); // TODO: Fix this.
|
|
123
|
+
})
|
|
124
|
+
.catch((e) => {
|
|
125
|
+
client.error(
|
|
126
|
+
'Unable to symbolicate stack trace from error object',
|
|
127
|
+
[]
|
|
128
|
+
);
|
|
129
|
+
client.debug(objectifyError(e));
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// the reactotron plugin interface
|
|
134
|
+
return {
|
|
135
|
+
onConnect: () => {
|
|
136
|
+
LogBox.addException = new Proxy(LogBox.addException, {
|
|
137
|
+
apply: function (
|
|
138
|
+
target,
|
|
139
|
+
thisArg,
|
|
140
|
+
argumentsList: Parameters<typeof LogBox.addException>
|
|
141
|
+
) {
|
|
142
|
+
const error = argumentsList[0];
|
|
143
|
+
reportError(error);
|
|
144
|
+
return target.apply(thisArg, argumentsList);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
// attach these functions to the Reactotron
|
|
150
|
+
features: {
|
|
151
|
+
reportError,
|
|
152
|
+
},
|
|
153
|
+
} satisfies Plugin<DReactionCore>;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export default trackGlobalErrors;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InferFeatures,
|
|
3
|
+
LoggerPlugin,
|
|
4
|
+
DReactionCore,
|
|
5
|
+
assertHasLoggerPlugin,
|
|
6
|
+
Plugin,
|
|
7
|
+
} from 'dreaction-client-core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Track calls to console.log, console.warn, and console.debug and send them to Reactotron logger
|
|
11
|
+
*/
|
|
12
|
+
const trackGlobalLogs = () => (reactotron: DReactionCore) => {
|
|
13
|
+
assertHasLoggerPlugin(reactotron);
|
|
14
|
+
const client = reactotron as DReactionCore &
|
|
15
|
+
InferFeatures<DReactionCore, LoggerPlugin>;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
onConnect: () => {
|
|
19
|
+
const originalConsoleLog = console.log;
|
|
20
|
+
console.log = (...args: Parameters<typeof console.log>) => {
|
|
21
|
+
originalConsoleLog(...args);
|
|
22
|
+
client.log(...args);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const originalConsoleWarn = console.warn;
|
|
26
|
+
console.warn = (...args: Parameters<typeof console.warn>) => {
|
|
27
|
+
originalConsoleWarn(...args);
|
|
28
|
+
client.warn(args[0]);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const originalConsoleDebug = console.debug;
|
|
32
|
+
console.debug = (...args: Parameters<typeof console.debug>) => {
|
|
33
|
+
originalConsoleDebug(...args);
|
|
34
|
+
client.debug(args[0]);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// console.error is taken care of by ./trackGlobalErrors.ts
|
|
38
|
+
},
|
|
39
|
+
} satisfies Plugin<DReactionCore>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default trackGlobalLogs;
|