@ramonclaudio/create-vexpo 0.1.0

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 (174) hide show
  1. package/README.md +50 -0
  2. package/dist/index.js +183 -0
  3. package/dist/templates/default/.eas/workflows/asc-events.yml +84 -0
  4. package/dist/templates/default/.eas/workflows/deploy-production.yml +129 -0
  5. package/dist/templates/default/.eas/workflows/development-builds.yml +19 -0
  6. package/dist/templates/default/.eas/workflows/e2e-tests.yml +42 -0
  7. package/dist/templates/default/.eas/workflows/pr-preview.yml +98 -0
  8. package/dist/templates/default/.eas/workflows/release.yml +44 -0
  9. package/dist/templates/default/.eas/workflows/rollback.yml +86 -0
  10. package/dist/templates/default/.eas/workflows/rollout.yml +84 -0
  11. package/dist/templates/default/.eas/workflows/rotate-apple-jwt.yml +42 -0
  12. package/dist/templates/default/.eas/workflows/testflight.yml +57 -0
  13. package/dist/templates/default/.github/workflows/check.yml +28 -0
  14. package/dist/templates/default/.maestro/launch.yaml +18 -0
  15. package/dist/templates/default/AGENTS.md +79 -0
  16. package/dist/templates/default/DESIGN.md +331 -0
  17. package/dist/templates/default/LICENSE +21 -0
  18. package/dist/templates/default/README.md +153 -0
  19. package/dist/templates/default/SETUP.md +618 -0
  20. package/dist/templates/default/__tests__/convex/constants.test.ts +49 -0
  21. package/dist/templates/default/__tests__/convex/validators.test.ts +23 -0
  22. package/dist/templates/default/__tests__/convex/webhook.test.ts +343 -0
  23. package/dist/templates/default/__tests__/lib/deep-link.test.ts +67 -0
  24. package/dist/templates/default/_easignore +22 -0
  25. package/dist/templates/default/_editorconfig +9 -0
  26. package/dist/templates/default/_env.example +34 -0
  27. package/dist/templates/default/_fingerprintignore +24 -0
  28. package/dist/templates/default/_gitattributes +7 -0
  29. package/dist/templates/default/_gitignore +69 -0
  30. package/dist/templates/default/_oxfmtrc.json +3 -0
  31. package/dist/templates/default/_oxlintrc.json +34 -0
  32. package/dist/templates/default/app/(app)/(tabs)/(home)/index.tsx +50 -0
  33. package/dist/templates/default/app/(app)/(tabs)/(home,search)/_layout.tsx +44 -0
  34. package/dist/templates/default/app/(app)/(tabs)/(search)/index.tsx +247 -0
  35. package/dist/templates/default/app/(app)/(tabs)/_layout.tsx +77 -0
  36. package/dist/templates/default/app/(app)/(tabs)/settings/_layout.tsx +37 -0
  37. package/dist/templates/default/app/(app)/(tabs)/settings/index.tsx +362 -0
  38. package/dist/templates/default/app/(app)/(tabs)/settings/preferences.tsx +184 -0
  39. package/dist/templates/default/app/(app)/_layout.tsx +73 -0
  40. package/dist/templates/default/app/(app)/debug.tsx +389 -0
  41. package/dist/templates/default/app/(app)/help.tsx +254 -0
  42. package/dist/templates/default/app/(app)/linked.tsx +116 -0
  43. package/dist/templates/default/app/(app)/privacy.tsx +159 -0
  44. package/dist/templates/default/app/(app)/profile.tsx +915 -0
  45. package/dist/templates/default/app/(app)/sessions.tsx +191 -0
  46. package/dist/templates/default/app/(app)/welcome.tsx +140 -0
  47. package/dist/templates/default/app/(auth)/_layout.tsx +31 -0
  48. package/dist/templates/default/app/(auth)/forgot-password.tsx +168 -0
  49. package/dist/templates/default/app/(auth)/reset-password.tsx +314 -0
  50. package/dist/templates/default/app/(auth)/sign-in.tsx +453 -0
  51. package/dist/templates/default/app/(auth)/sign-up.tsx +563 -0
  52. package/dist/templates/default/app/+native-intent.tsx +14 -0
  53. package/dist/templates/default/app/+not-found.tsx +51 -0
  54. package/dist/templates/default/app/_layout.tsx +102 -0
  55. package/dist/templates/default/app-store/screenshots/.gitkeep +0 -0
  56. package/dist/templates/default/app-store/screenshots/README.md +13 -0
  57. package/dist/templates/default/app.config.ts +201 -0
  58. package/dist/templates/default/app.json +11 -0
  59. package/dist/templates/default/assets/brand-icon-dark.png +0 -0
  60. package/dist/templates/default/assets/brand-icon-light.png +0 -0
  61. package/dist/templates/default/assets/fonts/Geist-Black.ttf +0 -0
  62. package/dist/templates/default/assets/fonts/Geist-BlackItalic.ttf +0 -0
  63. package/dist/templates/default/assets/fonts/Geist-Bold.ttf +0 -0
  64. package/dist/templates/default/assets/fonts/Geist-BoldItalic.ttf +0 -0
  65. package/dist/templates/default/assets/fonts/Geist-ExtraBold.ttf +0 -0
  66. package/dist/templates/default/assets/fonts/Geist-ExtraBoldItalic.ttf +0 -0
  67. package/dist/templates/default/assets/fonts/Geist-ExtraLight.ttf +0 -0
  68. package/dist/templates/default/assets/fonts/Geist-ExtraLightItalic.ttf +0 -0
  69. package/dist/templates/default/assets/fonts/Geist-Italic.ttf +0 -0
  70. package/dist/templates/default/assets/fonts/Geist-Light.ttf +0 -0
  71. package/dist/templates/default/assets/fonts/Geist-LightItalic.ttf +0 -0
  72. package/dist/templates/default/assets/fonts/Geist-Medium.ttf +0 -0
  73. package/dist/templates/default/assets/fonts/Geist-MediumItalic.ttf +0 -0
  74. package/dist/templates/default/assets/fonts/Geist-Regular.ttf +0 -0
  75. package/dist/templates/default/assets/fonts/Geist-SemiBold.ttf +0 -0
  76. package/dist/templates/default/assets/fonts/Geist-SemiBoldItalic.ttf +0 -0
  77. package/dist/templates/default/assets/fonts/Geist-Thin.ttf +0 -0
  78. package/dist/templates/default/assets/fonts/Geist-ThinItalic.ttf +0 -0
  79. package/dist/templates/default/assets/fonts/Geist-Variable-Italic.ttf +0 -0
  80. package/dist/templates/default/assets/fonts/Geist-Variable.ttf +0 -0
  81. package/dist/templates/default/assets/fonts/GeistMono-Bold.ttf +0 -0
  82. package/dist/templates/default/assets/fonts/GeistMono-BoldItalic.ttf +0 -0
  83. package/dist/templates/default/assets/fonts/GeistMono-Italic.ttf +0 -0
  84. package/dist/templates/default/assets/fonts/GeistMono-Medium.ttf +0 -0
  85. package/dist/templates/default/assets/fonts/GeistMono-MediumItalic.ttf +0 -0
  86. package/dist/templates/default/assets/fonts/GeistMono-Regular.ttf +0 -0
  87. package/dist/templates/default/assets/fonts/GeistPixel-Square.ttf +0 -0
  88. package/dist/templates/default/assets/icon.png +0 -0
  89. package/dist/templates/default/assets/sounds/notification.wav +0 -0
  90. package/dist/templates/default/assets/splash-image-dark.png +0 -0
  91. package/dist/templates/default/assets/splash-image-light.png +0 -0
  92. package/dist/templates/default/bun.lock +1860 -0
  93. package/dist/templates/default/components/auth/otp-verification.tsx +255 -0
  94. package/dist/templates/default/components/auth/password-field.tsx +121 -0
  95. package/dist/templates/default/components/auth/segmented-toggle.tsx +47 -0
  96. package/dist/templates/default/components/ui/convex-error.tsx +32 -0
  97. package/dist/templates/default/components/ui/error-boundary.tsx +57 -0
  98. package/dist/templates/default/components/ui/loading-screen.tsx +31 -0
  99. package/dist/templates/default/components/ui/material.tsx +94 -0
  100. package/dist/templates/default/components/ui/offline-banner.tsx +58 -0
  101. package/dist/templates/default/components/ui/prominent-button.tsx +71 -0
  102. package/dist/templates/default/components/ui/skeleton.tsx +107 -0
  103. package/dist/templates/default/components/ui/status-text.tsx +49 -0
  104. package/dist/templates/default/components/ui/update-banner.tsx +82 -0
  105. package/dist/templates/default/constants/layout.ts +102 -0
  106. package/dist/templates/default/constants/theme.ts +401 -0
  107. package/dist/templates/default/constants/ui.ts +77 -0
  108. package/dist/templates/default/convex/_generated/api.d.ts +77 -0
  109. package/dist/templates/default/convex/_generated/api.js +23 -0
  110. package/dist/templates/default/convex/_generated/dataModel.d.ts +60 -0
  111. package/dist/templates/default/convex/_generated/server.d.ts +143 -0
  112. package/dist/templates/default/convex/_generated/server.js +93 -0
  113. package/dist/templates/default/convex/admin.ts +102 -0
  114. package/dist/templates/default/convex/auth.config.ts +6 -0
  115. package/dist/templates/default/convex/auth.ts +335 -0
  116. package/dist/templates/default/convex/constants.ts +46 -0
  117. package/dist/templates/default/convex/convex.config.ts +11 -0
  118. package/dist/templates/default/convex/crons.ts +42 -0
  119. package/dist/templates/default/convex/email.ts +109 -0
  120. package/dist/templates/default/convex/env.ts +31 -0
  121. package/dist/templates/default/convex/errors.ts +33 -0
  122. package/dist/templates/default/convex/functions.ts +54 -0
  123. package/dist/templates/default/convex/http.ts +176 -0
  124. package/dist/templates/default/convex/log.ts +81 -0
  125. package/dist/templates/default/convex/pushTokens.ts +114 -0
  126. package/dist/templates/default/convex/rateLimit.ts +92 -0
  127. package/dist/templates/default/convex/schema.ts +28 -0
  128. package/dist/templates/default/convex/tsconfig.json +18 -0
  129. package/dist/templates/default/convex/users.ts +279 -0
  130. package/dist/templates/default/convex/validators.ts +74 -0
  131. package/dist/templates/default/convex/webhook.ts +193 -0
  132. package/dist/templates/default/convex.json +6 -0
  133. package/dist/templates/default/eas.json +56 -0
  134. package/dist/templates/default/fingerprint.config.js +9 -0
  135. package/dist/templates/default/hooks/use-debounce.ts +20 -0
  136. package/dist/templates/default/hooks/use-deep-link.ts +43 -0
  137. package/dist/templates/default/hooks/use-navigation-tracking.ts +15 -0
  138. package/dist/templates/default/hooks/use-network.ts +11 -0
  139. package/dist/templates/default/hooks/use-notifications.ts +107 -0
  140. package/dist/templates/default/hooks/use-onboarding.ts +15 -0
  141. package/dist/templates/default/hooks/use-reduced-motion.ts +11 -0
  142. package/dist/templates/default/hooks/use-theme.ts +53 -0
  143. package/dist/templates/default/hooks/use-updates.ts +86 -0
  144. package/dist/templates/default/lib/a11y.ts +5 -0
  145. package/dist/templates/default/lib/app.ts +14 -0
  146. package/dist/templates/default/lib/assets.ts +17 -0
  147. package/dist/templates/default/lib/auth-client.ts +21 -0
  148. package/dist/templates/default/lib/convex-auth.tsx +79 -0
  149. package/dist/templates/default/lib/deep-link.ts +71 -0
  150. package/dist/templates/default/lib/dev-menu.ts +119 -0
  151. package/dist/templates/default/lib/device.ts +40 -0
  152. package/dist/templates/default/lib/dynamic-font.ts +49 -0
  153. package/dist/templates/default/lib/env.ts +10 -0
  154. package/dist/templates/default/lib/haptics.ts +24 -0
  155. package/dist/templates/default/lib/notifications.ts +276 -0
  156. package/dist/templates/default/lib/preferences.ts +45 -0
  157. package/dist/templates/default/lib/schemas.ts +137 -0
  158. package/dist/templates/default/lib/storage.ts +47 -0
  159. package/dist/templates/default/lib/updates.ts +107 -0
  160. package/dist/templates/default/metro.config.js +14 -0
  161. package/dist/templates/default/package.json +129 -0
  162. package/dist/templates/default/patches/PR-368.patch +91 -0
  163. package/dist/templates/default/patches/convex-dev-better-auth-0.12.2.tgz +0 -0
  164. package/dist/templates/default/plugins/README.md +9 -0
  165. package/dist/templates/default/plugins/with-auto-signing.js +45 -0
  166. package/dist/templates/default/plugins/with-pod-deployment-target.js +35 -0
  167. package/dist/templates/default/scripts/README.md +36 -0
  168. package/dist/templates/default/scripts/_run.mjs +77 -0
  169. package/dist/templates/default/scripts/clean.ts +543 -0
  170. package/dist/templates/default/scripts/rotate-apple-jwt.mjs +80 -0
  171. package/dist/templates/default/store.config.json +58 -0
  172. package/dist/templates/default/tsconfig.json +13 -0
  173. package/dist/templates/default/vitest.config.ts +21 -0
  174. package/package.json +69 -0
