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.
@@ -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
- <TouchableOpacity
101
- style={[
102
- styles.button,
103
- styles.appleButton,
104
- loading === "apple" && styles.buttonLoading,
105
- ]}
106
- onPress={() => handleOAuth("apple", startAppleOAuth)}
107
- activeOpacity={0.7}
108
- disabled={loading !== null}
109
- >
110
- {loading === "apple" ? (
111
- <ActivityIndicator size={20} color="#FFFFFF" />
112
- ) : (
113
- <>
114
- <View style={styles.iconWrap}>
115
- <Svg width={20} height={20} viewBox="0 0 24 24" fill="#FFFFFF">
116
- <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" />
117
- </Svg>
118
- </View>
119
- <Text style={styles.appleText}>Continue with Apple</Text>
120
- </>
121
- )}
122
- </TouchableOpacity>
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}>
@@ -12,8 +12,10 @@ declare global {
12
12
 
13
13
  export function useFrameworkReady() {
14
14
  useEffect(() => {
15
- window.frameworkReady?.();
16
- });
15
+ if (typeof window !== "undefined") {
16
+ window.frameworkReady?.();
17
+ }
18
+ }, []);
17
19
  }
18
20
  `;
19
21
  }
package/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "create-100x-mobile",
3
- "version": "0.4.2",
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
- "build": "tsc",
10
+ "clean": "node -e \"require('fs').rmSync('dist',{ recursive: true, force: true })\"",
11
+ "build": "npm run clean && tsc",
11
12
  "dev": "tsc --watch",
12
- "prepublishOnly": "npm run build"
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"
@@ -1,7 +0,0 @@
1
- <claude-mem-context>
2
- # Recent Activity
3
-
4
- <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
-
6
- *No recent activity*
7
- </claude-mem-context>
@@ -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
- }
@@ -1,7 +0,0 @@
1
- <claude-mem-context>
2
- # Recent Activity
3
-
4
- <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
-
6
- *No recent activity*
7
- </claude-mem-context>