@terreno/mcp 57.19.2 → 57.20.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 (197) hide show
  1. package/CHANGELOG.md +393 -0
  2. package/README.md +32 -269
  3. package/dist/bootstrap.d.ts +12 -0
  4. package/dist/bootstrap.d.ts.map +1 -1
  5. package/dist/bootstrap.js +77 -122
  6. package/dist/bootstrap.js.map +1 -1
  7. package/dist/docs/guidelines/ui/guidelines/core.md +1 -1
  8. package/dist/docs/resources/overview.md +4 -2
  9. package/dist/docs/resources/patterns.md +237 -176
  10. package/dist/docs/resources/ui.md +48 -17
  11. package/dist/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +0 -26
  12. package/dist/docs/templates/bootstrap/frontend/app/_layout.template.tsx +3 -2
  13. package/dist/docs/templates/bootstrap/frontend/app/login.template.tsx +1 -1
  14. package/dist/docs/upgrades/57.20.0.md +238 -0
  15. package/dist/docs/versioned/next/approval-rubric.md +30 -12
  16. package/dist/docs/versioned/next/explanation/README.md +5 -0
  17. package/dist/docs/versioned/next/explanation/account-linking.md +169 -0
  18. package/dist/docs/versioned/next/explanation/admin-interface.md +1 -1
  19. package/dist/docs/versioned/next/explanation/agent-guidelines.md +173 -0
  20. package/dist/docs/versioned/next/explanation/ai-development-loop.md +196 -0
  21. package/dist/docs/versioned/next/explanation/authentication.md +45 -1
  22. package/dist/docs/versioned/next/explanation/consent-forms.md +105 -0
  23. package/dist/docs/versioned/next/explanation/example-coverage.md +1 -0
  24. package/dist/docs/versioned/next/explanation/local-first-data.md +1 -1
  25. package/dist/docs/versioned/next/explanation/organizations.md +37 -0
  26. package/dist/docs/versioned/next/explanation/planning-plugins.md +4 -0
  27. package/dist/docs/versioned/next/explanation/responsive-design.md +143 -0
  28. package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +11 -0
  29. package/dist/docs/versioned/next/explanation/schema-metadata.md +5 -0
  30. package/dist/docs/versioned/next/how-to/README.md +7 -2
  31. package/dist/docs/versioned/next/how-to/audit-log.md +22 -3
  32. package/dist/docs/versioned/next/how-to/automate-terreno-upgrades.md +169 -0
  33. package/dist/docs/versioned/next/how-to/build-list-detail-screens.md +160 -0
  34. package/dist/docs/versioned/next/how-to/circleci.md +15 -5
  35. package/dist/docs/versioned/next/how-to/configure-better-auth.md +673 -53
  36. package/dist/docs/versioned/next/how-to/create-a-terreno-app.md +8 -5
  37. package/dist/docs/versioned/next/how-to/debug-with-mcp.md +393 -23
  38. package/dist/docs/versioned/next/how-to/enable-mcp-oauth.md +54 -3
  39. package/dist/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +9 -0
  40. package/dist/docs/versioned/next/how-to/password-reset.md +1 -1
  41. package/dist/docs/versioned/next/how-to/recover-locked-out-user.md +112 -0
  42. package/dist/docs/versioned/next/how-to/run-tests-locally.md +37 -8
  43. package/dist/docs/versioned/next/how-to/set-up-social-login.md +424 -0
  44. package/dist/docs/versioned/next/how-to/set-up-terreno-mcp.md +241 -36
  45. package/dist/docs/versioned/next/how-to/sign-consent-on-behalf.md +139 -0
  46. package/dist/docs/versioned/next/how-to/upgrade-terreno.md +4 -0
  47. package/dist/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +47 -32
  48. package/dist/docs/versioned/next/implementationPlans/auth-experience.md +952 -0
  49. package/dist/docs/versioned/next/implementationPlans/consent-forms.md +8 -0
  50. package/dist/docs/versioned/next/implementationPlans/list-detail-layout.md +297 -0
  51. package/dist/docs/versioned/next/implementationPlans/login-redesign/HANDOFF.md +211 -0
  52. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/AnotherWay.html +121 -0
  53. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/BackupCode.html +72 -0
  54. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/Cancelled.html +87 -0
  55. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/ContinueEmail.html +64 -0
  56. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/FirstVisit.html +81 -0
  57. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/Main.html +88 -0
  58. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/ManageAccounts.html +77 -0
  59. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/NotLinked.html +92 -0
  60. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/SigningIn.html +60 -0
  61. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/TwoFactor.html +76 -0
  62. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/TwoFactorError.html +81 -0
  63. package/dist/docs/versioned/next/implementationPlans/login-redesign/boards/WrongPassword.html +69 -0
  64. package/dist/docs/versioned/next/implementationPlans/mcp-boost-parity.md +1 -1
  65. package/dist/docs/versioned/next/plans/2026-10-23-provisional-consent.md +297 -0
  66. package/dist/docs/versioned/next/plans/2026-10-29-fix-mcp-oauth-native-and-machine.md +68 -0
  67. package/dist/docs/versioned/next/reference/README.md +1 -0
  68. package/dist/docs/versioned/next/reference/account-security.md +700 -0
  69. package/dist/docs/versioned/next/reference/admin-backend.md +3 -1
  70. package/dist/docs/versioned/next/reference/admin-frontend.md +225 -1
  71. package/dist/docs/versioned/next/reference/api.md +461 -35
  72. package/dist/docs/versioned/next/reference/cli.md +1 -1
  73. package/dist/docs/versioned/next/reference/comms.md +8 -0
  74. package/dist/docs/versioned/next/reference/create-terreno-app.md +3 -1
  75. package/dist/docs/versioned/next/reference/environment-variables.md +9 -3
  76. package/dist/docs/versioned/next/reference/legacy/rtk.md +19 -3
  77. package/dist/docs/versioned/next/reference/lifecycle-plugin.md +6 -0
  78. package/dist/docs/versioned/next/reference/mcp-server.md +1158 -441
  79. package/dist/docs/versioned/next/reference/syncdb.md +8 -1
  80. package/dist/docs/versioned/next/reference/ui.md +1271 -27
  81. package/dist/docs/versioned/next/tasks/ai-dev-loop-boost.md +28 -16
  82. package/dist/docs/versioned/next/tutorials/README.md +4 -0
  83. package/dist/httpApp.d.ts +14 -0
  84. package/dist/httpApp.d.ts.map +1 -0
  85. package/dist/httpApp.js +99 -0
  86. package/dist/httpApp.js.map +1 -0
  87. package/dist/index.js +8 -90
  88. package/dist/index.js.map +1 -1
  89. package/dist/local/localTools.d.ts.map +1 -1
  90. package/dist/local/localTools.js +44 -14
  91. package/dist/local/localTools.js.map +1 -1
  92. package/dist/local/metro/metroDevSession.d.ts +18 -0
  93. package/dist/local/metro/metroDevSession.d.ts.map +1 -1
  94. package/dist/local/metro/metroDevSession.js +42 -3
  95. package/dist/local/metro/metroDevSession.js.map +1 -1
  96. package/dist/local/tools/databaseQuery.d.ts.map +1 -1
  97. package/dist/local/tools/databaseQuery.js +3 -13
  98. package/dist/local/tools/databaseQuery.js.map +1 -1
  99. package/dist/local/tools/databaseSchema.d.ts.map +1 -1
  100. package/dist/local/tools/databaseSchema.js +3 -13
  101. package/dist/local/tools/databaseSchema.js.map +1 -1
  102. package/dist/local/tools/localMongo.d.ts +10 -0
  103. package/dist/local/tools/localMongo.d.ts.map +1 -0
  104. package/dist/local/tools/localMongo.js +30 -0
  105. package/dist/local/tools/localMongo.js.map +1 -0
  106. package/dist/local/tools/runtime.d.ts +18 -2
  107. package/dist/local/tools/runtime.d.ts.map +1 -1
  108. package/dist/local/tools/runtime.js +75 -20
  109. package/dist/local/tools/runtime.js.map +1 -1
  110. package/dist/local/tools/syncDb.d.ts +11 -0
  111. package/dist/local/tools/syncDb.d.ts.map +1 -1
  112. package/dist/local/tools/syncDb.js +15 -3
  113. package/dist/local/tools/syncDb.js.map +1 -1
  114. package/dist/rateLimit.d.ts +35 -0
  115. package/dist/rateLimit.d.ts.map +1 -0
  116. package/dist/rateLimit.js +112 -0
  117. package/dist/rateLimit.js.map +1 -0
  118. package/dist/tools.d.ts.map +1 -1
  119. package/dist/tools.js +42 -60
  120. package/dist/tools.js.map +1 -1
  121. package/package.json +4 -3
  122. package/src/docs/guidelines/ui/guidelines/core.md +1 -1
  123. package/src/docs/resources/overview.md +4 -2
  124. package/src/docs/resources/patterns.md +237 -176
  125. package/src/docs/resources/ui.md +48 -17
  126. package/src/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +0 -26
  127. package/src/docs/templates/bootstrap/frontend/app/_layout.template.tsx +3 -2
  128. package/src/docs/templates/bootstrap/frontend/app/login.template.tsx +1 -1
  129. package/src/docs/upgrades/57.20.0.md +238 -0
  130. package/src/docs/versioned/next/approval-rubric.md +30 -12
  131. package/src/docs/versioned/next/explanation/README.md +5 -0
  132. package/src/docs/versioned/next/explanation/account-linking.md +169 -0
  133. package/src/docs/versioned/next/explanation/admin-interface.md +1 -1
  134. package/src/docs/versioned/next/explanation/agent-guidelines.md +173 -0
  135. package/src/docs/versioned/next/explanation/ai-development-loop.md +196 -0
  136. package/src/docs/versioned/next/explanation/authentication.md +45 -1
  137. package/src/docs/versioned/next/explanation/consent-forms.md +105 -0
  138. package/src/docs/versioned/next/explanation/example-coverage.md +1 -0
  139. package/src/docs/versioned/next/explanation/local-first-data.md +1 -1
  140. package/src/docs/versioned/next/explanation/organizations.md +37 -0
  141. package/src/docs/versioned/next/explanation/planning-plugins.md +4 -0
  142. package/src/docs/versioned/next/explanation/responsive-design.md +143 -0
  143. package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +11 -0
  144. package/src/docs/versioned/next/explanation/schema-metadata.md +5 -0
  145. package/src/docs/versioned/next/how-to/README.md +7 -2
  146. package/src/docs/versioned/next/how-to/audit-log.md +22 -3
  147. package/src/docs/versioned/next/how-to/automate-terreno-upgrades.md +169 -0
  148. package/src/docs/versioned/next/how-to/build-list-detail-screens.md +160 -0
  149. package/src/docs/versioned/next/how-to/circleci.md +15 -5
  150. package/src/docs/versioned/next/how-to/configure-better-auth.md +673 -53
  151. package/src/docs/versioned/next/how-to/create-a-terreno-app.md +8 -5
  152. package/src/docs/versioned/next/how-to/debug-with-mcp.md +393 -23
  153. package/src/docs/versioned/next/how-to/enable-mcp-oauth.md +54 -3
  154. package/src/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +9 -0
  155. package/src/docs/versioned/next/how-to/password-reset.md +1 -1
  156. package/src/docs/versioned/next/how-to/recover-locked-out-user.md +112 -0
  157. package/src/docs/versioned/next/how-to/run-tests-locally.md +37 -8
  158. package/src/docs/versioned/next/how-to/set-up-social-login.md +424 -0
  159. package/src/docs/versioned/next/how-to/set-up-terreno-mcp.md +241 -36
  160. package/src/docs/versioned/next/how-to/sign-consent-on-behalf.md +139 -0
  161. package/src/docs/versioned/next/how-to/upgrade-terreno.md +4 -0
  162. package/src/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +47 -32
  163. package/src/docs/versioned/next/implementationPlans/auth-experience.md +952 -0
  164. package/src/docs/versioned/next/implementationPlans/consent-forms.md +8 -0
  165. package/src/docs/versioned/next/implementationPlans/list-detail-layout.md +297 -0
  166. package/src/docs/versioned/next/implementationPlans/login-redesign/HANDOFF.md +211 -0
  167. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/AnotherWay.html +121 -0
  168. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/BackupCode.html +72 -0
  169. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/Cancelled.html +87 -0
  170. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/ContinueEmail.html +64 -0
  171. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/FirstVisit.html +81 -0
  172. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/Main.html +88 -0
  173. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/ManageAccounts.html +77 -0
  174. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/NotLinked.html +92 -0
  175. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/SigningIn.html +60 -0
  176. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/TwoFactor.html +76 -0
  177. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/TwoFactorError.html +81 -0
  178. package/src/docs/versioned/next/implementationPlans/login-redesign/boards/WrongPassword.html +69 -0
  179. package/src/docs/versioned/next/implementationPlans/mcp-boost-parity.md +1 -1
  180. package/src/docs/versioned/next/plans/2026-10-23-provisional-consent.md +297 -0
  181. package/src/docs/versioned/next/plans/2026-10-29-fix-mcp-oauth-native-and-machine.md +68 -0
  182. package/src/docs/versioned/next/reference/README.md +1 -0
  183. package/src/docs/versioned/next/reference/account-security.md +700 -0
  184. package/src/docs/versioned/next/reference/admin-backend.md +3 -1
  185. package/src/docs/versioned/next/reference/admin-frontend.md +225 -1
  186. package/src/docs/versioned/next/reference/api.md +461 -35
  187. package/src/docs/versioned/next/reference/cli.md +1 -1
  188. package/src/docs/versioned/next/reference/comms.md +8 -0
  189. package/src/docs/versioned/next/reference/create-terreno-app.md +3 -1
  190. package/src/docs/versioned/next/reference/environment-variables.md +9 -3
  191. package/src/docs/versioned/next/reference/legacy/rtk.md +19 -3
  192. package/src/docs/versioned/next/reference/lifecycle-plugin.md +6 -0
  193. package/src/docs/versioned/next/reference/mcp-server.md +1158 -441
  194. package/src/docs/versioned/next/reference/syncdb.md +8 -1
  195. package/src/docs/versioned/next/reference/ui.md +1271 -27
  196. package/src/docs/versioned/next/tasks/ai-dev-loop-boost.md +28 -16
  197. package/src/docs/versioned/next/tutorials/README.md +4 -0
