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.
Files changed (143) hide show
  1. package/dist/src/create.cjs +18 -1
  2. package/dist/src/create.cjs.map +1 -1
  3. package/dist/src/fs.cjs +65 -5
  4. package/dist/src/fs.cjs.map +1 -1
  5. package/dist/src/fs.d.cts +13 -2
  6. package/dist/src/index.cjs +0 -0
  7. package/dist/src/paths.cjs +2 -2
  8. package/dist/src/prompts.cjs +22 -0
  9. package/dist/src/prompts.cjs.map +1 -1
  10. package/dist/src/runCli.cjs +13 -2
  11. package/dist/src/runCli.cjs.map +1 -1
  12. package/dist/src/types.d.cts +9 -1
  13. package/package.json +8 -6
  14. package/templates/minimal-app/.cursor/rules/frontend-data-guide.mdc +46 -3
  15. package/templates/minimal-app/.cursor/rules/module-db-guide.mdc +15 -1
  16. package/templates/minimal-app/.cursor/rules/module-dto-guide.mdc +60 -0
  17. package/templates/minimal-app/.cursor/rules/module-repository-guide.mdc +98 -193
  18. package/templates/minimal-app/.cursor/rules/module-schema-guide.mdc +53 -173
  19. package/templates/minimal-app/.cursor/rules/module-service-guide.mdc +133 -240
  20. package/templates/minimal-app/.cursor/rules/module-trpc-guide.mdc +71 -113
  21. package/templates/minimal-app/README.md.tpl +3 -3
  22. package/templates/minimal-app/apps/.gitignore.tpl +13 -0
  23. package/templates/minimal-app/apps/e2e/package.json.tpl +23 -0
  24. package/templates/minimal-app/apps/e2e/playwright.config.ts.tpl +39 -0
  25. package/templates/minimal-app/apps/e2e/playwright.expo.config.ts.tpl +38 -0
  26. package/templates/minimal-app/apps/e2e/servers.ts.tpl +100 -0
  27. package/templates/minimal-app/apps/e2e/tests/email.spec.ts.tpl +47 -0
  28. package/templates/minimal-app/apps/e2e/tests/expo-helpers.ts.tpl +73 -0
  29. package/templates/minimal-app/apps/e2e/tests/expo-standard.spec.ts.tpl +517 -0
  30. package/templates/minimal-app/apps/e2e/tests/expo-waitlist.spec.ts.tpl +94 -0
  31. package/templates/minimal-app/apps/e2e/tests/helpers.ts.tpl +289 -0
  32. package/templates/minimal-app/apps/e2e/tests/standard.spec.ts.tpl +516 -0
  33. package/templates/minimal-app/apps/e2e/tests/waitlist.spec.ts.tpl +107 -0
  34. package/templates/minimal-app/apps/e2e/tsconfig.json.tpl +10 -0
  35. package/templates/minimal-app/apps/email/package.json.tpl +34 -34
  36. package/templates/minimal-app/apps/email/src/emails/accountDeletionEmail.tsx.tpl +35 -34
  37. package/templates/minimal-app/apps/email/src/emails/organizationInviteEmail.tsx.tpl +34 -33
  38. package/templates/minimal-app/apps/email/src/emails/passwordResetEmail.tsx.tpl +35 -34
  39. package/templates/minimal-app/apps/email/src/emails/verificationEmail.tsx.tpl +37 -36
  40. package/templates/minimal-app/apps/email/src/emails/waitlistEmails.tsx.tpl +87 -0
  41. package/templates/minimal-app/apps/email/src/index.ts.tpl +72 -32
  42. package/templates/minimal-app/apps/email/src/resources.ts.tpl +65 -36
  43. package/templates/minimal-app/apps/email/tsconfig.json.tpl +16 -11
  44. package/templates/minimal-app/apps/expo/.gitignore.tpl +44 -0
  45. package/templates/minimal-app/apps/expo/.prettierignore +13 -0
  46. package/templates/minimal-app/apps/expo/.prettierrc.json.tpl +9 -0
  47. package/templates/minimal-app/apps/expo/CHANGELOG.md.tpl +156 -0
  48. package/templates/minimal-app/apps/expo/README.md.tpl +44 -0
  49. package/templates/minimal-app/apps/expo/app.json.tpl +36 -0
  50. package/templates/minimal-app/apps/expo/assets/images/adaptive-icon.png +0 -0
  51. package/templates/minimal-app/apps/expo/assets/images/favicon.png +0 -0
  52. package/templates/minimal-app/apps/expo/assets/images/icon.png +0 -0
  53. package/templates/minimal-app/apps/expo/assets/images/splash-icon.png +0 -0
  54. package/templates/minimal-app/apps/expo/eslint.config.js.tpl +8 -0
  55. package/templates/minimal-app/apps/expo/expo-env.d.ts.tpl +3 -0
  56. package/templates/minimal-app/apps/expo/metro.config.js.tpl +16 -0
  57. package/templates/minimal-app/apps/expo/package.json.tpl +59 -0
  58. package/templates/minimal-app/apps/expo/src/app/_layout.tsx.tpl +31 -0
  59. package/templates/minimal-app/apps/expo/src/app/claim-account.tsx.tpl +151 -0
  60. package/templates/minimal-app/apps/expo/src/app/forgot-password.tsx.tpl +53 -0
  61. package/templates/minimal-app/apps/expo/src/app/index.tsx.tpl +8 -0
  62. package/templates/minimal-app/apps/expo/src/app/login.tsx.tpl +71 -0
  63. package/templates/minimal-app/apps/expo/src/app/logout.tsx.tpl +19 -0
  64. package/templates/minimal-app/apps/expo/src/app/organization/accept-invitation.tsx.tpl +85 -0
  65. package/templates/minimal-app/apps/expo/src/app/posts.tsx.tpl +40 -0
  66. package/templates/minimal-app/apps/expo/src/app/reset-password.tsx.tpl +75 -0
  67. package/templates/minimal-app/apps/expo/src/app/signup.tsx.tpl +193 -0
  68. package/templates/minimal-app/apps/expo/src/components/AuthScaffold.tsx.tpl +34 -0
  69. package/templates/minimal-app/apps/expo/src/components/FormTextField.tsx.tpl +37 -0
  70. package/templates/minimal-app/apps/expo/src/components/LoadingScreen.tsx.tpl +10 -0
  71. package/templates/minimal-app/apps/expo/src/components/StatusText.tsx.tpl +22 -0
  72. package/templates/minimal-app/apps/expo/src/config.ts.tpl +9 -0
  73. package/templates/minimal-app/apps/expo/src/global.css.tpl +11 -0
  74. package/templates/minimal-app/apps/expo/src/lib/trpc.ts.tpl +20 -0
  75. package/templates/minimal-app/apps/expo/tsconfig.json.tpl +11 -0
  76. package/templates/minimal-app/apps/expo/uniwind-env.d.ts.tpl +1 -0
  77. package/templates/minimal-app/apps/expo/uniwind-types.d.ts.tpl +10 -0
  78. package/templates/minimal-app/apps/server/AGENTS.md.tpl +39 -39
  79. package/templates/minimal-app/apps/server/drizzle/0000_wealthy_absorbing_man.sql +268 -0
  80. package/templates/minimal-app/apps/server/drizzle/db.ts.tpl +26 -0
  81. package/templates/minimal-app/apps/server/drizzle/meta/0000_snapshot.json.tpl +1890 -0
  82. package/templates/minimal-app/apps/server/drizzle/meta/_journal.json.tpl +13 -0
  83. package/templates/minimal-app/apps/server/drizzle/reset.ts.tpl +33 -0
  84. package/templates/minimal-app/apps/server/drizzle/seed.e2e.ts.tpl +244 -0
  85. package/templates/minimal-app/apps/server/drizzle/seed.ts.tpl +181 -180
  86. package/templates/minimal-app/apps/server/drizzle/sync.ts.tpl +14 -21
  87. package/templates/minimal-app/apps/server/drizzle.config.ts.tpl +33 -35
  88. package/templates/minimal-app/apps/server/package.json.tpl +56 -52
  89. package/templates/minimal-app/apps/server/src/app.ts.tpl +142 -126
  90. package/templates/minimal-app/apps/server/src/index.ts.tpl +58 -58
  91. package/templates/minimal-app/apps/server/src/lib/auth.ts.tpl +12 -12
  92. package/templates/minimal-app/apps/server/src/modules/posts/posts.db.ts.tpl +25 -25
  93. package/templates/minimal-app/apps/server/src/modules/posts/posts.dto.ts.tpl +23 -0
  94. package/templates/minimal-app/apps/server/src/modules/posts/posts.grants.ts.tpl +30 -40
  95. package/templates/minimal-app/apps/server/src/modules/posts/posts.module.ts.tpl +54 -54
  96. package/templates/minimal-app/apps/server/src/modules/posts/posts.repository.ts.tpl +67 -112
  97. package/templates/minimal-app/apps/server/src/modules/posts/posts.service.ts.tpl +104 -170
  98. package/templates/minimal-app/apps/server/src/modules/posts/posts.trpc.ts.tpl +37 -48
  99. package/templates/minimal-app/apps/server/src/modules/posts/posts.utils.ts.tpl +19 -0
  100. package/templates/minimal-app/apps/server/src/modules/test-harness/test-harness.module.ts.tpl +279 -0
  101. package/templates/minimal-app/apps/server/src/schema.ts.tpl +20 -0
  102. package/templates/minimal-app/apps/server/src/types.ts.tpl +1 -1
  103. package/templates/minimal-app/apps/server/tsconfig.json.tpl +20 -14
  104. package/templates/minimal-app/apps/server/tsup.config.ts.tpl +9 -9
  105. package/templates/minimal-app/apps/shared/package.json.tpl +24 -24
  106. package/templates/minimal-app/apps/shared/src/modules/app/app.constants.ts.tpl +28 -2
  107. package/templates/minimal-app/apps/shared/src/modules/notification/notification.schema.ts.tpl +3 -3
  108. package/templates/minimal-app/apps/shared/src/modules/posts/posts.constants.ts.tpl +5 -5
  109. package/templates/minimal-app/apps/shared/src/modules/posts/posts.schema.ts.tpl +25 -76
  110. package/templates/minimal-app/apps/shared/tsconfig.json.tpl +16 -12
  111. package/templates/minimal-app/apps/webapp/index.html.tpl +22 -22
  112. package/templates/minimal-app/apps/webapp/package.json.tpl +53 -52
  113. package/templates/minimal-app/apps/webapp/public/{push-sw.js → push-sw.js.tpl} +34 -34
  114. package/templates/minimal-app/apps/webapp/src/App.tsx.tpl +44 -13
  115. package/templates/minimal-app/apps/webapp/src/Layout.tsx.tpl +18 -12
  116. package/templates/minimal-app/apps/webapp/src/Router.tsx.tpl +33 -40
  117. package/templates/minimal-app/apps/webapp/src/index.css.tpl +15 -75
  118. package/templates/minimal-app/apps/webapp/src/main.tsx.tpl +26 -26
  119. package/templates/minimal-app/apps/webapp/src/modules/posts/PostsRoute.tsx.tpl +278 -307
  120. package/templates/minimal-app/apps/webapp/src/modules/posts/components/PostCard.tsx.tpl +96 -138
  121. package/templates/minimal-app/apps/webapp/src/modules/posts/components/PostEditorModal.tsx.tpl +118 -124
  122. package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostActions.ts.tpl +108 -116
  123. package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostsList.ts.tpl +15 -9
  124. package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostsRoute.ts.tpl +13 -13
  125. package/templates/minimal-app/apps/webapp/src/modules/posts/posts.utils.ts.tpl +16 -16
  126. package/templates/minimal-app/apps/webapp/src/utils/i18n.ts.tpl +13 -13
  127. package/templates/minimal-app/apps/webapp/src/utils/trpc.ts.tpl +10 -6
  128. package/templates/minimal-app/apps/webapp/src/vite-env.d.ts.tpl +1 -1
  129. package/templates/minimal-app/apps/webapp/translations/{app.json.tpl → en/app.json.tpl} +7 -7
  130. package/templates/minimal-app/apps/webapp/translations/en/{blog-app.json.tpl → {{APP_SLUG}}.json.tpl} +135 -135
  131. package/templates/minimal-app/apps/webapp/tsconfig.json.tpl +17 -17
  132. package/templates/minimal-app/apps/webapp/vite.config.ts.tpl +31 -31
  133. package/templates/minimal-app/template.manifest.json +21 -0
  134. package/templates/minimal-app/apps/server/drizzle/generate-schema.ts.tpl +0 -31
  135. package/templates/minimal-app/apps/server/src/db.ts.tpl +0 -7
  136. package/templates/minimal-app/apps/server/src/generated/schema.ts.tpl +0 -13
  137. package/templates/minimal-app/apps/server/src/utils/trpc.ts.tpl +0 -8
  138. package/templates/minimal-app/apps/shared/src/modules/app/locale.constants.ts.tpl +0 -7
  139. package/templates/minimal-app/apps/shared/src/modules/app/roles.constants.ts.tpl +0 -17
  140. package/templates/minimal-app/apps/webapp/src/Providers.tsx.tpl +0 -36
  141. package/templates/minimal-app/apps/webapp/src/modules/notification/PushNotificationsPanel.tsx.tpl +0 -89
  142. package/templates/minimal-app/apps/webapp/src/navigation/navigation.config.tsx.tpl +0 -85
  143. /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
