@amplitude/wizard 1.0.0-beta.2 → 1.0.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 (391) hide show
  1. package/README.md +171 -74
  2. package/dist/bin.js +338 -222
  3. package/dist/src/lib/agent-interface.js +64 -9
  4. package/dist/src/lib/agent-runner.js +1 -10
  5. package/dist/src/lib/api.d.ts +22 -4
  6. package/dist/src/lib/api.js +114 -12
  7. package/dist/src/lib/commandments.js +14 -1
  8. package/dist/src/lib/constants.d.ts +6 -5
  9. package/dist/src/lib/constants.js +13 -13
  10. package/dist/src/lib/credential-resolution.d.ts +45 -0
  11. package/dist/src/lib/credential-resolution.js +311 -0
  12. package/dist/src/lib/exit-codes.d.ts +10 -0
  13. package/dist/src/lib/exit-codes.js +12 -0
  14. package/dist/src/lib/health-checks/statuspage.d.ts +1 -0
  15. package/dist/src/lib/health-checks/statuspage.js +5 -1
  16. package/dist/src/lib/mode-config.d.ts +14 -0
  17. package/dist/src/lib/mode-config.js +14 -0
  18. package/dist/src/lib/session-checkpoint.d.ts +27 -0
  19. package/dist/src/lib/session-checkpoint.js +134 -0
  20. package/dist/src/lib/wizard-session.d.ts +44 -1
  21. package/dist/src/lib/wizard-session.js +70 -14
  22. package/dist/src/lib/wizard-tools.js +19 -4
  23. package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +3 -0
  24. package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js +6 -0
  25. package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +3 -1
  26. package/dist/src/ui/agent-ui.d.ts +91 -0
  27. package/dist/src/ui/agent-ui.js +277 -0
  28. package/dist/src/ui/logging-ui.js +1 -1
  29. package/dist/src/ui/tui/App.d.ts +12 -0
  30. package/dist/src/ui/tui/App.js +29 -18
  31. package/dist/src/ui/tui/components/AmplitudeLogo.js +16 -17
  32. package/dist/src/ui/tui/components/AmplitudeTextLogo.d.ts +0 -2
  33. package/dist/src/ui/tui/components/AmplitudeTextLogo.js +53 -18
  34. package/dist/src/ui/tui/components/BrailleSpinner.d.ts +8 -0
  35. package/dist/src/ui/tui/components/BrailleSpinner.js +15 -0
  36. package/dist/src/ui/tui/components/ConsoleView.d.ts +8 -11
  37. package/dist/src/ui/tui/components/ConsoleView.js +51 -34
  38. package/dist/src/ui/tui/components/HeaderBar.d.ts +12 -0
  39. package/dist/src/ui/tui/components/HeaderBar.js +17 -0
  40. package/dist/src/ui/tui/components/JourneyStepper.d.ts +16 -0
  41. package/dist/src/ui/tui/components/JourneyStepper.js +83 -0
  42. package/dist/src/ui/tui/components/KeyHintBar.d.ts +19 -0
  43. package/dist/src/ui/tui/components/KeyHintBar.js +20 -0
  44. package/dist/src/ui/tui/console-commands.d.ts +1 -2
  45. package/dist/src/ui/tui/console-commands.js +48 -7
  46. package/dist/src/ui/tui/flows.d.ts +1 -1
  47. package/dist/src/ui/tui/flows.js +1 -1
  48. package/dist/src/ui/tui/hooks/useAsyncEffect.d.ts +15 -0
  49. package/dist/src/ui/tui/hooks/useAsyncEffect.js +35 -0
  50. package/dist/src/ui/tui/hooks/useWizardStore.d.ts +9 -0
  51. package/dist/src/ui/tui/hooks/useWizardStore.js +11 -0
  52. package/dist/src/ui/tui/ink-ui.js +1 -1
  53. package/dist/src/ui/tui/primitives/DissolveTransition.js +4 -5
  54. package/dist/src/ui/tui/primitives/EventPlanViewer.d.ts +3 -1
  55. package/dist/src/ui/tui/primitives/EventPlanViewer.js +8 -3
  56. package/dist/src/ui/tui/primitives/ProgressList.js +1 -1
  57. package/dist/src/ui/tui/primitives/SlashCommandInput.js +19 -4
  58. package/dist/src/ui/tui/primitives/SplitView.d.ts +2 -1
  59. package/dist/src/ui/tui/primitives/SplitView.js +10 -2
  60. package/dist/src/ui/tui/primitives/TabContainer.js +10 -2
  61. package/dist/src/ui/tui/primitives/index.d.ts +0 -1
  62. package/dist/src/ui/tui/primitives/index.js +0 -1
  63. package/dist/src/ui/tui/router.js +1 -1
  64. package/dist/src/ui/tui/screen-registry.d.ts +0 -7
  65. package/dist/src/ui/tui/screen-registry.js +13 -4
  66. package/dist/src/ui/tui/screens/ActivationOptionsScreen.d.ts +2 -2
  67. package/dist/src/ui/tui/screens/ActivationOptionsScreen.js +8 -8
  68. package/dist/src/ui/tui/screens/AuthScreen.js +57 -27
  69. package/dist/src/ui/tui/screens/ChecklistScreen.d.ts +2 -12
  70. package/dist/src/ui/tui/screens/ChecklistScreen.js +22 -33
  71. package/dist/src/ui/tui/screens/DataIngestionCheckScreen.d.ts +3 -12
  72. package/dist/src/ui/tui/screens/DataIngestionCheckScreen.js +109 -39
  73. package/dist/src/ui/tui/screens/DataSetupScreen.d.ts +3 -3
  74. package/dist/src/ui/tui/screens/DataSetupScreen.js +17 -10
  75. package/dist/src/ui/tui/screens/IntroScreen.d.ts +5 -3
  76. package/dist/src/ui/tui/screens/IntroScreen.js +132 -41
  77. package/dist/src/ui/tui/screens/LoginScreen.d.ts +1 -1
  78. package/dist/src/ui/tui/screens/LoginScreen.js +4 -4
  79. package/dist/src/ui/tui/screens/LogoutScreen.d.ts +4 -2
  80. package/dist/src/ui/tui/screens/LogoutScreen.js +17 -5
  81. package/dist/src/ui/tui/screens/McpScreen.d.ts +4 -4
  82. package/dist/src/ui/tui/screens/McpScreen.js +25 -17
  83. package/dist/src/ui/tui/screens/OutageScreen.d.ts +1 -1
  84. package/dist/src/ui/tui/screens/OutageScreen.js +5 -5
  85. package/dist/src/ui/tui/screens/OutroScreen.d.ts +5 -0
  86. package/dist/src/ui/tui/screens/OutroScreen.js +21 -14
  87. package/dist/src/ui/tui/screens/RegionSelectScreen.js +15 -13
  88. package/dist/src/ui/tui/screens/RunScreen.d.ts +7 -5
  89. package/dist/src/ui/tui/screens/RunScreen.js +102 -157
  90. package/dist/src/ui/tui/screens/SettingsOverrideScreen.d.ts +1 -1
  91. package/dist/src/ui/tui/screens/SettingsOverrideScreen.js +6 -5
  92. package/dist/src/ui/tui/screens/SetupScreen.d.ts +1 -1
  93. package/dist/src/ui/tui/screens/SetupScreen.js +7 -7
  94. package/dist/src/ui/tui/screens/SlackScreen.d.ts +2 -2
  95. package/dist/src/ui/tui/screens/SlackScreen.js +60 -35
  96. package/dist/src/ui/tui/session-constants.d.ts +41 -0
  97. package/dist/src/ui/tui/session-constants.js +38 -0
  98. package/dist/src/ui/tui/start-tui.d.ts +3 -1
  99. package/dist/src/ui/tui/start-tui.js +14 -10
  100. package/dist/src/ui/tui/store.d.ts +2 -1
  101. package/dist/src/ui/tui/store.js +33 -7
  102. package/dist/src/ui/tui/styles.d.ts +75 -19
  103. package/dist/src/ui/tui/styles.js +101 -19
  104. package/dist/src/ui/tui/utils/classify-error.d.ts +14 -0
  105. package/dist/src/ui/tui/utils/classify-error.js +90 -0
  106. package/dist/src/ui/tui/utils/diagnostics.d.ts +21 -0
  107. package/dist/src/ui/tui/utils/diagnostics.js +72 -0
  108. package/dist/src/ui/tui/utils/with-retry.d.ts +12 -0
  109. package/dist/src/ui/tui/utils/with-retry.js +32 -0
  110. package/dist/src/ui/tui/utils/with-timeout.d.ts +10 -0
  111. package/dist/src/ui/tui/utils/with-timeout.js +24 -0
  112. package/dist/src/utils/ampli-settings.d.ts +1 -1
  113. package/dist/src/utils/ampli-settings.js +15 -5
  114. package/dist/src/utils/api-key-store.js +5 -5
  115. package/dist/src/utils/atomic-write.d.ts +15 -0
  116. package/dist/src/utils/atomic-write.js +34 -0
  117. package/dist/src/utils/setup-utils.js +2 -2
  118. package/dist/src/utils/token-refresh.d.ts +22 -0
  119. package/dist/src/utils/token-refresh.js +79 -0
  120. package/dist/src/utils/wizard-abort.js +6 -1
  121. package/package.json +6 -6
  122. package/skills/instrumentation/add-analytics-instrumentation/SKILL.md +142 -0
  123. package/skills/instrumentation/diff-intake/SKILL.md +128 -0
  124. package/skills/instrumentation/discover-analytics-patterns/SKILL.md +185 -0
  125. package/skills/instrumentation/discover-event-surfaces/SKILL.md +322 -0
  126. package/skills/instrumentation/discover-event-surfaces/references/best-practices.md +563 -0
  127. package/skills/instrumentation/instrument-events/SKILL.md +169 -0
  128. package/skills/instrumentation/instrument-events/references/best-practices.md +563 -0
  129. package/skills/integration/integration-android/SKILL.md +49 -0
  130. package/skills/integration/integration-android/references/EXAMPLE.md +1977 -0
  131. package/skills/integration/integration-android/references/amplitude-quickstart.md +1845 -0
  132. package/skills/integration/integration-android/references/analytics.md +1778 -0
  133. package/skills/integration/integration-android/references/basic-integration-1.0-begin.md +43 -0
  134. package/skills/integration/integration-android/references/basic-integration-1.1-edit.md +35 -0
  135. package/skills/integration/integration-android/references/basic-integration-1.2-revise.md +23 -0
  136. package/skills/integration/integration-android/references/basic-integration-1.3-conclude.md +57 -0
  137. package/skills/integration/integration-angular/SKILL.md +49 -0
  138. package/skills/integration/integration-angular/references/EXAMPLE.md +899 -0
  139. package/skills/integration/integration-angular/references/amplitude-quickstart.md +1845 -0
  140. package/skills/integration/integration-angular/references/basic-integration-1.0-begin.md +43 -0
  141. package/skills/integration/integration-angular/references/basic-integration-1.1-edit.md +35 -0
  142. package/skills/integration/integration-angular/references/basic-integration-1.2-revise.md +23 -0
  143. package/skills/integration/integration-angular/references/basic-integration-1.3-conclude.md +57 -0
  144. package/skills/integration/integration-angular/references/browser-sdk-2.md +4680 -0
  145. package/skills/integration/integration-astro-hybrid/SKILL.md +56 -0
  146. package/skills/integration/integration-astro-hybrid/references/EXAMPLE.md +1095 -0
  147. package/skills/integration/integration-astro-hybrid/references/amplitude-quickstart.md +1845 -0
  148. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.0-begin.md +43 -0
  149. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.1-edit.md +35 -0
  150. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.2-revise.md +23 -0
  151. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.3-conclude.md +57 -0
  152. package/skills/integration/integration-astro-hybrid/references/browser-sdk-2.md +4680 -0
  153. package/skills/integration/integration-astro-ssr/SKILL.md +52 -0
  154. package/skills/integration/integration-astro-ssr/references/EXAMPLE.md +1106 -0
  155. package/skills/integration/integration-astro-ssr/references/amplitude-quickstart.md +1845 -0
  156. package/skills/integration/integration-astro-ssr/references/basic-integration-1.0-begin.md +43 -0
  157. package/skills/integration/integration-astro-ssr/references/basic-integration-1.1-edit.md +35 -0
  158. package/skills/integration/integration-astro-ssr/references/basic-integration-1.2-revise.md +23 -0
  159. package/skills/integration/integration-astro-ssr/references/basic-integration-1.3-conclude.md +57 -0
  160. package/skills/integration/integration-astro-ssr/references/browser-sdk-2.md +4680 -0
  161. package/skills/integration/integration-astro-static/SKILL.md +49 -0
  162. package/skills/integration/integration-astro-static/references/EXAMPLE.md +910 -0
  163. package/skills/integration/integration-astro-static/references/amplitude-quickstart.md +1845 -0
  164. package/skills/integration/integration-astro-static/references/basic-integration-1.0-begin.md +43 -0
  165. package/skills/integration/integration-astro-static/references/basic-integration-1.1-edit.md +35 -0
  166. package/skills/integration/integration-astro-static/references/basic-integration-1.2-revise.md +23 -0
  167. package/skills/integration/integration-astro-static/references/basic-integration-1.3-conclude.md +57 -0
  168. package/skills/integration/integration-astro-static/references/browser-sdk-2.md +4680 -0
  169. package/skills/integration/integration-astro-view-transitions/SKILL.md +51 -0
  170. package/skills/integration/integration-astro-view-transitions/references/EXAMPLE.md +979 -0
  171. package/skills/integration/integration-astro-view-transitions/references/amplitude-quickstart.md +1845 -0
  172. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.0-begin.md +43 -0
  173. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.1-edit.md +35 -0
  174. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.2-revise.md +23 -0
  175. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.3-conclude.md +57 -0
  176. package/skills/integration/integration-astro-view-transitions/references/browser-sdk-2.md +4680 -0
  177. package/skills/integration/integration-django/SKILL.md +57 -0
  178. package/skills/integration/integration-django/references/EXAMPLE.md +1005 -0
  179. package/skills/integration/integration-django/references/amplitude-quickstart.md +1845 -0
  180. package/skills/integration/integration-django/references/basic-integration-1.0-begin.md +43 -0
  181. package/skills/integration/integration-django/references/basic-integration-1.1-edit.md +35 -0
  182. package/skills/integration/integration-django/references/basic-integration-1.2-revise.md +23 -0
  183. package/skills/integration/integration-django/references/basic-integration-1.3-conclude.md +57 -0
  184. package/skills/integration/integration-django/references/python.md +1424 -0
  185. package/skills/integration/integration-expo/SKILL.md +53 -0
  186. package/skills/integration/integration-expo/references/EXAMPLE.md +1291 -0
  187. package/skills/integration/integration-expo/references/amplitude-quickstart.md +1845 -0
  188. package/skills/integration/integration-expo/references/basic-integration-1.0-begin.md +43 -0
  189. package/skills/integration/integration-expo/references/basic-integration-1.1-edit.md +35 -0
  190. package/skills/integration/integration-expo/references/basic-integration-1.2-revise.md +23 -0
  191. package/skills/integration/integration-expo/references/basic-integration-1.3-conclude.md +57 -0
  192. package/skills/integration/integration-expo/references/react-native-sdk.md +2819 -0
  193. package/skills/integration/integration-fastapi/SKILL.md +57 -0
  194. package/skills/integration/integration-fastapi/references/EXAMPLE.md +1389 -0
  195. package/skills/integration/integration-fastapi/references/amplitude-quickstart.md +1845 -0
  196. package/skills/integration/integration-fastapi/references/basic-integration-1.0-begin.md +43 -0
  197. package/skills/integration/integration-fastapi/references/basic-integration-1.1-edit.md +35 -0
  198. package/skills/integration/integration-fastapi/references/basic-integration-1.2-revise.md +23 -0
  199. package/skills/integration/integration-fastapi/references/basic-integration-1.3-conclude.md +57 -0
  200. package/skills/integration/integration-fastapi/references/python.md +1424 -0
  201. package/skills/integration/integration-flask/SKILL.md +56 -0
  202. package/skills/integration/integration-flask/references/EXAMPLE.md +1130 -0
  203. package/skills/integration/integration-flask/references/amplitude-quickstart.md +1845 -0
  204. package/skills/integration/integration-flask/references/basic-integration-1.0-begin.md +43 -0
  205. package/skills/integration/integration-flask/references/basic-integration-1.1-edit.md +35 -0
  206. package/skills/integration/integration-flask/references/basic-integration-1.2-revise.md +23 -0
  207. package/skills/integration/integration-flask/references/basic-integration-1.3-conclude.md +57 -0
  208. package/skills/integration/integration-flask/references/python.md +1424 -0
  209. package/skills/integration/integration-javascript_node/SKILL.md +54 -0
  210. package/skills/integration/integration-javascript_node/references/EXAMPLE.md +365 -0
  211. package/skills/integration/integration-javascript_node/references/amplitude-quickstart.md +1845 -0
  212. package/skills/integration/integration-javascript_node/references/analytics.md +1778 -0
  213. package/skills/integration/integration-javascript_node/references/basic-integration-1.0-begin.md +43 -0
  214. package/skills/integration/integration-javascript_node/references/basic-integration-1.1-edit.md +35 -0
  215. package/skills/integration/integration-javascript_node/references/basic-integration-1.2-revise.md +23 -0
  216. package/skills/integration/integration-javascript_node/references/basic-integration-1.3-conclude.md +57 -0
  217. package/skills/integration/integration-javascript_web/SKILL.md +58 -0
  218. package/skills/integration/integration-javascript_web/references/EXAMPLE.md +451 -0
  219. package/skills/integration/integration-javascript_web/references/amplitude-quickstart.md +1845 -0
  220. package/skills/integration/integration-javascript_web/references/basic-integration-1.0-begin.md +43 -0
  221. package/skills/integration/integration-javascript_web/references/basic-integration-1.1-edit.md +35 -0
  222. package/skills/integration/integration-javascript_web/references/basic-integration-1.2-revise.md +23 -0
  223. package/skills/integration/integration-javascript_web/references/basic-integration-1.3-conclude.md +57 -0
  224. package/skills/integration/integration-javascript_web/references/browser-sdk-2.md +4680 -0
  225. package/skills/integration/integration-laravel/SKILL.md +52 -0
  226. package/skills/integration/integration-laravel/references/EXAMPLE.md +2039 -0
  227. package/skills/integration/integration-laravel/references/amplitude-quickstart.md +1845 -0
  228. package/skills/integration/integration-laravel/references/analytics.md +1778 -0
  229. package/skills/integration/integration-laravel/references/basic-integration-1.0-begin.md +43 -0
  230. package/skills/integration/integration-laravel/references/basic-integration-1.1-edit.md +35 -0
  231. package/skills/integration/integration-laravel/references/basic-integration-1.2-revise.md +23 -0
  232. package/skills/integration/integration-laravel/references/basic-integration-1.3-conclude.md +57 -0
  233. package/skills/integration/integration-nextjs-app-router/SKILL.md +54 -0
  234. package/skills/integration/integration-nextjs-app-router/references/EXAMPLE.md +673 -0
  235. package/skills/integration/integration-nextjs-app-router/references/amplitude-quickstart.md +1845 -0
  236. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.0-begin.md +43 -0
  237. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.1-edit.md +35 -0
  238. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.2-revise.md +23 -0
  239. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.3-conclude.md +57 -0
  240. package/skills/integration/integration-nextjs-app-router/references/browser-sdk-2.md +4680 -0
  241. package/skills/integration/integration-nextjs-pages-router/SKILL.md +54 -0
  242. package/skills/integration/integration-nextjs-pages-router/references/EXAMPLE.md +735 -0
  243. package/skills/integration/integration-nextjs-pages-router/references/amplitude-quickstart.md +1845 -0
  244. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.0-begin.md +43 -0
  245. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.1-edit.md +35 -0
  246. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.2-revise.md +23 -0
  247. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.3-conclude.md +57 -0
  248. package/skills/integration/integration-nextjs-pages-router/references/browser-sdk-2.md +4680 -0
  249. package/skills/integration/integration-nuxt-3.6/SKILL.md +46 -0
  250. package/skills/integration/integration-nuxt-3.6/references/EXAMPLE.md +8422 -0
  251. package/skills/integration/integration-nuxt-3.6/references/amplitude-quickstart.md +1845 -0
  252. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.0-begin.md +43 -0
  253. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.1-edit.md +35 -0
  254. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.2-revise.md +23 -0
  255. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.3-conclude.md +57 -0
  256. package/skills/integration/integration-nuxt-3.6/references/browser-sdk-2.md +4680 -0
  257. package/skills/integration/integration-nuxt-4/SKILL.md +46 -0
  258. package/skills/integration/integration-nuxt-4/references/EXAMPLE.md +8670 -0
  259. package/skills/integration/integration-nuxt-4/references/amplitude-quickstart.md +1845 -0
  260. package/skills/integration/integration-nuxt-4/references/basic-integration-1.0-begin.md +43 -0
  261. package/skills/integration/integration-nuxt-4/references/basic-integration-1.1-edit.md +35 -0
  262. package/skills/integration/integration-nuxt-4/references/basic-integration-1.2-revise.md +23 -0
  263. package/skills/integration/integration-nuxt-4/references/basic-integration-1.3-conclude.md +57 -0
  264. package/skills/integration/integration-nuxt-4/references/browser-sdk-2.md +4680 -0
  265. package/skills/integration/integration-python/SKILL.md +53 -0
  266. package/skills/integration/integration-python/references/EXAMPLE.md +445 -0
  267. package/skills/integration/integration-python/references/amplitude-quickstart.md +1845 -0
  268. package/skills/integration/integration-python/references/basic-integration-1.0-begin.md +43 -0
  269. package/skills/integration/integration-python/references/basic-integration-1.1-edit.md +35 -0
  270. package/skills/integration/integration-python/references/basic-integration-1.2-revise.md +23 -0
  271. package/skills/integration/integration-python/references/basic-integration-1.3-conclude.md +57 -0
  272. package/skills/integration/integration-python/references/python.md +1424 -0
  273. package/skills/integration/integration-react-native/SKILL.md +49 -0
  274. package/skills/integration/integration-react-native/references/EXAMPLE.md +2253 -0
  275. package/skills/integration/integration-react-native/references/amplitude-quickstart.md +1845 -0
  276. package/skills/integration/integration-react-native/references/basic-integration-1.0-begin.md +43 -0
  277. package/skills/integration/integration-react-native/references/basic-integration-1.1-edit.md +35 -0
  278. package/skills/integration/integration-react-native/references/basic-integration-1.2-revise.md +23 -0
  279. package/skills/integration/integration-react-native/references/basic-integration-1.3-conclude.md +57 -0
  280. package/skills/integration/integration-react-native/references/react-native-sdk.md +2819 -0
  281. package/skills/integration/integration-react-react-router-6/SKILL.md +53 -0
  282. package/skills/integration/integration-react-react-router-6/references/EXAMPLE.md +570 -0
  283. package/skills/integration/integration-react-react-router-6/references/amplitude-quickstart.md +1845 -0
  284. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.0-begin.md +43 -0
  285. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.1-edit.md +35 -0
  286. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.2-revise.md +23 -0
  287. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.3-conclude.md +57 -0
  288. package/skills/integration/integration-react-react-router-6/references/browser-sdk-2.md +4680 -0
  289. package/skills/integration/integration-react-react-router-7-data/SKILL.md +53 -0
  290. package/skills/integration/integration-react-react-router-7-data/references/EXAMPLE.md +830 -0
  291. package/skills/integration/integration-react-react-router-7-data/references/amplitude-quickstart.md +1845 -0
  292. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.0-begin.md +43 -0
  293. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.1-edit.md +35 -0
  294. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.2-revise.md +23 -0
  295. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.3-conclude.md +57 -0
  296. package/skills/integration/integration-react-react-router-7-data/references/browser-sdk-2.md +4680 -0
  297. package/skills/integration/integration-react-react-router-7-declarative/SKILL.md +53 -0
  298. package/skills/integration/integration-react-react-router-7-declarative/references/EXAMPLE.md +609 -0
  299. package/skills/integration/integration-react-react-router-7-declarative/references/amplitude-quickstart.md +1845 -0
  300. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.0-begin.md +43 -0
  301. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.1-edit.md +35 -0
  302. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.2-revise.md +23 -0
  303. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.3-conclude.md +57 -0
  304. package/skills/integration/integration-react-react-router-7-declarative/references/browser-sdk-2.md +4680 -0
  305. package/skills/integration/integration-react-react-router-7-framework/SKILL.md +53 -0
  306. package/skills/integration/integration-react-react-router-7-framework/references/EXAMPLE.md +1081 -0
  307. package/skills/integration/integration-react-react-router-7-framework/references/amplitude-quickstart.md +1845 -0
  308. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.0-begin.md +43 -0
  309. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.1-edit.md +35 -0
  310. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.2-revise.md +23 -0
  311. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.3-conclude.md +57 -0
  312. package/skills/integration/integration-react-react-router-7-framework/references/browser-sdk-2.md +4680 -0
  313. package/skills/integration/integration-react-tanstack-router-code-based/SKILL.md +57 -0
  314. package/skills/integration/integration-react-tanstack-router-code-based/references/EXAMPLE.md +659 -0
  315. package/skills/integration/integration-react-tanstack-router-code-based/references/amplitude-quickstart.md +1845 -0
  316. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.0-begin.md +43 -0
  317. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.1-edit.md +35 -0
  318. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.2-revise.md +23 -0
  319. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.3-conclude.md +57 -0
  320. package/skills/integration/integration-react-tanstack-router-code-based/references/browser-sdk-2.md +4680 -0
  321. package/skills/integration/integration-react-tanstack-router-file-based/SKILL.md +57 -0
  322. package/skills/integration/integration-react-tanstack-router-file-based/references/EXAMPLE.md +777 -0
  323. package/skills/integration/integration-react-tanstack-router-file-based/references/amplitude-quickstart.md +1845 -0
  324. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.0-begin.md +43 -0
  325. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.1-edit.md +35 -0
  326. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.2-revise.md +23 -0
  327. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.3-conclude.md +57 -0
  328. package/skills/integration/integration-react-tanstack-router-file-based/references/browser-sdk-2.md +4680 -0
  329. package/skills/integration/integration-react-vite/SKILL.md +53 -0
  330. package/skills/integration/integration-react-vite/references/EXAMPLE.md +542 -0
  331. package/skills/integration/integration-react-vite/references/amplitude-quickstart.md +1845 -0
  332. package/skills/integration/integration-react-vite/references/basic-integration-1.0-begin.md +43 -0
  333. package/skills/integration/integration-react-vite/references/basic-integration-1.1-edit.md +35 -0
  334. package/skills/integration/integration-react-vite/references/basic-integration-1.2-revise.md +23 -0
  335. package/skills/integration/integration-react-vite/references/basic-integration-1.3-conclude.md +57 -0
  336. package/skills/integration/integration-react-vite/references/browser-sdk-2.md +4680 -0
  337. package/skills/integration/integration-ruby/SKILL.md +50 -0
  338. package/skills/integration/integration-ruby/references/EXAMPLE.md +420 -0
  339. package/skills/integration/integration-ruby/references/amplitude-quickstart.md +1845 -0
  340. package/skills/integration/integration-ruby/references/analytics.md +1778 -0
  341. package/skills/integration/integration-ruby/references/basic-integration-1.0-begin.md +43 -0
  342. package/skills/integration/integration-ruby/references/basic-integration-1.1-edit.md +35 -0
  343. package/skills/integration/integration-ruby/references/basic-integration-1.2-revise.md +23 -0
  344. package/skills/integration/integration-ruby/references/basic-integration-1.3-conclude.md +57 -0
  345. package/skills/integration/integration-ruby-on-rails/SKILL.md +55 -0
  346. package/skills/integration/integration-ruby-on-rails/references/EXAMPLE.md +1013 -0
  347. package/skills/integration/integration-ruby-on-rails/references/amplitude-quickstart.md +1845 -0
  348. package/skills/integration/integration-ruby-on-rails/references/analytics.md +1778 -0
  349. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.0-begin.md +43 -0
  350. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.1-edit.md +35 -0
  351. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.2-revise.md +23 -0
  352. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.3-conclude.md +57 -0
  353. package/skills/integration/integration-sveltekit/SKILL.md +47 -0
  354. package/skills/integration/integration-sveltekit/references/EXAMPLE.md +14121 -0
  355. package/skills/integration/integration-sveltekit/references/amplitude-quickstart.md +1845 -0
  356. package/skills/integration/integration-sveltekit/references/basic-integration-1.0-begin.md +43 -0
  357. package/skills/integration/integration-sveltekit/references/basic-integration-1.1-edit.md +35 -0
  358. package/skills/integration/integration-sveltekit/references/basic-integration-1.2-revise.md +23 -0
  359. package/skills/integration/integration-sveltekit/references/basic-integration-1.3-conclude.md +57 -0
  360. package/skills/integration/integration-sveltekit/references/browser-sdk-2.md +4680 -0
  361. package/skills/integration/integration-swift/SKILL.md +49 -0
  362. package/skills/integration/integration-swift/references/EXAMPLE.md +660 -0
  363. package/skills/integration/integration-swift/references/amplitude-quickstart.md +1845 -0
  364. package/skills/integration/integration-swift/references/analytics.md +1778 -0
  365. package/skills/integration/integration-swift/references/basic-integration-1.0-begin.md +43 -0
  366. package/skills/integration/integration-swift/references/basic-integration-1.1-edit.md +35 -0
  367. package/skills/integration/integration-swift/references/basic-integration-1.2-revise.md +23 -0
  368. package/skills/integration/integration-swift/references/basic-integration-1.3-conclude.md +57 -0
  369. package/skills/integration/integration-tanstack-start/SKILL.md +58 -0
  370. package/skills/integration/integration-tanstack-start/references/EXAMPLE.md +998 -0
  371. package/skills/integration/integration-tanstack-start/references/amplitude-quickstart.md +1845 -0
  372. package/skills/integration/integration-tanstack-start/references/basic-integration-1.0-begin.md +43 -0
  373. package/skills/integration/integration-tanstack-start/references/basic-integration-1.1-edit.md +35 -0
  374. package/skills/integration/integration-tanstack-start/references/basic-integration-1.2-revise.md +23 -0
  375. package/skills/integration/integration-tanstack-start/references/basic-integration-1.3-conclude.md +57 -0
  376. package/skills/integration/integration-tanstack-start/references/browser-sdk-2.md +4680 -0
  377. package/skills/integration/integration-vue-3/SKILL.md +46 -0
  378. package/skills/integration/integration-vue-3/references/EXAMPLE.md +846 -0
  379. package/skills/integration/integration-vue-3/references/amplitude-quickstart.md +1845 -0
  380. package/skills/integration/integration-vue-3/references/basic-integration-1.0-begin.md +43 -0
  381. package/skills/integration/integration-vue-3/references/basic-integration-1.1-edit.md +35 -0
  382. package/skills/integration/integration-vue-3/references/basic-integration-1.2-revise.md +23 -0
  383. package/skills/integration/integration-vue-3/references/basic-integration-1.3-conclude.md +57 -0
  384. package/skills/integration/integration-vue-3/references/browser-sdk-2.md +4680 -0
  385. package/skills/taxonomy/amplitude-quickstart-taxonomy-agent/SKILL.md +228 -0
  386. package/dist/src/ui/tui/components/TitleBar.d.ts +0 -8
  387. package/dist/src/ui/tui/components/TitleBar.js +0 -27
  388. package/dist/src/ui/tui/primitives/KagiSmallWebViewer.d.ts +0 -7
  389. package/dist/src/ui/tui/primitives/KagiSmallWebViewer.js +0 -101
  390. package/dist/src/utils/anthropic-status.d.ts +0 -17
  391. package/dist/src/utils/anthropic-status.js +0 -51