@@ -100,7 +100,6 @@ import { Text, Heading, Title } from "@terreno/ui";
100
100
  import {
101
101
  TextField,
102
102
  EmailField,
103
- PasswordField,
104
103
  NumberField,
105
104
  TextArea,
106
105
  SelectField,
@@ -110,19 +109,26 @@ import {
110
109
  RadioField,
111
110
  } from "@terreno/ui";
112
111
 
112
+ // Fields share `title`, `value`, `onChange`, `errorText`, and `helperText`.
113
113
  <TextField
114
- label="Name"
114
+ title="Name"
115
115
  value={name}
116
- onChangeText={setName}
116
+ onChange={setName}
117
117
  placeholder="Enter your name"
118
- error={errors.name}
118
+ errorText={errors.name}
119
119
  helperText="Your full legal name"
120
120
  />
121
121
 
122
+ // Passwords: TextField with type="password" (adds a show/hide control).
123
+ <TextField title="Password" type="password" value={password} onChange={setPassword} />
124
+
125
+ // NumberField values are strings; type is "number" or "decimal".
126
+ <NumberField title="Age" type="number" value={age} onChange={setAge} />
127
+
122
128
  <SelectField
123
- label="Country"
129
+ title="Country"
124
130
  value={country}
125
- onChangeValue={setCountry}
131
+ onChange={setCountry}
126
132
  options={[
127
133
  { label: "United States", value: "US" },
128
134
  { label: "Canada", value: "CA" },
@@ -130,16 +136,16 @@ import {
130
136
  />
131
137
 
132
138
  <DateTimeField
133
- label="Date of Birth"
139
+ title="Date of Birth"
140
+ type="date"
134
141
  value={dob}
135
142
  onChange={setDob}
136
- mode="date"
137
143
  />
138
144
 
139
145
  <BooleanField
140
- label="Accept Terms"
146
+ title="Accept Terms"
141
147
  value={accepted}
142
- onChangeValue={setAccepted}
148
+ onChange={setAccepted}
143
149
  />
144
150
  ```
145
151
 
@@ -202,7 +208,7 @@ import {
202
208
  ### Page & Layout
203
209
 
204
210
  ```typescript
205
- import { Page, SplitPage, ScrollView } from "@terreno/ui";
211
+ import { Page, ScrollView } from "@terreno/ui";
206
212
 
207
213
  <Page
208
214
  navigation={navigation}
@@ -215,6 +221,32 @@ import { Page, SplitPage, ScrollView } from "@terreno/ui";
215
221
  </Page>
216
222
  ```
217
223
 
224
+ List/detail screens (mail, inbox, records) use `ListDetailLayout` as a route group's
225
+ `_layout.tsx`. Phones push the detail route; tablets and wide browsers show the list in a left
226
+ pane beside it. The open item lives in the URL.
227
+
228
+ ```typescript
229
+ import { ListDetailIndex, ListDetailLayout, useListDetail } from "@terreno/ui";
230
+
231
+ // app/mail/_layout.tsx
232
+ export const unstable_settings = { initialRouteName: "index" };
233
+ export default () => (
234
+ <ListDetailLayout
235
+ detailHref={(id) => `/mail/${id}`}
236
+ indexHref="/mail"
237
+ list={<MailList />}
238
+ />
239
+ );
240
+
241
+ // app/mail/index.tsx
242
+ export default () => <ListDetailIndex />;
243
+
244
+ // MailList rows read and change the open item
245
+ const { selectedId, select } = useListDetail();
246
+ ```
247
+
248
+ Use `SplitPage` only for list/detail views without their own routes.
249
+
218
250
  ## Theme System
219
251
 
220
252
  ### Using Theme
@@ -253,17 +285,16 @@ radiusSm, radiusMd, radiusLg, radiusXl, radius2xl, radius3xl
253
285
  ## Utilities
254
286
 
255
287
  ```typescript
256
- import { useStoredState, MediaQuery, isNarrowViewport } from "@terreno/ui";
288
+ import {isNarrowViewport, isSupportedDesktopWidth, useStoredState} from "@terreno/ui";
289
+ import {useWindowDimensions} from "react-native";
257
290
 
258
291
  // Persist state to storage
259
292
  const [value, setValue] = useStoredState("key", defaultValue);
260
293
 
261
- // Responsive rendering
262
- <MediaQuery minWidth={768}>
263
- <DesktopLayout />
264
- </MediaQuery>
294
+ const {width} = useWindowDimensions();
295
+ const isDesktopLayout = isSupportedDesktopWidth({width});
265
296
 
266
- // Current window is below the desktop breakpoint.
297
+ // Current window is below the desktop floor (web lg / native xl, 1024pt).
267
298
  // isMobileDevice() is deprecated in favor of isNarrowViewport().
268
299
  if (isNarrowViewport()) {
269
300
  // Narrow-viewport code
@@ -11,7 +11,6 @@ const ProfileScreen: React.FC = () => {
11
11
  const [updateProfile] = usePatchMeMutation();
12
12
  const [name, setName] = useState<string>("");
13
13
  const [email, setEmail] = useState<string>("");
14
- const [password, setPassword] = useState<string>("");
15
14
  const [currentPassword, setCurrentPassword] = useState<string>("");
16
15
  const [saveError, setSaveError] = useState<string | null>(null);
17
16
 
@@ -75,23 +74,6 @@ const ProfileScreen: React.FC = () => {
75
74
  [currentPassword, isEmailChanged, updateProfile]
76
75
  );
77
76
 
78
- const handleSavePassword = useCallback(
79
- async (value: string): Promise<void> => {
80
- if (!value) {
81
- return;
82
- }
83
- setSaveError(null);
84
- try {
85
- await updateProfile({password: value}).unwrap();
86
- setPassword("");
87
- } catch (err) {
88
- console.error("Error updating password:", err);
89
- setSaveError("Failed to update password");
90
- }
91
- },
92
- [updateProfile]
93
- );
94
-
95
77
  if (isLoading) {
96
78
  return (
97
79
  <Page navigation={undefined} title="Profile">
@@ -132,14 +114,6 @@ const ProfileScreen: React.FC = () => {
132
114
  value={currentPassword}
133
115
  />
134
116
  )}
135
- <TapToEdit
136
- helperText="Leave blank to keep your current password"
137
- onSave={handleSavePassword}
138
- setValue={setPassword}
139
- title="New Password"
140
- type="password"
141
- value={password}
142
- />
143
117
  {saveError && <Text color="error">{saveError}</Text>}
144
118
  </Box>
145
119
  </Card>
@@ -5,14 +5,15 @@ import {Stack} from "expo-router";
5
5
  import * as SplashScreen from "expo-splash-screen";
6
6
  import {useEffect} from "react";
7
7
  import "react-native-reanimated";
8
- import {baseUrl, installTerrenoDevConsoleLogger, selectBetterAuthUserId} from "@terreno/rtk";
8
+ import {baseUrl, selectBetterAuthUserId} from "@terreno/rtk";
9
+ import {installTerrenoDevConsoleLogger} from "@terreno/syncdb";
9
10
  import {TerrenoProvider} from "@terreno/ui";
10
11
  import {Provider, useSelector} from "react-redux";
11
12
  import {PersistGate} from "redux-persist/integration/react";
12
13
  import {useColorScheme} from "@/components/useColorScheme";
13
14
  import store, {persistor} from "@/store/index";
14
15
 
15
- installTerrenoDevConsoleLogger();
16
+ installTerrenoDevConsoleLogger({baseUrl});
16
17
 
17
18
  export {ErrorBoundary} from "expo-router";
18
19
 
@@ -68,7 +68,7 @@ const LoginScreen: React.FC = () => {
68
68
  />
69
69
  )}
70
70
  <TextField
71
- autoComplete="off"
71
+ autoComplete="username"
72
72
  disabled={isLoading}
73
73
  onChange={setEmail}
74
74
  placeholder="Email"
@@ -0,0 +1,238 @@
1
+ # Upgrading to 57.20.0
2
+
3
+ **Action required:** Yes
4
+ **Affected packages:** @terreno/api, @terreno/rtk, @terreno/ui, @terreno/admin-frontend, @terreno/mcp
5
+
6
+ ## Summary
7
+
8
+ This release ships the Better Auth account suite: social login, account linking, passkeys,
9
+ two-factor with backup codes, closed sign-up, and staff account recovery (`AccountSecurityApp`,
10
+ org-admin recovery). It adds drop-in `TerrenoLoginScreen` and `TerrenoAccountSecurityScreen`
11
+ screens, `ListDetailLayout`, provisional consent signing, and MCP OAuth client credentials. The
12
+ app `User` claim guard now runs before a Better Auth user is created, which can refuse sign-ups
13
+ that 57.17.0 accepted. Several defaults also change: the desktop layout floor, sign-out timing,
14
+ web autofill, and the hosted MCP URL.
15
+
16
+ ## Breaking changes
17
+
18
+ ### Better Auth claims an existing app `User` only with a verified email or its password
19
+
20
+ **What changed**
21
+
22
+ A Better Auth sign-up or sign-in links to an unlinked app `User` with the same email (ignoring
23
+ case) only when the provider verified the email, or when the password verifies against that
24
+ `User`'s passport-local-mongoose hash. Otherwise the request answers 409 with
25
+ `code: "VERIFY_EMAIL_TO_USE_ACCOUNT"` and creates no Better Auth user, account, or verification
26
+ email. OAuth callbacks redirect with that `error`. A `User` already bound to another Better Auth
27
+ account is refused with `code: "ACCOUNT_ALREADY_EXISTS"`. `syncBetterAuthUser` throws `APIError`
28
+ 409 instead of inserting a duplicate `User`, and takes a new `password` option.
29
+
30
+ `BetterAuthApp` registered without a `userModel` now adopts `TerrenoApp`'s user model, and the
31
+ `terreno-app-user-sync` plugin syncs the app `User` when each session is created. A
32
+ password-proven link that fails to save fails the sign-in with 500 `APP_USER_LINK_FAILED`.
33
+
34
+ **Why**
35
+
36
+ 57.17.0 checked the claim only after the Better Auth user existed, so a later email verification
37
+ could still hand that user someone else's `User`.
38
+
39
+ **Migration**
40
+
41
+ Users who sign up with their existing password, or sign in with a provider that verified their
42
+ email, link at once. Users with no password hash (for example GitHub JWT sign-in) must reset their
43
+ password through JWT `POST /auth/forgotPassword` first, or sign in with a verified provider. Keep
44
+ the JWT auth routes mounted while users move. Handle the new 409 codes on your login screen:
45
+
46
+ ```typescript
47
+ import {getLoginFeedback} from "@terreno/rtk";
48
+
49
+ // Before: a generic error for any refused sign-up
50
+ setError(error.message);
51
+
52
+ // After: VERIFY_EMAIL_TO_USE_ACCOUNT reads as "verify your email"
53
+ const {notice, error: errorLine} = getLoginFeedback({
54
+ failure: {code: error.code, message: error.message, source: "response"},
55
+ mode: methods?.accountLinking.mode,
56
+ });
57
+ ```
58
+
59
+ `TerrenoLoginScreen` from `@terreno/rtk` handles these codes for you. See
60
+ `docs/explanation/account-linking.md`.
61
+
62
+ ### `accountLinking: {mode: "never"}` refuses `link-social` up front
63
+
64
+ **What changed**
65
+
66
+ With linking off (`accountLinking: {mode: "never"}` or
67
+ `options.account.accountLinking.enabled: false`), `POST {basePath}/link-social` answers 403
68
+ `LINKING_DISABLED` instead of failing at the provider callback.
69
+
70
+ **Why**
71
+
72
+ The user learns linking is off before leaving for the provider.
73
+
74
+ **Migration**
75
+
76
+ Hide the "Link" action when `useAuthMethods(authClient)` reports linking is off, or treat 403
77
+ `LINKING_DISABLED` as a final answer:
78
+
79
+ ```typescript
80
+ // Before
81
+ await authClient.linkSocial({provider: "google"}); // failed later at the callback
82
+
83
+ // After
84
+ const {methods} = useAuthMethods(authClient);
85
+ const canLink = methods?.accountLinking.mode !== "never";
86
+ ```
87
+
88
+ ### Desktop layout floor moves from 768pt to 1024pt
89
+
90
+ **What changed**
91
+
92
+ `Card`, `MarkdownEditor`, the admin shell, and the admin filter drawer use the narrow layout
93
+ below 1024pt instead of 768pt. Admin home stacks its panes below that floor.
94
+ `ADMIN_FILTER_MOBILE_BREAKPOINT` is now 1024, and `isSupportedDesktopWidth({width})` reports the
95
+ floor.
96
+
97
+ **Why**
98
+
99
+ Tablets between 768pt and 1023pt got cramped desktop layouts. See
100
+ `docs/explanation/responsive-design.md`.
101
+
102
+ **Migration**
103
+
104
+ ```typescript
105
+ // Before
106
+ const isDesktop = width >= 768;
107
+
108
+ // After
109
+ import {isSupportedDesktopWidth} from "@terreno/ui";
110
+ const isDesktop = isSupportedDesktopWidth({width});
111
+ ```
112
+
113
+ Check screens you tuned for 768–1023pt widths, such as iPad portrait.
114
+
115
+ ### `logout()` waits for the server before clearing the session
116
+
117
+ **What changed**
118
+
119
+ In `@terreno/rtk` `generateBetterAuthSlice`, `logout()` keeps the session until
120
+ `authClient.signOut()` finishes (`signOutTimeoutMs`, default 10 seconds). Meanwhile
121
+ `isSigningOut` (`selectBetterAuthIsSigningOut`) is true. A sign-out that fails while the session
122
+ is still live stays signed in and sets `error` to `SIGN_OUT_FAILED_MESSAGE`. With `apisToReset`,
123
+ the cache purges when the session clears, not at dispatch.
124
+
125
+ **Why**
126
+
127
+ A login screen that opened at once could find the still-live session and sign the user straight
128
+ back in.
129
+
130
+ **Migration**
131
+
132
+ ```typescript
133
+ // Before: navigate as soon as logout is dispatched
134
+ dispatch(betterAuth.actions.logout());
135
+ router.replace("/login");
136
+
137
+ // After: navigate when the session clears; show progress meanwhile
138
+ const isSigningOut = useSelector(selectBetterAuthIsSigningOut);
139
+ const isAuthenticated = useSelector(selectBetterAuthIsAuthenticated);
140
+ ```
141
+
142
+ ### `TextField` `autoComplete` now reaches the browser
143
+
144
+ **What changed**
145
+
146
+ `TextField` sets `autoComplete` as the input's `autocomplete` attribute on web, and as
147
+ `autoComplete` / `textContentType` on native. `autoComplete="off"` now turns autofill off on web.
148
+ `LoginScreen` and `SignUpScreen` default email to `"username"`.
149
+
150
+ **Why**
151
+
152
+ Password managers could not offer saved credentials or new passwords.
153
+
154
+ **Migration**
155
+
156
+ ```tsx
157
+ // Before
158
+ <TextField autoComplete="off" type="email" ... />
159
+ <TextField type="password" ... /> // on a set-new-password form
160
+
161
+ // After
162
+ <TextField autoComplete="username" type="email" ... /> // "email" on sign-up
163
+ <TextField autoComplete="new-password" type="password" ... />
164
+ ```
165
+
166
+ ### Hosted Terreno MCP server moves to `https://mcp.terreno.app/mcp`
167
+
168
+ **What changed**
169
+
170
+ Docs and `create-terreno-app` now use `https://mcp.terreno.app/mcp`.
171
+ `https://mcp.terreno.flourish.health/mcp` keeps serving for at least one more release.
172
+
173
+ **Why**
174
+
175
+ The hosted server has a Terreno-owned domain.
176
+
177
+ **Migration**
178
+
179
+ ```json
180
+ // Before (.cursor/mcp.json, .mcp.json)
181
+ {"url": "https://mcp.terreno.flourish.health/mcp"}
182
+
183
+ // After
184
+ {"url": "https://mcp.terreno.app/mcp"}
185
+ ```
186
+
187
+ Re-run `claude mcp add` registrations with the new URL. See `docs/how-to/set-up-terreno-mcp.md`.
188
+
189
+ ### `SyncStatusBanner` waits before showing Offline
190
+
191
+ **What changed**
192
+
193
+ The Offline badge appears only after `isOnline` stays false for `offlineGraceMs` (default 3000 ms).
194
+
195
+ **Why**
196
+
197
+ It flashed Offline during the first socket connect and brief drops.
198
+
199
+ **Migration**
200
+
201
+ ```tsx
202
+ // Before: shown immediately
203
+ <SyncStatusBanner />
204
+
205
+ // After: pass 0 to keep the old behavior
206
+ <SyncStatusBanner offlineGraceMs={0} />
207
+ ```
208
+
209
+ ## Deprecations
210
+
211
+ - `installTerrenoDevConsoleLogger` moves to `@terreno/syncdb` (also
212
+ `@terreno/syncdb/devConsoleLogger`) and takes `{baseUrl}`. The `@terreno/rtk` export is a
213
+ deprecated wrapper that keeps working with no arguments.
214
+ - `terreno-mcp-local` `get_rtk_state` is a deprecated alias of the new `get_client_state` for one
215
+ release. It returns the same wrapped response, now with a `layer` field.
216
+
217
+ ## New capabilities
218
+
219
+ - Better Auth features as config: `accountLinking`, `twoFactor`, `passkey`, `signUp: {mode: "closed"}`,
220
+ `oauthProxy`, `oauthHandoff` linking, and the Sign in with Apple key form. Login screens read
221
+ `GET {basePath}/terreno/methods` through `useAuthMethods`.
222
+ - Drop-in screens in `@terreno/rtk`: `TerrenoLoginScreen` (remembered accounts, passkeys, inline
223
+ two-factor) and `TerrenoAccountSecurityScreen`, built on new `@terreno/ui` security cards,
224
+ `OtpField`, `TwoFactorChallengeScreen`, and `FormContainer`.
225
+ - `AccountSecurityApp` for staff account recovery under `/users/:id/security`, org-admin recovery
226
+ under `/orgs/:orgId/members/:userId/security`, security notification emails, and
227
+ `UserSecurityScreen` / `MemberSecurityPanel` in `@terreno/admin-frontend`.
228
+ - `ListDetailLayout` in `@terreno/ui`, provisional consent signing, and MCP OAuth
229
+ `client_credentials` with loopback redirect ports.
230
+
231
+ ## Verification
232
+
233
+ - `bun run compile` and `bun run lint` at the app root.
234
+ - `cd <your frontend> && bun run sdk` to pick up the new auth and security routes.
235
+ - Sign up with an email that matches an existing unverified `User` and confirm a 409
236
+ `VERIFY_EMAIL_TO_USE_ACCOUNT`; sign up with that `User`'s password and confirm it links.
237
+ - Sign out on web and confirm the app does not sign back in before the server answers.
238
+ - Load key screens at 900pt width and confirm the narrow layout reads well.
@@ -5,11 +5,25 @@ enforced in code before and after this judgment; your level moves only inside th
5
5
 
6
6
  ## Levels
7
7
 
8
- | Level | Meaning | Examples |
9
- | --- | --- | --- |
10
- | low | A mistake is cheap and visible; the PR proves itself | docs; tests, snapshots, fixtures; copy and i18n strings; lint autofix; regenerated files whose source changed in the same PR; changelog fragments; dependency patch bumps with green CI; one-line bug fixes with a regression test |
11
- | medium | Ordinary product logic a reviewer would read once | new or changed behavior with tests; UI changes with screenshots; new endpoints with permission tests; minor dependency bumps; refactors inside one package |
12
- | high | A mistake is costly, hidden, or hard to undo | auth, sessions, permissions; schema and migrations; data backfills; billing; PHI handling; secrets, env, infra, Dockerfiles; CI; public API shape; lockstep framework bumps; feature-flag removals; reverts of security changes; hotfix branches with commits not on master; deleted or skipped tests |
8
+ Most features are medium. High is reserved for security-related code.
9
+
10
+ | Level | Human approvals | Meaning | Examples |
11
+ | --- | --- | --- | --- |
12
+ | low | None, once automated review and security checks are green | A mistake is cheap and visible; the PR proves itself | docs; copy and i18n strings; tests, snapshots, fixtures; internal-only features (admin screens, dev tooling, scripts no user runs); additive changes behind a feature flag that defaults off; lint autofix; regenerated files whose source changed in the same PR; changelog fragments; dependency patch bumps with green CI; one-line bug fixes with a regression test; small presentational UI tweaks (see below) |
13
+ | medium | One person | Ordinary product changes, and changes to sensitive areas | new or changed behavior with tests; UI changes with screenshots beyond a small presentational tweak; new endpoints with permission tests; schema changes, migrations, and backfills; caching (RTK tags, syncdb, HTTP/CDN caching); app updates (expo-updates, `eas.json`, `app.json`, release channels); AI system prompts and tool definitions; billing; infra, Dockerfiles, CI; public API shape (removed, renamed, or retyped exports, props, or endpoints); dependency minor and major bumps; feature-flag removals; hotfix branches; deleted or skipped tests |
14
+ | high | One person | Security-related code, where a mistake is costly, hidden, or hard to undo | auth, sessions, tokens, Better Auth and Passport config; permissions, RBAC, `queryFilter`s that scope data to a user; MCP OAuth; `socketAuth` and `sessionRevalidation`; secrets and env files; crypto, hashing, signature verification (webhook verifiers); PHI handling, consent, and audit logging; rate limits on unauthenticated routes; CORS and trusted origins; IAM, network, and firewall rules in infra; dependencies added for auth, crypto, or parsing untrusted input; reverts of security changes |
15
+
16
+ A PR is high only when it changes how the system decides who may see or do something,
17
+ or how secrets, credentials, or PHI are handled. Touching a security-adjacent file for an
18
+ unrelated reason (a typo, a log message, a rename) is judged by what the change does.
19
+
20
+ A **small presentational UI tweak** is low. It changes how one component looks or when it
21
+ shows something (layout, spacing, copy, color, a display delay or debounce, an animation)
22
+ and nothing else: no data fetching or syncdb/RTK changes, no navigation, no change to what
23
+ a user can submit or do, no auth or consent screens. It may add an optional prop with a
24
+ default, and that default may change what every consumer sees, as long as the old look is
25
+ one prop away. It still needs tests that would fail without the change and before/after
26
+ screenshots or video. A changelog fragment and docs update do not raise it.
13
27
 
14
28
  ## Dimensions
15
29
 
@@ -27,7 +41,8 @@ Score each 0–3 (0 absent, 1 weak, 2 adequate, 3 strong) and give reasons a rev
27
41
  or weakened; snapshot updates explained; a coverage gate check green when present.
28
42
  - **Evidence**: the `Verification` table names commands and outcomes, not just commands;
29
43
  UI changes carry screenshots or video; CI is green on this head; `⚠️ Not tested` rows
30
- are absent or covered by an explicit reviewer instruction; each plan acceptance criterion
44
+ are absent or each carries an explicit reviewer instruction (the blocked behavior and the
45
+ exact steps to check it); each plan acceptance criterion
31
46
  has its named verification present.
32
47
 
33
48
  ## Architecture: Terreno rules
@@ -99,13 +114,14 @@ A finding here is blocking when it is certain and should-fix when it is likely.
99
114
  - A new runtime dependency is named in the PR body with the reason and is on the catalog
100
115
  in `.rulesync/rules/01-dependency-catalog.md` or justified against it; a missing reason
101
116
  lowers Architecture. Dev-only additions need no reason.
102
- - Patch bumps of catalog packages with green CI stay low. Minor bumps are medium. Major
103
- bumps, Expo SDK and React Native upgrades, Better Auth and Mongoose majors, and
104
- lockfile-only changes without a `package.json` change are high.
117
+ - Patch bumps of catalog packages with green CI stay low. Minor and major bumps, Expo SDK
118
+ and React Native upgrades, Mongoose majors, and lockfile-only changes without a
119
+ `package.json` change are medium. Better Auth and other auth or crypto majors are high.
105
120
  - A bump that changes generated output (`bun.lock`, snapshots, `openApiSdk.ts`,
106
121
  `plugins/terreno-claude/`) ships the regenerated output in the same PR.
107
122
  - A new dependency's license passes `bun run check:licenses`.
108
- - A `patches/` change is high: it edits a third party and needs the upstream issue linked.
123
+ - A `patches/` change is medium (high when it patches an auth, crypto, or parsing
124
+ dependency): it edits a third party and needs the upstream issue linked.
109
125
  - Removing a dependency the code still imports is a correctness finding; `knip` must stay
110
126
  at zero findings.
111
127
 
@@ -136,11 +152,13 @@ A finding here is blocking when it is certain and should-fix when it is likely.
136
152
 
137
153
  ## Signals that move the level
138
154
 
139
- - Raise one level: more than two packages touched; deletions outnumber additions in
155
+ - Raise one level, never above medium unless the change is security-related: more than
156
+ two packages touched; deletions outnumber additions in
140
157
  source; a `TODO`, `FIXME`, or commented-out code added; explicit `any` added; PR body
141
158
  missing `Why`, `What changed`, or `Verification`; `WIP` in the title; the plan edited
142
159
  in the same PR to match the code.
143
- - Never low: new logic without a test; a `⚠️ Not tested` row without a reviewer action; an unresolved bot thread;
160
+ - Never low: new logic without a test; a `⚠️ Not tested` row without an explicit reviewer instruction
161
+ (a row that does not name the blocked behavior and the exact steps to check it); an unresolved bot thread;
144
162
  a revert.
145
163
  - Size never moves the level. Changed lines and file counts say nothing about risk on
146
164
  their own: judge what the lines do. Pure renames and moves, regenerated SDK or
@@ -15,12 +15,15 @@ Understanding-oriented documentation: concepts, architecture, and context.
15
15
  - [Loop engineering](loop-engineering.md) — Fresh-invocation lifecycle, state, evidence, and orchestration boundaries
16
16
  - [GitHub issue lifecycle](../how-to/github-issue-lifecycle.md) — Pick-ready issues and plan comments for Pick/Roast
17
17
  - [Install agent skills](../how-to/install-agent-skills.md) — `npx skills add TerrenoLabs/terreno`
18
+ - [AI development loop](ai-development-loop.md) — The five-stage Ask, Generate, Run, Observe, Fix loop, what the agent can and cannot see, and how it composes with expo-mcp, Playwright MCP, and Maestro
19
+ - [Agent guidelines](agent-guidelines.md) — How hosted docs, per-package `.ai/` guidelines, and `.rulesync/` rules reach an agent, and how apps extend them
18
20
  - [AI observability](ai-observability.md) — Two planes (telemetry vs control), plugins vs LangfuseApp, SOP loop
19
21
  - [Durable agent harness](durable-agent-harness.md) — Phases, checkpoints, and why the audit span shares the checkpoint transaction
20
22
  - [AI-powered workflows](ai-workflows.md) — Autonomous documentation, testing, and maintenance workflows
21
23
  - [Agent UI Asks](agent-ui-asks.md) — Why agent questions are client-side tool calls, the pause and resume round trip, why cards carry exact answers, the watch paths, asks vs blocks
22
24
  - [Agent UI blocks](agent-ui-blocks.md) — Why chat replies use a closed YAML catalog instead of free-form UI, why steppers and checklists call the server, and the rich-blocks rollout
23
25
  - [Authentication architecture](authentication.md) — Better Auth, JWT, and optional MCP service tokens
26
+ - [Account linking](account-linking.md) — Linking modes, why both emails must be verified, Apple relay emails, and migrating JWT users
24
27
  - [Organization tenancy](organizations.md) — Optional Membership-backed tenancy, context, and isolation boundaries
25
28
  - [Configuration system](configuration-system.md) — Runtime configuration with database persistence
26
29
  - [Dependency management](dependency-management.md) — Catalog pins, exercise tests, fingerprint freeze
@@ -34,8 +37,10 @@ Understanding-oriented documentation: concepts, architecture, and context.
34
37
  - [Versioning policy](versioning-policy.md) — Lockstep `@terreno/*` versions, pre-1.0 breaks, deprecation window
35
38
  - [How admin interfaces are shaped](admin-interface.md) — Screens, sidebar, `apiBase` vs `routeBase`
36
39
  - [Admin plugin frontend widgets](admin-plugin-frontend.md) — Widget IDs from backend plugins
40
+ - [Consent forms](consent-forms.md) — Versions, responses, the consent gate, and why provisional signatures don't clear it
37
41
  - [Consent admin migration](admin-consent-migration.md) — Which consent screens stay hand-written
38
42
  - [Public roadmap process](roadmap-process.md) — GitHub roadmap vs Linear execution
39
43
  - [Example app coverage](example-coverage.md) — Which framework capabilities the example apps exercise
40
44
  - [Repository settings](repository-settings.md) — Maintainer GitHub settings that cannot be committed
41
45
  - [Why Terreno owns chart SVG](charts.md) — Owned `react-native-svg` vs victory-native
46
+ - [Responsive design](responsive-design.md) — Support levels, breakpoints, and the desktop floor