- "rootDir": ".",
4
- "compilerOptions": {
5
- "jsx": "react-jsx",
6
- "noEmit": true,
7
- "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo"
8
- },
9
- "exclude": ["node_modules"],
10
- "include": ["src/**/*.ts", "src/**/*.tsx"]
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,13 @@
1
+ node_modules
2
+ .expo
3
+ dist
4
+ ios
5
+ android
6
+ *.lock
7
+ pnpm-lock.yaml
8
+ yarn.lock
9
+ package-lock.json
10
+ bun.lockb
11
+ expo-env.d.ts
12
+ uniwind-types.d.ts
13
+ .DS_Store
@@ -0,0 +1,9 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "trailingComma": "es5",
5
+ "printWidth": 100,
6
+ "tabWidth": 2,
7
+ "arrowParens": "always",
8
+ "endOfLine": "lf"
9
+ }
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ const expoConfig = require("eslint-config-expo/flat");
2
+
3
+ module.exports = [
4
+ ...expoConfig,
5
+ {
6
+ ignores: ["dist/*", ".expo/*", "node_modules/*", "expo-env.d.ts", "uniwind-types.d.ts"],
7
+ },
8
+ ];
@@ -0,0 +1,3 @@
1
+ /// <reference types="expo/types" />
2
+
3
+ // NOTE: This file should not be edited and should be in your git ignore
@@ -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
+ }