@codyswann/lisa 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 (322) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +867 -0
  3. package/all/copy-overwrite/.claude/README.md +205 -0
  4. package/all/copy-overwrite/.claude/agents/agent-architect.md +311 -0
  5. package/all/copy-overwrite/.claude/agents/codebase-analyzer.md +146 -0
  6. package/all/copy-overwrite/.claude/agents/codebase-locator.md +125 -0
  7. package/all/copy-overwrite/.claude/agents/codebase-pattern-finder.md +237 -0
  8. package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +183 -0
  9. package/all/copy-overwrite/.claude/agents/hooks-expert.md +74 -0
  10. package/all/copy-overwrite/.claude/agents/skill-evaluator.md +246 -0
  11. package/all/copy-overwrite/.claude/agents/slash-command-architect.md +87 -0
  12. package/all/copy-overwrite/.claude/agents/web-search-researcher.md +112 -0
  13. package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +8 -0
  14. package/all/copy-overwrite/.claude/commands/git/commit.md +44 -0
  15. package/all/copy-overwrite/.claude/commands/git/prune.md +34 -0
  16. package/all/copy-overwrite/.claude/commands/git/submit-pr.md +50 -0
  17. package/all/copy-overwrite/.claude/commands/jira/create.md +50 -0
  18. package/all/copy-overwrite/.claude/commands/jira/verify.md +34 -0
  19. package/all/copy-overwrite/.claude/commands/project/archive.md +8 -0
  20. package/all/copy-overwrite/.claude/commands/project/bootstrap.md +49 -0
  21. package/all/copy-overwrite/.claude/commands/project/complete-task.md +7 -0
  22. package/all/copy-overwrite/.claude/commands/project/debrief.md +65 -0
  23. package/all/copy-overwrite/.claude/commands/project/execute.md +94 -0
  24. package/all/copy-overwrite/.claude/commands/project/implement.md +42 -0
  25. package/all/copy-overwrite/.claude/commands/project/local-code-review.md +88 -0
  26. package/all/copy-overwrite/.claude/commands/project/lower-code-complexity.md +74 -0
  27. package/all/copy-overwrite/.claude/commands/project/plan.md +314 -0
  28. package/all/copy-overwrite/.claude/commands/project/research.md +248 -0
  29. package/all/copy-overwrite/.claude/commands/project/review.md +63 -0
  30. package/all/copy-overwrite/.claude/commands/project/setup.md +19 -0
  31. package/all/copy-overwrite/.claude/commands/project/verify.md +38 -0
  32. package/all/copy-overwrite/.claude/commands/pull-request/review.md +12 -0
  33. package/all/copy-overwrite/.claude/commands/rules/format-md.md +72 -0
  34. package/all/copy-overwrite/.claude/commands/sonarqube/check.md +6 -0
  35. package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +3 -0
  36. package/all/copy-overwrite/.claude/hooks/README.md +301 -0
  37. package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +181 -0
  38. package/all/copy-overwrite/.claude/settings.json +41 -0
  39. package/all/copy-overwrite/.claude/settings.local.json.example +14 -0
  40. package/all/copy-overwrite/.claude/skills/coding-philosophy/SKILL.md +405 -0
  41. package/all/copy-overwrite/.claude/skills/coding-philosophy/references/function-structure.md +416 -0
  42. package/all/copy-overwrite/.claude/skills/coding-philosophy/references/immutable-patterns.md +316 -0
  43. package/all/copy-overwrite/.claude/skills/prompt-complexity-scorer/SKILL.md +118 -0
  44. package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +202 -0
  45. package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +210 -0
  46. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
  47. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
  48. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
  49. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
  50. package/all/copy-overwrite/CLAUDE.md +77 -0
  51. package/all/copy-overwrite/HUMAN.md +17 -0
  52. package/all/copy-overwrite/specs/.keep +0 -0
  53. package/all/create-only/PROJECT_RULES.md +0 -0
  54. package/cdk/merge/package.json +20 -0
  55. package/dist/cli/index.d.ts +7 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +107 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/cli/prompts.d.ts +45 -0
  60. package/dist/cli/prompts.d.ts.map +1 -0
  61. package/dist/cli/prompts.js +58 -0
  62. package/dist/cli/prompts.js.map +1 -0
  63. package/dist/core/config.d.ts +73 -0
  64. package/dist/core/config.d.ts.map +1 -0
  65. package/dist/core/config.js +36 -0
  66. package/dist/core/config.js.map +1 -0
  67. package/dist/core/index.d.ts +4 -0
  68. package/dist/core/index.d.ts.map +1 -0
  69. package/dist/core/index.js +4 -0
  70. package/dist/core/index.js.map +1 -0
  71. package/dist/core/lisa.d.ts +81 -0
  72. package/dist/core/lisa.d.ts.map +1 -0
  73. package/dist/core/lisa.js +459 -0
  74. package/dist/core/lisa.js.map +1 -0
  75. package/dist/core/manifest.d.ts +58 -0
  76. package/dist/core/manifest.d.ts.map +1 -0
  77. package/dist/core/manifest.js +104 -0
  78. package/dist/core/manifest.js.map +1 -0
  79. package/dist/detection/detector.interface.d.ts +15 -0
  80. package/dist/detection/detector.interface.d.ts.map +1 -0
  81. package/dist/detection/detector.interface.js +2 -0
  82. package/dist/detection/detector.interface.js.map +1 -0
  83. package/dist/detection/detectors/cdk.d.ts +10 -0
  84. package/dist/detection/detectors/cdk.d.ts.map +1 -0
  85. package/dist/detection/detectors/cdk.js +34 -0
  86. package/dist/detection/detectors/cdk.js.map +1 -0
  87. package/dist/detection/detectors/expo.d.ts +10 -0
  88. package/dist/detection/detectors/expo.d.ts.map +1 -0
  89. package/dist/detection/detectors/expo.js +30 -0
  90. package/dist/detection/detectors/expo.js.map +1 -0
  91. package/dist/detection/detectors/nestjs.d.ts +10 -0
  92. package/dist/detection/detectors/nestjs.d.ts.map +1 -0
  93. package/dist/detection/detectors/nestjs.js +34 -0
  94. package/dist/detection/detectors/nestjs.js.map +1 -0
  95. package/dist/detection/detectors/npm-package.d.ts +13 -0
  96. package/dist/detection/detectors/npm-package.d.ts.map +1 -0
  97. package/dist/detection/detectors/npm-package.js +30 -0
  98. package/dist/detection/detectors/npm-package.js.map +1 -0
  99. package/dist/detection/detectors/typescript.d.ts +10 -0
  100. package/dist/detection/detectors/typescript.d.ts.map +1 -0
  101. package/dist/detection/detectors/typescript.js +25 -0
  102. package/dist/detection/detectors/typescript.js.map +1 -0
  103. package/dist/detection/index.d.ts +24 -0
  104. package/dist/detection/index.d.ts.map +1 -0
  105. package/dist/detection/index.js +57 -0
  106. package/dist/detection/index.js.map +1 -0
  107. package/dist/errors/index.d.ts +69 -0
  108. package/dist/errors/index.d.ts.map +1 -0
  109. package/dist/errors/index.js +110 -0
  110. package/dist/errors/index.js.map +1 -0
  111. package/dist/index.d.ts +3 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +8 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/logging/console-logger.d.ts +12 -0
  116. package/dist/logging/console-logger.d.ts.map +1 -0
  117. package/dist/logging/console-logger.js +22 -0
  118. package/dist/logging/console-logger.js.map +1 -0
  119. package/dist/logging/index.d.ts +4 -0
  120. package/dist/logging/index.d.ts.map +1 -0
  121. package/dist/logging/index.js +3 -0
  122. package/dist/logging/index.js.map +1 -0
  123. package/dist/logging/logger.interface.d.ts +20 -0
  124. package/dist/logging/logger.interface.d.ts.map +1 -0
  125. package/dist/logging/logger.interface.js +2 -0
  126. package/dist/logging/logger.interface.js.map +1 -0
  127. package/dist/logging/silent-logger.d.ts +12 -0
  128. package/dist/logging/silent-logger.d.ts.map +1 -0
  129. package/dist/logging/silent-logger.js +21 -0
  130. package/dist/logging/silent-logger.js.map +1 -0
  131. package/dist/strategies/copy-contents.d.ts +14 -0
  132. package/dist/strategies/copy-contents.d.ts.map +1 -0
  133. package/dist/strategies/copy-contents.js +69 -0
  134. package/dist/strategies/copy-contents.js.map +1 -0
  135. package/dist/strategies/copy-overwrite.d.ts +14 -0
  136. package/dist/strategies/copy-overwrite.d.ts.map +1 -0
  137. package/dist/strategies/copy-overwrite.js +47 -0
  138. package/dist/strategies/copy-overwrite.js.map +1 -0
  139. package/dist/strategies/create-only.d.ts +13 -0
  140. package/dist/strategies/create-only.d.ts.map +1 -0
  141. package/dist/strategies/create-only.js +30 -0
  142. package/dist/strategies/create-only.js.map +1 -0
  143. package/dist/strategies/index.d.ts +31 -0
  144. package/dist/strategies/index.d.ts.map +1 -0
  145. package/dist/strategies/index.js +52 -0
  146. package/dist/strategies/index.js.map +1 -0
  147. package/dist/strategies/merge.d.ts +13 -0
  148. package/dist/strategies/merge.d.ts.map +1 -0
  149. package/dist/strategies/merge.js +60 -0
  150. package/dist/strategies/merge.js.map +1 -0
  151. package/dist/strategies/strategy.interface.d.ts +31 -0
  152. package/dist/strategies/strategy.interface.d.ts.map +1 -0
  153. package/dist/strategies/strategy.interface.js +2 -0
  154. package/dist/strategies/strategy.interface.js.map +1 -0
  155. package/dist/transaction/backup.d.ts +38 -0
  156. package/dist/transaction/backup.d.ts.map +1 -0
  157. package/dist/transaction/backup.js +97 -0
  158. package/dist/transaction/backup.js.map +1 -0
  159. package/dist/transaction/index.d.ts +4 -0
  160. package/dist/transaction/index.d.ts.map +1 -0
  161. package/dist/transaction/index.js +3 -0
  162. package/dist/transaction/index.js.map +1 -0
  163. package/dist/transaction/transaction.d.ts +34 -0
  164. package/dist/transaction/transaction.d.ts.map +1 -0
  165. package/dist/transaction/transaction.js +68 -0
  166. package/dist/transaction/transaction.js.map +1 -0
  167. package/dist/utils/file-operations.d.ts +29 -0
  168. package/dist/utils/file-operations.d.ts.map +1 -0
  169. package/dist/utils/file-operations.js +84 -0
  170. package/dist/utils/file-operations.js.map +1 -0
  171. package/dist/utils/index.d.ts +4 -0
  172. package/dist/utils/index.d.ts.map +1 -0
  173. package/dist/utils/index.js +4 -0
  174. package/dist/utils/index.js.map +1 -0
  175. package/dist/utils/json-utils.d.ts +22 -0
  176. package/dist/utils/json-utils.d.ts.map +1 -0
  177. package/dist/utils/json-utils.js +57 -0
  178. package/dist/utils/json-utils.js.map +1 -0
  179. package/dist/utils/path-utils.d.ts +21 -0
  180. package/dist/utils/path-utils.d.ts.map +1 -0
  181. package/dist/utils/path-utils.js +35 -0
  182. package/dist/utils/path-utils.js.map +1 -0
  183. package/eslint-plugin-code-organization/README.md +149 -0
  184. package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
  185. package/eslint-plugin-code-organization/index.js +23 -0
  186. package/eslint-plugin-code-organization/package.json +10 -0
  187. package/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
  188. package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +238 -0
  189. package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +360 -0
  190. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +360 -0
  191. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
  192. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
  193. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
  194. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +327 -0
  195. package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +299 -0
  196. package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +749 -0
  197. package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +318 -0
  198. package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +198 -0
  199. package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +207 -0
  200. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +268 -0
  201. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +619 -0
  202. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
  203. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +276 -0
  204. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +414 -0
  205. package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +202 -0
  206. package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +443 -0
  207. package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +309 -0
  208. package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +417 -0
  209. package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +431 -0
  210. package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +290 -0
  211. package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +169 -0
  212. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +411 -0
  213. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +343 -0
  214. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +307 -0
  215. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
  216. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +354 -0
  217. package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +362 -0
  218. package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +505 -0
  219. package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +711 -0
  220. package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +446 -0
  221. package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +223 -0
  222. package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +319 -0
  223. package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +420 -0
  224. package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +556 -0
  225. package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +590 -0
  226. package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +291 -0
  227. package/expo/copy-overwrite/.easignore.extra +2 -0
  228. package/expo/copy-overwrite/.mcp.json +33 -0
  229. package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +234 -0
  230. package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +84 -0
  231. package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +196 -0
  232. package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +289 -0
  233. package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +32 -0
  234. package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +10 -0
  235. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +230 -0
  236. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +91 -0
  237. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +178 -0
  238. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +238 -0
  239. package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +260 -0
  240. package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +29 -0
  241. package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +10 -0
  242. package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +51 -0
  243. package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +55 -0
  244. package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-inline-styles.js +73 -0
  245. package/expo/copy-overwrite/eslint.config.mjs +560 -0
  246. package/expo/copy-overwrite/lighthouserc.js +194 -0
  247. package/expo/create-only/lighthouserc-config.json +28 -0
  248. package/expo/merge/package.json +132 -0
  249. package/lisa.sh +35 -0
  250. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +176 -0
  251. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +527 -0
  252. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +483 -0
  253. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +257 -0
  254. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
  255. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +513 -0
  256. package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +536 -0
  257. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +275 -0
  258. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
  259. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +450 -0
  260. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +536 -0
  261. package/nestjs/merge/package.json +75 -0
  262. package/package.json +124 -0
  263. package/typescript/copy-contents/.husky/commit-msg +91 -0
  264. package/typescript/copy-contents/.husky/pre-commit +96 -0
  265. package/typescript/copy-contents/.husky/pre-push +211 -0
  266. package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +74 -0
  267. package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +59 -0
  268. package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +103 -0
  269. package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +388 -0
  270. package/typescript/copy-overwrite/.github/README.md +455 -0
  271. package/typescript/copy-overwrite/.github/dependabot.yml +40 -0
  272. package/typescript/copy-overwrite/.github/k6/BROWSER_TESTING_NOTE.md +129 -0
  273. package/typescript/copy-overwrite/.github/k6/INTEGRATION_GUIDE.md +354 -0
  274. package/typescript/copy-overwrite/.github/k6/README.md +386 -0
  275. package/typescript/copy-overwrite/.github/k6/SCENARIO_SELECTION_GUIDE.md +264 -0
  276. package/typescript/copy-overwrite/.github/k6/examples/customer-deploy-integration.yml +115 -0
  277. package/typescript/copy-overwrite/.github/k6/examples/data-driven-test.js +268 -0
  278. package/typescript/copy-overwrite/.github/k6/scenarios/load.js +142 -0
  279. package/typescript/copy-overwrite/.github/k6/scenarios/load.json +27 -0
  280. package/typescript/copy-overwrite/.github/k6/scenarios/smoke.js +26 -0
  281. package/typescript/copy-overwrite/.github/k6/scenarios/smoke.json +20 -0
  282. package/typescript/copy-overwrite/.github/k6/scenarios/soak.js +244 -0
  283. package/typescript/copy-overwrite/.github/k6/scenarios/soak.json +29 -0
  284. package/typescript/copy-overwrite/.github/k6/scenarios/spike.js +180 -0
  285. package/typescript/copy-overwrite/.github/k6/scenarios/spike.json +32 -0
  286. package/typescript/copy-overwrite/.github/k6/scenarios/stress.js +206 -0
  287. package/typescript/copy-overwrite/.github/k6/scenarios/stress.json +38 -0
  288. package/typescript/copy-overwrite/.github/k6/scripts/api-test.js +452 -0
  289. package/typescript/copy-overwrite/.github/k6/scripts/default-test.js +185 -0
  290. package/typescript/copy-overwrite/.github/k6/thresholds/normal.json +30 -0
  291. package/typescript/copy-overwrite/.github/k6/thresholds/relaxed.json +21 -0
  292. package/typescript/copy-overwrite/.github/k6/thresholds/strict.json +29 -0
  293. package/typescript/copy-overwrite/.github/workflows/build.yml +72 -0
  294. package/typescript/copy-overwrite/.github/workflows/ci.yml +49 -0
  295. package/typescript/copy-overwrite/.github/workflows/claude.yml +51 -0
  296. package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +113 -0
  297. package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +195 -0
  298. package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +267 -0
  299. package/typescript/copy-overwrite/.github/workflows/deploy.yml +228 -0
  300. package/typescript/copy-overwrite/.github/workflows/k6-load-test-README.md +230 -0
  301. package/typescript/copy-overwrite/.github/workflows/lighthouse.yml +68 -0
  302. package/typescript/copy-overwrite/.github/workflows/load-test.yml +282 -0
  303. package/typescript/copy-overwrite/.github/workflows/quality.yml +1737 -0
  304. package/typescript/copy-overwrite/.github/workflows/release.yml +1599 -0
  305. package/typescript/copy-overwrite/.gitleaksignore +28 -0
  306. package/typescript/copy-overwrite/.nvmrc +1 -0
  307. package/typescript/copy-overwrite/.prettierignore +23 -0
  308. package/typescript/copy-overwrite/.prettierrc.json +22 -0
  309. package/typescript/copy-overwrite/.versionrc +42 -0
  310. package/typescript/copy-overwrite/.yamllint +20 -0
  311. package/typescript/copy-overwrite/commitlint.config.js +11 -0
  312. package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +149 -0
  313. package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
  314. package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +23 -0
  315. package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +10 -0
  316. package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
  317. package/typescript/copy-overwrite/eslint.config.mjs +390 -0
  318. package/typescript/copy-overwrite/eslint.ignore.config.json +57 -0
  319. package/typescript/copy-overwrite/eslint.thresholds.config.json +5 -0
  320. package/typescript/github-rulesets/base.json +106 -0
  321. package/typescript/merge/.claude/settings.json +28 -0
  322. package/typescript/merge/package.json +71 -0
