vybekiit 0.7.26 → 0.7.27

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 (232) hide show
  1. package/dist/bin.js +3891 -1301
  2. package/dist/global-skills/aws-cdk/SKILL.md +19 -5
  3. package/dist/global-skills/aws-cdk/references/fast-deployments.md +191 -0
  4. package/dist/global-skills/aws-cdk/references/troubleshooting-deployment.md +16 -0
  5. package/dist/global-skills/aws-cloudformation/SKILL.md +16 -26
  6. package/dist/global-skills/aws-cloudformation/references/check-cloudformation-template-compliance.script.md +7 -3
  7. package/dist/global-skills/aws-cloudformation/references/cloudformation-language-server.md +177 -0
  8. package/dist/global-skills/aws-cloudformation/references/cloudformation-pre-deploy-validation.script.md +8 -2
  9. package/dist/global-skills/aws-cloudformation/references/persist-template-context.script.md +5 -8
  10. package/dist/global-skills/aws-cloudformation/references/retrieve-template-context.script.md +1 -1
  11. package/dist/global-skills/aws-cloudformation/references/security-considerations.md +51 -0
  12. package/dist/global-skills/aws-cloudformation/references/troubleshoot-failed-stack.script.md +138 -0
  13. package/dist/global-skills/aws-cloudformation/references/{validate-cloudformation-template.script.md → validate-with-cfn-lint.script.md} +15 -27
  14. package/dist/global-skills/aws-cloudformation/references/validate-with-cloudformation-validate.script.md +181 -0
  15. package/dist/global-skills/aws-cloudformation/references/validation-tool-selection.md +44 -0
  16. package/dist/global-skills/aws-serverless/SKILL.md +9 -1
  17. package/dist/global-skills/aws-serverless/references/architecture.md +3 -1
  18. package/dist/global-skills/aws-serverless/references/lambda.md +3 -1
  19. package/dist/global-skills/aws-serverless/references/orchestration.md +1 -0
  20. package/dist/global-skills/better-auth-best-practices/SKILL.md +18 -8
  21. package/dist/global-skills/eas-app-stores/SKILL.md +31 -15
  22. package/dist/global-skills/eas-app-stores/agents/openai.yaml +2 -2
  23. package/dist/global-skills/eas-app-stores/references/ios-app-store.md +37 -32
  24. package/dist/global-skills/eas-app-stores/references/native-ios.md +167 -0
  25. package/dist/global-skills/eas-app-stores/references/play-store.md +3 -7
  26. package/dist/global-skills/eas-app-stores/references/testflight.md +39 -35
  27. package/dist/global-skills/eas-simulator/SKILL.md +48 -26
  28. package/dist/global-skills/eas-simulator/references/controllers.md +32 -3
  29. package/dist/global-skills/eas-simulator/references/run-your-app.md +34 -4
  30. package/dist/global-skills/eas-simulator/references/troubleshooting.md +8 -4
  31. package/dist/global-skills/eas-update/SKILL.md +146 -0
  32. package/dist/global-skills/eas-update/agents/openai.yaml +4 -0
  33. package/dist/global-skills/expo-animation/RECIPES.md +2 -2
  34. package/dist/global-skills/expo-animation/SKILL.md +9 -2
  35. package/dist/global-skills/expo-brownfield/SKILL.md +18 -11
  36. package/dist/global-skills/expo-brownfield/agents/openai.yaml +2 -2
  37. package/dist/global-skills/expo-brownfield/references/brownfield-integrated.md +94 -69
  38. package/dist/global-skills/expo-brownfield/references/brownfield-isolated.md +40 -42
  39. package/dist/global-skills/expo-brownfield/references/comparison.md +5 -5
  40. package/dist/global-skills/expo-brownfield/references/feature-integration.md +163 -0
  41. package/dist/global-skills/expo-brownfield/references/troubleshooting.md +17 -17
  42. package/dist/global-skills/expo-brownfield/references/version-compatibility.md +40 -0
  43. package/dist/global-skills/expo-data-fetching/SKILL.md +27 -6
  44. package/dist/global-skills/expo-design-system/SKILL.md +27 -7
  45. package/dist/global-skills/expo-design-system/references/audit.md +7 -2
  46. package/dist/global-skills/expo-design-system/references/native-slop.md +74 -0
  47. package/dist/global-skills/expo-examples/SKILL.md +0 -1
  48. package/dist/global-skills/expo-examples/references/catalog.md +1 -1
  49. package/dist/global-skills/expo-migrate-module/SKILL.md +21 -10
  50. package/dist/global-skills/expo-migrate-module/references/compatibility.md +80 -23
  51. package/dist/global-skills/expo-migrate-module/references/migration-map.md +162 -11
  52. package/dist/global-skills/expo-native-ui/SKILL.md +25 -16
  53. package/dist/global-skills/expo-native-ui/agents/openai.yaml +2 -2
  54. package/dist/global-skills/expo-native-ui/references/controls.md +5 -46
  55. package/dist/global-skills/expo-native-ui/references/icons.md +21 -2
  56. package/dist/global-skills/expo-native-ui/references/media.md +15 -20
  57. package/dist/global-skills/expo-native-ui/references/visual-effects.md +12 -11
  58. package/dist/global-skills/expo-overview/SKILL.md +17 -12
  59. package/dist/global-skills/expo-router/SKILL.md +5 -3
  60. package/dist/global-skills/expo-router/references/tabs.md +5 -5
  61. package/dist/global-skills/expo-upgrade/SKILL.md +3 -1
  62. package/dist/global-skills/expo-web-to-native/references/false-friends.md +2 -2
  63. package/dist/global-skills/expo-web-to-native/references/native-patterns.md +1 -1
  64. package/dist/global-skills/firebase-ai-logic-basics/SKILL.md +13 -16
  65. package/dist/global-skills/firebase-ai-logic-basics/references/ios_setup.md +4 -5
  66. package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_android.md +4 -4
  67. package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_web.md +3 -3
  68. package/dist/global-skills/firebase-auth-basics/SKILL.md +11 -6
  69. package/dist/global-skills/firebase-auth-basics/references/client_sdk_android.md +4 -5
  70. package/dist/global-skills/firebase-auth-basics/references/client_sdk_web.md +3 -3
  71. package/dist/global-skills/firebase-auth-basics/references/flutter_setup.md +24 -25
  72. package/dist/global-skills/firebase-auth-basics/references/security_rules.md +4 -2
  73. package/dist/global-skills/firebase-crashlytics/references/android_setup.md +7 -4
  74. package/dist/global-skills/firebase-crashlytics/references/ios_setup.md +2 -3
  75. package/dist/global-skills/firebase-data-connect/SKILL.md +2 -1
  76. package/dist/global-skills/firebase-data-connect/examples.md +4 -4
  77. package/dist/global-skills/firebase-data-connect/reference/config.md +5 -4
  78. package/dist/global-skills/firebase-data-connect/reference/realtime.md +1 -2
  79. package/dist/global-skills/firebase-data-connect/reference/sdk_flutter.md +2 -2
  80. package/dist/global-skills/firebase-data-connect/reference/sdk_ios.md +2 -2
  81. package/dist/global-skills/firebase-data-connect/reference/sdk_web.md +17 -6
  82. package/dist/global-skills/firebase-data-connect/reference/security.md +5 -5
  83. package/dist/global-skills/firebase-data-connect/templates.md +2 -1
  84. package/dist/global-skills/firebase-firestore/SKILL.md +20 -8
  85. package/dist/global-skills/firebase-firestore/references/enterprise/android_sdk_usage.md +5 -4
  86. package/dist/global-skills/firebase-firestore/references/enterprise/data_model.md +12 -3
  87. package/dist/global-skills/firebase-firestore/references/enterprise/indexes.md +16 -18
  88. package/dist/global-skills/firebase-firestore/references/enterprise/provisioning.md +1 -1
  89. package/dist/global-skills/firebase-firestore/references/enterprise/python_sdk_usage.md +5 -1
  90. package/dist/global-skills/firebase-firestore/references/enterprise/web_sdk_usage.md +7 -7
  91. package/dist/global-skills/firebase-firestore/references/standard/android_sdk_usage.md +5 -5
  92. package/dist/global-skills/firebase-firestore/references/standard/flutter_setup.md +4 -4
  93. package/dist/global-skills/firebase-firestore/references/standard/indexes.md +16 -18
  94. package/dist/global-skills/firebase-firestore/references/standard/provisioning.md +1 -1
  95. package/dist/global-skills/firebase-remote-config-basics/SKILL.md +0 -5
  96. package/dist/global-skills/firebase-remote-config-basics/references/android_setup.md +36 -8
  97. package/dist/global-skills/firebase-remote-config-basics/references/ios_setup.md +1 -7
  98. package/dist/global-skills/firebase-security-rules-auditor/SKILL.md +17 -6
  99. package/dist/global-skills/{firebase-firestore/references/standard/security_rules.md → firestore-rules-creation/SKILL.md} +24 -13
  100. package/dist/global-skills/grow-my-customers/SKILL.md +23 -0
  101. package/dist/global-skills/instrument-feature-flags/SKILL.md +25 -25
  102. package/dist/global-skills/instrument-feature-flags/references/adding-feature-flag-code.md +141 -285
  103. package/dist/global-skills/instrument-feature-flags/references/android.md +6 -15
  104. package/dist/global-skills/instrument-feature-flags/references/api.md +4 -11
  105. package/dist/global-skills/instrument-feature-flags/references/best-practices.md +1 -13
  106. package/dist/global-skills/instrument-feature-flags/references/django.md +14 -27
  107. package/dist/global-skills/instrument-feature-flags/references/dotnet.md +20 -79
  108. package/dist/global-skills/instrument-feature-flags/references/elixir.md +1 -9
  109. package/dist/global-skills/instrument-feature-flags/references/flask.md +13 -13
  110. package/dist/global-skills/instrument-feature-flags/references/flutter.md +3 -24
  111. package/dist/global-skills/instrument-feature-flags/references/go.md +3 -15
  112. package/dist/global-skills/instrument-feature-flags/references/ios.md +4 -17
  113. package/dist/global-skills/instrument-feature-flags/references/java.md +5 -13
  114. package/dist/global-skills/instrument-feature-flags/references/laravel.md +13 -17
  115. package/dist/global-skills/instrument-feature-flags/references/next-js.md +25 -32
  116. package/dist/global-skills/instrument-feature-flags/references/nodejs.md +8 -15
  117. package/dist/global-skills/instrument-feature-flags/references/php.md +1 -15
  118. package/dist/global-skills/instrument-feature-flags/references/python.md +2 -15
  119. package/dist/global-skills/instrument-feature-flags/references/react-native.md +13 -15
  120. package/dist/global-skills/instrument-feature-flags/references/react.md +17 -21
  121. package/dist/global-skills/instrument-feature-flags/references/ruby-on-rails.md +37 -83
  122. package/dist/global-skills/instrument-feature-flags/references/ruby.md +2 -15
  123. package/dist/global-skills/instrument-feature-flags/references/rust.md +13 -25
  124. package/dist/global-skills/instrument-feature-flags/references/usage.md +14 -63
  125. package/dist/global-skills/instrument-feature-flags/references/web.md +9 -14
  126. package/dist/global-skills/instrument-product-analytics/SKILL.md +29 -29
  127. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-hybrid.md +3 -1
  128. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-ssr.md +3 -1
  129. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-static.md +3 -1
  130. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-view-transitions.md +3 -1
  131. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-ruby-on-rails.md +3 -1
  132. package/dist/global-skills/instrument-product-analytics/references/android.md +72 -107
  133. package/dist/global-skills/instrument-product-analytics/references/angular.md +26 -28
  134. package/dist/global-skills/instrument-product-analytics/references/astro.md +13 -24
  135. package/dist/global-skills/instrument-product-analytics/references/configuration.md +45 -63
  136. package/dist/global-skills/instrument-product-analytics/references/django.md +14 -27
  137. package/dist/global-skills/instrument-product-analytics/references/dotnet.md +20 -79
  138. package/dist/global-skills/instrument-product-analytics/references/elixir.md +47 -49
  139. package/dist/global-skills/instrument-product-analytics/references/flask.md +13 -13
  140. package/dist/global-skills/instrument-product-analytics/references/flutter.md +60 -90
  141. package/dist/global-skills/instrument-product-analytics/references/go.md +17 -56
  142. package/dist/global-skills/instrument-product-analytics/references/identify-users.md +15 -15
  143. package/dist/global-skills/instrument-product-analytics/references/ios.md +11 -15
  144. package/dist/global-skills/instrument-product-analytics/references/laravel.md +13 -17
  145. package/dist/global-skills/instrument-product-analytics/references/next-js.md +25 -32
  146. package/dist/global-skills/instrument-product-analytics/references/nuxt-js-3-6.md +13 -27
  147. package/dist/global-skills/instrument-product-analytics/references/nuxt-js.md +14 -28
  148. package/dist/global-skills/instrument-product-analytics/references/php.md +33 -84
  149. package/dist/global-skills/instrument-product-analytics/references/posthog-python.md +229 -9
  150. package/dist/global-skills/instrument-product-analytics/references/python.md +415 -106
  151. package/dist/global-skills/instrument-product-analytics/references/react-native.md +161 -155
  152. package/dist/global-skills/instrument-product-analytics/references/react-router-v6.md +12 -33
  153. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-data-mode.md +15 -33
  154. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md +12 -33
  155. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-framework-mode.md +26 -41
  156. package/dist/global-skills/instrument-product-analytics/references/ruby-on-rails.md +37 -83
  157. package/dist/global-skills/instrument-product-analytics/references/ruby.md +48 -108
  158. package/dist/global-skills/instrument-product-analytics/references/svelte.md +18 -24
  159. package/dist/global-skills/instrument-product-analytics/references/tanstack-start.md +17 -19
  160. package/dist/global-skills/instrument-product-analytics/references/usage.md +14 -63
  161. package/dist/global-skills/instrument-product-analytics/references/vue-js.md +29 -28
  162. package/dist/global-skills/manifest.json +8 -2
  163. package/dist/global-skills/mongodb-search-and-ai/SKILL.md +28 -37
  164. package/dist/global-skills/mongodb-search-and-ai/references/automated-embedding.md +438 -0
  165. package/dist/global-skills/mongodb-search-and-ai/references/hybrid-search.md +60 -4
  166. package/dist/global-skills/mongodb-search-and-ai/references/vector-search.md +46 -108
  167. package/dist/global-skills/neon/SKILL.md +207 -213
  168. package/dist/global-skills/neon/references/auth.md +12 -0
  169. package/dist/global-skills/neon/references/claimable-neon.md +10 -14
  170. package/dist/global-skills/neon/references/function-triggers.md +53 -0
  171. package/dist/global-skills/neon/references/logs-loki.md +61 -0
  172. package/dist/global-skills/neon/references/parse-env.md +32 -0
  173. package/dist/global-skills/neon/references/sdk.md +7 -0
  174. package/dist/global-skills/neon-ai-gateway/SKILL.md +14 -16
  175. package/dist/global-skills/neon-auth/SKILL.md +155 -0
  176. package/dist/global-skills/neon-auth/references/managed-auth.md +173 -0
  177. package/dist/global-skills/neon-auth/references/self-managed.md +25 -0
  178. package/dist/global-skills/neon-functions/SKILL.md +159 -84
  179. package/dist/global-skills/neon-functions/references/ai-sdk.md +4 -6
  180. package/dist/global-skills/neon-functions/references/function-triggers.md +249 -0
  181. package/dist/global-skills/neon-functions/references/mastra-studio.md +3 -3
  182. package/dist/global-skills/neon-functions/references/mcp.md +1 -1
  183. package/dist/global-skills/neon-functions/references/production-hardening.md +340 -0
  184. package/dist/global-skills/neon-functions/references/sse.md +8 -5
  185. package/dist/global-skills/neon-object-storage/SKILL.md +10 -11
  186. package/dist/global-skills/neon-postgres/SKILL.md +120 -17
  187. package/dist/global-skills/neon-postgres/references/full-text-search.md +99 -0
  188. package/dist/global-skills/neon-postgres/references/hybrid-search.md +90 -0
  189. package/dist/global-skills/neon-postgres/references/lakebase-search-drizzle.md +172 -0
  190. package/dist/global-skills/neon-postgres/references/vector-search.md +137 -0
  191. package/dist/global-skills/neon-postgres-branches/SKILL.md +3 -3
  192. package/dist/global-skills/neon-postgres-egress-optimizer/SKILL.md +1 -1
  193. package/dist/global-skills/onboarding/SKILL.md +8 -6
  194. package/dist/global-skills/resend/SKILL.md +4 -2
  195. package/dist/global-skills/resend/references/broadcasts.md +6 -1
  196. package/dist/global-skills/resend/references/receiving.md +29 -10
  197. package/dist/global-skills/resend/references/sending/email-management.md +14 -4
  198. package/dist/global-skills/resend/references/topics.md +9 -6
  199. package/dist/global-skills/resend/references/usage.md +117 -0
  200. package/dist/global-skills/resend/references/webhooks.md +59 -2
  201. package/dist/global-skills/stripe-best-practices/SKILL.md +35 -29
  202. package/dist/global-skills/stripe-best-practices/references/billing.md +9 -2
  203. package/dist/global-skills/stripe-best-practices/references/payments.md +4 -2
  204. package/dist/global-skills/stripe-best-practices/references/security.md +3 -1
  205. package/dist/global-skills/stripe-best-practices/references/tax.md +39 -20
  206. package/dist/global-skills/supabase/SKILL.md +6 -0
  207. package/dist/global-skills/use-railway/SKILL.md +42 -22
  208. package/dist/global-skills/use-railway/references/analyze-db.md +7 -6
  209. package/dist/global-skills/use-railway/references/cloud-agents.md +70 -0
  210. package/dist/global-skills/use-railway/references/configure.md +17 -2
  211. package/dist/global-skills/use-railway/references/databases.md +107 -0
  212. package/dist/global-skills/use-railway/references/deploy.md +5 -5
  213. package/dist/global-skills/use-railway/references/feature-flags.md +25 -13
  214. package/dist/global-skills/use-railway/references/iac.md +66 -77
  215. package/dist/global-skills/use-railway/references/operate.md +26 -3
  216. package/dist/global-skills/use-railway/references/request.md +31 -23
  217. package/dist/global-skills/use-railway/references/setup.md +16 -5
  218. package/dist/global-skills/use-railway/references/tracing.md +261 -0
  219. package/dist/global-skills/use-railway/references/usage.md +52 -0
  220. package/dist/global-skills/validate-my-idea/SKILL.md +54 -0
  221. package/dist/global-skills/{feedback → vybekiit-feedback}/SKILL.md +16 -12
  222. package/dist/global-skills/watch-my-app/SKILL.md +53 -0
  223. package/dist/global-skills/workers-best-practices/SKILL.md +36 -103
  224. package/dist/global-skills/workers-best-practices/references/configuration.md +139 -0
  225. package/dist/global-skills/workers-best-practices/references/platform-apis.md +51 -0
  226. package/dist/global-skills/workers-best-practices/references/{rules.md → runtime-patterns.md} +13 -137
  227. package/dist/global-skills/wrangler/SKILL.md +48 -901
  228. package/dist/global-skills/xcode-project-setup/scripts/xcode_spm_setup/Sources/main.swift +19 -15
  229. package/package.json +9 -8
  230. package/dist/global-skills/expo-native-ui/references/animations.md +0 -220
  231. package/dist/global-skills/firebase-firestore/references/enterprise/security_rules.md +0 -577
  232. package/dist/global-skills/workers-best-practices/references/review.md +0 -174
