create-100x-mobile 0.4.2 → 0.4.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/dist/cli.js +10 -9
- package/dist/commands/new/args.js +76 -0
- package/dist/commands/new/scaffold.js +33 -0
- package/dist/commands/new/steps.js +379 -0
- package/dist/commands/new.js +134 -367
- package/dist/lib/clerk.js +3 -0
- package/dist/lib/fs.js +5 -0
- package/dist/lib/run.js +5 -1
- package/dist/templates/app/settingsScreen.js +5 -2
- package/dist/templates/app/signIn.js +25 -23
- package/dist/templates/hooks/useFrameworkReady.js +4 -2
- package/package.json +7 -3
- package/dist/commands/CLAUDE.md +0 -7
- package/dist/templates/app/signUp.js +0 -298
- package/dist/templates/config/CLAUDE.md +0 -7
|
@@ -50,14 +50,17 @@ export default function SettingsScreen() {
|
|
|
50
50
|
SecureStore.deleteItemAsync("__clerk_db_jwt"),
|
|
51
51
|
SecureStore.deleteItemAsync("__clerk_session_jwt"),
|
|
52
52
|
]);
|
|
53
|
-
} catch {
|
|
53
|
+
} catch (storageError) {
|
|
54
|
+
console.warn("SecureStore cleanup failed:", storageError);
|
|
55
|
+
}
|
|
54
56
|
|
|
55
57
|
await signOut();
|
|
56
58
|
// Sign-out succeeded — navigation will happen automatically
|
|
57
|
-
} catch {
|
|
59
|
+
} catch (error) {
|
|
58
60
|
// After signOut(), the session is cleared and the app navigates away.
|
|
59
61
|
// This may cause errors as the component unmounts — that's expected.
|
|
60
62
|
// Only a real pre-signout failure would leave the user stuck here.
|
|
63
|
+
console.warn("Sign out flow warning:", error);
|
|
61
64
|
}
|
|
62
65
|
};
|
|
63
66
|
|
|
@@ -97,29 +97,31 @@ export default function SignInScreen() {
|
|
|
97
97
|
)}
|
|
98
98
|
</TouchableOpacity>
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
100
|
+
{Platform.OS === "ios" ? (
|
|
101
|
+
<TouchableOpacity
|
|
102
|
+
style={[
|
|
103
|
+
styles.button,
|
|
104
|
+
styles.appleButton,
|
|
105
|
+
loading === "apple" && styles.buttonLoading,
|
|
106
|
+
]}
|
|
107
|
+
onPress={() => handleOAuth("apple", startAppleOAuth)}
|
|
108
|
+
activeOpacity={0.7}
|
|
109
|
+
disabled={loading !== null}
|
|
110
|
+
>
|
|
111
|
+
{loading === "apple" ? (
|
|
112
|
+
<ActivityIndicator size={20} color="#FFFFFF" />
|
|
113
|
+
) : (
|
|
114
|
+
<>
|
|
115
|
+
<View style={styles.iconWrap}>
|
|
116
|
+
<Svg width={20} height={20} viewBox="0 0 24 24" fill="#FFFFFF">
|
|
117
|
+
<Path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" />
|
|
118
|
+
</Svg>
|
|
119
|
+
</View>
|
|
120
|
+
<Text style={styles.appleText}>Continue with Apple</Text>
|
|
121
|
+
</>
|
|
122
|
+
)}
|
|
123
|
+
</TouchableOpacity>
|
|
124
|
+
) : null}
|
|
123
125
|
</View>
|
|
124
126
|
|
|
125
127
|
<Text style={styles.terms}>
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-100x-mobile",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Scaffold a full-stack mobile app with Expo + Convex + Clerk in seconds",
|
|
5
5
|
"main": "dist/cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-100x-mobile": "./dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"
|
|
10
|
+
"clean": "node -e \"require('fs').rmSync('dist',{ recursive: true, force: true })\"",
|
|
11
|
+
"build": "npm run clean && tsc",
|
|
11
12
|
"dev": "tsc --watch",
|
|
12
|
-
"
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"test": "npm run build && node --test tests/**/*.test.cjs",
|
|
15
|
+
"check": "npm run typecheck && npm test && npm pack --dry-run",
|
|
16
|
+
"prepublishOnly": "npm run check"
|
|
13
17
|
},
|
|
14
18
|
"files": [
|
|
15
19
|
"dist"
|
package/dist/commands/CLAUDE.md
DELETED
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.signUpTemplate = signUpTemplate;
|
|
4
|
-
function signUpTemplate() {
|
|
5
|
-
return `import React, { useState } from "react";
|
|
6
|
-
import {
|
|
7
|
-
View,
|
|
8
|
-
Text,
|
|
9
|
-
TextInput,
|
|
10
|
-
TouchableOpacity,
|
|
11
|
-
StyleSheet,
|
|
12
|
-
KeyboardAvoidingView,
|
|
13
|
-
Platform,
|
|
14
|
-
Alert,
|
|
15
|
-
ActivityIndicator,
|
|
16
|
-
Modal,
|
|
17
|
-
} from "react-native";
|
|
18
|
-
import { useSignUp } from "@clerk/clerk-expo";
|
|
19
|
-
import { useRouter, Link } from "expo-router";
|
|
20
|
-
|
|
21
|
-
export default function SignUpScreen() {
|
|
22
|
-
const { isLoaded, signUp, setActive } = useSignUp();
|
|
23
|
-
const router = useRouter();
|
|
24
|
-
|
|
25
|
-
const [emailAddress, setEmailAddress] = useState("");
|
|
26
|
-
const [password, setPassword] = useState("");
|
|
27
|
-
const [loading, setLoading] = useState(false);
|
|
28
|
-
const [pendingVerification, setPendingVerification] = useState(false);
|
|
29
|
-
const [code, setCode] = useState("");
|
|
30
|
-
const [errorMessage, setErrorMessage] = useState("");
|
|
31
|
-
|
|
32
|
-
const onSignUpPress = async () => {
|
|
33
|
-
if (!isLoaded) return;
|
|
34
|
-
|
|
35
|
-
setLoading(true);
|
|
36
|
-
setErrorMessage("");
|
|
37
|
-
try {
|
|
38
|
-
const result = await signUp.create({
|
|
39
|
-
emailAddress,
|
|
40
|
-
password,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
if (result.status === "complete") {
|
|
44
|
-
await setActive({ session: result.createdSessionId });
|
|
45
|
-
router.replace("/(tabs)");
|
|
46
|
-
} else if (result.status === "missing_requirements") {
|
|
47
|
-
await signUp.prepareEmailAddressVerification({
|
|
48
|
-
strategy: "email_code",
|
|
49
|
-
});
|
|
50
|
-
setPendingVerification(true);
|
|
51
|
-
}
|
|
52
|
-
} catch (err: any) {
|
|
53
|
-
const message = err.errors?.[0]?.message || "Sign up failed";
|
|
54
|
-
setErrorMessage(message);
|
|
55
|
-
Alert.alert("Error", message);
|
|
56
|
-
} finally {
|
|
57
|
-
setLoading(false);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const onPressVerify = async () => {
|
|
62
|
-
if (!isLoaded) return;
|
|
63
|
-
|
|
64
|
-
setLoading(true);
|
|
65
|
-
try {
|
|
66
|
-
const completeSignUp = await signUp.attemptEmailAddressVerification({
|
|
67
|
-
code,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (completeSignUp.status === "complete") {
|
|
71
|
-
await setActive({ session: completeSignUp.createdSessionId });
|
|
72
|
-
router.replace("/(tabs)");
|
|
73
|
-
} else {
|
|
74
|
-
Alert.alert("Error", "Verification failed. Please try again.");
|
|
75
|
-
}
|
|
76
|
-
} catch (err: any) {
|
|
77
|
-
Alert.alert("Error", err.errors?.[0]?.message || "Verification failed");
|
|
78
|
-
} finally {
|
|
79
|
-
setLoading(false);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<>
|
|
85
|
-
<KeyboardAvoidingView
|
|
86
|
-
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
87
|
-
style={styles.container}
|
|
88
|
-
>
|
|
89
|
-
<View style={styles.content}>
|
|
90
|
-
<Text style={styles.title}>Create Account</Text>
|
|
91
|
-
<Text style={styles.subtitle}>Sign up to get started</Text>
|
|
92
|
-
|
|
93
|
-
{errorMessage ? (
|
|
94
|
-
<View style={styles.errorContainer}>
|
|
95
|
-
<Text style={styles.errorText}>{errorMessage}</Text>
|
|
96
|
-
</View>
|
|
97
|
-
) : null}
|
|
98
|
-
|
|
99
|
-
<TextInput
|
|
100
|
-
style={styles.input}
|
|
101
|
-
placeholder="Email"
|
|
102
|
-
placeholderTextColor="#999"
|
|
103
|
-
value={emailAddress}
|
|
104
|
-
onChangeText={setEmailAddress}
|
|
105
|
-
autoCapitalize="none"
|
|
106
|
-
keyboardType="email-address"
|
|
107
|
-
/>
|
|
108
|
-
|
|
109
|
-
<TextInput
|
|
110
|
-
style={styles.input}
|
|
111
|
-
placeholder="Password"
|
|
112
|
-
placeholderTextColor="#999"
|
|
113
|
-
value={password}
|
|
114
|
-
onChangeText={setPassword}
|
|
115
|
-
secureTextEntry
|
|
116
|
-
/>
|
|
117
|
-
|
|
118
|
-
<TouchableOpacity
|
|
119
|
-
style={[styles.button, loading && styles.buttonDisabled]}
|
|
120
|
-
onPress={onSignUpPress}
|
|
121
|
-
disabled={loading}
|
|
122
|
-
>
|
|
123
|
-
{loading ? (
|
|
124
|
-
<ActivityIndicator color="#fff" />
|
|
125
|
-
) : (
|
|
126
|
-
<Text style={styles.buttonText}>Sign Up</Text>
|
|
127
|
-
)}
|
|
128
|
-
</TouchableOpacity>
|
|
129
|
-
|
|
130
|
-
<View style={styles.footer}>
|
|
131
|
-
<Text style={styles.footerText}>Already have an account? </Text>
|
|
132
|
-
<Link href="/(auth)/sign-in" asChild>
|
|
133
|
-
<TouchableOpacity>
|
|
134
|
-
<Text style={styles.link}>Sign In</Text>
|
|
135
|
-
</TouchableOpacity>
|
|
136
|
-
</Link>
|
|
137
|
-
</View>
|
|
138
|
-
</View>
|
|
139
|
-
</KeyboardAvoidingView>
|
|
140
|
-
|
|
141
|
-
<Modal
|
|
142
|
-
animationType="slide"
|
|
143
|
-
transparent={true}
|
|
144
|
-
visible={pendingVerification}
|
|
145
|
-
>
|
|
146
|
-
<View style={styles.modalOverlay}>
|
|
147
|
-
<View style={styles.modalContent}>
|
|
148
|
-
<Text style={styles.modalTitle}>Verify Email</Text>
|
|
149
|
-
<Text style={styles.modalSubtitle}>
|
|
150
|
-
We've sent a verification code to {emailAddress}
|
|
151
|
-
</Text>
|
|
152
|
-
|
|
153
|
-
<TextInput
|
|
154
|
-
style={styles.input}
|
|
155
|
-
placeholder="Verification Code"
|
|
156
|
-
placeholderTextColor="#999"
|
|
157
|
-
value={code}
|
|
158
|
-
onChangeText={setCode}
|
|
159
|
-
keyboardType="number-pad"
|
|
160
|
-
/>
|
|
161
|
-
|
|
162
|
-
<TouchableOpacity
|
|
163
|
-
style={[styles.button, loading && styles.buttonDisabled]}
|
|
164
|
-
onPress={onPressVerify}
|
|
165
|
-
disabled={loading}
|
|
166
|
-
>
|
|
167
|
-
{loading ? (
|
|
168
|
-
<ActivityIndicator color="#fff" />
|
|
169
|
-
) : (
|
|
170
|
-
<Text style={styles.buttonText}>Verify Email</Text>
|
|
171
|
-
)}
|
|
172
|
-
</TouchableOpacity>
|
|
173
|
-
|
|
174
|
-
<TouchableOpacity
|
|
175
|
-
style={styles.cancelButton}
|
|
176
|
-
onPress={() => setPendingVerification(false)}
|
|
177
|
-
>
|
|
178
|
-
<Text style={styles.cancelButtonText}>Cancel</Text>
|
|
179
|
-
</TouchableOpacity>
|
|
180
|
-
</View>
|
|
181
|
-
</View>
|
|
182
|
-
</Modal>
|
|
183
|
-
</>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const styles = StyleSheet.create({
|
|
188
|
-
container: {
|
|
189
|
-
flex: 1,
|
|
190
|
-
backgroundColor: "#f5f5f5",
|
|
191
|
-
},
|
|
192
|
-
content: {
|
|
193
|
-
flex: 1,
|
|
194
|
-
justifyContent: "center",
|
|
195
|
-
paddingHorizontal: 20,
|
|
196
|
-
},
|
|
197
|
-
title: {
|
|
198
|
-
fontSize: 32,
|
|
199
|
-
fontWeight: "bold",
|
|
200
|
-
color: "#333",
|
|
201
|
-
marginBottom: 8,
|
|
202
|
-
textAlign: "center",
|
|
203
|
-
},
|
|
204
|
-
subtitle: {
|
|
205
|
-
fontSize: 16,
|
|
206
|
-
color: "#666",
|
|
207
|
-
marginBottom: 40,
|
|
208
|
-
textAlign: "center",
|
|
209
|
-
},
|
|
210
|
-
input: {
|
|
211
|
-
backgroundColor: "#fff",
|
|
212
|
-
borderRadius: 8,
|
|
213
|
-
paddingHorizontal: 16,
|
|
214
|
-
paddingVertical: 12,
|
|
215
|
-
fontSize: 16,
|
|
216
|
-
marginBottom: 16,
|
|
217
|
-
borderWidth: 1,
|
|
218
|
-
borderColor: "#e0e0e0",
|
|
219
|
-
},
|
|
220
|
-
button: {
|
|
221
|
-
backgroundColor: "#007AFF",
|
|
222
|
-
borderRadius: 8,
|
|
223
|
-
paddingVertical: 14,
|
|
224
|
-
alignItems: "center",
|
|
225
|
-
marginTop: 8,
|
|
226
|
-
},
|
|
227
|
-
buttonDisabled: {
|
|
228
|
-
opacity: 0.7,
|
|
229
|
-
},
|
|
230
|
-
buttonText: {
|
|
231
|
-
color: "#fff",
|
|
232
|
-
fontSize: 18,
|
|
233
|
-
fontWeight: "600",
|
|
234
|
-
},
|
|
235
|
-
footer: {
|
|
236
|
-
flexDirection: "row",
|
|
237
|
-
justifyContent: "center",
|
|
238
|
-
marginTop: 24,
|
|
239
|
-
},
|
|
240
|
-
footerText: {
|
|
241
|
-
color: "#666",
|
|
242
|
-
fontSize: 14,
|
|
243
|
-
},
|
|
244
|
-
link: {
|
|
245
|
-
color: "#007AFF",
|
|
246
|
-
fontSize: 14,
|
|
247
|
-
fontWeight: "600",
|
|
248
|
-
},
|
|
249
|
-
modalOverlay: {
|
|
250
|
-
flex: 1,
|
|
251
|
-
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
252
|
-
justifyContent: "center",
|
|
253
|
-
alignItems: "center",
|
|
254
|
-
},
|
|
255
|
-
modalContent: {
|
|
256
|
-
backgroundColor: "#fff",
|
|
257
|
-
borderRadius: 16,
|
|
258
|
-
padding: 24,
|
|
259
|
-
width: "90%",
|
|
260
|
-
maxWidth: 400,
|
|
261
|
-
},
|
|
262
|
-
modalTitle: {
|
|
263
|
-
fontSize: 24,
|
|
264
|
-
fontWeight: "bold",
|
|
265
|
-
color: "#333",
|
|
266
|
-
marginBottom: 8,
|
|
267
|
-
textAlign: "center",
|
|
268
|
-
},
|
|
269
|
-
modalSubtitle: {
|
|
270
|
-
fontSize: 14,
|
|
271
|
-
color: "#666",
|
|
272
|
-
marginBottom: 24,
|
|
273
|
-
textAlign: "center",
|
|
274
|
-
},
|
|
275
|
-
cancelButton: {
|
|
276
|
-
marginTop: 12,
|
|
277
|
-
alignItems: "center",
|
|
278
|
-
},
|
|
279
|
-
cancelButtonText: {
|
|
280
|
-
color: "#666",
|
|
281
|
-
fontSize: 16,
|
|
282
|
-
},
|
|
283
|
-
errorContainer: {
|
|
284
|
-
backgroundColor: "#ffebee",
|
|
285
|
-
borderRadius: 8,
|
|
286
|
-
padding: 12,
|
|
287
|
-
marginBottom: 16,
|
|
288
|
-
borderWidth: 1,
|
|
289
|
-
borderColor: "#ef5350",
|
|
290
|
-
},
|
|
291
|
-
errorText: {
|
|
292
|
-
color: "#c62828",
|
|
293
|
-
fontSize: 14,
|
|
294
|
-
textAlign: "center",
|
|
295
|
-
},
|
|
296
|
-
});
|
|
297
|
-
`;
|
|
298
|
-
}
|