@@ -0,0 +1,86 @@
1
+ name: Rollback
2
+
3
+ # Manually trigger a rollback on any branch. Two flavors, matching the
4
+ # canonical eas-cli surface:
5
+ #
6
+ # "previous" → republish an earlier update group on the same branch.
7
+ # Picks the most recent successful update before the
8
+ # currently-active one. Use this when a recent OTA broke
9
+ # something users on previous builds didn't see.
10
+ # Maps to `eas update:republish`.
11
+ # https://docs.expo.dev/eas-update/rollbacks/
12
+ #
13
+ # "embedded" → roll back to the build's embedded bundle (the JS that
14
+ # shipped with the .ipa). Effectively makes the next-OTA-check
15
+ # ignore the current rollout and serve the binary as-is.
16
+ # Use this when a broken OTA shouldn't ship to ANYONE on
17
+ # that build. Maps to `eas update:roll-back-to-embedded`.
18
+ # https://docs.expo.dev/eas-update/rollbacks/
19
+ #
20
+ # Pair with the asc-events workflow's Slack notify so the team knows.
21
+
22
+ on:
23
+ workflow_dispatch:
24
+ inputs:
25
+ branch:
26
+ description: Branch to roll back (production | pr-<n>)
27
+ type: string
28
+ required: true
29
+ type:
30
+ description: Rollback flavor
31
+ type: select
32
+ required: true
33
+ default: previous
34
+ options:
35
+ - previous
36
+ - embedded
37
+ message:
38
+ description: Optional message stored on the update group
39
+ type: string
40
+ required: false
41
+
42
+ concurrency:
43
+ cancel_in_progress: false
44
+ group: ${{ workflow.filename }}-${{ inputs.branch }}
45
+
46
+ defaults:
47
+ tools:
48
+ bun: latest
49
+
50
+ jobs:
51
+ rollback:
52
+ name: Roll back ${{ inputs.branch }} (${{ inputs.type }})
53
+ environment: ${{ inputs.branch == 'production' && 'production' || 'development' }}
54
+ runs_on: linux-medium
55
+ steps:
56
+ - uses: eas/checkout
57
+ - uses: eas/install_node_modules
58
+ - name: Roll back
59
+ run: |
60
+ MSG="${{ inputs.message }}"
61
+ MSG_ARG=""
62
+ if [ -n "$MSG" ]; then MSG_ARG="--message \"$MSG\""; fi
63
+ if [ "${{ inputs.type }}" = "embedded" ]; then
64
+ eval bunx eas-cli update:roll-back-to-embedded \
65
+ --branch "${{ inputs.branch }}" \
66
+ --platform ios \
67
+ --non-interactive \
68
+ $MSG_ARG
69
+ else
70
+ eval bunx eas-cli update:republish \
71
+ --branch "${{ inputs.branch }}" \
72
+ --platform ios \
73
+ --non-interactive \
74
+ $MSG_ARG
75
+ fi
76
+
77
+ notify:
78
+ name: Notify Slack
79
+ needs: [rollback]
80
+ type: slack
81
+ params:
82
+ webhook_url: https://hooks.slack.com/services/REPLACE/ME/HERE
83
+ message: |
84
+ :rewind: Rolled back `${{ inputs.branch }}` to ${{ inputs.type }}.
85
+ Triggered by: ${{ github.triggering_actor }}
86
+ Workflow: ${{ workflow.url }}
@@ -0,0 +1,84 @@
1
+ name: Rollout
2
+
3
+ # Manually run a gradual rollout: publish a fresh OTA at a non-100%
4
+ # percentage, or bump/lower the % of the most recent rollout group on a
5
+ # branch. Mirrors the canonical EAS Update rollout flow:
6
+ # https://docs.expo.dev/eas-update/rollouts/
7
+ #
8
+ # Two paths, controlled by `action`:
9
+ #
10
+ # "publish" → `eas update --branch <b> --rollout-percentage <%>`
11
+ # Publishes a fresh OTA from the current HEAD at the given %.
12
+ # Use to start a new rollout (e.g. 5% → 25% → 100%).
13
+ #
14
+ # "edit" → `eas update:edit --branch <b> --rollout-percentage <%>`
15
+ # Bumps the percentage of the currently-active rollout group
16
+ # on the branch. Use to ramp an existing rollout.
17
+ #
18
+ # After confirming adoption looks healthy on the Insights dashboard, set
19
+ # the rollout to 100. To kill a bad rollout, use the `rollback` workflow.
20
+
21
+ on:
22
+ workflow_dispatch:
23
+ inputs:
24
+ branch:
25
+ description: Branch (production | pr-<n>)
26
+ type: string
27
+ required: true
28
+ default: production
29
+ action:
30
+ description: Publish a new rollout, or edit the % of the existing one
31
+ type: select
32
+ required: true
33
+ default: edit
34
+ options:
35
+ - edit
36
+ - publish
37
+ percentage:
38
+ description: Rollout percentage (1-100)
39
+ type: number
40
+ required: true
41
+ default: 25
42
+
43
+ concurrency:
44
+ cancel_in_progress: false
45
+ group: ${{ workflow.filename }}-${{ inputs.branch }}
46
+
47
+ defaults:
48
+ tools:
49
+ bun: latest
50
+
51
+ jobs:
52
+ rollout:
53
+ name: ${{ inputs.action }} → ${{ inputs.percentage }}% on ${{ inputs.branch }}
54
+ environment: ${{ inputs.branch == 'production' && 'production' || 'development' }}
55
+ runs_on: linux-medium
56
+ steps:
57
+ - uses: eas/checkout
58
+ - uses: eas/install_node_modules
59
+ - name: Roll out
60
+ run: |
61
+ if [ "${{ inputs.action }}" = "publish" ]; then
62
+ bunx eas-cli update \
63
+ --branch "${{ inputs.branch }}" \
64
+ --platform ios \
65
+ --rollout-percentage "${{ inputs.percentage }}" \
66
+ --non-interactive \
67
+ --message "Rollout publish @ ${{ inputs.percentage }}%"
68
+ else
69
+ bunx eas-cli update:edit \
70
+ --branch "${{ inputs.branch }}" \
71
+ --rollout-percentage "${{ inputs.percentage }}" \
72
+ --non-interactive
73
+ fi
74
+
75
+ notify:
76
+ name: Notify Slack
77
+ needs: [rollout]
78
+ type: slack
79
+ params:
80
+ webhook_url: https://hooks.slack.com/services/REPLACE/ME/HERE
81
+ message: |
82
+ :chart_with_upwards_trend: Rollout ${{ inputs.action }} on `${{ inputs.branch }}` → ${{ inputs.percentage }}%
83
+ Triggered by: ${{ github.triggering_actor }}
84
+ Workflow: ${{ workflow.url }}
@@ -0,0 +1,42 @@
1
+ name: Rotate Apple Sign In JWT
2
+
3
+ # Apple caps client_secret JWTs at 180 days. We re-sign every 90 days so
4
+ # we always have plenty of headroom and never get caught with an expired
5
+ # token. Replaces the GitHub Actions equivalent. runs on EAS infrastructure
6
+ # and reads secrets from EAS env vars (production, secret visibility) rather
7
+ # than GitHub repo secrets.
8
+ #
9
+ # Required EAS env vars (production environment, secret visibility):
10
+ # APPLE_P8_PRIVATE_KEY PEM contents of the Sign In with Apple .p8
11
+ # APPLE_TEAM_ID 10-char Apple Team id
12
+ # APPLE_KEY_ID 10-char Sign In with Apple key id
13
+ # APPLE_SERVICES_ID Services id (e.g. com.you.app.signin)
14
+ # CONVEX_DEPLOY_KEY Production Convex deploy key
15
+ #
16
+ # Set them once with:
17
+ # eas env:create --name APPLE_P8_PRIVATE_KEY --value-file <path-to-.p8> \
18
+ # --environment production --visibility secret
19
+ # eas env:create --name APPLE_TEAM_ID --value <value> \
20
+ # --environment production --visibility secret
21
+ # ...etc
22
+
23
+ on:
24
+ schedule:
25
+ - cron: "0 12 1 */3 *" # 12:00 UTC on the 1st, every 3rd month
26
+ workflow_dispatch: {}
27
+
28
+ defaults:
29
+ tools:
30
+ bun: latest
31
+
32
+ jobs:
33
+ rotate:
34
+ name: Sign + push fresh client_secret
35
+ type: custom
36
+ runs_on: linux-medium
37
+ environment: production # pulls EAS env vars from production
38
+ steps:
39
+ - uses: eas/checkout
40
+ - uses: eas/install_node_modules
41
+ - name: Sign + push to Convex
42
+ run: node scripts/rotate-apple-jwt.mjs
@@ -0,0 +1,57 @@
1
+ name: TestFlight
2
+
3
+ # Builds and distributes to TestFlight using the dedicated `testflight` job
4
+ # (https://docs.expo.dev/eas/workflows/pre-packaged-jobs/#testflight). Unlike a
5
+ # plain `submit`, this job lets us name internal/external groups, attach a
6
+ # changelog, and gate on Beta App Review.
7
+
8
+ on:
9
+ push:
10
+ branches: ["beta/*"]
11
+ workflow_dispatch:
12
+ inputs:
13
+ changelog:
14
+ type: string
15
+ required: false
16
+ description: 'What to test ("Bug fixes" if omitted)'
17
+
18
+ concurrency:
19
+ cancel_in_progress: true
20
+ group: ${{ workflow.filename }}-${{ github.ref }}
21
+
22
+ defaults:
23
+ tools:
24
+ bun: latest
25
+
26
+ jobs:
27
+ precheck:
28
+ name: Precheck
29
+ type: custom
30
+ runs_on: linux-medium
31
+ steps:
32
+ - uses: eas/checkout
33
+ - uses: eas/install_node_modules
34
+ - name: Typecheck
35
+ run: bun run typecheck
36
+ - name: Lint
37
+ run: bun run lint
38
+ - name: Test
39
+ run: bun run test
40
+
41
+ build_ios:
42
+ name: Build iOS
43
+ needs: [precheck]
44
+ type: build
45
+ params:
46
+ platform: ios
47
+ profile: production
48
+
49
+ testflight:
50
+ name: Distribute to TestFlight
51
+ needs: [build_ios]
52
+ type: testflight
53
+ params:
54
+ build_id: ${{ needs.build_ios.outputs.build_id }}
55
+ profile: testflight
56
+ internal_groups: ["Internal"]
57
+ changelog: ${{ inputs.changelog || github.event.head_commit.message || 'Bug fixes' }}
@@ -0,0 +1,28 @@
1
+ name: Check
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ check:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: oven-sh/setup-bun@v2
13
+ - run: bun install
14
+ - run: bunx expo-doctor
15
+ - run: bun run typecheck
16
+ - run: bun run lint
17
+ - run: bun run format:check
18
+ - run: bun run test
19
+
20
+ fingerprint:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0
26
+ - uses: oven-sh/setup-bun@v2
27
+ - run: bun install
28
+ - run: bun run fp:diff
@@ -0,0 +1,18 @@
1
+ # Smoke test: app launches and the welcome screen renders.
2
+ #
3
+ # Maestro auto-derives the appId from the build's bundle id, so the same
4
+ # flow runs against the dev simulator binary (`com.example.<pkg>` fallback
5
+ # in app.config.ts) and the production binary (`com.<your-team>.<app>`)
6
+ # without edits.
7
+ #
8
+ # Run locally: `maestro test .maestro/launch.yaml`
9
+ # Run on EAS: triggered by `.eas/workflows/e2e-tests.yml` on every PR.
10
+ appId: ${MAESTRO_APP_ID}
11
+ ---
12
+ - launchApp:
13
+ clearState: true
14
+ - assertVisible:
15
+ text: "Welcome"
16
+ timeout: 30000
17
+ - assertVisible: "Your new app starts here."
18
+ - takeScreenshot: welcome
@@ -0,0 +1,79 @@
1
+ # AGENTS
2
+
3
+ Guidance for AI coding assistants (Claude Code, Cursor, Aider, etc.) working in
4
+ a scaffolded vexpo project. The same content applies to humans reading by
5
+ hand. These are conventions, not magic.
6
+
7
+ ## Stack at a glance
8
+
9
+ - **Backend.** Convex. Reactive queries, real-time sync, storage. No raw DB
10
+ calls. Everything goes through `convex/` (server) and `convex/react`
11
+ (client). After running `npx convex ai-files install`, read
12
+ `convex/_generated/ai/guidelines.md` before touching anything in `convex/`.
13
+ - **Auth.** Better Auth via `@convex-dev/better-auth`. Patched locally with
14
+ PR #368 until upstream merges (`patches/`). Email verification is gated on
15
+ the `REQUIRE_EMAIL_VERIFICATION` Convex env var.
16
+ - **Mobile.** Expo SDK 56 canary, RN 0.85, React 19. **iOS only today.**
17
+ Native UI exclusively via `@expo/ui/swift-ui`. No NativeWind, no Tailwind,
18
+ no `react-native-paper`.
19
+ - **CI/CD.** EAS Workflows (`.eas/workflows/*.yml`) for everything
20
+ Expo-shaped. GitHub Actions (`.github/workflows/check.yml`) only for
21
+ general-purpose checks (typecheck, lint, format, tests, fingerprint).
22
+
23
+ ## Conventions
24
+
25
+ - **TypeScript:** `strict: true`. Don't add `any` casts. If a type is hard,
26
+ ask before reaching for `any`.
27
+ - **Imports:** Path alias `@/` resolves to the template root. No deep
28
+ relative imports (`../../../`).
29
+ - **Files:** Lowercase, kebab-case filenames. One component per file. Default
30
+ export the component, named exports for everything else.
31
+ - **State:** Convex `useQuery`/`useMutation` for server state. React `useState`
32
+ for local UI state. No Redux, no Zustand, no Jotai.
33
+ - **Styling:** `@expo/ui/swift-ui` primitives + `modifiers`. The chassis is
34
+ SwiftUI, not RN. `<Host>` boundary tells you you're crossing into native.
35
+ - **Validation:** Zod on the client (`lib/schemas.ts`), Convex validators on
36
+ the server (`convex/validators.ts`). Don't pick one. Both, at each
37
+ boundary.
38
+ - **Errors:** Throw real `Error` instances. Wrap server errors with
39
+ `formatError` from `components/ui/convex-error.tsx`. Don't swallow.
40
+ - **Tests:** Vitest. `templates/default/__tests__/` covers Convex constants,
41
+ validators, and deep-link parsing. Add tests for new validator logic and
42
+ new HTTP handlers.
43
+
44
+ ## What requires extra care
45
+
46
+ - **Convex functions**: every query/mutation needs both server-side
47
+ validators and matching client types. The `convex/_generated/` directory is
48
+ the contract. Run `bunx convex codegen` after schema or function changes.
49
+ - **HTTP routes** (`convex/http.ts`): every public endpoint must use
50
+ `convex/webhook.ts` `withWebhook()` factory for HMAC verification + body
51
+ cap + structured logging, or document why it doesn't. Inbound webhooks are
52
+ untrusted by default.
53
+ - **Apple SIWA JWT**: rotates every 90 days via
54
+ `.eas/workflows/rotate-apple-jwt.yml`. Don't break the env-var contract
55
+ that cron depends on (`APPLE_P8_PRIVATE_KEY`, `APPLE_TEAM_ID`,
56
+ `APPLE_KEY_ID`, `APPLE_SERVICES_ID`, `CONVEX_DEPLOY_KEY`).
57
+ - **Push notifications**: only work on a physical device. iOS Simulator does
58
+ not deliver APNs. Don't try to test push flows in the simulator.
59
+ - **`store.config.json`**: ships with placeholder values. `bunx vexpo
60
+ rebrand` fills them in. App Review will reject builds with placeholder
61
+ contact info.
62
+
63
+ ## When in doubt
64
+
65
+ - Run `bunx vexpo doctor` to check that `.env.local`, Convex env, EAS env,
66
+ and `app.config.ts` agree.
67
+ - Use `bunx eas <subcommand>` for canonical EAS operations. **Don't reinvent
68
+ EAS.** That's the vexpo design principle.
69
+ - Read `SETUP.md` for the long-form orchestration walkthrough.
70
+
71
+ <!-- convex-ai-start -->
72
+
73
+ This project uses [Convex](https://convex.dev) as its backend.
74
+
75
+ When working on Convex code, **always read `convex/_generated/ai/guidelines.md` first** for important guidelines on how to correctly use Convex APIs and patterns. The file contains rules that override what you may have learned about Convex from training data.
76
+
77
+ Convex agent skills for common tasks can be installed by running `npx convex ai-files install`.
78
+
79
+ <!-- convex-ai-end -->