@@ -16,17 +16,17 @@ If a single team owns both layers, is comfortable with React Native tooling and
16
16
  | Platform | Artifact | Default location |
17
17
  | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
18
18
  | Android | `{group}:{libraryName}:{version}` AAR | Local Maven (`~/.m2`) by default; remote Maven also supported |
19
- | iOS | Set of `.xcframework`s — see [the iOS section below](#ios) for how `ios.buildReactNativeFromSource` (default `false` on SDK 56+) controls whether you get 5 frameworks or 2 — or a single Swift Package via `--package` | `./artifacts` |
19
+ | iOS | Set of `.xcframework`s (depends on source/prebuilt settings and package version), or a Swift Package via `--package`; see [iOS](#ios) | `./artifacts` |
20
20
 
21
21
  The JavaScript bundle is **embedded inside the artifact** in release builds, so the native app does not need Metro at runtime in production.
22
22
 
23
23
  ## Prerequisites
24
24
 
25
- - **Expo SDK 55 or later** — brownfield support, `expo-brownfield`, and the required runtime classes are only available on SDK 55+. Earlier SDKs will not work.
25
+ - **Expo SDK 55 or later for this Expo toolkit** — `expo-brownfield` was introduced in SDK 55. Match package versions and native requirements to the selected SDK; this is not a minimum for historical integrated setups.
26
26
  - **Node.js (LTS)** — runs JavaScript and the Expo CLI.
27
- - **Yarn** — manages JavaScript dependencies.
27
+ - The existing package manager and lockfile. Yarn is not required.
28
28
 
29
- Node and Yarn are only needed in the environment that _builds_ the artifact. The consuming native app does not need them.
29
+ Node and the JS package manager are only needed in the environment that _builds_ the artifact. The consuming native app does not need them.
30
30
 
31
31
  ---
32
32
 
@@ -35,10 +35,10 @@ Node and Yarn are only needed in the environment that _builds_ the artifact. The
35
35
  ### Create a new Expo project
36
36
 
37
37
  ```sh
38
- npx create-expo-app@latest my-project --template default@sdk-55
38
+ npx create-expo-app@latest my-project --template blank@latest
39
39
  ```
40
40
 
41
- **Pin to SDK 55 or later — earlier SDKs do not support brownfield.** The project can live in a separate repo or alongside the native app in a monorepo; it does not need to be inside the native project.
41
+ Use this current stable blank template for a small embedded feature after the [version/toolchain checks](./version-compatibility.md). If host constraints require another SDK, select its published template tag instead. Keep an existing producer and its entry point when present. The project can live in a separate repo or alongside the native app in a monorepo; it does not need to be inside the native project.
42
42
 
43
43
  ### Install expo-brownfield
44
44
 
@@ -47,7 +47,7 @@ cd my-project
47
47
  npx expo install expo-brownfield
48
48
  ```
49
49
 
50
- The plugin self-registers in `app.json` with defaults derived from your app config.
50
+ Check that the plugin registered in `app.json`; add it explicitly if the install command did not update the config (for example, with dynamic app configuration). Defaults derive from your app config.
51
51
 
52
52
  ### Check what the host app already ships
53
53
 
@@ -92,7 +92,7 @@ To override the auto-generated names, expand the plugin entry in `app.json`:
92
92
 
93
93
  ### Speed up iOS builds with prebuilt Expo modules
94
94
 
95
- Enable `expo-build-properties`'s `ios.usePrecompiledModules` so `pod install` downloads each Expo module as a prebuilt `.xcframework` instead of compiling it from source. `build:ios` detects those xcframeworks under `ios/Pods/` and bundles them into the Swift Package output alongside the brownfield framework, React, Hermes, and `ReactNativeDependencies`.
95
+ SDK 57 enables precompiled Expo modules by default. For a supported SDK where an explicit opt-in is needed, install `expo-build-properties` with `npx expo install expo-build-properties` and enable its `ios.usePrecompiledModules` so `pod install` downloads each Expo module as a prebuilt `.xcframework` instead of compiling it from source. `build:ios` detects those xcframeworks under `ios/Pods/` and bundles them into the Swift Package output alongside the brownfield framework, React, Hermes, and `ReactNativeDependencies`.
96
96
 
97
97
  ```json
98
98
  {
@@ -208,56 +208,52 @@ Not everything is fused: the React Native runtime, Kotlin stdlib, host-common li
208
208
  npx expo-brownfield build:ios
209
209
  ```
210
210
 
211
- Outputs to `./artifacts`. The set depends on the `ios.buildReactNativeFromSource` flag (set via `expo-build-properties`):
211
+ Outputs to `./artifacts`. Set `ios.buildReactNativeFromSource` on the **`expo-brownfield` plugin**; it applies the build-properties configuration itself and can override a separate `expo-build-properties` entry. The set depends on that setting and the installed package version:
212
212
 
213
- - **`buildReactNativeFromSource: false`** (default on SDK 56+) — React Native is consumed as a prebuilt binary, so `build:ios` emits five xcframeworks side-by-side: `{TargetName}.xcframework`, `React.xcframework`, `ReactNativeDependencies.xcframework`, `ExpoModulesJSI.xcframework`, and `hermesvm.xcframework`.
214
- - **`buildReactNativeFromSource: true`** (default on SDK 55, opt-in on SDK 56+) — React Native is compiled from source and statically linked into the brownfield framework, leaving two xcframeworks: `{TargetName}.xcframework` and `hermesvm.xcframework`.
213
+ - **`buildReactNativeFromSource: false`** (default on SDK 56+) — React Native is consumed as a prebuilt binary. A typical set includes: `{TargetName}.xcframework`, `React.xcframework`, `ReactNativeDependencies.xcframework`, `ExpoModulesJSI.xcframework`, and `hermesvm.xcframework`.
214
+ - **`buildReactNativeFromSource: true`** (default on SDK 55, opt-in on SDK 56+) — React Native is compiled from source and statically linked into the brownfield framework, typically leaving: `{TargetName}.xcframework` and `hermesvm.xcframework`.
215
215
 
216
- To force source builds on SDK 56+, add `expo-build-properties` to `app.json`:
216
+ To force source builds, configure the brownfield plugin directly in `app.json`:
217
217
 
218
218
  ```json
219
219
  {
220
220
  "expo": {
221
221
  "plugins": [
222
222
  [
223
- "expo-build-properties",
223
+ "expo-brownfield",
224
224
  { "ios": { "buildReactNativeFromSource": true } }
225
- ],
226
- "expo-brownfield"
225
+ ]
227
226
  ]
228
227
  }
229
228
  }
230
229
  ```
231
230
 
232
- **Every xcframework in the produced set must be embedded in the consuming app** (Embed & Sign). The Swift Package output below (`--package`) wires this for you automatically.
231
+ Use the actual output and generated package manifest as the dependency inventory; precompiled modules can add more binaries. Link all required frameworks and **Embed & Sign dynamic frameworks**. Static binaries are linked, not embedded. Do not mix source-linked React Native with another copy already in the host. The Swift Package output below describes the produced dependencies.
233
232
 
234
- > **iOS deployment target:** the brownfield artifact inherits the Expo project's iOS deployment target (16.4 on SDK 56+). The consuming app's deployment target must be set to 16.4 or higher; otherwise Xcode will refuse to link the embedded frameworks. If the host app is on an older floor (e.g. iOS 14.0), bump its `IPHONEOS_DEPLOYMENT_TARGET` before adding the artifact.
233
+ > **iOS deployment target:** compare the host's supported OS versions with the selected Expo/RN version and every produced binary. If the artifact requires a higher floor, resolve that product constraint before integration; changing a build setting cannot make a newer binary support older iOS releases.
235
234
 
236
235
  #### Ship as a Swift Package (recommended)
237
236
 
238
- Pass `--package [name]` to bundle the output as a self-contained Swift Package instead of separate `.xcframework` directories. The host iOS app then consumes it via **Add Package Dependencies → Add Local** in Xcode and links every bundled framework automatically — no manual drag-and-drop, no per-framework "Embed & Sign" toggles.
237
+ Pass `--package [name]` to generate a local Swift Package around the XCFramework output. Add it with **Add Package Dependencies → Add Local**, then inspect `Package.swift` and select the products the host requires. Packaging layout and products vary by CLI version.
239
238
 
240
239
  ```sh
241
240
  npx expo-brownfield build:ios --release --package MyAppPackage
242
241
  ```
243
242
 
244
- The flag accepts an optional name. If omitted, the package is named `{TargetName}Artifacts`. The resulting directory is a complete Swift Package:
243
+ Confirm `--package` in the installed CLI's help before using it. It accepts an optional package name. Inspect the printed output directory and its `Package.swift` instead of assuming the package name also changes the framework/module name (`MyBrownfield` in this guide).
245
244
 
246
- ```
247
- artifacts/MyAppPackage/
248
- ├── Package.swift
249
- └── xcframeworks/
250
- ├── MyAppPackage.xcframework
251
- ├── hermesvm.xcframework
252
- ├── React.xcframework
253
- └── ReactNativeDependencies.xcframework
245
+ Use separate output directories for Debug and Release. The CLI can clear its selected artifacts directory before writing a package, so changing only the package name is not a safe way to preserve the previous flavor:
246
+
247
+ ```sh
248
+ npx expo-brownfield build:ios --debug --artifacts ./artifacts-debug --package MyAppPackage
249
+ npx expo-brownfield build:ios --release --artifacts ./artifacts-release --package MyAppPackage
254
250
  ```
255
251
 
256
- When `usePrecompiledModules` is enabled, the package directory is suffixed with the build flavor (e.g. `MyAppPackage-release/`) and includes every prebuilt Expo module xcframework. Run `build:ios --debug --package …` and `build:ios --release --package …` separately, and point your host app at the matching package for each build configuration.
252
+ Build Debug and Release artifacts separately when the producer requires a single flavor per package. A host built in Debug with a Release binary still contains Release RN code; it does not become a Metro-enabled artifact. Swift Package Manager does not select `.binaryTarget(path:)` by Xcode configuration. Select the matching package before each host build, or use explicit build-system wiring that supplies matching binaries; do not link both packages with duplicate module names into one target.
257
253
 
258
254
  ### Generate native projects for debugging
259
255
 
260
- To inspect or debug the generated native code, run prebuild:
256
+ To inspect the generated native code, run prebuild **from the separate Expo producer whose native directories are CNG-owned**, never from the consuming host:
261
257
 
262
258
  ```sh
263
259
  npx expo prebuild
@@ -349,31 +345,31 @@ startActivity(Intent(this, ExpoActivity::class.java))
349
345
  If you built a **Swift Package** (`build:ios --package …`):
350
346
 
351
347
  - In Xcode, **File → Add Package Dependencies… → Add Local…**, then select the generated package directory (e.g. `artifacts/MyAppPackage/`).
352
- - Add the package's product to your app target. Xcode links every bundled XCFramework through the aggregate library product — no manual "Embed & Sign" step.
353
- - If you produced both debug and release packages (because `usePrecompiledModules` is enabled), point the host app at the matching package per build configuration.
348
+ - In `expo-brownfield@57.0.18`, precompiled-module builds generate a configuration-suffixed package/product such as `MyAppPackage-release`; select that aggregate product, which includes the binary targets. The Swift import remains the configured framework module (`MyBrownfield`), not the package name. Without precompiled modules, the CLI generates separate library products: add all required products from `Package.swift`. SDK 55.0.28 likewise exposes separate `MyBrownfield` and `hermesvm` products.
349
+ - If you produced Debug and Release packages, explicitly select the matching dependency before building the host; Xcode does not switch local binary packages automatically.
354
350
 
355
351
  If you built **standalone XCFrameworks** (default output):
356
352
 
357
353
  - Drag **every** `.xcframework` produced under `./artifacts` into the Xcode project navigator.
358
354
  - In the import dialog, check **Copy items if needed** and add them to your app target.
359
- - Under the app target's **General** tab → **Frameworks, Libraries, and Embedded Content**, set **every** framework to **Embed & Sign**. Forgetting one (commonly `hermesvm.xcframework`) is a leading cause of runtime "Library not loaded" crashes — see [./troubleshooting.md](./troubleshooting.md#ios-xcframework-signing-isolated-approach).
355
+ - Under the app target's **General** tab → **Frameworks, Libraries, and Embedded Content**, embed and sign the dynamic frameworks; link static binaries without embedding them. For missing runtime dependencies, see [./troubleshooting.md](./troubleshooting.md#ios-xcframework-signing-isolated-approach).
360
356
 
361
357
  #### Initialize React Native at app launch
362
358
 
363
- Call `ReactNativeHostManager.shared.initialize()` from `AppDelegate` **before any React Native view is created**. Initialization is asynchronous-friendly but must precede the first `ReactNativeViewController`/`ReactNativeView` instantiation.
359
+ Merge `ReactNativeHostManager.shared.initialize()` into the existing launch callback **before any React Native view is created**. Keep the native window and navigation. This delegate example uses the generated framework's `ExpoBrownfieldAppDelegate` to forward lifecycle callbacks; if a custom superclass prevents that, use the delegate-forwarding path in [feature integration](./feature-integration.md#forward-lifecycle-events).
364
360
 
365
361
  ```swift
366
362
  import UIKit
367
- import MyAppBrownfield // Replace with your target name
363
+ import MyBrownfield // The configured framework target, not the Swift Package name
368
364
 
369
- @main
370
- class AppDelegate: UIResponder, UIApplicationDelegate {
371
- func application(
365
+ // Merge into the existing delegate. Keep its existing @main only for a UIKit entry point.
366
+ class AppDelegate: ExpoBrownfieldAppDelegate {
367
+ override func application(
372
368
  _ application: UIApplication,
373
369
  didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
374
370
  ) -> Bool {
375
371
  ReactNativeHostManager.shared.initialize()
376
- return true
372
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
377
373
  }
378
374
  }
379
375
  ```
@@ -382,7 +378,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
382
378
 
383
379
  ```swift
384
380
  import UIKit
385
- import MyAppBrownfield
381
+ import MyBrownfield
386
382
 
387
383
  class ViewController: UIViewController {
388
384
  @IBAction func openReactNative(_ sender: Any) {
@@ -406,9 +402,11 @@ let rnViewController = ReactNativeViewController(
406
402
 
407
403
  #### Present a React Native view (SwiftUI)
408
404
 
405
+ Keep the existing `@main struct HostApp: App`. Add `@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate` there only if the host has no delegate adaptor yet. Extend an existing delegate instead of introducing a second one. This connects initialization and lifecycle forwarding without changing the `WindowGroup`.
406
+
409
407
  ```swift
410
408
  import SwiftUI
411
- import MyAppBrownfield
409
+ import MyBrownfield
412
410
 
413
411
  struct ContentView: View {
414
412
  @State private var showReactNative = false
@@ -436,11 +434,11 @@ Start Metro in the Expo project:
436
434
  npx expo start
437
435
  ```
438
436
 
439
- Build and run the native app in debug. React Native screens load JS from the Metro dev server over HTTP with full hot reloading. The device or emulator must be able to reach the dev machine — see [./troubleshooting.md](./troubleshooting.md) if Metro connections fail.
437
+ Build a Debug artifact (`npx expo-brownfield build:ios --debug` on iOS), select it in the host, then build and run the native app in Debug. React Native screens load JS from the Metro dev server over HTTP with full hot reloading. The device or emulator must be able to reach the dev machine — see [./troubleshooting.md](./troubleshooting.md) if Metro connections fail.
440
438
 
441
439
  ### Production (release builds)
442
440
 
443
- The JS bundle is embedded inside the AAR/XCFramework. Metro is not used. Build the native app in Release configuration and confirm the React Native screen loads.
441
+ Build/select the Release artifact and build the host in Release. Stop Metro and verify JS and image assets load, then exercise input, result, dismissal, and reopening using the [acceptance scenario](./feature-integration.md#acceptance-scenario).
444
442
 
445
443
  ---
446
444
 
@@ -11,7 +11,7 @@ Use this reference to choose between the two ways of adding React Native + Expo
11
11
  - **Choose isolated** if React Native and the native app live in **separate repositories**, or release on **different cadences**.
12
12
  - **Choose isolated** if the existing native build is heavily customized (Tuist, Bazel, Buck, custom Gradle plugins) and adding the React Native Gradle plugin or CocoaPods autolinking would be disruptive.
13
13
  - **Choose integrated** if a **single team** owns the native and React Native code and is willing to maintain the RN build chain inside the native project.
14
- - **Choose integrated** if you want **hot reload, JS source maps, and devtools** to "just work" inside the existing native build with no extra orchestration.
14
+ - Both approaches can use **Metro and Fast Refresh** in Debug; choose based on artifact/build ownership.
15
15
  - **Choose integrated** if you expect to add many Expo modules and want them autolinked by the standard Expo tooling rather than rebuilt into a fresh artifact each time.
16
16
 
17
17
  When in doubt — and especially when the question is "can the native team avoid React Native tooling?" — pick **isolated**.
@@ -22,7 +22,7 @@ When in doubt — and especially when the question is "can the native team avoid
22
22
  | ---------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- |
23
23
  | What ships to the native app | Prebuilt AAR + XCFramework | React Native + Expo sources, autolinked into the existing build |
24
24
  | Native team needs Node / Yarn / RN CLI | **No** | **Yes** |
25
- | Build-system footprint | Minimal — one Maven dependency, two embedded XCFrameworks | Pervasive — React Native Gradle plugin, Podfile, autolinking, codegen |
25
+ | Build-system footprint | Artifact dependency plus its required runtime libraries | Pervasive — React Native Gradle plugin, Podfile, autolinking, codegen |
26
26
  | Iteration speed for RN devs | Fast in isolation; native rebuild needed to pick up new artifact | Fast end-to-end; one combined build |
27
27
  | Dev-time hot reload | Yes (via Metro, when running the consumer app in debug) | Yes (native build embeds Metro detection) |
28
28
  | Production JS bundle location | Embedded in the AAR/XCFramework | Embedded in the APK/IPA by the RN Gradle plugin / Xcode build phase |
@@ -44,10 +44,10 @@ When in doubt — and especially when the question is "can the native team avoid
44
44
  → **Isolated.** Removing the dependency removes the framework; the native build is barely touched.
45
45
 
46
46
  **"Our iOS team uses Tuist and refuses to add Node to the iOS build."**
47
- → **Isolated.** Ship an XCFramework. The iOS team adds two `.xcframework` files and one call to `ReactNativeHostManager.shared.initialize()` in `AppDelegate`. No Node, no CocoaPods changes to Expo.
47
+ → **Isolated.** Ship an XCFramework. The iOS team adds the generated Swift Package or complete XCFramework set and one call to `ReactNativeHostManager.shared.initialize()` in `AppDelegate`. No Node, no CocoaPods changes to Expo.
48
48
 
49
49
  **"We have one repo, one team, and we want to deeply integrate React Native with the onboarding flow to an existing Android app."**
50
- → **Integrated.** Move the existing `android-project` into `my-project/android/`, add the React Native Gradle plugin to `settings.gradle`, register `MainApplication`, and host the flow in a `ReactActivity`. One build pipeline.
50
+ → **Integrated.** Keep the host layout or place its Gradle root directly at `my-project/android/`, add the React Native Gradle plugin to `settings.gradle`, register `MainApplication`, and host the flow in a `ReactActivity`. One build pipeline.
51
51
 
52
52
  **"We want to use CNG on the RN code and not worry about manual RN upgrades."**
53
53
  → **Isolated.** The AAR/XCFramework approach decouples the Expo RN version from the native app's build, so you can upgrade Expo and React Native independently of the native app's release cycle. The integrated approach requires more coordination between the RN version and the native app's build.
@@ -59,5 +59,5 @@ When in doubt — and especially when the question is "can the native team avoid
59
59
 
60
60
  ## What is different at runtime
61
61
 
62
- - **Isolated** uses Expo's brownfield runtime wrappers — `ReactNativeHostManager`, `BrownfieldActivity`, `ReactNativeViewController`, `ReactNativeView`. These are generated by `npx expo-brownfield build:*` and bundled into the artifact.
62
+ - **Isolated** uses Expo's brownfield runtime wrappers — `ReactNativeHostManager`, `BrownfieldActivity`, `ReactNativeViewController`, `ReactNativeView`. These are generated by the Expo config plugin and bundled into the artifact.
63
63
  - **Integrated** uses the standard React Native runtime — `ReactActivity`, `ReactActivityDelegate`, `RCTReactNativeFactory`, `ExpoReactNativeFactory` — exposed by `react-native` and `expo` directly.
@@ -0,0 +1,163 @@
1
+ # Integrate a complete native-hosted feature
2
+
3
+ Read after choosing the build approach. Packaging a framework and displaying its first view are only part of integration: the host also owns presentation, input, results, and lifecycle events.
4
+
5
+ ## Define the boundary
6
+
7
+ - Use initial props for a presentation's input, including a fresh `requestId` to correlate replies. Use JSON-compatible values rather than Swift objects or JS callbacks.
8
+ - Use messages for events such as context requests, completed, and cancelled. Subscribe before mounting the feature. Keep required startup data in initial props; a message sent during mounting is not a durable inbox or an acknowledgement that the receiving native emitter is ready. Correlate and acknowledge later updates if delivery matters.
9
+ - Keep long-lived business state in its existing owner. If both sides must observe mutable state, inspect the installed `expo-brownfield` shared-state APIs (`useSharedState`, `setSharedStateValue`, and `deleteSharedState`) and native facade. Namespace per-feature keys and clear session data when its owner ends the session. Messages alone do not provide persistent state or delivery guarantees.
10
+
11
+ ## Register the component that receives input
12
+
13
+ For a small standalone producer, set `package.json`'s `main` to `index.ts` and register a component explicitly. If the scaffold has no TypeScript setup, first run `npx expo install typescript @types/react`:
14
+
15
+ ```ts
16
+ import { registerRootComponent } from 'expo';
17
+ import Feature from './Feature';
18
+
19
+ registerRootComponent(Feature); // Registers "main", matching the native examples.
20
+ ```
21
+
22
+ Do not overwrite an existing app entry point blindly. A Router-based producer needs an explicit adapter to carry root props into the feature; native `initialProps` are not automatically route parameters.
23
+
24
+ `Feature.tsx`:
25
+
26
+ ```tsx
27
+ import { useEffect, useState } from 'react';
28
+ import { Button, Text, View } from 'react-native';
29
+ import * as Brownfield from 'expo-brownfield';
30
+
31
+ export default function Feature({ requestId, userId, greeting: initialGreeting }: {
32
+ requestId: string; userId: string; greeting: string;
33
+ }) {
34
+ const [greeting, setGreeting] = useState(initialGreeting);
35
+
36
+ useEffect(() => {
37
+ const subscription = Brownfield.addMessageListener((event) => {
38
+ if (event.requestId === requestId && event.type === 'feature.context') {
39
+ setGreeting(String(event.greeting));
40
+ }
41
+ });
42
+ return () => subscription.remove();
43
+ }, [requestId]);
44
+
45
+ return (
46
+ <View style={{ flex: 1, justifyContent: 'center', padding: 24 }}>
47
+ <Text>{greeting}: {userId}</Text>
48
+ <Button title="Refresh greeting" onPress={() => Brownfield.sendMessage({
49
+ type: 'feature.request-context', requestId,
50
+ })} />
51
+ <Button title="Done" onPress={() => Brownfield.sendMessage({
52
+ type: 'feature.completed', requestId, selectedId: 'item-42',
53
+ })} />
54
+ <Button title="Cancel" onPress={() => Brownfield.sendMessage({
55
+ type: 'feature.cancelled', requestId,
56
+ })} />
57
+ </View>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ## SwiftUI host: receive the result and dismiss
63
+
64
+ This example uses **Expo's isolated generated framework**, configured as `MyBrownfield`, with `ReactNativeHostManager.shared.initialize()` already connected to the host's app delegate as in [isolated setup](./brownfield-isolated.md). It adds a feature to the existing SwiftUI view hierarchy; it introduces no app entry point.
65
+
66
+ ```swift
67
+ import SwiftUI
68
+ import MyBrownfield
69
+
70
+ private struct FeatureRequest: Identifiable {
71
+ let id = UUID().uuidString
72
+ let userId: String
73
+ }
74
+
75
+ struct FeatureLauncher: View {
76
+ @State private var request: FeatureRequest?
77
+ @State private var listenerId: String?
78
+ @State private var selectedId: String?
79
+
80
+ var body: some View {
81
+ VStack {
82
+ Text(selectedId ?? "No selection")
83
+ Button("Open feature") { openFeature(userId: "123") }
84
+ }
85
+ .sheet(item: $request, onDismiss: stopListening) { request in
86
+ ReactNativeView(
87
+ moduleName: "main",
88
+ initialProps: ["requestId": request.id, "userId": request.userId, "greeting": "Hello"]
89
+ )
90
+ }
91
+ }
92
+
93
+ private func openFeature(userId: String) {
94
+ guard request == nil else { return }
95
+ stopListening()
96
+ let next = FeatureRequest(userId: userId)
97
+ listenerId = BrownfieldMessaging.addListener { message in
98
+ // Messaging callbacks are not a promise of execution on the UI thread.
99
+ DispatchQueue.main.async {
100
+ guard request?.id == next.id,
101
+ message["requestId"] as? String == next.id,
102
+ let type = message["type"] as? String else { return }
103
+ switch type {
104
+ case "feature.request-context":
105
+ BrownfieldMessaging.sendMessage([
106
+ "type": "feature.context", "requestId": next.id, "greeting": "Updated hello"
107
+ ])
108
+ case "feature.completed":
109
+ guard let value = message["selectedId"] as? String else { return }
110
+ selectedId = value
111
+ closeFeature()
112
+ case "feature.cancelled":
113
+ closeFeature()
114
+ default:
115
+ break
116
+ }
117
+ }
118
+ }
119
+ request = next
120
+ }
121
+
122
+ private func closeFeature() {
123
+ stopListening()
124
+ request = nil
125
+ }
126
+
127
+ private func stopListening() {
128
+ if let listenerId {
129
+ BrownfieldMessaging.removeListener(id: listenerId)
130
+ self.listenerId = nil
131
+ }
132
+ }
133
+ }
134
+ ```
135
+
136
+ The same message contract works with UIKit: the presenting coordinator owns the subscription, passes the request as `initialProps`, handles the result on the main thread, then pops or dismisses its controller. Remove the subscription on interactive cancellation and coordinator teardown too. Remove only the listener you own, not every feature's listeners.
137
+
138
+ For **integrated** builds, install/autolink `expo-brownfield` only if using these APIs. The isolated plugin's generated `BrownfieldMessaging` facade is not automatically present in the host. In `expo-brownfield` 55.0.28 and 57.0.18, `internal import ExpoBrownfield` (matching the generated module provider) exposes `BrownfieldMessagingInternal.shared` with instance `addListener`, `sendMessage`, and `removeListener(id:)` methods. Confirm the installed Swift interface before adapting the example, or keep a small host adapter around that SDK-specific surface. Use the [integrated controller](./brownfield-integrated.md#present-a-react-native-screen) instead of the isolated `ReactNativeView`.
139
+
140
+ Navigation behavior depends on the native container. In the SDK 55 and 57 wrappers, the generated UIKit controller handles `popToNative()` by popping its navigation controller, while the generated SwiftUI `ReactNativeView` also listens for that event and calls SwiftUI `dismiss()`. A custom integrated controller does not acquire these handlers automatically. The example above lets the host consume a result before closing its sheet. Use either that result/close contract or the wrapper's navigation API for a given action; do not trigger both.
141
+
142
+ ## Forward lifecycle events
143
+
144
+ Some modules require launch, URL, notification, and application-state callbacks even when a basic RN view renders successfully.
145
+
146
+ - **iOS:** use `ExpoAppDelegate` forwarding when compatible with the host's delegate. The isolated generated framework exports `ExpoBrownfieldAppDelegate`; the integrated app uses `ExpoAppDelegate` from `Expo`. Preserve existing override behavior and call the superclass. With a required custom superclass, an isolated host can retain a generated `ExpoBrownfieldAppDelegate` helper and forward the relevant delegate methods to it. An integrated host can use `ExpoAppDelegateSubscriberManager` from `ExpoModulesCore` directly, following the installed SDK's interface. Forward each event once. For scene-based URL handling, connect the existing scene/SwiftUI handler to the module's required callback; an app-delegate adaptor alone does not replace scene delivery.
147
+ - **Android:** preserve `ApplicationLifecycleDispatcher` calls and the activity lifecycle/back handling from the chosen approach. Exercise configuration changes and native back navigation in the host.
148
+
149
+ Use the [Expo lifecycle guide](https://docs.expo.dev/brownfield/lifecycle-listeners/) and the installed delegate source to choose callbacks. Test the actual modules in use, including warm/cold deep links or push registration where applicable; a first-screen render does not verify these paths.
150
+
151
+ ## Acceptance scenario
152
+
153
+ 1. Build the existing host and record its native launch/navigation behavior before integration.
154
+ 2. Build/select the matching Debug artifact (isolated), run Metro in the producer, and open the feature from the native host with identifiable input.
155
+ 3. Confirm initial input on screen, then use **Refresh greeting** to verify a later native reply. Complete once: native receives one matching result and closes the feature.
156
+ 4. Reopen with a fresh request ID and different input. Verify no stale result or duplicate callback. Cancel through both the RN button and native swipe/back dismissal; repeat.
157
+ 5. Build/select the Release artifact and host Release configuration. Stop Metro, launch afresh, and repeat the interaction, including any bundled images/fonts. Check the original native screens and relevant lifecycle callbacks.
158
+
159
+ For runnable examples of both SwiftUI hosts, see the [iOS brownfield playgrounds](https://github.com/expo/skills/tree/main/tests/fixtures/expo-brownfield).
160
+
161
+ EAS Build/Submit can distribute the host after this integration works; they do not implement the runtime boundary. EAS Update requires an updates-enabled RN runtime and separate brownfield setup, not just an EAS project ID. Consult the [existing-native-app Update guide](https://docs.expo.dev/eas-update/integration-in-existing-native-apps/) if requested; use the chosen toolchain's setup for isolated artifacts. Updates cannot replace compiled Swift code or add a native module absent from the shipped binary.
162
+
163
+ Select the matching SDK/API using [version compatibility](./version-compatibility.md). Current reference: [Brownfield API](https://docs.expo.dev/versions/latest/sdk/brownfield/); implementation: [Expo SDK 57 brownfield](https://github.com/expo/expo/tree/sdk-57/packages/expo-brownfield).
@@ -6,19 +6,12 @@ Cross-cutting issues that apply to both the isolated and integrated approaches.
6
6
 
7
7
  **Symptom:** Gradle or Xcode build fails after a config change, dependency upgrade, or Expo SDK bump.
8
8
 
9
- - **Integrated approach** — regenerate native projects from scratch:
10
- ```sh
11
- npx expo prebuild --clean
12
- ```
13
- Then `cd ios && pod install` and re-open the `.xcworkspace`.
14
- - **Isolated approach** — clear the local Maven cache and rebuild the artifact:
15
- ```sh
16
- rm -rf ~/.m2/repository/<group>/<libraryName>
17
- npx expo-brownfield build:android
18
- npx expo-brownfield build:ios
19
- ```
20
- - For stubborn iOS issues, also delete `ios/build/`, `ios/Pods/`, and `ios/Podfile.lock`, then re-run `pod install`.
21
- - For stubborn Android issues, `./gradlew clean` and delete the project's `.gradle/` and `build/` directories.
9
+ First inspect the failing build step and the dependency/configuration diff.
10
+
11
+ - **Integrated approach:** keep the hand-maintained host intact. Run `npx expo install --check` in the JS project, apply SDK-matched native template changes selectively, then run `bundle exec pod install` (or `pod install` without Bundler) in the host's Podfile directory. Open the `.xcworkspace`. Neither `prebuild` nor `prebuild --clean` is a recovery step for this host: [clean prebuild deletes native directories](https://docs.expo.dev/workflow/continuous-native-generation/#optionality).
12
+ - **Isolated approach:** rebuild the affected platform in the separate Expo producer, then replace the consumer's artifact and its accompanying dependencies. CNG regeneration belongs only in that producer, after checking that its native files are generated and reproducible.
13
+ - For stale iOS build products, clean the affected target's build folder/DerivedData. Preserve `Podfile.lock`; deleting it changes dependency resolution and can hide the cause. Reinstall pods only when the error points to the pod installation.
14
+ - For Android, clean the affected project's build outputs with its Gradle wrapper. Inspect publication coordinates and dependency resolution before removing a specific stale local Maven artifact; do not clear unrelated caches.
22
15
 
23
16
  ## Missing autolinked Expo modules
24
17
 
@@ -42,9 +35,9 @@ Cross-cutting issues that apply to both the isolated and integrated approaches.
42
35
 
43
36
  **Symptom:** App launches but immediately crashes with "Library not loaded" or codesign errors during archive.
44
37
 
45
- - **Every** xcframework produced by `build:ios` must be set to **Embed & Sign** in the app target's **Frameworks, Libraries, and Embedded Content** section. On SDK 56+ this is five frameworks: `{TargetName}.xcframework`, `React.xcframework`, `ReactNativeDependencies.xcframework`, `ExpoModulesJSI.xcframework`, and `hermesvm.xcframework`. On SDK 55 it's two: `{TargetName}.xcframework` and `hermesvm.xcframework`. Missing any of them is a common cause of runtime crashes.
38
+ - Inspect the actual output and generated `Package.swift`; the framework set depends on package version and source/prebuilt settings, not only the SDK major. Link all required binaries and embed/sign dynamic frameworks. Do not apply **Embed & Sign** to static binaries. See the [artifact instructions](./brownfield-isolated.md#ios).
46
39
  - The frameworks must be added to the _app target_, not a framework or extension target.
47
- - Prefer the Swift Package output (`build:ios --package`) — it links every bundled xcframework through one aggregate product, so you cannot forget one.
40
+ - With Swift Package output (`build:ios --package`), inspect the manifest and link all required products. Precompiled builds on SDK 57 expose an aggregate product; other configurations and older packages can expose separate products. See [version compatibility](./version-compatibility.md).
48
41
 
49
42
  ## iOS architecture / simulator mismatch
50
43
 
@@ -81,8 +74,15 @@ Cross-cutting issues that apply to both the isolated and integrated approaches.
81
74
 
82
75
  ## After upgrading Expo SDK
83
76
 
84
- If the brownfield setup stops building after an SDK upgrade:
77
+ First check the selected SDK's Node, Xcode, and minimum OS requirements in [version compatibility](./version-compatibility.md). An unsupported compiler or older deployment target is not repaired by clearing caches. If the brownfield setup stops building after an SDK upgrade:
85
78
 
86
79
  - Re-run `npx expo install --fix` in the Expo project to align native module versions.
87
- - Rebuild the artifact (isolated) or run `npx expo prebuild --clean` (integrated).
80
+ - Isolated: regenerate only the CNG-owned producer if needed, rebuild its artifact, and update the host dependency. Integrated: apply native upgrade diffs to the existing host and reinstall pods; preserve its source files and project configuration.
88
81
  - Compare the new `templates/expo-template-bare-minimum` for the target SDK against your customized native files — Expo occasionally changes Gradle plugin names, Podfile helpers, or AppDelegate entry points across SDKs.
82
+
83
+ ## Result missing, duplicate callbacks, or a sheet that will not close
84
+
85
+ - Check the module registration and per-presentation request ID. Root props need an explicit JS entry point; do not assume a Router route receives native `initialProps` directly.
86
+ - Attach the host listener before mounting RN and supply required startup data through initial props. For live updates, verify subscription readiness and use acknowledgements where delivery matters; messages are not a durable queue.
87
+ - Remove only this feature's listeners on completion, cancellation, and host dismissal. Dispatch UI changes to the main thread.
88
+ - `popToNative()` depends on the native wrapper: the SDK 55 UIKit controller pops navigation, and its SwiftUI wrapper separately calls `dismiss()`. Custom integrated containers need their own handler. Check which wrapper is actually mounted, or let the host close it on a result/close message. See [feature integration](./feature-integration.md).
@@ -0,0 +1,40 @@
1
+ # Select versions before integrating
2
+
3
+ Keep the workflow version-aware rather than pinning every host to one SDK. Existing projects retain their SDK unless an upgrade is part of the task. New producers should use the current stable Expo release when the host and toolchain can support it.
4
+
5
+ ## Inspect and select
6
+
7
+ 1. Read the producer's `package.json` and lockfile; record resolved `expo`, `react-native`, and `expo-brownfield` versions. Check the host's deployment targets, Xcode/Node versions, and native dependency graph, including any existing RN runtime.
8
+ 2. For new work, check the [Expo releases](https://expo.dev/changelog/) and [SDK compatibility table](https://docs.expo.dev/versions/latest/#each-expo-sdk-version-depends-on-a-react-native-version). `npm view expo dist-tags --json` can confirm the current stable `latest` version. Do not infer stability from the highest SDK number or select `canary`/`next` by default.
9
+ 3. Select an SDK compatible with the host's supported OS versions, modules, and build tools. Do not silently raise the host's minimum OS or swap its toolchain to satisfy a tutorial. If a constraint conflicts, explain the concrete choices before changing that product requirement.
10
+ 4. Use that SDK's versioned Brownfield API docs and `sdk-<major>` native template. Install modules with `npx expo install`; run `npx expo install --check` before native builds. For an SDK upgrade, use `expo-upgrade`, preserve the host, and apply native diffs selectively.
11
+ 5. Inspect the **installed** CLI's `build:ios --help` / `build:android --help`, plugin schema, generated Swift/Kotlin wrappers, and `Package.swift`. Flags, prebuilt defaults, import names, and binary products can change within a major release.
12
+
13
+ To scaffold a small new feature after those checks:
14
+
15
+ ```sh
16
+ npx create-expo-app@latest my-project --template blank@latest
17
+ cd my-project
18
+ npx expo install expo-brownfield typescript @types/react
19
+ ```
20
+
21
+ This avoids adding a Router shell just to export one component. For an existing Router app, preserve it and add the root-props adapter described in [feature integration](./feature-integration.md). If selecting an older SDK, use a verified template tag such as `blank@sdk-55`; the scaffolder's own `@latest` version does not determine the template's SDK. Commit the producer's lockfile for repeatable builds.
22
+
23
+ ## SDK requirements and build defaults
24
+
25
+ | Surface | SDK 55 | SDK 57 |
26
+ | --- | --- | --- |
27
+ | React Native family | 0.83 | 0.86 |
28
+ | iOS minimum in the Expo template | 15.1 | 16.4 |
29
+ | Documented minimum Node / Xcode | 20.19.x / 26.2 | 22.13.x / 26.4 |
30
+ | Brownfield React Native build default | Source | Prebuilt |
31
+ | Precompiled Expo modules | Version/configuration dependent | Enabled by default in the native template |
32
+ | Swift Package products | 55.0.28: separate feature and Hermes products | 57.0.18: one aggregate product when precompiled modules are detected; otherwise separate products |
33
+
34
+ React Native prebuilt binaries and precompiled Expo modules are separate settings. Set React Native source mode on `expo-brownfield`'s `ios.buildReactNativeFromSource`. Expo module precompilation is controlled by `expo-build-properties`' `ios.usePrecompiledModules`. Do not disable defaults as a generic build fix; first inspect the failing dependency and toolchain requirement.
35
+
36
+ In 57.0.18, precompiled builds suffix the generated package/product with its configuration (`MyAppPackage-release` or `MyAppPackage-debug`). They do not rename the generated Swift module: continue to import the configured target, such as `MyBrownfield`. Inspect the emitted manifest instead of constructing an assumed package path.
37
+
38
+ SDK 56 introduced additional brownfield capabilities carried into SDK 57, including experimental multiple isolated frameworks and registering host Turbo Module classes. Load the selected SDK's API and installed interfaces only when the task needs them. Do not enable experimental multi-framework support for a single feature or assume two independently packaged RN runtimes can be linked together without collision handling.
39
+
40
+ Sources: [SDK requirements](https://docs.expo.dev/versions/latest/), [SDK 57 Brownfield API](https://docs.expo.dev/versions/v57.0.0/sdk/brownfield/), [SDK 57 native template](https://github.com/expo/expo/tree/sdk-57/templates/expo-template-bare-minimum), [SDK 56 brownfield additions](https://expo.dev/changelog/sdk-56), [published Brownfield package](https://www.npmjs.com/package/expo-brownfield).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: expo-data-fetching
3
- description: Framework (OSS). Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`).
3
+ description: Framework (OSS). Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, loading/empty/error screen states, and Expo Router data loaders (`useLoaderData`).
4
4
  version: 1.0.0
5
5
  license: MIT
6
6
  ---
@@ -36,6 +36,17 @@ Use this skill when:
36
36
 
37
37
  - Avoid axios, prefer expo/fetch
38
38
 
39
+ ## Every Screen Has Four States
40
+
41
+ Design **loading**, **error**, **empty**, and **content** for screens that load data. These can overlap: a refresh error should coexist with cached content.
42
+
43
+ - **Loading ≠ empty.** Empty means *resolved with zero items*, not missing data. Handle initial loading, failure, and hydration before checking list length. In TanStack Query v5, `isLoading` means the first fetch is running; a disabled or offline-paused query can have no data without being loading. Show the prerequisite or offline state in that case.
44
+ - **Empty is a designed state, not a blank list.** Use `ListEmptyComponent` on FlatList/FlashList: explain why it is empty and offer the relevant next action. "No items yet" can offer Create; "No results" should offer changing or clearing the search/filter.
45
+ - **Refetches keep stale content.** Render cached `data` even if a refresh fails, with a nonblocking error and retry. Use `isLoading` for first-fetch spinners and `isFetching` for background activity; prefer a skeleton for a slow initial load with a known layout, and `RefreshControl` for user-initiated refresh.
46
+ - **Gate on hydration.** When initial UI or a redirect depends on persisted state (auth token, onboarding flag), the root layout renders nothing - or the splash - until that state has loaded. Deciding on unhydrated state flashes the wrong screen on every cold start and misroutes deep links that arrive before hydration.
47
+
48
+ **Saves preserve work.** While a mutation is pending, disable repeat submission. On failure, retain the draft, show an inline error, and let the user retry; clear or dismiss only after success. If updating optimistically, restore the previous value or mark the edit as unsynced on failure. Verify with a failed save followed by retry.
49
+
39
50
  ## Common Issues & Solutions
40
51
 
41
52
  ### 1. Basic Fetch Usage
@@ -110,15 +121,23 @@ export default function RootLayout() {
110
121
  import { useQuery } from "@tanstack/react-query";
111
122
 
112
123
  function UserProfile({ userId }: { userId: string }) {
113
- const { data, isLoading, error, refetch } = useQuery({
124
+ const { data, fetchStatus, error, refetch } = useQuery({
114
125
  queryKey: ["user", userId],
115
126
  queryFn: () => fetchUser(userId),
116
127
  });
117
128
 
118
- if (isLoading) return <Loading />;
119
- if (error) return <Error message={error.message} />;
129
+ if (data === undefined) {
130
+ if (error) return <ErrorState message={error.message} onRetry={() => refetch()} />;
131
+ if (fetchStatus === "paused") return <OfflineState />;
132
+ return <Loading />;
133
+ }
120
134
 
121
- return <Profile user={data} />;
135
+ return (
136
+ <>
137
+ {error && <InlineError message="Could not refresh. Showing saved data." onRetry={() => refetch()} />}
138
+ {data === null ? <EmptyState message="User not found" /> : <Profile user={data} />}
139
+ </>
140
+ );
122
141
  }
123
142
  ```
124
143
 
@@ -139,10 +158,12 @@ function CreateUserForm() {
139
158
  });
140
159
 
141
160
  const handleSubmit = (data: UserData) => {
161
+ if (mutation.isPending) return;
142
162
  mutation.mutate(data);
143
163
  };
144
164
 
145
- return <Form onSubmit={handleSubmit} isLoading={mutation.isPending} />;
165
+ // Form keeps its draft on error and disables Submit while isLoading.
166
+ return <Form onSubmit={handleSubmit} isLoading={mutation.isPending} error={mutation.error?.message} />;
146
167
  }
147
168
  ```
148
169