@@ -0,0 +1,1291 @@
1
+ # Amplitude Expo Example Project
2
+
3
+ Repository: https://github.com/amplitude/context-hub
4
+ Path: basics/expo
5
+
6
+ ---
7
+
8
+ ## README.md
9
+
10
+ # Burrito Consideration App (Expo)
11
+
12
+ A React Native Expo app demonstrating Amplitude product analytics integration with modern React Native best practices.
13
+
14
+ ## Features
15
+
16
+ - **Product Analytics**: Full Amplitude integration with event tracking
17
+ - **User Authentication**: Demo login with Amplitude user identification
18
+ - **Session Persistence**: AsyncStorage for session management
19
+ - **Modern React**: React 19 with React Compiler for automatic memoization
20
+ - **File-based Routing**: Expo Router for navigation
21
+ - **New Architecture**: Enabled by default for better performance
22
+
23
+ ## Project Structure
24
+
25
+ ```
26
+ basics/expo/
27
+ ├── app/ # Expo Router screens (file-based routing)
28
+ │ ├── _layout.tsx # Root layout with AuthProvider
29
+ │ ├── index.tsx # Home screen (login/welcome)
30
+ │ ├── burrito.tsx # Burrito consideration screen
31
+ │ └── profile.tsx # User profile screen
32
+ ├── src/
33
+ │ ├── config/
34
+ │ │ └── amplitude.ts # Amplitude client configuration
35
+ │ ├── contexts/
36
+ │ │ └── AuthContext.tsx # Authentication context with Amplitude
37
+ │ ├── services/
38
+ │ │ └── storage.ts # AsyncStorage wrapper
39
+ │ └── styles/
40
+ │ └── theme.ts # Shared style constants
41
+ ├── app.config.js # Expo configuration
42
+ ├── babel.config.js # Babel config with React Compiler
43
+ ├── eslint.config.js # ESLint flat config
44
+ ├── package.json # Dependencies
45
+ ├── tsconfig.json # TypeScript strict configuration
46
+ └── .env.example # Environment variables template
47
+ ```
48
+
49
+ ## Getting Started
50
+
51
+ ### Prerequisites
52
+
53
+ - Node.js 18+
54
+ - iOS: Xcode (for iOS Simulator)
55
+ - Android: Android Studio with emulator
56
+
57
+ **For Android builds:** Set environment variables (required):
58
+
59
+ Add to `~/.zshrc` or `~/.bashrc`:
60
+ ```bash
61
+ # Java from Android Studio (required for Gradle)
62
+ export JAVA_HOME="<path-to-android-studio-jdk>"
63
+
64
+ # Android SDK location
65
+ export ANDROID_HOME="$HOME/Library/Android/sdk"
66
+ ```
67
+
68
+ Examples:
69
+ - `export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"`
70
+ - `export ANDROID_HOME="$HOME/Library/Android/sdk"`
71
+
72
+ Then run `source ~/.zshrc` to apply.
73
+
74
+ ### Installation
75
+
76
+ 1. Install dependencies:
77
+ ```bash
78
+ cd basics/expo
79
+ npm install
80
+ ```
81
+
82
+ 2. Configure Amplitude (optional):
83
+ ```bash
84
+ cp .env.example .env
85
+ # Edit .env with your Amplitude API key
86
+ ```
87
+
88
+ 3. Start the development server:
89
+ ```bash
90
+ npx expo start
91
+ ```
92
+
93
+ ### Running the App
94
+
95
+ ```bash
96
+ # Start development server
97
+ npx expo start
98
+
99
+ # Run on iOS Simulator
100
+ npx expo run:ios
101
+
102
+ # Run on Android Emulator
103
+ npx expo run:android
104
+ ```
105
+
106
+ ## Amplitude Integration
107
+
108
+ ### Configuration
109
+
110
+ Amplitude is configured in `src/config/amplitude.ts` using environment variables from `app.config.js`:
111
+
112
+ ```typescript
113
+ import Constants from 'expo-constants'
114
+
115
+ const apiKey = Constants.expoConfig?.extra?.amplitudeApiKey
116
+ ```
117
+
118
+ ### Event Tracking
119
+
120
+ Events are tracked with properties:
121
+
122
+ ```typescript
123
+ amplitude.track('Burrito Considered', {
124
+ total_considerations: count,
125
+ username: user.username,
126
+ })
127
+ ```
128
+
129
+ ### User Identification
130
+
131
+ Users are identified on login:
132
+
133
+ ```typescript
134
+ amplitude.setUserId(username)
135
+ const identifyObj = new Identify()
136
+ identifyObj.set('username', username)
137
+ amplitude.identify(identifyObj)
138
+ ```
139
+
140
+ ### Screen Tracking
141
+
142
+ Manual screen tracking with Expo Router:
143
+
144
+ ```typescript
145
+ useEffect(() => {
146
+ amplitude.track('Screen Viewed', {
147
+ screen_name: pathname,
148
+ previous_screen: previousPathname.current,
149
+ })
150
+ }, [pathname])
151
+ ```
152
+
153
+ ## Modern React Features
154
+
155
+ ### React Compiler
156
+
157
+ Automatic memoization is enabled via `babel-plugin-react-compiler`. No need for manual `useMemo`, `useCallback`, or `React.memo`.
158
+
159
+ ### React 19 `use` API
160
+
161
+ The `useAuth` hook uses the new `use` API for context:
162
+
163
+ ```typescript
164
+ export function useAuth() {
165
+ const context = use(AuthContext)
166
+ if (context === undefined) {
167
+ throw new Error('useAuth must be used within an AuthProvider')
168
+ }
169
+ return context
170
+ }
171
+ ```
172
+
173
+ ### New Architecture
174
+
175
+ Enabled in `app.config.js` for better performance:
176
+
177
+ ```javascript
178
+ {
179
+ expo: {
180
+ newArchEnabled: true
181
+ }
182
+ }
183
+ ```
184
+
185
+ ## Building for Production
186
+
187
+ Use EAS Build for production builds:
188
+
189
+ ```bash
190
+ # Install EAS CLI
191
+ npm install -g eas-cli
192
+
193
+ # Configure EAS
194
+ eas build:configure
195
+
196
+ # Build for iOS
197
+ eas build --platform ios
198
+
199
+ # Build for Android
200
+ eas build --platform android
201
+ ```
202
+
203
+ ## Tech Stack
204
+
205
+ - **Expo SDK 54** - Managed workflow
206
+ - **React 19** - Latest React with Compiler support
207
+ - **React Native 0.81** - Latest stable
208
+ - **Expo Router 6** - File-based navigation
209
+ - **Amplitude** - Product analytics
210
+ - **TypeScript** - Strict mode enabled
211
+ - **React Native Reanimated** - Smooth animations
212
+ - **React Native Gesture Handler** - Native gestures
213
+
214
+ ## License
215
+
216
+ MIT
217
+
218
+ ---
219
+
220
+ ## .env.example
221
+
222
+ ```example
223
+ AMPLITUDE_API_KEY=your_amplitude_api_key_here
224
+
225
+ ```
226
+
227
+ ---
228
+
229
+ ## .npmrc
230
+
231
+ ```
232
+ legacy-peer-deps=true
233
+
234
+ ```
235
+
236
+ ---
237
+
238
+ ## app.config.js
239
+
240
+ ```js
241
+ export default {
242
+ expo: {
243
+ name: 'BurritoApp',
244
+ slug: 'burrito-app',
245
+ version: '1.0.0',
246
+ orientation: 'portrait',
247
+ icon: './assets/icon.png',
248
+ userInterfaceStyle: 'light',
249
+ newArchEnabled: true,
250
+ experiments: {
251
+ reactCompiler: true,
252
+ },
253
+ splash: {
254
+ image: './assets/splash-icon.png',
255
+ resizeMode: 'contain',
256
+ backgroundColor: '#333333',
257
+ },
258
+ ios: {
259
+ supportsTablet: true,
260
+ bundleIdentifier: 'com.amplitude.burritoapp',
261
+ },
262
+ android: {
263
+ adaptiveIcon: {
264
+ foregroundImage: './assets/adaptive-icon.png',
265
+ backgroundColor: '#333333',
266
+ },
267
+ package: 'com.amplitude.burritoapp',
268
+ edgeToEdgeEnabled: true,
269
+ },
270
+ web: {
271
+ favicon: './assets/favicon.png',
272
+ },
273
+ scheme: 'burritoapp',
274
+ extra: {
275
+ amplitudeApiKey: process.env.AMPLITUDE_API_KEY,
276
+ },
277
+ plugins: ['expo-router', 'expo-localization'],
278
+ },
279
+ }
280
+
281
+ ```
282
+
283
+ ---
284
+
285
+ ## app/_layout.tsx
286
+
287
+ ```tsx
288
+ import { Stack, usePathname, useGlobalSearchParams } from 'expo-router'
289
+ import { useEffect, useRef } from 'react'
290
+ import { StatusBar } from 'expo-status-bar'
291
+ import { SafeAreaProvider } from 'react-native-safe-area-context'
292
+ import { GestureHandlerRootView } from 'react-native-gesture-handler'
293
+
294
+ import { AuthProvider } from '../src/contexts/AuthContext'
295
+ import { amplitude } from '../src/config/amplitude'
296
+ import { colors } from '../src/styles/theme'
297
+
298
+ export default function RootLayout() {
299
+ const pathname = usePathname()
300
+ const params = useGlobalSearchParams()
301
+ const previousPathname = useRef<string | undefined>(undefined)
302
+
303
+ // Manual screen tracking for Expo Router
304
+ // @see https://docs.expo.dev/router/reference/screen-tracking/
305
+ // React Compiler will auto-optimize this effect
306
+ useEffect(() => {
307
+ if (previousPathname.current !== pathname) {
308
+ amplitude.track('Screen Viewed', {
309
+ screen_name: pathname,
310
+ previous_screen: previousPathname.current ?? null,
311
+ // Include route params for analytics (filter sensitive data if needed)
312
+ ...params,
313
+ })
314
+ previousPathname.current = pathname
315
+ }
316
+ }, [pathname, params])
317
+
318
+ return (
319
+ <GestureHandlerRootView style={{ flex: 1 }}>
320
+ <SafeAreaProvider>
321
+ <StatusBar style="light" backgroundColor={colors.headerBackground} />
322
+ <AuthProvider>
323
+ <Stack
324
+ screenOptions={{
325
+ headerStyle: { backgroundColor: colors.headerBackground },
326
+ headerTintColor: colors.headerText,
327
+ headerTitleStyle: { fontWeight: 'bold' },
328
+ animation: 'slide_from_right',
329
+ }}
330
+ >
331
+ <Stack.Screen name="index" options={{ title: 'Burrito App' }} />
332
+ <Stack.Screen name="burrito" options={{ title: 'Burrito Consideration' }} />
333
+ <Stack.Screen name="profile" options={{ title: 'Profile' }} />
334
+ </Stack>
335
+ </AuthProvider>
336
+ </SafeAreaProvider>
337
+ </GestureHandlerRootView>
338
+ )
339
+ }
340
+
341
+ ```
342
+
343
+ ---
344
+
345
+ ## app/burrito.tsx
346
+
347
+ ```tsx
348
+ import { useState, useEffect } from 'react'
349
+ import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
350
+ import { useRouter } from 'expo-router'
351
+ import { useAuth } from '../src/contexts/AuthContext'
352
+ import { amplitude } from '../src/config/amplitude'
353
+ import { colors, spacing, typography, borderRadius, shadows } from '../src/styles/theme'
354
+
355
+ /**
356
+ * Burrito Consideration Screen
357
+ *
358
+ * Demonstrates Amplitude event tracking with custom properties.
359
+ * Each time the user considers a burrito, an event is captured.
360
+ *
361
+ * @see https://amplitude.com/docs/sdks/analytics/react-native
362
+ */
363
+ export default function BurritoScreen() {
364
+ const { user, incrementBurritoConsiderations } = useAuth()
365
+ const router = useRouter()
366
+ const [hasConsidered, setHasConsidered] = useState(false)
367
+
368
+ // Redirect to home if not logged in
369
+ useEffect(() => {
370
+ if (!user) {
371
+ router.replace('/')
372
+ }
373
+ }, [user, router])
374
+
375
+ if (!user) {
376
+ return null
377
+ }
378
+
379
+ const handleConsideration = async () => {
380
+ const newCount = user.burritoConsiderations + 1
381
+
382
+ // Update state first for immediate feedback
383
+ await incrementBurritoConsiderations()
384
+ setHasConsidered(true)
385
+
386
+ // Hide success message after 2 seconds
387
+ setTimeout(() => setHasConsidered(false), 2000)
388
+
389
+ // Capture custom event in Amplitude with properties
390
+ amplitude.track('Burrito Considered', {
391
+ total_considerations: newCount,
392
+ username: user.username,
393
+ })
394
+ }
395
+
396
+ return (
397
+ <View style={styles.container}>
398
+ <View style={styles.card}>
399
+ <Text style={styles.title}>Burrito Consideration Zone</Text>
400
+ <Text style={styles.text}>
401
+ Take a moment to truly consider the potential of burritos.
402
+ </Text>
403
+
404
+ <TouchableOpacity
405
+ style={styles.burritoButton}
406
+ onPress={handleConsideration}
407
+ activeOpacity={0.8}
408
+ testID="consider-burrito-button"
409
+ >
410
+ <Text style={styles.burritoButtonText}>Consider Burrito</Text>
411
+ </TouchableOpacity>
412
+
413
+ {hasConsidered && (
414
+ <View style={styles.successContainer}>
415
+ <Text style={styles.success}>Thank you for your consideration!</Text>
416
+ <Text style={styles.successCount}>Count: {user.burritoConsiderations}</Text>
417
+ </View>
418
+ )}
419
+
420
+ <View style={styles.stats}>
421
+ <Text style={styles.statsTitle}>Consideration Stats</Text>
422
+ <Text style={styles.statsText}>Total considerations: {user.burritoConsiderations}</Text>
423
+ </View>
424
+ </View>
425
+ </View>
426
+ )
427
+ }
428
+
429
+ const styles = StyleSheet.create({
430
+ container: {
431
+ flex: 1,
432
+ backgroundColor: colors.background,
433
+ padding: spacing.md,
434
+ },
435
+ card: {
436
+ backgroundColor: colors.cardBackground,
437
+ borderRadius: borderRadius.md,
438
+ padding: spacing.lg,
439
+ ...shadows.md,
440
+ },
441
+ title: {
442
+ fontSize: typography.sizes.xl,
443
+ fontWeight: typography.weights.bold,
444
+ color: colors.text,
445
+ marginBottom: spacing.sm,
446
+ },
447
+ text: {
448
+ fontSize: typography.sizes.md,
449
+ color: colors.text,
450
+ marginBottom: spacing.lg,
451
+ lineHeight: 24,
452
+ },
453
+ burritoButton: {
454
+ backgroundColor: colors.burrito,
455
+ borderRadius: borderRadius.sm,
456
+ padding: spacing.lg,
457
+ alignItems: 'center',
458
+ marginVertical: spacing.md,
459
+ ...shadows.sm,
460
+ },
461
+ burritoButtonText: {
462
+ color: colors.white,
463
+ fontSize: typography.sizes.lg,
464
+ fontWeight: typography.weights.bold,
465
+ },
466
+ successContainer: {
467
+ alignItems: 'center',
468
+ marginVertical: spacing.sm,
469
+ },
470
+ success: {
471
+ color: colors.success,
472
+ fontSize: typography.sizes.md,
473
+ fontWeight: typography.weights.medium,
474
+ },
475
+ successCount: {
476
+ color: colors.success,
477
+ fontSize: typography.sizes.lg,
478
+ fontWeight: typography.weights.bold,
479
+ marginTop: spacing.xs,
480
+ },
481
+ stats: {
482
+ backgroundColor: colors.statsBackground,
483
+ padding: spacing.md,
484
+ borderRadius: borderRadius.sm,
485
+ marginTop: spacing.lg,
486
+ },
487
+ statsTitle: {
488
+ fontSize: typography.sizes.lg,
489
+ fontWeight: typography.weights.semibold,
490
+ color: colors.text,
491
+ marginBottom: spacing.xs,
492
+ },
493
+ statsText: {
494
+ fontSize: typography.sizes.md,
495
+ color: colors.text,
496
+ },
497
+ })
498
+
499
+ ```
500
+
501
+ ---
502
+
503
+ ## app/index.tsx
504
+
505
+ ```tsx
506
+ import { useState } from 'react'
507
+ import {
508
+ View,
509
+ Text,
510
+ TextInput,
511
+ TouchableOpacity,
512
+ StyleSheet,
513
+ ScrollView,
514
+ KeyboardAvoidingView,
515
+ Platform,
516
+ } from 'react-native'
517
+ import { useRouter } from 'expo-router'
518
+ import { useAuth } from '../src/contexts/AuthContext'
519
+ import { colors, spacing, typography, borderRadius, shadows } from '../src/styles/theme'
520
+
521
+ export default function HomeScreen() {
522
+ const { user, login, logout } = useAuth()
523
+ const router = useRouter()
524
+ const [username, setUsername] = useState('')
525
+ const [password, setPassword] = useState('')
526
+ const [error, setError] = useState('')
527
+ const [isSubmitting, setIsSubmitting] = useState(false)
528
+
529
+ const handleSubmit = async () => {
530
+ setError('')
531
+
532
+ if (!username.trim() || !password.trim()) {
533
+ setError('Please provide both username and password')
534
+ return
535
+ }
536
+
537
+ setIsSubmitting(true)
538
+ try {
539
+ const success = await login(username, password)
540
+ if (success) {
541
+ setUsername('')
542
+ setPassword('')
543
+ } else {
544
+ setError('An error occurred during login')
545
+ }
546
+ } catch {
547
+ setError('An error occurred during login')
548
+ } finally {
549
+ setIsSubmitting(false)
550
+ }
551
+ }
552
+
553
+ // Logged in view
554
+ if (user) {
555
+ return (
556
+ <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContent}>
557
+ <View style={styles.card}>
558
+ <Text style={styles.title}>Welcome back, {user.username}!</Text>
559
+ <Text style={styles.text}>You are now logged in. Feel free to explore:</Text>
560
+
561
+ <View style={styles.buttonGroup}>
562
+ <TouchableOpacity
563
+ style={[styles.button, styles.burritoButton]}
564
+ onPress={() => router.push('/burrito')}
565
+ activeOpacity={0.8}
566
+ >
567
+ <Text style={styles.buttonText}>Consider Burritos</Text>
568
+ </TouchableOpacity>
569
+
570
+ <TouchableOpacity
571
+ style={[styles.button, styles.primaryButton]}
572
+ onPress={() => router.push('/profile')}
573
+ activeOpacity={0.8}
574
+ >
575
+ <Text style={styles.buttonText}>View Profile</Text>
576
+ </TouchableOpacity>
577
+
578
+ <TouchableOpacity
579
+ style={[styles.button, styles.logoutButton]}
580
+ onPress={logout}
581
+ activeOpacity={0.8}
582
+ >
583
+ <Text style={styles.buttonText}>Logout</Text>
584
+ </TouchableOpacity>
585
+ </View>
586
+ </View>
587
+ </ScrollView>
588
+ )
589
+ }
590
+
591
+ // Login view
592
+ return (
593
+ <KeyboardAvoidingView
594
+ style={styles.container}
595
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
596
+ >
597
+ <ScrollView
598
+ style={styles.scrollView}
599
+ contentContainerStyle={styles.scrollContent}
600
+ keyboardShouldPersistTaps="handled"
601
+ >
602
+ <View style={styles.card}>
603
+ <Text style={styles.title}>Welcome to Burrito Consideration App</Text>
604
+ <Text style={styles.text}>Please sign in to begin your burrito journey</Text>
605
+
606
+ <View style={styles.form}>
607
+ <Text style={styles.label}>Username:</Text>
608
+ <TextInput
609
+ style={styles.input}
610
+ value={username}
611
+ onChangeText={setUsername}
612
+ placeholder="Enter any username"
613
+ placeholderTextColor={colors.textLight}
614
+ autoCapitalize="none"
615
+ autoCorrect={false}
616
+ autoComplete="username"
617
+ editable={!isSubmitting}
618
+ />
619
+
620
+ <Text style={styles.label}>Password:</Text>
621
+ <TextInput
622
+ style={styles.input}
623
+ value={password}
624
+ onChangeText={setPassword}
625
+ placeholder="Enter any password"
626
+ placeholderTextColor={colors.textLight}
627
+ secureTextEntry
628
+ autoComplete="password"
629
+ editable={!isSubmitting}
630
+ />
631
+
632
+ {error ? <Text style={styles.error}>{error}</Text> : null}
633
+
634
+ <TouchableOpacity
635
+ style={[styles.button, styles.primaryButton, isSubmitting && styles.buttonDisabled]}
636
+ onPress={handleSubmit}
637
+ disabled={isSubmitting}
638
+ activeOpacity={0.8}
639
+ >
640
+ <Text style={styles.buttonText}>{isSubmitting ? 'Signing In...' : 'Sign In'}</Text>
641
+ </TouchableOpacity>
642
+ </View>
643
+
644
+ <Text style={styles.note}>
645
+ Note: This is a demo app. Use any username and password to sign in.
646
+ </Text>
647
+ </View>
648
+ </ScrollView>
649
+ </KeyboardAvoidingView>
650
+ )
651
+ }
652
+
653
+ const styles = StyleSheet.create({
654
+ container: {
655
+ flex: 1,
656
+ backgroundColor: colors.background,
657
+ },
658
+ scrollView: {
659
+ flex: 1,
660
+ backgroundColor: colors.background,
661
+ },
662
+ scrollContent: {
663
+ flexGrow: 1,
664
+ padding: spacing.md,
665
+ justifyContent: 'center',
666
+ },
667
+ card: {
668
+ backgroundColor: colors.cardBackground,
669
+ borderRadius: borderRadius.md,
670
+ padding: spacing.lg,
671
+ ...shadows.md,
672
+ },
673
+ title: {
674
+ fontSize: typography.sizes.xl,
675
+ fontWeight: typography.weights.bold,
676
+ color: colors.text,
677
+ marginBottom: spacing.sm,
678
+ },
679
+ text: {
680
+ fontSize: typography.sizes.md,
681
+ color: colors.text,
682
+ marginBottom: spacing.md,
683
+ lineHeight: 24,
684
+ },
685
+ form: {
686
+ marginTop: spacing.md,
687
+ },
688
+ label: {
689
+ fontSize: typography.sizes.md,
690
+ fontWeight: typography.weights.medium,
691
+ color: colors.text,
692
+ marginBottom: spacing.xs,
693
+ },
694
+ input: {
695
+ backgroundColor: colors.inputBackground,
696
+ borderWidth: 1,
697
+ borderColor: colors.border,
698
+ borderRadius: borderRadius.sm,
699
+ padding: spacing.sm,
700
+ fontSize: typography.sizes.md,
701
+ color: colors.text,
702
+ marginBottom: spacing.md,
703
+ },
704
+ buttonGroup: {
705
+ marginTop: spacing.md,
706
+ gap: spacing.sm,
707
+ },
708
+ button: {
709
+ borderRadius: borderRadius.sm,
710
+ padding: spacing.md,
711
+ alignItems: 'center',
712
+ marginTop: spacing.sm,
713
+ },
714
+ primaryButton: {
715
+ backgroundColor: colors.primary,
716
+ },
717
+ burritoButton: {
718
+ backgroundColor: colors.burrito,
719
+ },
720
+ logoutButton: {
721
+ backgroundColor: colors.danger,
722
+ },
723
+ buttonDisabled: {
724
+ opacity: 0.6,
725
+ },
726
+ buttonText: {
727
+ color: colors.white,
728
+ fontSize: typography.sizes.md,
729
+ fontWeight: typography.weights.semibold,
730
+ },
731
+ error: {
732
+ color: colors.danger,
733
+ marginBottom: spacing.sm,
734
+ fontSize: typography.sizes.sm,
735
+ },
736
+ note: {
737
+ marginTop: spacing.lg,
738
+ color: colors.textSecondary,
739
+ fontSize: typography.sizes.sm,
740
+ textAlign: 'center',
741
+ lineHeight: 20,
742
+ },
743
+ })
744
+
745
+ ```
746
+
747
+ ---
748
+
749
+ ## app/profile.tsx
750
+
751
+ ```tsx
752
+ import { useEffect } from 'react'
753
+ import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
754
+ import { useRouter } from 'expo-router'
755
+ import { useAuth } from '../src/contexts/AuthContext'
756
+ import { amplitude } from '../src/config/amplitude'
757
+ import { colors, spacing, typography, borderRadius, shadows } from '../src/styles/theme'
758
+
759
+ /**
760
+ * Profile Screen
761
+ *
762
+ * Displays user information and demonstrates Amplitude event tracking.
763
+ *
764
+ * @see https://amplitude.com/docs/sdks/analytics/react-native
765
+ */
766
+ export default function ProfileScreen() {
767
+ const { user } = useAuth()
768
+ const router = useRouter()
769
+
770
+ // Redirect to home if not logged in
771
+ useEffect(() => {
772
+ if (!user) {
773
+ router.replace('/')
774
+ }
775
+ }, [user, router])
776
+
777
+ if (!user) {
778
+ return null
779
+ }
780
+
781
+ const getJourneyMessage = () => {
782
+ const count = user.burritoConsiderations
783
+ if (count === 0) {
784
+ return "You haven't considered any burritos yet. Visit the Burrito Consideration page to start!"
785
+ } else if (count === 1) {
786
+ return "You've considered the burrito potential once. Keep going!"
787
+ } else if (count < 5) {
788
+ return "You're getting the hang of burrito consideration!"
789
+ } else if (count < 10) {
790
+ return "You're becoming a burrito consideration expert!"
791
+ } else {
792
+ return 'You are a true burrito consideration master!'
793
+ }
794
+ }
795
+
796
+ return (
797
+ <View style={styles.container}>
798
+ <View style={styles.card}>
799
+ <Text style={styles.title}>User Profile</Text>
800
+
801
+ <View style={styles.stats}>
802
+ <Text style={styles.statsTitle}>Your Information</Text>
803
+ <View style={styles.infoRow}>
804
+ <Text style={styles.infoLabel}>Username:</Text>
805
+ <Text style={styles.infoValue}>{user.username}</Text>
806
+ </View>
807
+ <View style={styles.infoRow}>
808
+ <Text style={styles.infoLabel}>Burrito Considerations:</Text>
809
+ <Text style={styles.infoValue}>{user.burritoConsiderations}</Text>
810
+ </View>
811
+ </View>
812
+
813
+ <View style={styles.journey}>
814
+ <Text style={styles.journeyTitle}>Your Burrito Journey</Text>
815
+ <Text style={styles.journeyText}>{getJourneyMessage()}</Text>
816
+ </View>
817
+ </View>
818
+ </View>
819
+ )
820
+ }
821
+
822
+ const styles = StyleSheet.create({
823
+ container: {
824
+ flex: 1,
825
+ backgroundColor: colors.background,
826
+ padding: spacing.md,
827
+ },
828
+ card: {
829
+ backgroundColor: colors.cardBackground,
830
+ borderRadius: borderRadius.md,
831
+ padding: spacing.lg,
832
+ ...shadows.md,
833
+ },
834
+ title: {
835
+ fontSize: typography.sizes.xl,
836
+ fontWeight: typography.weights.bold,
837
+ color: colors.text,
838
+ marginBottom: spacing.md,
839
+ },
840
+ stats: {
841
+ backgroundColor: colors.statsBackground,
842
+ padding: spacing.md,
843
+ borderRadius: borderRadius.sm,
844
+ },
845
+ statsTitle: {
846
+ fontSize: typography.sizes.lg,
847
+ fontWeight: typography.weights.semibold,
848
+ color: colors.text,
849
+ marginBottom: spacing.sm,
850
+ },
851
+ infoRow: {
852
+ flexDirection: 'row',
853
+ marginBottom: spacing.xs,
854
+ },
855
+ infoLabel: {
856
+ fontSize: typography.sizes.md,
857
+ fontWeight: typography.weights.bold,
858
+ color: colors.text,
859
+ marginRight: spacing.xs,
860
+ },
861
+ infoValue: {
862
+ fontSize: typography.sizes.md,
863
+ color: colors.text,
864
+ },
865
+ journey: {
866
+ marginTop: spacing.lg,
867
+ },
868
+ journeyTitle: {
869
+ fontSize: typography.sizes.lg,
870
+ fontWeight: typography.weights.semibold,
871
+ color: colors.text,
872
+ marginBottom: spacing.sm,
873
+ },
874
+ journeyText: {
875
+ fontSize: typography.sizes.md,
876
+ color: colors.text,
877
+ lineHeight: 24,
878
+ },
879
+ })
880
+
881
+ ```
882
+
883
+ ---
884
+
885
+ ## babel.config.js
886
+
887
+ ```js
888
+ module.exports = function (api) {
889
+ api.cache(true)
890
+ return {
891
+ presets: ['babel-preset-expo'],
892
+ plugins: [
893
+ ['babel-plugin-react-compiler'],
894
+ 'react-native-reanimated/plugin', // Must be last
895
+ ],
896
+ }
897
+ }
898
+
899
+ ```
900
+
901
+ ---
902
+
903
+ ## src/config/amplitude.ts
904
+
905
+ ```ts
906
+ import * as amplitude from '@amplitude/analytics-react-native'
907
+ import Constants from 'expo-constants'
908
+
909
+ // Configuration loaded from app.config.js extras via expo-constants
910
+ // Environment variables are read at build time in app.config.js
911
+ const apiKey = Constants.expoConfig?.extra?.amplitudeApiKey as string | undefined
912
+ const isAmplitudeConfigured = !!apiKey
913
+
914
+ if (__DEV__) {
915
+ console.log('Amplitude config:', {
916
+ apiKey: apiKey ? 'SET' : 'NOT SET',
917
+ isConfigured: isAmplitudeConfigured,
918
+ })
919
+ }
920
+
921
+ if (!isAmplitudeConfigured) {
922
+ console.warn(
923
+ 'Amplitude API key not configured. Analytics will be disabled. ' +
924
+ 'Set AMPLITUDE_API_KEY in your .env file to enable analytics.'
925
+ )
926
+ }
927
+
928
+ /**
929
+ * Initialize the Amplitude SDK for Expo
930
+ *
931
+ * Configuration loaded from app.config.js extras via expo-constants.
932
+ *
933
+ * @see https://amplitude.com/docs/sdks/analytics/react-native
934
+ */
935
+ if (isAmplitudeConfigured && apiKey) {
936
+ amplitude.init(apiKey)
937
+ }
938
+
939
+ export { amplitude }
940
+ export const isAmplitudeEnabled = isAmplitudeConfigured
941
+
942
+ ```
943
+
944
+ ---
945
+
946
+ ## src/contexts/AuthContext.tsx
947
+
948
+ ```tsx
949
+ import React, { createContext, useState, useEffect, use } from 'react'
950
+ import type { ReactNode } from 'react'
951
+ import { Identify } from '@amplitude/analytics-react-native'
952
+ import { amplitude } from '../config/amplitude'
953
+ import { storage } from '../services/storage'
954
+ import type { User } from '../services/storage'
955
+
956
+ interface AuthContextType {
957
+ user: User | null
958
+ isLoading: boolean
959
+ login: (username: string, password: string) => Promise<boolean>
960
+ logout: () => Promise<void>
961
+ incrementBurritoConsiderations: () => Promise<void>
962
+ }
963
+
964
+ const AuthContext = createContext<AuthContextType | undefined>(undefined)
965
+
966
+ interface AuthProviderProps {
967
+ children: ReactNode
968
+ }
969
+
970
+ export function AuthProvider({ children }: AuthProviderProps) {
971
+ const [user, setUser] = useState<User | null>(null)
972
+ const [isLoading, setIsLoading] = useState(true)
973
+
974
+ useEffect(() => {
975
+ const restoreSession = async () => {
976
+ try {
977
+ const storedUsername = await storage.getCurrentUser()
978
+ if (storedUsername) {
979
+ const existingUser = await storage.getUser(storedUsername)
980
+ if (existingUser) {
981
+ setUser(existingUser)
982
+ amplitude.setUserId(storedUsername)
983
+ const identifyObj = new Identify()
984
+ identifyObj.set('username', storedUsername)
985
+ amplitude.identify(identifyObj)
986
+ }
987
+ }
988
+ } catch (error) {
989
+ console.error('Failed to restore session:', error)
990
+ } finally {
991
+ setIsLoading(false)
992
+ }
993
+ }
994
+ restoreSession()
995
+ }, [])
996
+
997
+ // React Compiler auto-memoizes these callbacks - no useCallback needed!
998
+ const login = async (username: string, password: string): Promise<boolean> => {
999
+ if (!username.trim() || !password.trim()) {
1000
+ return false
1001
+ }
1002
+
1003
+ try {
1004
+ const existingUser = await storage.getUser(username)
1005
+ const isNewUser = !existingUser
1006
+
1007
+ const userData: User = existingUser || {
1008
+ username,
1009
+ burritoConsiderations: 0,
1010
+ }
1011
+
1012
+ await storage.saveUser(userData)
1013
+ await storage.setCurrentUser(username)
1014
+ setUser(userData)
1015
+
1016
+ // Amplitude: Identify user and capture login event
1017
+ amplitude.setUserId(username)
1018
+ const identifyObj = new Identify()
1019
+ identifyObj.set('username', username)
1020
+ amplitude.identify(identifyObj)
1021
+
1022
+ amplitude.track('User Logged In', {
1023
+ username,
1024
+ is_new_user: isNewUser,
1025
+ })
1026
+
1027
+ return true
1028
+ } catch (error) {
1029
+ console.error('Login error:', error)
1030
+ return false
1031
+ }
1032
+ }
1033
+
1034
+ const logout = async () => {
1035
+ amplitude.track('User Logged Out')
1036
+ amplitude.reset()
1037
+ await storage.removeCurrentUser()
1038
+ setUser(null)
1039
+ }
1040
+
1041
+ const incrementBurritoConsiderations = async () => {
1042
+ if (user) {
1043
+ const updatedUser: User = {
1044
+ ...user,
1045
+ burritoConsiderations: user.burritoConsiderations + 1,
1046
+ }
1047
+ setUser(updatedUser)
1048
+ await storage.saveUser(updatedUser)
1049
+ }
1050
+ }
1051
+
1052
+ return (
1053
+ <AuthContext
1054
+ value={{
1055
+ user,
1056
+ isLoading,
1057
+ login,
1058
+ logout,
1059
+ incrementBurritoConsiderations,
1060
+ }}
1061
+ >
1062
+ {children}
1063
+ </AuthContext>
1064
+ )
1065
+ }
1066
+
1067
+ /**
1068
+ * React 19: Use the `use` API instead of useContext
1069
+ * - Can be called conditionally (unlike useContext)
1070
+ * - Enables more flexible component composition
1071
+ */
1072
+ export function useAuth() {
1073
+ const context = use(AuthContext)
1074
+ if (context === undefined) {
1075
+ throw new Error('useAuth must be used within an AuthProvider')
1076
+ }
1077
+ return context
1078
+ }
1079
+
1080
+ ```
1081
+
1082
+ ---
1083
+
1084
+ ## src/services/storage.ts
1085
+
1086
+ ```ts
1087
+ import AsyncStorage from '@react-native-async-storage/async-storage'
1088
+
1089
+ const CURRENT_USER_KEY = 'currentUser'
1090
+ const USERS_KEY = 'users'
1091
+
1092
+ export interface User {
1093
+ username: string
1094
+ burritoConsiderations: number
1095
+ }
1096
+
1097
+ /**
1098
+ * Storage service for persisting user data
1099
+ * Uses AsyncStorage (React Native's async key-value storage)
1100
+ */
1101
+ export const storage = {
1102
+ /**
1103
+ * Get the currently logged in user's username
1104
+ */
1105
+ getCurrentUser: async (): Promise<string | null> => {
1106
+ try {
1107
+ return await AsyncStorage.getItem(CURRENT_USER_KEY)
1108
+ } catch (error) {
1109
+ console.error('Error getting current user:', error)
1110
+ return null
1111
+ }
1112
+ },
1113
+
1114
+ /**
1115
+ * Set the currently logged in user's username
1116
+ */
1117
+ setCurrentUser: async (username: string): Promise<void> => {
1118
+ try {
1119
+ await AsyncStorage.setItem(CURRENT_USER_KEY, username)
1120
+ } catch (error) {
1121
+ console.error('Error setting current user:', error)
1122
+ }
1123
+ },
1124
+
1125
+ /**
1126
+ * Remove the current user (logout)
1127
+ */
1128
+ removeCurrentUser: async (): Promise<void> => {
1129
+ try {
1130
+ await AsyncStorage.removeItem(CURRENT_USER_KEY)
1131
+ } catch (error) {
1132
+ console.error('Error removing current user:', error)
1133
+ }
1134
+ },
1135
+
1136
+ /**
1137
+ * Get all stored users
1138
+ */
1139
+ getUsers: async (): Promise<Record<string, User>> => {
1140
+ try {
1141
+ const data = await AsyncStorage.getItem(USERS_KEY)
1142
+ return data ? JSON.parse(data) : {}
1143
+ } catch (error) {
1144
+ console.error('Error getting users:', error)
1145
+ return {}
1146
+ }
1147
+ },
1148
+
1149
+ /**
1150
+ * Get a specific user by username
1151
+ */
1152
+ getUser: async (username: string): Promise<User | null> => {
1153
+ try {
1154
+ const users = await storage.getUsers()
1155
+ return users[username] || null
1156
+ } catch (error) {
1157
+ console.error('Error getting user:', error)
1158
+ return null
1159
+ }
1160
+ },
1161
+
1162
+ /**
1163
+ * Save a user to storage
1164
+ */
1165
+ saveUser: async (user: User): Promise<void> => {
1166
+ try {
1167
+ const users = await storage.getUsers()
1168
+ users[user.username] = user
1169
+ await AsyncStorage.setItem(USERS_KEY, JSON.stringify(users))
1170
+ } catch (error) {
1171
+ console.error('Error saving user:', error)
1172
+ }
1173
+ },
1174
+
1175
+ /**
1176
+ * Clear all stored data (for testing/debugging)
1177
+ */
1178
+ clearAll: async (): Promise<void> => {
1179
+ try {
1180
+ await AsyncStorage.multiRemove([CURRENT_USER_KEY, USERS_KEY])
1181
+ } catch (error) {
1182
+ console.error('Error clearing storage:', error)
1183
+ }
1184
+ },
1185
+ }
1186
+
1187
+ ```
1188
+
1189
+ ---
1190
+
1191
+ ## src/styles/theme.ts
1192
+
1193
+ ```ts
1194
+ /**
1195
+ * Theme constants for consistent styling across the app
1196
+ * Matches the color scheme from the TanStack Start web version
1197
+ */
1198
+
1199
+ export const colors = {
1200
+ // Primary colors
1201
+ primary: '#0070f3',
1202
+ primaryDark: '#0051cc',
1203
+
1204
+ // Status colors
1205
+ success: '#28a745',
1206
+ successDark: '#218838',
1207
+ danger: '#dc3545',
1208
+ dangerDark: '#c82333',
1209
+
1210
+ // Feature colors
1211
+ burrito: '#e07c24',
1212
+ burritoDark: '#c96a1a',
1213
+
1214
+ // Neutral colors
1215
+ background: '#f5f5f5',
1216
+ white: '#ffffff',
1217
+ text: '#333333',
1218
+ textSecondary: '#666666',
1219
+ textLight: '#999999',
1220
+ border: '#dddddd',
1221
+ borderLight: '#eeeeee',
1222
+
1223
+ // Component-specific
1224
+ statsBackground: '#f8f9fa',
1225
+ headerBackground: '#333333',
1226
+ headerText: '#ffffff',
1227
+ inputBackground: '#ffffff',
1228
+ cardBackground: '#ffffff',
1229
+ }
1230
+
1231
+ export const spacing = {
1232
+ xs: 4,
1233
+ sm: 8,
1234
+ md: 16,
1235
+ lg: 24,
1236
+ xl: 32,
1237
+ xxl: 48,
1238
+ }
1239
+
1240
+ export const typography = {
1241
+ sizes: {
1242
+ xs: 12,
1243
+ sm: 14,
1244
+ md: 16,
1245
+ lg: 18,
1246
+ xl: 24,
1247
+ xxl: 32,
1248
+ },
1249
+ weights: {
1250
+ normal: '400' as const,
1251
+ medium: '500' as const,
1252
+ semibold: '600' as const,
1253
+ bold: '700' as const,
1254
+ },
1255
+ }
1256
+
1257
+ export const borderRadius = {
1258
+ sm: 4,
1259
+ md: 8,
1260
+ lg: 12,
1261
+ full: 9999,
1262
+ }
1263
+
1264
+ export const shadows = {
1265
+ sm: {
1266
+ shadowColor: '#000',
1267
+ shadowOffset: { width: 0, height: 1 },
1268
+ shadowOpacity: 0.05,
1269
+ shadowRadius: 2,
1270
+ elevation: 1,
1271
+ },
1272
+ md: {
1273
+ shadowColor: '#000',
1274
+ shadowOffset: { width: 0, height: 2 },
1275
+ shadowOpacity: 0.1,
1276
+ shadowRadius: 4,
1277
+ elevation: 3,
1278
+ },
1279
+ lg: {
1280
+ shadowColor: '#000',
1281
+ shadowOffset: { width: 0, height: 4 },
1282
+ shadowOpacity: 0.15,
1283
+ shadowRadius: 8,
1284
+ elevation: 5,
1285
+ },
1286
+ }
1287
+
1288
+ ```
1289
+
1290
+ ---
1291
+