@teardown/dev-client 2.0.44
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.kts +34 -0
- package/android/react-native.config.js +10 -0
- package/android/src/main/AndroidManifest.xml +7 -0
- package/android/src/main/java/com/teardown/devclient/DevSettingsModule.kt +130 -0
- package/android/src/main/java/com/teardown/devclient/ShakeDetectorModule.kt +118 -0
- package/android/src/main/java/com/teardown/devclient/TeardownDevClientPackage.kt +23 -0
- package/ios/TeardownDevClient/DevSettingsModule.swift +135 -0
- package/ios/TeardownDevClient/ShakeDetector.swift +102 -0
- package/ios/TeardownDevClient/TeardownDevClient.h +14 -0
- package/ios/TeardownDevClient/TeardownDevClient.mm +42 -0
- package/ios/TeardownDevClient.podspec +23 -0
- package/package.json +56 -0
- package/src/components/dev-menu/dev-menu.tsx +254 -0
- package/src/components/dev-menu/index.ts +5 -0
- package/src/components/error-overlay/error-overlay.tsx +256 -0
- package/src/components/error-overlay/index.ts +5 -0
- package/src/components/index.ts +7 -0
- package/src/components/splash-screen/index.ts +5 -0
- package/src/components/splash-screen/splash-screen.tsx +99 -0
- package/src/dev-client-provider.tsx +204 -0
- package/src/hooks/index.ts +24 -0
- package/src/hooks/use-bundler-status.ts +139 -0
- package/src/hooks/use-dev-menu.ts +306 -0
- package/src/hooks/use-splash-screen.ts +177 -0
- package/src/index.ts +77 -0
- package/src/native/dev-settings.ts +132 -0
- package/src/native/index.ts +16 -0
- package/src/native/shake-detector.ts +105 -0
- package/src/types.ts +235 -0
- package/src/utils/bundler-url.ts +103 -0
- package/src/utils/index.ts +19 -0
- package/src/utils/platform.ts +64 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @teardown/dev-client type definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ImageSourcePropType } from "react-native";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Dev client configuration options
|
|
9
|
+
*/
|
|
10
|
+
export interface DevClientConfig {
|
|
11
|
+
/** Whether to enable shake gesture for dev menu (default: true) */
|
|
12
|
+
enableShakeGesture?: boolean;
|
|
13
|
+
|
|
14
|
+
/** Whether to enable 3-finger tap for dev menu (default: true) */
|
|
15
|
+
enableThreeFingerTap?: boolean;
|
|
16
|
+
|
|
17
|
+
/** Splash screen configuration */
|
|
18
|
+
splash?: SplashScreenConfig;
|
|
19
|
+
|
|
20
|
+
/** Custom dev menu actions */
|
|
21
|
+
customMenuItems?: DevMenuItem[];
|
|
22
|
+
|
|
23
|
+
/** Metro bundler URL override */
|
|
24
|
+
bundlerUrl?: string;
|
|
25
|
+
|
|
26
|
+
/** Enable verbose logging (default: __DEV__) */
|
|
27
|
+
verbose?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Splash screen configuration
|
|
32
|
+
*/
|
|
33
|
+
export interface SplashScreenConfig {
|
|
34
|
+
/** Background color (hex string, default: #ffffff) */
|
|
35
|
+
backgroundColor?: string;
|
|
36
|
+
|
|
37
|
+
/** Logo image source */
|
|
38
|
+
logo?: ImageSourcePropType;
|
|
39
|
+
|
|
40
|
+
/** Resize mode for logo (default: contain) */
|
|
41
|
+
resizeMode?: "contain" | "cover" | "center";
|
|
42
|
+
|
|
43
|
+
/** Minimum display time in ms (default: 500) */
|
|
44
|
+
minDisplayTime?: number;
|
|
45
|
+
|
|
46
|
+
/** Fade out duration in ms (default: 300) */
|
|
47
|
+
fadeOutDuration?: number;
|
|
48
|
+
|
|
49
|
+
/** Auto-hide when app is ready (default: true) */
|
|
50
|
+
autoHide?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Dev menu item configuration
|
|
55
|
+
*/
|
|
56
|
+
export interface DevMenuItem {
|
|
57
|
+
/** Unique identifier for the menu item */
|
|
58
|
+
id: string;
|
|
59
|
+
|
|
60
|
+
/** Display label */
|
|
61
|
+
label: string;
|
|
62
|
+
|
|
63
|
+
/** Optional icon name */
|
|
64
|
+
icon?: string;
|
|
65
|
+
|
|
66
|
+
/** Action handler */
|
|
67
|
+
onPress: () => void | Promise<void>;
|
|
68
|
+
|
|
69
|
+
/** Show only in development (default: true) */
|
|
70
|
+
devOnly?: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Bundler connection status
|
|
75
|
+
*/
|
|
76
|
+
export interface BundlerStatus {
|
|
77
|
+
/** Whether connected to Metro bundler */
|
|
78
|
+
connected: boolean;
|
|
79
|
+
|
|
80
|
+
/** Current bundler URL */
|
|
81
|
+
url: string | null;
|
|
82
|
+
|
|
83
|
+
/** Error message if connection failed */
|
|
84
|
+
error: string | null;
|
|
85
|
+
|
|
86
|
+
/** Last successful connection timestamp */
|
|
87
|
+
lastConnectedAt: Date | null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Dev menu state
|
|
92
|
+
*/
|
|
93
|
+
export interface DevMenuState {
|
|
94
|
+
/** Whether dev menu is visible */
|
|
95
|
+
isVisible: boolean;
|
|
96
|
+
|
|
97
|
+
/** Whether an action is in progress */
|
|
98
|
+
isLoading: boolean;
|
|
99
|
+
|
|
100
|
+
/** Current bundler status */
|
|
101
|
+
bundlerStatus: BundlerStatus;
|
|
102
|
+
|
|
103
|
+
/** Whether hot reloading is enabled */
|
|
104
|
+
hotReloadEnabled: boolean;
|
|
105
|
+
|
|
106
|
+
/** Whether fast refresh is enabled */
|
|
107
|
+
fastRefreshEnabled: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Dev menu actions
|
|
112
|
+
*/
|
|
113
|
+
export interface DevMenuActions {
|
|
114
|
+
/** Show the dev menu */
|
|
115
|
+
show: () => void;
|
|
116
|
+
|
|
117
|
+
/** Hide the dev menu */
|
|
118
|
+
hide: () => void;
|
|
119
|
+
|
|
120
|
+
/** Toggle dev menu visibility */
|
|
121
|
+
toggle: () => void;
|
|
122
|
+
|
|
123
|
+
/** Reload the app */
|
|
124
|
+
reload: () => Promise<void>;
|
|
125
|
+
|
|
126
|
+
/** Open debugger */
|
|
127
|
+
openDebugger: () => Promise<void>;
|
|
128
|
+
|
|
129
|
+
/** Toggle element inspector */
|
|
130
|
+
toggleElementInspector: () => Promise<void>;
|
|
131
|
+
|
|
132
|
+
/** Toggle performance monitor */
|
|
133
|
+
togglePerfMonitor: () => Promise<void>;
|
|
134
|
+
|
|
135
|
+
/** Set hot reload enabled state */
|
|
136
|
+
setHotReloadEnabled: (enabled: boolean) => Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Native module interface for dev settings
|
|
141
|
+
*/
|
|
142
|
+
export interface DevSettingsNativeModule {
|
|
143
|
+
/** Reload the JavaScript bundle */
|
|
144
|
+
reload(): void;
|
|
145
|
+
|
|
146
|
+
/** Open the debugger */
|
|
147
|
+
openDebugger(): void;
|
|
148
|
+
|
|
149
|
+
/** Toggle element inspector overlay */
|
|
150
|
+
toggleElementInspector(): void;
|
|
151
|
+
|
|
152
|
+
/** Set hot loading enabled state */
|
|
153
|
+
setHotLoadingEnabled(enabled: boolean): void;
|
|
154
|
+
|
|
155
|
+
/** Set fast refresh enabled state */
|
|
156
|
+
setFastRefreshEnabled(enabled: boolean): void;
|
|
157
|
+
|
|
158
|
+
/** Get current dev settings */
|
|
159
|
+
getDevSettings(): Promise<DevSettings>;
|
|
160
|
+
|
|
161
|
+
/** Open native dev menu */
|
|
162
|
+
openDevMenu(): void;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Current dev settings state from native
|
|
167
|
+
*/
|
|
168
|
+
export interface DevSettings {
|
|
169
|
+
/** Whether remote JS debugging is enabled */
|
|
170
|
+
isDebuggingRemotely: boolean;
|
|
171
|
+
|
|
172
|
+
/** Whether element inspector is shown */
|
|
173
|
+
isElementInspectorShown: boolean;
|
|
174
|
+
|
|
175
|
+
/** Whether hot loading is enabled */
|
|
176
|
+
isHotLoadingEnabled: boolean;
|
|
177
|
+
|
|
178
|
+
/** Whether fast refresh is enabled */
|
|
179
|
+
isFastRefreshEnabled: boolean;
|
|
180
|
+
|
|
181
|
+
/** Whether performance monitor is shown */
|
|
182
|
+
isPerfMonitorShown: boolean;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Splash screen control API
|
|
187
|
+
*/
|
|
188
|
+
export interface SplashScreenApi {
|
|
189
|
+
/** Hide the splash screen */
|
|
190
|
+
hide: (options?: { fade?: boolean }) => Promise<void>;
|
|
191
|
+
|
|
192
|
+
/** Show the splash screen (for manual control) */
|
|
193
|
+
show: () => Promise<void>;
|
|
194
|
+
|
|
195
|
+
/** Whether splash screen is currently visible */
|
|
196
|
+
isVisible: boolean;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Dev client context value
|
|
201
|
+
*/
|
|
202
|
+
export interface DevClientContextValue {
|
|
203
|
+
/** Current configuration */
|
|
204
|
+
config: DevClientConfig;
|
|
205
|
+
|
|
206
|
+
/** Dev menu state and actions */
|
|
207
|
+
devMenu: {
|
|
208
|
+
state: DevMenuState;
|
|
209
|
+
actions: DevMenuActions;
|
|
210
|
+
defaultItems: DevMenuItem[];
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/** Splash screen API */
|
|
214
|
+
splashScreen: SplashScreenApi;
|
|
215
|
+
|
|
216
|
+
/** Bundler status */
|
|
217
|
+
bundlerStatus: BundlerStatus;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Options for getting bundler URL
|
|
222
|
+
*/
|
|
223
|
+
export interface GetBundlerUrlOptions {
|
|
224
|
+
/** Target platform */
|
|
225
|
+
platform: "ios" | "android";
|
|
226
|
+
|
|
227
|
+
/** Whether running on emulator/simulator */
|
|
228
|
+
isEmulator: boolean;
|
|
229
|
+
|
|
230
|
+
/** Custom port (default: 8081) */
|
|
231
|
+
port?: number;
|
|
232
|
+
|
|
233
|
+
/** URL override */
|
|
234
|
+
override?: string;
|
|
235
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundler URL utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers for determining and validating Metro bundler URLs
|
|
5
|
+
* based on platform and environment.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { GetBundlerUrlOptions } from "../types";
|
|
9
|
+
|
|
10
|
+
/** Default Metro bundler port */
|
|
11
|
+
export const DEFAULT_BUNDLER_PORT = 8081;
|
|
12
|
+
|
|
13
|
+
/** Android emulator host - special IP that routes to host machine */
|
|
14
|
+
const ANDROID_EMULATOR_HOST = "10.0.2.2";
|
|
15
|
+
|
|
16
|
+
/** Default host for iOS and physical devices */
|
|
17
|
+
const DEFAULT_HOST = "localhost";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the default bundler URL based on platform and environment
|
|
21
|
+
*
|
|
22
|
+
* @param platform - Target platform (ios or android)
|
|
23
|
+
* @param isEmulator - Whether running on emulator/simulator
|
|
24
|
+
* @param port - Custom port (defaults to 8081)
|
|
25
|
+
* @returns The bundler URL string
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* getDefaultBundlerUrl('ios', true); // http://localhost:8081
|
|
30
|
+
* getDefaultBundlerUrl('android', true); // http://10.0.2.2:8081
|
|
31
|
+
* getDefaultBundlerUrl('android', true, 9000); // http://10.0.2.2:9000
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function getDefaultBundlerUrl(
|
|
35
|
+
platform: "ios" | "android",
|
|
36
|
+
isEmulator: boolean,
|
|
37
|
+
port: number = DEFAULT_BUNDLER_PORT
|
|
38
|
+
): string {
|
|
39
|
+
// Android emulator needs special host to reach the host machine
|
|
40
|
+
const host = platform === "android" && isEmulator ? ANDROID_EMULATOR_HOST : DEFAULT_HOST;
|
|
41
|
+
|
|
42
|
+
return `http://${host}:${port}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Validate a bundler URL
|
|
47
|
+
*
|
|
48
|
+
* @param url - URL string to validate
|
|
49
|
+
* @returns true if the URL is valid for bundler connection
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* isValidBundlerUrl('http://localhost:8081'); // true
|
|
54
|
+
* isValidBundlerUrl('https://bundler.example.com'); // true
|
|
55
|
+
* isValidBundlerUrl('not-a-url'); // false
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function isValidBundlerUrl(url: string): boolean {
|
|
59
|
+
if (!url || url.trim() === "") {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const parsed = new URL(url);
|
|
65
|
+
// Only allow http and https protocols
|
|
66
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
67
|
+
} catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get the bundler URL based on options
|
|
74
|
+
*
|
|
75
|
+
* Respects override URL if provided and valid, otherwise
|
|
76
|
+
* returns the appropriate default URL for the platform.
|
|
77
|
+
*
|
|
78
|
+
* @param options - Configuration options
|
|
79
|
+
* @returns The bundler URL string
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* getBundlerUrl({ platform: 'ios', isEmulator: true });
|
|
84
|
+
* // Returns: http://localhost:8081
|
|
85
|
+
*
|
|
86
|
+
* getBundlerUrl({ platform: 'android', isEmulator: true, port: 9000 });
|
|
87
|
+
* // Returns: http://10.0.2.2:9000
|
|
88
|
+
*
|
|
89
|
+
* getBundlerUrl({ platform: 'ios', isEmulator: true, override: 'http://custom:8080' });
|
|
90
|
+
* // Returns: http://custom:8080
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export function getBundlerUrl(options: GetBundlerUrlOptions): string {
|
|
94
|
+
const { platform, isEmulator, port = DEFAULT_BUNDLER_PORT, override } = options;
|
|
95
|
+
|
|
96
|
+
// Use override if provided and valid
|
|
97
|
+
if (override && isValidBundlerUrl(override)) {
|
|
98
|
+
return override;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Return default URL for platform
|
|
102
|
+
return getDefaultBundlerUrl(platform, isEmulator, port);
|
|
103
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
DEFAULT_BUNDLER_PORT,
|
|
7
|
+
getBundlerUrl,
|
|
8
|
+
getDefaultBundlerUrl,
|
|
9
|
+
isValidBundlerUrl,
|
|
10
|
+
} from "./bundler-url";
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
currentPlatform,
|
|
14
|
+
isAndroid,
|
|
15
|
+
isDev,
|
|
16
|
+
isEmulator,
|
|
17
|
+
isIOS,
|
|
18
|
+
platformSelect,
|
|
19
|
+
} from "./platform";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform detection utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Platform } from "react-native";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Current platform
|
|
9
|
+
*/
|
|
10
|
+
export const currentPlatform = Platform.OS as "ios" | "android";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Whether running on iOS
|
|
14
|
+
*/
|
|
15
|
+
export const isIOS = Platform.OS === "ios";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Whether running on Android
|
|
19
|
+
*/
|
|
20
|
+
export const isAndroid = Platform.OS === "android";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether running in development mode
|
|
24
|
+
* Safe when __DEV__ is not defined (e.g. in test runners).
|
|
25
|
+
*/
|
|
26
|
+
export const isDev =
|
|
27
|
+
typeof globalThis !== "undefined" && "__DEV__" in globalThis
|
|
28
|
+
? (globalThis as typeof globalThis & { __DEV__: boolean }).__DEV__
|
|
29
|
+
: false;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Detect if running on an emulator/simulator
|
|
33
|
+
*
|
|
34
|
+
* Note: This is a heuristic and may not be 100% accurate.
|
|
35
|
+
* For iOS, simulators have specific device names.
|
|
36
|
+
* For Android, emulators typically have specific fingerprints.
|
|
37
|
+
*
|
|
38
|
+
* @returns Promise resolving to true if likely on emulator
|
|
39
|
+
*/
|
|
40
|
+
export async function isEmulator(): Promise<boolean> {
|
|
41
|
+
// In development, we generally assume emulator for simplicity
|
|
42
|
+
// A more robust implementation would check device info
|
|
43
|
+
if (__DEV__) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// In production, assume physical device
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get platform-specific value
|
|
53
|
+
*
|
|
54
|
+
* @param options - Object with ios and android values
|
|
55
|
+
* @returns The value for the current platform
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const color = platformSelect({ ios: 'blue', android: 'green' });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function platformSelect<T>(options: { ios: T; android: T }): T {
|
|
63
|
+
return Platform.select(options) as T;
|
|
64
|
+
}
|