create-m5kdev 0.25.3 → 0.26.1
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/src/create.cjs +18 -1
- package/dist/src/create.cjs.map +1 -1
- package/dist/src/fs.cjs +65 -5
- package/dist/src/fs.cjs.map +1 -1
- package/dist/src/fs.d.cts +13 -2
- package/dist/src/index.cjs +0 -0
- package/dist/src/paths.cjs +2 -2
- package/dist/src/prompts.cjs +22 -0
- package/dist/src/prompts.cjs.map +1 -1
- package/dist/src/runCli.cjs +13 -2
- package/dist/src/runCli.cjs.map +1 -1
- package/dist/src/types.d.cts +9 -1
- package/package.json +8 -6
- package/templates/minimal-app/.cursor/rules/frontend-data-guide.mdc +46 -3
- package/templates/minimal-app/.cursor/rules/module-db-guide.mdc +15 -1
- package/templates/minimal-app/.cursor/rules/module-dto-guide.mdc +60 -0
- package/templates/minimal-app/.cursor/rules/module-repository-guide.mdc +98 -193
- package/templates/minimal-app/.cursor/rules/module-schema-guide.mdc +53 -173
- package/templates/minimal-app/.cursor/rules/module-service-guide.mdc +133 -240
- package/templates/minimal-app/.cursor/rules/module-trpc-guide.mdc +71 -113
- package/templates/minimal-app/README.md.tpl +3 -3
- package/templates/minimal-app/apps/.gitignore.tpl +13 -0
- package/templates/minimal-app/apps/e2e/package.json.tpl +23 -0
- package/templates/minimal-app/apps/e2e/playwright.config.ts.tpl +39 -0
- package/templates/minimal-app/apps/e2e/playwright.expo.config.ts.tpl +38 -0
- package/templates/minimal-app/apps/e2e/servers.ts.tpl +100 -0
- package/templates/minimal-app/apps/e2e/tests/email.spec.ts.tpl +47 -0
- package/templates/minimal-app/apps/e2e/tests/expo-helpers.ts.tpl +73 -0
- package/templates/minimal-app/apps/e2e/tests/expo-standard.spec.ts.tpl +517 -0
- package/templates/minimal-app/apps/e2e/tests/expo-waitlist.spec.ts.tpl +94 -0
- package/templates/minimal-app/apps/e2e/tests/helpers.ts.tpl +289 -0
- package/templates/minimal-app/apps/e2e/tests/standard.spec.ts.tpl +516 -0
- package/templates/minimal-app/apps/e2e/tests/waitlist.spec.ts.tpl +107 -0
- package/templates/minimal-app/apps/e2e/tsconfig.json.tpl +10 -0
- package/templates/minimal-app/apps/email/package.json.tpl +34 -34
- package/templates/minimal-app/apps/email/src/emails/accountDeletionEmail.tsx.tpl +35 -34
- package/templates/minimal-app/apps/email/src/emails/organizationInviteEmail.tsx.tpl +34 -33
- package/templates/minimal-app/apps/email/src/emails/passwordResetEmail.tsx.tpl +35 -34
- package/templates/minimal-app/apps/email/src/emails/verificationEmail.tsx.tpl +37 -36
- package/templates/minimal-app/apps/email/src/emails/waitlistEmails.tsx.tpl +87 -0
- package/templates/minimal-app/apps/email/src/index.ts.tpl +72 -32
- package/templates/minimal-app/apps/email/src/resources.ts.tpl +65 -36
- package/templates/minimal-app/apps/email/tsconfig.json.tpl +16 -11
- package/templates/minimal-app/apps/expo/.gitignore.tpl +44 -0
- package/templates/minimal-app/apps/expo/.prettierignore +13 -0
- package/templates/minimal-app/apps/expo/.prettierrc.json.tpl +9 -0
- package/templates/minimal-app/apps/expo/CHANGELOG.md.tpl +156 -0
- package/templates/minimal-app/apps/expo/README.md.tpl +44 -0
- package/templates/minimal-app/apps/expo/app.json.tpl +36 -0
- package/templates/minimal-app/apps/expo/assets/images/adaptive-icon.png +0 -0
- package/templates/minimal-app/apps/expo/assets/images/favicon.png +0 -0
- package/templates/minimal-app/apps/expo/assets/images/icon.png +0 -0
- package/templates/minimal-app/apps/expo/assets/images/splash-icon.png +0 -0
- package/templates/minimal-app/apps/expo/eslint.config.js.tpl +8 -0
- package/templates/minimal-app/apps/expo/expo-env.d.ts.tpl +3 -0
- package/templates/minimal-app/apps/expo/metro.config.js.tpl +16 -0
- package/templates/minimal-app/apps/expo/package.json.tpl +59 -0
- package/templates/minimal-app/apps/expo/src/app/_layout.tsx.tpl +31 -0
- package/templates/minimal-app/apps/expo/src/app/claim-account.tsx.tpl +151 -0
- package/templates/minimal-app/apps/expo/src/app/forgot-password.tsx.tpl +53 -0
- package/templates/minimal-app/apps/expo/src/app/index.tsx.tpl +8 -0
- package/templates/minimal-app/apps/expo/src/app/login.tsx.tpl +71 -0
- package/templates/minimal-app/apps/expo/src/app/logout.tsx.tpl +19 -0
- package/templates/minimal-app/apps/expo/src/app/organization/accept-invitation.tsx.tpl +85 -0
- package/templates/minimal-app/apps/expo/src/app/posts.tsx.tpl +40 -0
- package/templates/minimal-app/apps/expo/src/app/reset-password.tsx.tpl +75 -0
- package/templates/minimal-app/apps/expo/src/app/signup.tsx.tpl +193 -0
- package/templates/minimal-app/apps/expo/src/components/AuthScaffold.tsx.tpl +34 -0
- package/templates/minimal-app/apps/expo/src/components/FormTextField.tsx.tpl +37 -0
- package/templates/minimal-app/apps/expo/src/components/LoadingScreen.tsx.tpl +10 -0
- package/templates/minimal-app/apps/expo/src/components/StatusText.tsx.tpl +22 -0
- package/templates/minimal-app/apps/expo/src/config.ts.tpl +9 -0
- package/templates/minimal-app/apps/expo/src/global.css.tpl +11 -0
- package/templates/minimal-app/apps/expo/src/lib/trpc.ts.tpl +20 -0
- package/templates/minimal-app/apps/expo/tsconfig.json.tpl +11 -0
- package/templates/minimal-app/apps/expo/uniwind-env.d.ts.tpl +1 -0
- package/templates/minimal-app/apps/expo/uniwind-types.d.ts.tpl +10 -0
- package/templates/minimal-app/apps/server/AGENTS.md.tpl +39 -39
- package/templates/minimal-app/apps/server/drizzle/0000_wealthy_absorbing_man.sql +268 -0
- package/templates/minimal-app/apps/server/drizzle/db.ts.tpl +26 -0
- package/templates/minimal-app/apps/server/drizzle/meta/0000_snapshot.json.tpl +1890 -0
- package/templates/minimal-app/apps/server/drizzle/meta/_journal.json.tpl +13 -0
- package/templates/minimal-app/apps/server/drizzle/reset.ts.tpl +33 -0
- package/templates/minimal-app/apps/server/drizzle/seed.e2e.ts.tpl +244 -0
- package/templates/minimal-app/apps/server/drizzle/seed.ts.tpl +181 -180
- package/templates/minimal-app/apps/server/drizzle/sync.ts.tpl +14 -21
- package/templates/minimal-app/apps/server/drizzle.config.ts.tpl +33 -35
- package/templates/minimal-app/apps/server/package.json.tpl +56 -52
- package/templates/minimal-app/apps/server/src/app.ts.tpl +142 -126
- package/templates/minimal-app/apps/server/src/index.ts.tpl +58 -58
- package/templates/minimal-app/apps/server/src/lib/auth.ts.tpl +12 -12
- package/templates/minimal-app/apps/server/src/modules/posts/posts.db.ts.tpl +25 -25
- package/templates/minimal-app/apps/server/src/modules/posts/posts.dto.ts.tpl +23 -0
- package/templates/minimal-app/apps/server/src/modules/posts/posts.grants.ts.tpl +30 -40
- package/templates/minimal-app/apps/server/src/modules/posts/posts.module.ts.tpl +54 -54
- package/templates/minimal-app/apps/server/src/modules/posts/posts.repository.ts.tpl +67 -112
- package/templates/minimal-app/apps/server/src/modules/posts/posts.service.ts.tpl +104 -170
- package/templates/minimal-app/apps/server/src/modules/posts/posts.trpc.ts.tpl +37 -48
- package/templates/minimal-app/apps/server/src/modules/posts/posts.utils.ts.tpl +19 -0
- package/templates/minimal-app/apps/server/src/modules/test-harness/test-harness.module.ts.tpl +279 -0
- package/templates/minimal-app/apps/server/src/schema.ts.tpl +20 -0
- package/templates/minimal-app/apps/server/src/types.ts.tpl +1 -1
- package/templates/minimal-app/apps/server/tsconfig.json.tpl +20 -14
- package/templates/minimal-app/apps/server/tsup.config.ts.tpl +9 -9
- package/templates/minimal-app/apps/shared/package.json.tpl +24 -24
- package/templates/minimal-app/apps/shared/src/modules/app/app.constants.ts.tpl +28 -2
- package/templates/minimal-app/apps/shared/src/modules/notification/notification.schema.ts.tpl +3 -3
- package/templates/minimal-app/apps/shared/src/modules/posts/posts.constants.ts.tpl +5 -5
- package/templates/minimal-app/apps/shared/src/modules/posts/posts.schema.ts.tpl +25 -76
- package/templates/minimal-app/apps/shared/tsconfig.json.tpl +16 -12
- package/templates/minimal-app/apps/webapp/index.html.tpl +22 -22
- package/templates/minimal-app/apps/webapp/package.json.tpl +53 -52
- package/templates/minimal-app/apps/webapp/public/{push-sw.js → push-sw.js.tpl} +34 -34
- package/templates/minimal-app/apps/webapp/src/App.tsx.tpl +44 -13
- package/templates/minimal-app/apps/webapp/src/Layout.tsx.tpl +18 -12
- package/templates/minimal-app/apps/webapp/src/Router.tsx.tpl +33 -40
- package/templates/minimal-app/apps/webapp/src/index.css.tpl +15 -75
- package/templates/minimal-app/apps/webapp/src/main.tsx.tpl +26 -26
- package/templates/minimal-app/apps/webapp/src/modules/posts/PostsRoute.tsx.tpl +278 -307
- package/templates/minimal-app/apps/webapp/src/modules/posts/components/PostCard.tsx.tpl +96 -138
- package/templates/minimal-app/apps/webapp/src/modules/posts/components/PostEditorModal.tsx.tpl +118 -124
- package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostActions.ts.tpl +108 -116
- package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostsList.ts.tpl +15 -9
- package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostsRoute.ts.tpl +13 -13
- package/templates/minimal-app/apps/webapp/src/modules/posts/posts.utils.ts.tpl +16 -16
- package/templates/minimal-app/apps/webapp/src/utils/i18n.ts.tpl +13 -13
- package/templates/minimal-app/apps/webapp/src/utils/trpc.ts.tpl +10 -6
- package/templates/minimal-app/apps/webapp/src/vite-env.d.ts.tpl +1 -1
- package/templates/minimal-app/apps/webapp/translations/{app.json.tpl → en/app.json.tpl} +7 -7
- package/templates/minimal-app/apps/webapp/translations/en/{blog-app.json.tpl → {{APP_SLUG}}.json.tpl} +135 -135
- package/templates/minimal-app/apps/webapp/tsconfig.json.tpl +17 -17
- package/templates/minimal-app/apps/webapp/vite.config.ts.tpl +31 -31
- package/templates/minimal-app/template.manifest.json +21 -0
- package/templates/minimal-app/apps/server/drizzle/generate-schema.ts.tpl +0 -31
- package/templates/minimal-app/apps/server/src/db.ts.tpl +0 -7
- package/templates/minimal-app/apps/server/src/generated/schema.ts.tpl +0 -13
- package/templates/minimal-app/apps/server/src/utils/trpc.ts.tpl +0 -8
- package/templates/minimal-app/apps/shared/src/modules/app/locale.constants.ts.tpl +0 -7
- package/templates/minimal-app/apps/shared/src/modules/app/roles.constants.ts.tpl +0 -17
- package/templates/minimal-app/apps/webapp/src/Providers.tsx.tpl +0 -36
- package/templates/minimal-app/apps/webapp/src/modules/notification/PushNotificationsPanel.tsx.tpl +0 -89
- package/templates/minimal-app/apps/webapp/src/navigation/navigation.config.tsx.tpl +0 -85
- /package/templates/minimal-app/apps/webapp/public/{logo.svg → logo.svg.tpl} +0 -0
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@m5kdev/config/tsconfig.node.json",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
},
|
|
9
|
-
"exclude": [
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
{
|
|
2
|
+
"extends": "@m5kdev/config/tsconfig.node.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"jsx": "react-jsx",
|
|
5
|
+
"noEmit": true,
|
|
6
|
+
"tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
|
|
7
|
+
"rootDir": "."
|
|
8
|
+
},
|
|
9
|
+
"exclude": [
|
|
10
|
+
"node_modules"
|
|
11
|
+
],
|
|
12
|
+
"include": [
|
|
13
|
+
"src/**/*.ts",
|
|
14
|
+
"src/**/*.tsx"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
|
2
|
+
|
|
3
|
+
# Dependencies
|
|
4
|
+
node_modules/
|
|
5
|
+
|
|
6
|
+
# Expo
|
|
7
|
+
.expo/
|
|
8
|
+
dist/
|
|
9
|
+
web-build/
|
|
10
|
+
expo-env.d.ts
|
|
11
|
+
|
|
12
|
+
# Uniwind (generated on first `expo start`)
|
|
13
|
+
uniwind-types.d.ts
|
|
14
|
+
|
|
15
|
+
# Native
|
|
16
|
+
.kotlin/
|
|
17
|
+
*.orig.*
|
|
18
|
+
*.jks
|
|
19
|
+
*.p8
|
|
20
|
+
*.p12
|
|
21
|
+
*.key
|
|
22
|
+
*.mobileprovision
|
|
23
|
+
|
|
24
|
+
# Metro
|
|
25
|
+
.metro-health-check*
|
|
26
|
+
|
|
27
|
+
# Debug
|
|
28
|
+
npm-debug.*
|
|
29
|
+
yarn-debug.*
|
|
30
|
+
yarn-error.*
|
|
31
|
+
|
|
32
|
+
# macOS
|
|
33
|
+
.DS_Store
|
|
34
|
+
*.pem
|
|
35
|
+
|
|
36
|
+
# Local env files
|
|
37
|
+
.env*.local
|
|
38
|
+
|
|
39
|
+
# TypeScript
|
|
40
|
+
*.tsbuildinfo
|
|
41
|
+
|
|
42
|
+
# Generated native folders
|
|
43
|
+
/ios
|
|
44
|
+
/android
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# m5kdev-auth-e2e-expo
|
|
2
|
+
|
|
3
|
+
## 1.5.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- reconcile
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @m5kdev/commons@0.25.3
|
|
10
|
+
- @m5kdev/frontend@0.25.3
|
|
11
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
12
|
+
|
|
13
|
+
## 1.5.2
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- errors 500
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @m5kdev/commons@0.25.2
|
|
20
|
+
- @m5kdev/frontend@0.25.2
|
|
21
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
22
|
+
|
|
23
|
+
## 1.5.1
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- error handeling
|
|
28
|
+
- Updated dependencies
|
|
29
|
+
- @m5kdev/commons@0.25.1
|
|
30
|
+
- @m5kdev/frontend@0.25.1
|
|
31
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
32
|
+
|
|
33
|
+
## 1.5.0
|
|
34
|
+
|
|
35
|
+
### Minor Changes
|
|
36
|
+
|
|
37
|
+
- roles
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- Updated dependencies
|
|
42
|
+
- @m5kdev/frontend@0.25.0
|
|
43
|
+
- @m5kdev/commons@0.25.0
|
|
44
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
45
|
+
|
|
46
|
+
## 1.4.0
|
|
47
|
+
|
|
48
|
+
### Minor Changes
|
|
49
|
+
|
|
50
|
+
- roles
|
|
51
|
+
|
|
52
|
+
### Patch Changes
|
|
53
|
+
|
|
54
|
+
- Updated dependencies
|
|
55
|
+
- @m5kdev/commons@0.24.0
|
|
56
|
+
- @m5kdev/frontend@0.24.0
|
|
57
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
58
|
+
|
|
59
|
+
## 1.3.0
|
|
60
|
+
|
|
61
|
+
### Minor Changes
|
|
62
|
+
|
|
63
|
+
- i18next
|
|
64
|
+
|
|
65
|
+
### Patch Changes
|
|
66
|
+
|
|
67
|
+
- Updated dependencies
|
|
68
|
+
- @m5kdev/commons@0.23.0
|
|
69
|
+
- @m5kdev/frontend@0.23.0
|
|
70
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
71
|
+
|
|
72
|
+
## 1.2.0
|
|
73
|
+
|
|
74
|
+
### Minor Changes
|
|
75
|
+
|
|
76
|
+
- i18n
|
|
77
|
+
|
|
78
|
+
### Patch Changes
|
|
79
|
+
|
|
80
|
+
- Updated dependencies
|
|
81
|
+
- @m5kdev/commons@0.22.0
|
|
82
|
+
- @m5kdev/frontend@0.22.0
|
|
83
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
84
|
+
|
|
85
|
+
## 1.1.6
|
|
86
|
+
|
|
87
|
+
### Patch Changes
|
|
88
|
+
|
|
89
|
+
- table columns
|
|
90
|
+
- Updated dependencies
|
|
91
|
+
- @m5kdev/commons@0.21.9
|
|
92
|
+
- @m5kdev/frontend@0.21.9
|
|
93
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
94
|
+
|
|
95
|
+
## 1.1.5
|
|
96
|
+
|
|
97
|
+
### Patch Changes
|
|
98
|
+
|
|
99
|
+
- emails
|
|
100
|
+
- Updated dependencies
|
|
101
|
+
- @m5kdev/frontend@0.21.7
|
|
102
|
+
- @m5kdev/commons@0.21.7
|
|
103
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
104
|
+
|
|
105
|
+
## 1.1.4
|
|
106
|
+
|
|
107
|
+
### Patch Changes
|
|
108
|
+
|
|
109
|
+
- verify
|
|
110
|
+
- Updated dependencies
|
|
111
|
+
- @m5kdev/commons@0.21.4
|
|
112
|
+
- @m5kdev/frontend@0.21.4
|
|
113
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
114
|
+
|
|
115
|
+
## 1.1.3
|
|
116
|
+
|
|
117
|
+
### Patch Changes
|
|
118
|
+
|
|
119
|
+
- hide upgrade
|
|
120
|
+
- Updated dependencies
|
|
121
|
+
- @m5kdev/commons@0.21.3
|
|
122
|
+
- @m5kdev/frontend@0.21.3
|
|
123
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
124
|
+
|
|
125
|
+
## 1.1.2
|
|
126
|
+
|
|
127
|
+
### Patch Changes
|
|
128
|
+
|
|
129
|
+
- provider
|
|
130
|
+
- Updated dependencies
|
|
131
|
+
- @m5kdev/commons@0.21.2
|
|
132
|
+
- @m5kdev/frontend@0.21.2
|
|
133
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
134
|
+
|
|
135
|
+
## 1.1.1
|
|
136
|
+
|
|
137
|
+
### Patch Changes
|
|
138
|
+
|
|
139
|
+
- frontend rework
|
|
140
|
+
- Updated dependencies
|
|
141
|
+
- @m5kdev/commons@0.21.1
|
|
142
|
+
- @m5kdev/frontend@0.21.1
|
|
143
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
144
|
+
|
|
145
|
+
## 1.1.0
|
|
146
|
+
|
|
147
|
+
### Minor Changes
|
|
148
|
+
|
|
149
|
+
- frontend rework
|
|
150
|
+
|
|
151
|
+
### Patch Changes
|
|
152
|
+
|
|
153
|
+
- Updated dependencies
|
|
154
|
+
- @m5kdev/commons@0.21.0
|
|
155
|
+
- @m5kdev/frontend@0.21.0
|
|
156
|
+
- m5kdev-auth-e2e-shared@0.0.0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Welcome to your HeroUI Native app 👋
|
|
2
|
+
|
|
3
|
+
This is an [Expo](https://expo.dev) project preconfigured with
|
|
4
|
+
[HeroUI Native](https://heroui.com/docs/native), [Uniwind](https://docs.uniwind.dev)
|
|
5
|
+
(Tailwind CSS for React Native), and [Expo Router](https://docs.expo.dev/router/introduction).
|
|
6
|
+
|
|
7
|
+
## Get started
|
|
8
|
+
|
|
9
|
+
1. Install dependencies
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
2. Start the app
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx expo start
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
In the output, you'll find options to open the app in a
|
|
22
|
+
|
|
23
|
+
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
|
|
24
|
+
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
|
|
25
|
+
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
|
|
26
|
+
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
|
|
27
|
+
|
|
28
|
+
You can start developing by editing the files inside the **src/app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
|
|
29
|
+
|
|
30
|
+
## What's preconfigured
|
|
31
|
+
|
|
32
|
+
- **HeroUI Native** (`heroui-native`) wrapped in `HeroUINativeProvider` and `GestureHandlerRootView` in `src/app/_layout.tsx`
|
|
33
|
+
- **Uniwind** + **Tailwind CSS** wired through `metro.config.js` and `src/global.css`
|
|
34
|
+
- All HeroUI Native mandatory peer dependencies: `react-native-reanimated`, `react-native-gesture-handler`, `react-native-worklets`, `react-native-safe-area-context`, `react-native-svg`, `react-native-screens`
|
|
35
|
+
- `@gorhom/bottom-sheet` for bottom-sheet UIs
|
|
36
|
+
- TypeScript with `strict: true` and `@/*` path alias to `./src/*`
|
|
37
|
+
- React Compiler enabled
|
|
38
|
+
|
|
39
|
+
## Learn more
|
|
40
|
+
|
|
41
|
+
- [HeroUI Native components](https://heroui.com/docs/native) — full component reference
|
|
42
|
+
- [Expo documentation](https://docs.expo.dev/) — Expo fundamentals and guides
|
|
43
|
+
- [Uniwind documentation](https://docs.uniwind.dev) — Tailwind for React Native
|
|
44
|
+
- [Expo Router](https://docs.expo.dev/router/introduction) — file-based routing
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "Auth E2E Expo",
|
|
4
|
+
"slug": "auth-e2e-expo",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/images/icon.png",
|
|
8
|
+
"scheme": "auth-e2e-expo",
|
|
9
|
+
"userInterfaceStyle": "automatic",
|
|
10
|
+
"ios": {
|
|
11
|
+
"supportsTablet": true
|
|
12
|
+
},
|
|
13
|
+
"android": {
|
|
14
|
+
"adaptiveIcon": {
|
|
15
|
+
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
16
|
+
"backgroundColor": "#ffffff"
|
|
17
|
+
},
|
|
18
|
+
"predictiveBackGestureEnabled": false
|
|
19
|
+
},
|
|
20
|
+
"plugins": [
|
|
21
|
+
"expo-router",
|
|
22
|
+
[
|
|
23
|
+
"expo-splash-screen",
|
|
24
|
+
{
|
|
25
|
+
"image": "./assets/images/splash-icon.png",
|
|
26
|
+
"resizeMode": "contain",
|
|
27
|
+
"backgroundColor": "#ffffff"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
],
|
|
31
|
+
"experiments": {
|
|
32
|
+
"typedRoutes": true,
|
|
33
|
+
"reactCompiler": true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const { getDefaultConfig } = require("expo/metro-config");
|
|
2
|
+
const { withUniwindConfig } = require("uniwind/metro");
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
|
|
5
|
+
const config = getDefaultConfig(__dirname);
|
|
6
|
+
const workspaceRoot = path.resolve(__dirname, "../../..");
|
|
7
|
+
|
|
8
|
+
config.watchFolders = [workspaceRoot];
|
|
9
|
+
config.resolver.nodeModulesPaths = [
|
|
10
|
+
path.resolve(__dirname, "node_modules"),
|
|
11
|
+
path.resolve(workspaceRoot, "node_modules"),
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
module.exports = withUniwindConfig(config, {
|
|
15
|
+
cssEntryFile: "./src/global.css",
|
|
16
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_SCOPE}}/expo",
|
|
3
|
+
"version": "1.5.3",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "expo-router/entry",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "expo export --platform web --output-dir dist",
|
|
8
|
+
"start": "expo start",
|
|
9
|
+
"dev:standard": "EXPO_PUBLIC_ENABLE_WAITLIST=false EXPO_PUBLIC_SERVER_URL=http://127.0.0.1:18182 EXPO_PUBLIC_APP_URL=http://127.0.0.1:15183 EXPO_NO_TELEMETRY=1 BROWSER=none expo start --web --port 15183 --host localhost",
|
|
10
|
+
"dev:waitlist": "EXPO_PUBLIC_ENABLE_WAITLIST=true EXPO_PUBLIC_SERVER_URL=http://127.0.0.1:18183 EXPO_PUBLIC_APP_URL=http://127.0.0.1:15184 EXPO_NO_TELEMETRY=1 BROWSER=none expo start --web --port 15184 --host localhost",
|
|
11
|
+
"android": "expo start --android",
|
|
12
|
+
"ios": "expo start --ios",
|
|
13
|
+
"lint": "biome check app.json package.json metro.config.js eslint.config.js src tsconfig.json uniwind-env.d.ts",
|
|
14
|
+
"lint:fix": "biome check app.json package.json metro.config.js eslint.config.js src tsconfig.json uniwind-env.d.ts --write",
|
|
15
|
+
"format": "prettier --write .",
|
|
16
|
+
"format:check": "prettier --check .",
|
|
17
|
+
"check-types": "tsc --noEmit",
|
|
18
|
+
"typecheck": "pnpm check-types"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@expo/metro-runtime": "~56.0.13",
|
|
22
|
+
"@gorhom/bottom-sheet": "^5.2.14",
|
|
23
|
+
"@m5kdev/commons": "catalog:",
|
|
24
|
+
"@m5kdev/frontend": "catalog:",
|
|
25
|
+
"@trpc/client": "catalog:",
|
|
26
|
+
"expo": "~56.0.5",
|
|
27
|
+
"expo-constants": "~56.0.16",
|
|
28
|
+
"expo-linking": "~56.0.12",
|
|
29
|
+
"expo-router": "~56.2.7",
|
|
30
|
+
"expo-splash-screen": "~56.0.10",
|
|
31
|
+
"expo-status-bar": "~56.0.4",
|
|
32
|
+
"heroui-native": "^1.0.2",
|
|
33
|
+
"{{PACKAGE_SCOPE}}/shared": "workspace:*",
|
|
34
|
+
"react": "19.2.3",
|
|
35
|
+
"react-dom": "19.2.3",
|
|
36
|
+
"react-native": "0.85.3",
|
|
37
|
+
"react-native-gesture-handler": "~2.31.2",
|
|
38
|
+
"react-native-reanimated": "~4.3.1",
|
|
39
|
+
"react-native-safe-area-context": "~5.7.0",
|
|
40
|
+
"react-native-screens": "~4.25.2",
|
|
41
|
+
"react-native-svg": "15.15.4",
|
|
42
|
+
"react-native-web": "catalog:",
|
|
43
|
+
"react-native-worklets": "0.8.3",
|
|
44
|
+
"tailwind-merge": "^3.4.0",
|
|
45
|
+
"tailwind-variants": "^3.2.2",
|
|
46
|
+
"tailwindcss": "^4.1.17",
|
|
47
|
+
"uniwind": "^1.5.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@biomejs/biome": "catalog:",
|
|
51
|
+
"@m5kdev/backend": "catalog:",
|
|
52
|
+
"@m5kdev/config": "catalog:",
|
|
53
|
+
"@types/react": "~19.2.15",
|
|
54
|
+
"eslint": "^9.39.4",
|
|
55
|
+
"eslint-config-expo": "^56.0.4",
|
|
56
|
+
"prettier": "^3.8.3",
|
|
57
|
+
"typescript": "~6.0.3"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AppConfigProvider } from "@m5kdev/frontend/modules/app/components/AppConfigProvider";
|
|
2
|
+
import { AuthProvider } from "@m5kdev/frontend/modules/auth/components/AuthProvider";
|
|
3
|
+
import { Stack } from "expo-router";
|
|
4
|
+
import { HeroUINativeProvider } from "heroui-native";
|
|
5
|
+
import { APP_NAME } from "{{PACKAGE_SCOPE}}/shared/modules/app/app.constants";
|
|
6
|
+
import type { JSX } from "react";
|
|
7
|
+
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
8
|
+
import { LoadingScreen } from "../components/LoadingScreen";
|
|
9
|
+
import { appUrl, serverUrl } from "../config";
|
|
10
|
+
|
|
11
|
+
import "../global.css";
|
|
12
|
+
|
|
13
|
+
export default function RootLayout(): JSX.Element {
|
|
14
|
+
return (
|
|
15
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
16
|
+
<HeroUINativeProvider>
|
|
17
|
+
<AppConfigProvider
|
|
18
|
+
config={{
|
|
19
|
+
appName: APP_NAME,
|
|
20
|
+
appUrl,
|
|
21
|
+
serverUrl,
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
<AuthProvider loader={<LoadingScreen />}>
|
|
25
|
+
<Stack screenOptions={{ headerShown: false }} />
|
|
26
|
+
</AuthProvider>
|
|
27
|
+
</AppConfigProvider>
|
|
28
|
+
</HeroUINativeProvider>
|
|
29
|
+
</GestureHandlerRootView>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { useAppConfig } from "@m5kdev/frontend/modules/app/hooks/useAppConfig";
|
|
2
|
+
import { useSession } from "@m5kdev/frontend/modules/auth/hooks/useSession";
|
|
3
|
+
import { Button } from "heroui-native";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import { AuthScaffold } from "../components/AuthScaffold";
|
|
7
|
+
import { FormTextField } from "../components/FormTextField";
|
|
8
|
+
import { StatusText } from "../components/StatusText";
|
|
9
|
+
import { trpcClient } from "../lib/trpc";
|
|
10
|
+
|
|
11
|
+
export default function ClaimAccountScreen() {
|
|
12
|
+
const { serverUrl } = useAppConfig();
|
|
13
|
+
const { data: session, registerSession } = useSession();
|
|
14
|
+
const [email, setEmail] = useState("");
|
|
15
|
+
const [password, setPassword] = useState("");
|
|
16
|
+
const [status, setStatus] = useState<string | null>("Loading claim status...");
|
|
17
|
+
const [statusTone, setStatusTone] = useState<"default" | "error" | "success">("default");
|
|
18
|
+
const [hasClaim, setHasClaim] = useState(false);
|
|
19
|
+
const [isClaimed, setIsClaimed] = useState(false);
|
|
20
|
+
const [isBusy, setIsBusy] = useState(false);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (session?.user.email) {
|
|
24
|
+
setEmail(session.user.email);
|
|
25
|
+
}
|
|
26
|
+
}, [session?.user.email]);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
let cancelled = false;
|
|
30
|
+
|
|
31
|
+
if (isClaimed) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!session?.user) {
|
|
36
|
+
setStatusTone("error");
|
|
37
|
+
setStatus("You need to sign in with your magic link before claiming this account.");
|
|
38
|
+
setHasClaim(false);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
trpcClient.auth.getMyAccountClaimStatus
|
|
43
|
+
.query()
|
|
44
|
+
.then((claim) => {
|
|
45
|
+
if (cancelled) return;
|
|
46
|
+
setHasClaim(Boolean(claim));
|
|
47
|
+
setStatusTone(claim ? "success" : "error");
|
|
48
|
+
setStatus(claim ? "Claim your account" : "No pending account claim was found.");
|
|
49
|
+
if (claim?.claimedEmail) {
|
|
50
|
+
setEmail(claim.claimedEmail);
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
if (cancelled) return;
|
|
55
|
+
setHasClaim(false);
|
|
56
|
+
setStatusTone("error");
|
|
57
|
+
setStatus(error instanceof Error ? error.message : "Unable to load claim status");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
cancelled = true;
|
|
62
|
+
};
|
|
63
|
+
}, [isClaimed, session?.user]);
|
|
64
|
+
|
|
65
|
+
const saveEmail = async () => {
|
|
66
|
+
setIsBusy(true);
|
|
67
|
+
setStatus(null);
|
|
68
|
+
try {
|
|
69
|
+
await trpcClient.auth.setMyAccountClaimEmail.mutate({ email });
|
|
70
|
+
registerSession();
|
|
71
|
+
setStatusTone("success");
|
|
72
|
+
setStatus("Email updated");
|
|
73
|
+
} catch (error) {
|
|
74
|
+
setStatusTone("error");
|
|
75
|
+
setStatus(error instanceof Error ? error.message : "Unable to update email");
|
|
76
|
+
} finally {
|
|
77
|
+
setIsBusy(false);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const setPasswordAndClaim = async () => {
|
|
82
|
+
setIsBusy(true);
|
|
83
|
+
setStatus(null);
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetch(`${serverUrl}/api/auth/set-password`, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
credentials: "include",
|
|
88
|
+
headers: {
|
|
89
|
+
"Content-Type": "application/json",
|
|
90
|
+
},
|
|
91
|
+
body: JSON.stringify({
|
|
92
|
+
newPassword: password,
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
const payload = (await response.json().catch(() => ({}))) as { message?: string };
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
throw new Error(payload.message ?? "Unable to set password");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await trpcClient.auth.acceptMyAccountClaim.mutate();
|
|
101
|
+
setIsClaimed(true);
|
|
102
|
+
registerSession();
|
|
103
|
+
setStatusTone("success");
|
|
104
|
+
setStatus("Password set. Account claimed.");
|
|
105
|
+
} catch (error) {
|
|
106
|
+
setStatusTone("error");
|
|
107
|
+
setStatus(error instanceof Error ? error.message : "Unable to claim account");
|
|
108
|
+
} finally {
|
|
109
|
+
setIsBusy(false);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<AuthScaffold
|
|
115
|
+
title="Claim your account"
|
|
116
|
+
description="Set permanent credentials for a provisioned account."
|
|
117
|
+
>
|
|
118
|
+
<View className="gap-4">
|
|
119
|
+
<FormTextField
|
|
120
|
+
label="Email"
|
|
121
|
+
testID="claim-email"
|
|
122
|
+
value={email}
|
|
123
|
+
onChangeText={setEmail}
|
|
124
|
+
keyboardType="email-address"
|
|
125
|
+
editable={hasClaim && !isBusy}
|
|
126
|
+
/>
|
|
127
|
+
<Button testID="claim-email-submit" onPress={saveEmail} isDisabled={!hasClaim || isBusy}>
|
|
128
|
+
Save Email
|
|
129
|
+
</Button>
|
|
130
|
+
<FormTextField
|
|
131
|
+
label="Set password"
|
|
132
|
+
testID="claim-password"
|
|
133
|
+
value={password}
|
|
134
|
+
onChangeText={setPassword}
|
|
135
|
+
secureTextEntry
|
|
136
|
+
editable={hasClaim && !isBusy}
|
|
137
|
+
/>
|
|
138
|
+
<Button
|
|
139
|
+
testID="claim-password-submit"
|
|
140
|
+
onPress={setPasswordAndClaim}
|
|
141
|
+
isDisabled={!hasClaim || !password || isBusy}
|
|
142
|
+
>
|
|
143
|
+
Set Password and Claim
|
|
144
|
+
</Button>
|
|
145
|
+
<StatusText testID="claim-status" tone={statusTone}>
|
|
146
|
+
{status}
|
|
147
|
+
</StatusText>
|
|
148
|
+
</View>
|
|
149
|
+
</AuthScaffold>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useAuthClient } from "@m5kdev/frontend/modules/auth/hooks/useAuthClient";
|
|
2
|
+
import { Button } from "heroui-native";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
import { AuthScaffold } from "../components/AuthScaffold";
|
|
6
|
+
import { FormTextField } from "../components/FormTextField";
|
|
7
|
+
import { StatusText } from "../components/StatusText";
|
|
8
|
+
|
|
9
|
+
export default function ForgotPasswordScreen() {
|
|
10
|
+
const authClient = useAuthClient();
|
|
11
|
+
const [email, setEmail] = useState("");
|
|
12
|
+
const [status, setStatus] = useState<string | null>(null);
|
|
13
|
+
const [tone, setTone] = useState<"error" | "success">("success");
|
|
14
|
+
const [isBusy, setIsBusy] = useState(false);
|
|
15
|
+
|
|
16
|
+
const submit = async () => {
|
|
17
|
+
setIsBusy(true);
|
|
18
|
+
setStatus(null);
|
|
19
|
+
try {
|
|
20
|
+
await authClient.requestPasswordReset({
|
|
21
|
+
email,
|
|
22
|
+
redirectTo: "/reset-password",
|
|
23
|
+
});
|
|
24
|
+
setTone("success");
|
|
25
|
+
setStatus("Password reset email sent");
|
|
26
|
+
} catch (error) {
|
|
27
|
+
setTone("error");
|
|
28
|
+
setStatus(error instanceof Error ? error.message : "Failed to request password reset");
|
|
29
|
+
} finally {
|
|
30
|
+
setIsBusy(false);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<AuthScaffold title="Reset password">
|
|
36
|
+
<View className="gap-4">
|
|
37
|
+
<FormTextField
|
|
38
|
+
label="Email"
|
|
39
|
+
testID="forgot-password-email"
|
|
40
|
+
value={email}
|
|
41
|
+
onChangeText={setEmail}
|
|
42
|
+
keyboardType="email-address"
|
|
43
|
+
/>
|
|
44
|
+
<StatusText testID="auth-status" tone={tone}>
|
|
45
|
+
{status}
|
|
46
|
+
</StatusText>
|
|
47
|
+
<Button testID="forgot-password-submit" onPress={submit} isDisabled={isBusy}>
|
|
48
|
+
Reset password
|
|
49
|
+
</Button>
|
|
50
|
+
</View>
|
|
51
|
+
</AuthScaffold>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useSession } from "@m5kdev/frontend/modules/auth/hooks/useSession";
|
|
2
|
+
import { Redirect } from "expo-router";
|
|
3
|
+
|
|
4
|
+
export default function IndexScreen() {
|
|
5
|
+
const { data: session } = useSession();
|
|
6
|
+
|
|
7
|
+
return <Redirect href={session ? "/posts" : "/login"} />;
|
|
8
|
+
}
|