@@ -0,0 +1,309 @@
1
+ ---
2
+ name: expo-env-config
3
+ description: This skill should be used when creating, modifying, or accessing environment variables in this Expo/React Native codebase. It enforces type-safe, validated environment configuration using Zod schemas. Use this skill when adding new environment variables, setting up env validation, or writing code that reads from process.env.
4
+ ---
5
+
6
+ # Expo Environment Configuration
7
+
8
+ ## Overview
9
+
10
+ This skill enforces type-safe, validated environment variable management for Expo/React Native using Zod schemas. Environment variables are validated at build time and provide full TypeScript inference, regardless of their source (`.env` files, EAS Build secrets, CI/CD pipelines, or command-line exports).
11
+
12
+ ## Why This Pattern?
13
+
14
+ Unlike NestJS's `@nestjs/config`, Expo has no official type-safe env solution. The Zod validation pattern provides:
15
+
16
+ 1. **Type safety** - Full TypeScript inference via `z.infer<typeof schema>`
17
+ 2. **Build-time validation** - Fails fast with clear error messages before deployment
18
+ 3. **Source agnostic** - Works with `.env`, EAS secrets, CI variables
19
+ 4. **Testing support** - Easy mocking via module aliases
20
+
21
+ ## Core Pattern
22
+
23
+ ### Environment Schema (`src/lib/env.ts`)
24
+
25
+ ```typescript
26
+ import { z } from "zod";
27
+
28
+ /**
29
+ * Environment variable schema with Zod validation.
30
+ * Variables are validated at module load time.
31
+ */
32
+ const envSchema = z.object({
33
+ // Required variables
34
+ EXPO_PUBLIC_API_URL: z.string().url(),
35
+ EXPO_PUBLIC_APP_ENV: z.enum(["development", "staging", "production"]),
36
+
37
+ // Optional variables with defaults
38
+ EXPO_PUBLIC_SENTRY_DSN: z.string().optional(),
39
+ EXPO_PUBLIC_FEATURE_FLAG: z
40
+ .string()
41
+ .transform(v => v === "true")
42
+ .default("false"),
43
+ });
44
+
45
+ /**
46
+ * Validated environment configuration.
47
+ * Throws at module load if validation fails.
48
+ */
49
+ export const env = envSchema.parse(process.env);
50
+
51
+ /**
52
+ * Type-safe environment configuration.
53
+ */
54
+ export type Env = z.infer<typeof envSchema>;
55
+ ```
56
+
57
+ ### Usage in Components/Hooks
58
+
59
+ ```typescript
60
+ import { env } from "@/lib/env";
61
+
62
+ // Full autocomplete and type safety
63
+ const apiUrl = env.EXPO_PUBLIC_API_URL; // string
64
+ const isDev = env.EXPO_PUBLIC_APP_ENV === "development"; // boolean
65
+ ```
66
+
67
+ ## Build-Time Validation (`app.config.ts`)
68
+
69
+ For variables needed during the build process, validate in `app.config.ts`:
70
+
71
+ ```javascript
72
+ // app.config.ts
73
+ const { z } = require("zod");
74
+
75
+ const buildEnvSchema = z.object({
76
+ EXPO_PUBLIC_API_URL: z.string().url(),
77
+ EXPO_PUBLIC_APP_ENV: z.enum(["development", "staging", "production"]),
78
+ // Build-only secrets (not exposed to client)
79
+ SENTRY_AUTH_TOKEN: z.string().optional(),
80
+ });
81
+
82
+ // Throws during `eas build` if invalid
83
+ const env = buildEnvSchema.parse(process.env);
84
+
85
+ module.exports = {
86
+ name: "MyApp",
87
+ slug: "my-app",
88
+ extra: {
89
+ apiUrl: env.EXPO_PUBLIC_API_URL,
90
+ appEnv: env.EXPO_PUBLIC_APP_ENV,
91
+ },
92
+ };
93
+ ```
94
+
95
+ ## Variable Sources
96
+
97
+ Environment variables arrive in `process.env` from multiple sources:
98
+
99
+ | Source | When Available | How Set |
100
+ |--------|----------------|---------|
101
+ | `.env.local` | Local dev | Expo CLI auto-loads |
102
+ | `.env.development` | Local dev | Copied to `.env.local` via npm script |
103
+ | `eas.json` env | EAS Build | `build.production.env` section |
104
+ | EAS Secrets | EAS Build | `eas secret:create` |
105
+ | CI Variables | CI builds | GitHub Actions / GitLab CI settings |
106
+
107
+ The Zod pattern validates `process.env` directly - it doesn't care how variables got there.
108
+
109
+ ## Testing Pattern
110
+
111
+ ### Jest Setup (`jest.setup.ts`)
112
+
113
+ ```typescript
114
+ // Mock the env module for all tests
115
+ jest.mock("@/lib/env", () => ({
116
+ env: {
117
+ EXPO_PUBLIC_API_URL: "https://test.example.com",
118
+ EXPO_PUBLIC_APP_ENV: "development",
119
+ EXPO_PUBLIC_SENTRY_DSN: undefined,
120
+ EXPO_PUBLIC_FEATURE_FLAG: false,
121
+ },
122
+ }));
123
+ ```
124
+
125
+ ### Override in Specific Tests
126
+
127
+ ```typescript
128
+ import { env } from "@/lib/env";
129
+
130
+ jest.mock("@/lib/env");
131
+
132
+ describe("ProductionFeature", () => {
133
+ beforeEach(() => {
134
+ (env as jest.Mocked<typeof env>).EXPO_PUBLIC_APP_ENV = "production";
135
+ });
136
+
137
+ it("should behave differently in production", () => {
138
+ // Test production-specific behavior
139
+ });
140
+ });
141
+ ```
142
+
143
+ ## ESLint Enforcement
144
+
145
+ This pattern is enforced by ESLint's `no-restricted-syntax` rule in `eslint.config.mjs`:
146
+
147
+ ```javascript
148
+ "no-restricted-syntax": [
149
+ "error",
150
+ {
151
+ selector: "MemberExpression[object.name='process'][property.name='env']",
152
+ message: "Direct process.env access is forbidden. Import { env } from '@/lib/env' instead.",
153
+ },
154
+ ],
155
+ ```
156
+
157
+ **Exceptions** (files allowed to use `process.env`):
158
+ - `lib/env.ts` - The env validation module itself
159
+ - `app.config.ts` - Expo build config
160
+ - `codegen.ts` - GraphQL codegen config
161
+ - `playwright.config.ts` - E2E test config
162
+ - `lighthouserc.js` - Lighthouse CI config
163
+
164
+ ## Core Rules
165
+
166
+ ### 1. Always Prefix with EXPO_PUBLIC_
167
+
168
+ Variables without this prefix are not available in client code:
169
+
170
+ ```typescript
171
+ // CORRECT - available in client
172
+ EXPO_PUBLIC_API_URL=https://api.example.com
173
+
174
+ // INCORRECT - only available at build time
175
+ API_URL=https://api.example.com
176
+ ```
177
+
178
+ ### 2. Never Access process.env Directly
179
+
180
+ Always use the validated `env` object:
181
+
182
+ ```typescript
183
+ // CORRECT - type-safe, validated
184
+ import { env } from "@/lib/env";
185
+ const url = env.EXPO_PUBLIC_API_URL;
186
+
187
+ // INCORRECT - untyped, unvalidated
188
+ const url = process.env.EXPO_PUBLIC_API_URL;
189
+ ```
190
+
191
+ ### 3. Validate Early, Fail Fast
192
+
193
+ Validation happens at module load. If a required variable is missing, the app fails immediately with a clear error rather than at runtime.
194
+
195
+ ### 4. Use Transforms for Non-String Types
196
+
197
+ Environment variables are always strings. Use Zod transforms:
198
+
199
+ ```typescript
200
+ const envSchema = z.object({
201
+ // Boolean from string
202
+ EXPO_PUBLIC_DEBUG: z
203
+ .string()
204
+ .transform(v => v === "true")
205
+ .default("false"),
206
+
207
+ // Number from string
208
+ EXPO_PUBLIC_TIMEOUT_MS: z
209
+ .string()
210
+ .transform(v => parseInt(v, 10))
211
+ .default("5000"),
212
+
213
+ // Array from comma-separated string
214
+ EXPO_PUBLIC_ALLOWED_HOSTS: z
215
+ .string()
216
+ .transform(v => v.split(",").map(s => s.trim()))
217
+ .default(""),
218
+ });
219
+ ```
220
+
221
+ ### 5. Separate Client vs Build-Only Variables
222
+
223
+ Keep sensitive build-time variables out of the client schema:
224
+
225
+ ```typescript
226
+ // Client variables (embedded in JS bundle)
227
+ const clientSchema = z.object({
228
+ EXPO_PUBLIC_API_URL: z.string().url(),
229
+ });
230
+
231
+ // Build-only variables (NOT in bundle)
232
+ const buildSchema = z.object({
233
+ SENTRY_AUTH_TOKEN: z.string(),
234
+ EAS_PROJECT_ID: z.string(),
235
+ });
236
+ ```
237
+
238
+ ## File Organization
239
+
240
+ ```
241
+ src/
242
+ lib/
243
+ env.ts # Main env schema and exports
244
+ app.config.ts # Build-time validation (if needed)
245
+ .env.localhost # Local development (git-ignored)
246
+ .env.development # Development environment
247
+ .env.staging # Staging environment
248
+ .env.production # Production environment
249
+ ```
250
+
251
+ ## Detailed Reference
252
+
253
+ For comprehensive patterns, transforms, and testing examples:
254
+
255
+ - **[references/validation-patterns.md](references/validation-patterns.md)** - Advanced Zod schemas, transforms, and refinements
256
+
257
+ ## Anti-Patterns to Avoid
258
+
259
+ ### Never use process.env directly in components
260
+
261
+ ```typescript
262
+ // WRONG - untyped, could be undefined
263
+ const Component = () => {
264
+ const url = process.env.EXPO_PUBLIC_API_URL;
265
+ // url is string | undefined, no validation
266
+ };
267
+
268
+ // CORRECT - validated and typed
269
+ import { env } from "@/lib/env";
270
+ const Component = () => {
271
+ const url = env.EXPO_PUBLIC_API_URL;
272
+ // url is string, guaranteed to be valid URL
273
+ };
274
+ ```
275
+
276
+ ### Never skip validation for "simple" variables
277
+
278
+ ```typescript
279
+ // WRONG - skipping validation
280
+ export const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3000";
281
+
282
+ // CORRECT - always validate
283
+ const envSchema = z.object({
284
+ EXPO_PUBLIC_API_URL: z.string().url().default("http://localhost:3000"),
285
+ });
286
+ export const { EXPO_PUBLIC_API_URL: API_URL } = envSchema.parse(process.env);
287
+ ```
288
+
289
+ ### Never store secrets in EXPO_PUBLIC_ variables
290
+
291
+ ```typescript
292
+ // WRONG - secrets exposed in client bundle
293
+ EXPO_PUBLIC_API_SECRET=super-secret-key
294
+
295
+ // CORRECT - secrets only at build time, passed securely
296
+ SENTRY_AUTH_TOKEN=secret # Build-only, not in bundle
297
+ ```
298
+
299
+ ## Validation Checklist
300
+
301
+ When adding or modifying environment variables:
302
+
303
+ - [ ] Variable is prefixed with `EXPO_PUBLIC_` (if needed in client code)
304
+ - [ ] Variable is added to the Zod schema in `src/lib/env.ts`
305
+ - [ ] Appropriate Zod type/transform is used (url, enum, boolean transform, etc.)
306
+ - [ ] Default value provided for optional variables
307
+ - [ ] Jest mock updated in `jest.setup.ts`
308
+ - [ ] Variable documented in `.env.example` or `.env.development`
309
+ - [ ] Sensitive values use EAS Secrets, not `.env` files
@@ -0,0 +1,417 @@
1
+ # Environment Validation Patterns
2
+
3
+ Advanced Zod patterns for environment variable validation in Expo/React Native.
4
+
5
+ ## Complete Schema Example
6
+
7
+ ```typescript
8
+ import { z } from "zod";
9
+
10
+ /**
11
+ * Transforms a string "true"/"false" to boolean.
12
+ */
13
+ const booleanString = z
14
+ .string()
15
+ .transform(v => v.toLowerCase() === "true")
16
+ .default("false");
17
+
18
+ /**
19
+ * Transforms a string to number with validation.
20
+ */
21
+ const numberString = (defaultValue: number) =>
22
+ z
23
+ .string()
24
+ .transform(v => {
25
+ const parsed = parseInt(v, 10);
26
+ if (isNaN(parsed)) {
27
+ throw new Error(`Invalid number: ${v}`);
28
+ }
29
+ return parsed;
30
+ })
31
+ .default(String(defaultValue));
32
+
33
+ /**
34
+ * Transforms comma-separated string to array.
35
+ */
36
+ const arrayString = z
37
+ .string()
38
+ .transform(v => (v ? v.split(",").map(s => s.trim()) : []))
39
+ .default("");
40
+
41
+ /**
42
+ * Complete environment schema.
43
+ */
44
+ const envSchema = z.object({
45
+ // Required strings
46
+ EXPO_PUBLIC_API_URL: z.string().url(),
47
+ EXPO_PUBLIC_APP_ENV: z.enum(["development", "staging", "production"]),
48
+
49
+ // Optional strings
50
+ EXPO_PUBLIC_SENTRY_DSN: z.string().url().optional(),
51
+ EXPO_PUBLIC_ANALYTICS_ID: z.string().optional(),
52
+
53
+ // Booleans (from string)
54
+ EXPO_PUBLIC_DEBUG_MODE: booleanString,
55
+ EXPO_PUBLIC_FEATURE_NEW_UI: booleanString,
56
+
57
+ // Numbers (from string)
58
+ EXPO_PUBLIC_API_TIMEOUT_MS: numberString(5000),
59
+ EXPO_PUBLIC_MAX_RETRIES: numberString(3),
60
+
61
+ // Arrays (from comma-separated string)
62
+ EXPO_PUBLIC_ALLOWED_ORIGINS: arrayString,
63
+
64
+ // Conditional/derived
65
+ EXPO_PUBLIC_LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
66
+ });
67
+
68
+ export const env = envSchema.parse(process.env);
69
+ export type Env = z.infer<typeof envSchema>;
70
+ ```
71
+
72
+ ## Common Transforms
73
+
74
+ ### Boolean from String
75
+
76
+ ```typescript
77
+ // Handles "true", "TRUE", "True", etc.
78
+ const booleanEnv = z
79
+ .string()
80
+ .transform(v => v.toLowerCase() === "true")
81
+ .default("false");
82
+
83
+ // Usage
84
+ EXPO_PUBLIC_FEATURE_FLAG: booleanEnv,
85
+ ```
86
+
87
+ ### Number from String
88
+
89
+ ```typescript
90
+ // With validation
91
+ const numberEnv = z.string().transform((v, ctx) => {
92
+ const parsed = parseInt(v, 10);
93
+ if (isNaN(parsed)) {
94
+ ctx.addIssue({
95
+ code: z.ZodIssueCode.custom,
96
+ message: "Must be a valid number",
97
+ });
98
+ return z.NEVER;
99
+ }
100
+ return parsed;
101
+ });
102
+
103
+ // With default
104
+ const numberWithDefault = (def: number) =>
105
+ z
106
+ .string()
107
+ .optional()
108
+ .transform(v => (v ? parseInt(v, 10) : def));
109
+ ```
110
+
111
+ ### Array from Comma-Separated String
112
+
113
+ ```typescript
114
+ const arrayEnv = z
115
+ .string()
116
+ .transform(v =>
117
+ v
118
+ .split(",")
119
+ .map(s => s.trim())
120
+ .filter(Boolean)
121
+ )
122
+ .default("");
123
+
124
+ // Example: "host1.com, host2.com" -> ["host1.com", "host2.com"]
125
+ ```
126
+
127
+ ### URL with Protocol Validation
128
+
129
+ ```typescript
130
+ const httpUrl = z.string().url().refine(
131
+ url => url.startsWith("https://") || url.startsWith("http://"),
132
+ { message: "Must be an HTTP(S) URL" }
133
+ );
134
+
135
+ // HTTPS only in production
136
+ const secureUrl = z.string().url().refine(
137
+ url => {
138
+ if (process.env.EXPO_PUBLIC_APP_ENV === "production") {
139
+ return url.startsWith("https://");
140
+ }
141
+ return true;
142
+ },
143
+ { message: "Production URLs must use HTTPS" }
144
+ );
145
+ ```
146
+
147
+ ## Environment-Specific Defaults
148
+
149
+ ```typescript
150
+ const getDefaultApiUrl = () => {
151
+ switch (process.env.EXPO_PUBLIC_APP_ENV) {
152
+ case "production":
153
+ return "https://api.example.com";
154
+ case "staging":
155
+ return "https://staging-api.example.com";
156
+ default:
157
+ return "http://localhost:3000";
158
+ }
159
+ };
160
+
161
+ const envSchema = z.object({
162
+ EXPO_PUBLIC_API_URL: z.string().url().default(getDefaultApiUrl()),
163
+ });
164
+ ```
165
+
166
+ ## Refinements and Cross-Field Validation
167
+
168
+ ```typescript
169
+ const envSchema = z
170
+ .object({
171
+ EXPO_PUBLIC_APP_ENV: z.enum(["development", "staging", "production"]),
172
+ EXPO_PUBLIC_DEBUG_MODE: booleanString,
173
+ EXPO_PUBLIC_SENTRY_DSN: z.string().url().optional(),
174
+ })
175
+ .refine(
176
+ data => {
177
+ // Sentry DSN required in production
178
+ if (data.EXPO_PUBLIC_APP_ENV === "production") {
179
+ return !!data.EXPO_PUBLIC_SENTRY_DSN;
180
+ }
181
+ return true;
182
+ },
183
+ {
184
+ message: "EXPO_PUBLIC_SENTRY_DSN is required in production",
185
+ path: ["EXPO_PUBLIC_SENTRY_DSN"],
186
+ }
187
+ )
188
+ .refine(
189
+ data => {
190
+ // Debug mode forbidden in production
191
+ if (data.EXPO_PUBLIC_APP_ENV === "production") {
192
+ return !data.EXPO_PUBLIC_DEBUG_MODE;
193
+ }
194
+ return true;
195
+ },
196
+ {
197
+ message: "Debug mode cannot be enabled in production",
198
+ path: ["EXPO_PUBLIC_DEBUG_MODE"],
199
+ }
200
+ );
201
+ ```
202
+
203
+ ## Error Handling
204
+
205
+ ### Custom Error Messages
206
+
207
+ ```typescript
208
+ const envSchema = z.object({
209
+ EXPO_PUBLIC_API_URL: z
210
+ .string({
211
+ required_error: "API URL is required. Set EXPO_PUBLIC_API_URL in your .env file.",
212
+ })
213
+ .url({
214
+ message: "API URL must be a valid URL (e.g., https://api.example.com)",
215
+ }),
216
+ });
217
+ ```
218
+
219
+ ### Graceful Error Formatting
220
+
221
+ ```typescript
222
+ const parseEnv = () => {
223
+ const result = envSchema.safeParse(process.env);
224
+
225
+ if (!result.success) {
226
+ const formatted = result.error.issues
227
+ .map(issue => ` - ${issue.path.join(".")}: ${issue.message}`)
228
+ .join("\n");
229
+
230
+ throw new Error(`Environment validation failed:\n${formatted}`);
231
+ }
232
+
233
+ return result.data;
234
+ };
235
+
236
+ export const env = parseEnv();
237
+ ```
238
+
239
+ ## Testing Patterns
240
+
241
+ ### Complete Mock Setup
242
+
243
+ ```typescript
244
+ // jest.setup.ts
245
+ const mockEnv = {
246
+ EXPO_PUBLIC_API_URL: "https://test.example.com",
247
+ EXPO_PUBLIC_APP_ENV: "development" as const,
248
+ EXPO_PUBLIC_DEBUG_MODE: false,
249
+ EXPO_PUBLIC_FEATURE_NEW_UI: true,
250
+ EXPO_PUBLIC_API_TIMEOUT_MS: 5000,
251
+ EXPO_PUBLIC_MAX_RETRIES: 3,
252
+ EXPO_PUBLIC_ALLOWED_ORIGINS: ["localhost"],
253
+ EXPO_PUBLIC_LOG_LEVEL: "info" as const,
254
+ EXPO_PUBLIC_SENTRY_DSN: undefined,
255
+ EXPO_PUBLIC_ANALYTICS_ID: undefined,
256
+ };
257
+
258
+ jest.mock("@/lib/env", () => ({
259
+ env: mockEnv,
260
+ }));
261
+ ```
262
+
263
+ ### Override for Specific Tests
264
+
265
+ ```typescript
266
+ // In test file
267
+ import { env } from "@/lib/env";
268
+
269
+ jest.mock("@/lib/env");
270
+
271
+ const mockEnv = env as jest.Mocked<typeof env>;
272
+
273
+ describe("Feature with production behavior", () => {
274
+ beforeEach(() => {
275
+ mockEnv.EXPO_PUBLIC_APP_ENV = "production";
276
+ mockEnv.EXPO_PUBLIC_DEBUG_MODE = false;
277
+ });
278
+
279
+ afterEach(() => {
280
+ mockEnv.EXPO_PUBLIC_APP_ENV = "development";
281
+ });
282
+
283
+ it("should disable debug features in production", () => {
284
+ // Test production-specific behavior
285
+ });
286
+ });
287
+ ```
288
+
289
+ ### Testing Validation Itself
290
+
291
+ ```typescript
292
+ // env.test.ts
293
+ describe("Environment Schema Validation", () => {
294
+ const originalEnv = process.env;
295
+
296
+ beforeEach(() => {
297
+ jest.resetModules();
298
+ process.env = { ...originalEnv };
299
+ });
300
+
301
+ afterAll(() => {
302
+ process.env = originalEnv;
303
+ });
304
+
305
+ it("should throw for missing required variables", () => {
306
+ delete process.env.EXPO_PUBLIC_API_URL;
307
+
308
+ expect(() => {
309
+ require("@/lib/env");
310
+ }).toThrow(/EXPO_PUBLIC_API_URL/);
311
+ });
312
+
313
+ it("should throw for invalid URL format", () => {
314
+ process.env.EXPO_PUBLIC_API_URL = "not-a-url";
315
+
316
+ expect(() => {
317
+ require("@/lib/env");
318
+ }).toThrow(/url/i);
319
+ });
320
+
321
+ it("should use defaults for optional variables", () => {
322
+ process.env.EXPO_PUBLIC_API_URL = "https://api.example.com";
323
+ process.env.EXPO_PUBLIC_APP_ENV = "development";
324
+
325
+ const { env } = require("@/lib/env");
326
+
327
+ expect(env.EXPO_PUBLIC_DEBUG_MODE).toBe(false);
328
+ expect(env.EXPO_PUBLIC_API_TIMEOUT_MS).toBe(5000);
329
+ });
330
+ });
331
+ ```
332
+
333
+ ## EAS Build Integration
334
+
335
+ ### eas.json Configuration
336
+
337
+ ```json
338
+ {
339
+ "build": {
340
+ "development": {
341
+ "env": {
342
+ "EXPO_PUBLIC_APP_ENV": "development",
343
+ "EXPO_PUBLIC_API_URL": "https://dev-api.example.com"
344
+ }
345
+ },
346
+ "staging": {
347
+ "env": {
348
+ "EXPO_PUBLIC_APP_ENV": "staging",
349
+ "EXPO_PUBLIC_API_URL": "https://staging-api.example.com"
350
+ }
351
+ },
352
+ "production": {
353
+ "env": {
354
+ "EXPO_PUBLIC_APP_ENV": "production",
355
+ "EXPO_PUBLIC_API_URL": "https://api.example.com"
356
+ }
357
+ }
358
+ }
359
+ }
360
+ ```
361
+
362
+ ### EAS Secrets for Sensitive Values
363
+
364
+ ```bash
365
+ # Set secrets via CLI (not in eas.json)
366
+ eas secret:create --name SENTRY_AUTH_TOKEN --value "your-token"
367
+ eas secret:create --name GOOGLE_SERVICES_JSON --type file --value ./google-services.json
368
+ ```
369
+
370
+ ## app.config.ts Build-Time Validation
371
+
372
+ ```javascript
373
+ // app.config.ts
374
+ const { z } = require("zod");
375
+
376
+ // Validate at build time
377
+ const buildSchema = z.object({
378
+ EXPO_PUBLIC_API_URL: z.string().url(),
379
+ EXPO_PUBLIC_APP_ENV: z.enum(["development", "staging", "production"]),
380
+ // Build-only (not exposed to client)
381
+ SENTRY_AUTH_TOKEN: z.string().optional(),
382
+ EAS_PROJECT_ID: z.string().optional(),
383
+ });
384
+
385
+ const result = buildSchema.safeParse(process.env);
386
+
387
+ if (!result.success) {
388
+ console.error("Build environment validation failed:");
389
+ result.error.issues.forEach(issue => {
390
+ console.error(` - ${issue.path.join(".")}: ${issue.message}`);
391
+ });
392
+ throw new Error("Invalid build environment");
393
+ }
394
+
395
+ const env = result.data;
396
+
397
+ module.exports = {
398
+ name: "MyApp",
399
+ slug: "my-app",
400
+ version: "1.0.0",
401
+ extra: {
402
+ eas: {
403
+ projectId: env.EAS_PROJECT_ID,
404
+ },
405
+ },
406
+ hooks: {
407
+ postPublish: [
408
+ {
409
+ file: "sentry-expo/upload-sourcemaps",
410
+ config: {
411
+ authToken: env.SENTRY_AUTH_TOKEN,
412
+ },
413
+ },
414
+ ],
415
+ },
416
+ };
417
+ ```