@terreno/mcp 57.21.0 → 58.0.0-beta.1

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 (244) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +57 -3
  3. package/dist/bootstrap.d.ts.map +1 -1
  4. package/dist/bootstrap.js +17 -16
  5. package/dist/bootstrap.js.map +1 -1
  6. package/dist/docs/guidelines/admin-frontend/guidelines/core.md +6 -5
  7. package/dist/docs/guidelines/ui/guidelines/core.md +1 -1
  8. package/dist/docs/prompts/debug.md +6 -4
  9. package/dist/docs/prompts/screen.md +11 -17
  10. package/dist/docs/resources/overview.md +5 -3
  11. package/dist/docs/resources/patterns.md +157 -238
  12. package/dist/docs/resources/syncdb.md +44 -16
  13. package/dist/docs/templates/bootstrap/CLAUDE.template.md +2 -2
  14. package/dist/docs/templates/bootstrap/cursorrules.template.md +7 -5
  15. package/dist/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +8 -12
  16. package/dist/docs/templates/bootstrap/frontend/app/_layout.template.tsx +75 -52
  17. package/dist/docs/templates/bootstrap/frontend/app/login.template.tsx +46 -108
  18. package/dist/docs/templates/bootstrap/frontend/app/signup.template.tsx +53 -0
  19. package/dist/docs/templates/bootstrap/frontend/lib/betterAuth.template.md +18 -0
  20. package/dist/docs/templates/bootstrap/frontend/store/apiClient.template.md +33 -0
  21. package/dist/docs/templates/bootstrap/frontend/store/apiSdk.template.md +76 -0
  22. package/dist/docs/templates/bootstrap/frontend/store/syncdb.template.md +56 -0
  23. package/dist/docs/templates/bootstrap/frontend/utils/index.template.md +0 -4
  24. package/dist/docs/upgrades/58.0.0-beta.1.md +504 -0
  25. package/dist/docs/upgrades/58.0.0.md +495 -4
  26. package/dist/docs/versioned/next/README.md +2 -2
  27. package/dist/docs/versioned/next/approval-rubric.md +2 -2
  28. package/dist/docs/versioned/next/explanation/admin-interface.md +6 -5
  29. package/dist/docs/versioned/next/explanation/admin-plugin-frontend.md +1 -1
  30. package/dist/docs/versioned/next/explanation/ai-workflows.md +5 -3
  31. package/dist/docs/versioned/next/explanation/announcements/rtk-deprecation.md +16 -11
  32. package/dist/docs/versioned/next/explanation/authentication.md +62 -43
  33. package/dist/docs/versioned/next/explanation/dependency-management.md +1 -1
  34. package/dist/docs/versioned/next/explanation/deployment-baseline.md +1 -1
  35. package/dist/docs/versioned/next/explanation/example-coverage.md +2 -2
  36. package/dist/docs/versioned/next/explanation/explicit-any-policy.md +5 -6
  37. package/dist/docs/versioned/next/explanation/gcp-hosting-architecture.md +1 -1
  38. package/dist/docs/versioned/next/explanation/local-first-data.md +11 -9
  39. package/dist/docs/versioned/next/explanation/model-router-actions.md +1 -1
  40. package/dist/docs/versioned/next/explanation/modular-api-design.md +2 -2
  41. package/dist/docs/versioned/next/explanation/no-barrel-imports.md +5 -5
  42. package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +4 -3
  43. package/dist/docs/versioned/next/explanation/source-rules.md +2 -2
  44. package/dist/docs/versioned/next/explanation/typescript-configuration.md +2 -4
  45. package/dist/docs/versioned/next/explanation/versioning-policy.md +3 -3
  46. package/dist/docs/versioned/next/how-to/README.md +3 -2
  47. package/dist/docs/versioned/next/how-to/add-feature-flags.md +50 -25
  48. package/dist/docs/versioned/next/how-to/add-organizations.md +2 -1
  49. package/dist/docs/versioned/next/how-to/admin-custom-home.md +8 -2
  50. package/dist/docs/versioned/next/how-to/admin-custom-widget.md +0 -1
  51. package/dist/docs/versioned/next/how-to/agent-ui-asks.md +6 -6
  52. package/dist/docs/versioned/next/how-to/build-admin-screens.md +10 -8
  53. package/dist/docs/versioned/next/how-to/build-for-web.md +1 -1
  54. package/dist/docs/versioned/next/how-to/call-external-apis.md +2 -2
  55. package/dist/docs/versioned/next/how-to/circleci.md +12 -6
  56. package/dist/docs/versioned/next/how-to/configure-better-auth.md +114 -60
  57. package/dist/docs/versioned/next/how-to/connect-mcp-service-token.md +10 -4
  58. package/dist/docs/versioned/next/how-to/create-a-terreno-app.md +14 -2
  59. package/dist/docs/versioned/next/how-to/debug-with-mcp.md +8 -13
  60. package/dist/docs/versioned/next/how-to/expose-mcp-tools.md +15 -4
  61. package/dist/docs/versioned/next/how-to/generate-the-client-sdk.md +33 -0
  62. package/dist/docs/versioned/next/how-to/github-actions-ci.md +2 -2
  63. package/dist/docs/versioned/next/how-to/in-app-notifications.md +1 -1
  64. package/dist/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +318 -447
  65. package/dist/docs/versioned/next/how-to/password-reset.md +1 -1
  66. package/dist/docs/versioned/next/how-to/product-announcements.md +6 -3
  67. package/dist/docs/versioned/next/how-to/rate-limiting.md +38 -16
  68. package/dist/docs/versioned/next/how-to/run-mongodb-migrations.md +19 -0
  69. package/dist/docs/versioned/next/how-to/run-tests-locally.md +2 -3
  70. package/dist/docs/versioned/next/how-to/set-up-social-login.md +1 -1
  71. package/dist/docs/versioned/next/how-to/set-up-terreno-mcp.md +2 -2
  72. package/dist/docs/versioned/next/how-to/track-upstream-expo.md +1 -1
  73. package/dist/docs/versioned/next/how-to/upgrade-banner.md +5 -3
  74. package/dist/docs/versioned/next/how-to/upgrade-terreno.md +5 -5
  75. package/dist/docs/versioned/next/how-to/use-syncdb-correctly.md +1 -1
  76. package/dist/docs/versioned/next/how-to/websocket-integration.md +113 -402
  77. package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
  78. package/dist/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +5 -0
  79. package/dist/docs/versioned/next/implementationPlans/native-module-baseline.md +29 -5
  80. package/dist/docs/versioned/next/implementationPlans/remove-legacy-realtime.md +1 -1
  81. package/dist/docs/versioned/next/implementationPlans/remove-rtk.md +185 -0
  82. package/dist/docs/versioned/next/reference/README.md +1 -1
  83. package/dist/docs/versioned/next/reference/admin-frontend.md +85 -70
  84. package/dist/docs/versioned/next/reference/admin-spa.md +10 -4
  85. package/dist/docs/versioned/next/reference/ai.md +36 -4
  86. package/dist/docs/versioned/next/reference/announcements.md +3 -3
  87. package/dist/docs/versioned/next/reference/api.md +39 -24
  88. package/dist/docs/versioned/next/reference/cli.md +3 -4
  89. package/dist/docs/versioned/next/reference/environment-variables.md +16 -16
  90. package/dist/docs/versioned/next/reference/feature-flags.md +48 -7
  91. package/dist/docs/versioned/next/reference/jobs.md +2 -2
  92. package/dist/docs/versioned/next/reference/legacy/rtk.md +25 -600
  93. package/dist/docs/versioned/next/reference/mcp-server.md +441 -1158
  94. package/dist/docs/versioned/next/reference/syncdb.md +426 -16
  95. package/dist/docs/versioned/next/reference/test.md +28 -3
  96. package/dist/docs/versioned/next/reference/ui.md +132 -19
  97. package/dist/docs/versioned/next/tasks/native-module-baseline.md +8 -4
  98. package/dist/docs/versioned/next/tasks/rate-limiting.md +9 -2
  99. package/dist/docs/versioned/next/tasks/remove-legacy-realtime.md +5 -5
  100. package/dist/docs/versioned/next/tasks/remove-rtk.md +155 -0
  101. package/dist/local/localTools.d.ts.map +1 -1
  102. package/dist/local/localTools.js +3 -54
  103. package/dist/local/localTools.js.map +1 -1
  104. package/dist/local/tools/runtime.d.ts +0 -21
  105. package/dist/local/tools/runtime.d.ts.map +1 -1
  106. package/dist/local/tools/runtime.js +0 -176
  107. package/dist/local/tools/runtime.js.map +1 -1
  108. package/dist/local/tools/syncDb.d.ts +0 -11
  109. package/dist/local/tools/syncDb.d.ts.map +1 -1
  110. package/dist/local/tools/syncDb.js +1 -5
  111. package/dist/local/tools/syncDb.js.map +1 -1
  112. package/dist/packageGuidelines.d.ts +3 -2
  113. package/dist/packageGuidelines.d.ts.map +1 -1
  114. package/dist/packageGuidelines.js +4 -11
  115. package/dist/packageGuidelines.js.map +1 -1
  116. package/dist/prompts.d.ts.map +1 -1
  117. package/dist/prompts.js +17 -18
  118. package/dist/prompts.js.map +1 -1
  119. package/dist/resources.d.ts.map +1 -1
  120. package/dist/resources.js +1 -8
  121. package/dist/resources.js.map +1 -1
  122. package/dist/search/chunker.d.ts +1 -1
  123. package/dist/search/chunker.d.ts.map +1 -1
  124. package/dist/search/inferPackages.d.ts +1 -1
  125. package/dist/search/inferPackages.js +5 -5
  126. package/dist/search/inferPackages.js.map +1 -1
  127. package/dist/tools.d.ts +6 -0
  128. package/dist/tools.d.ts.map +1 -1
  129. package/dist/tools.js +126 -119
  130. package/dist/tools.js.map +1 -1
  131. package/package.json +6 -6
  132. package/src/docs/guidelines/admin-frontend/guidelines/core.md +6 -5
  133. package/src/docs/guidelines/ui/guidelines/core.md +1 -1
  134. package/src/docs/prompts/debug.md +6 -4
  135. package/src/docs/prompts/screen.md +11 -17
  136. package/src/docs/resources/overview.md +5 -3
  137. package/src/docs/resources/patterns.md +157 -238
  138. package/src/docs/resources/syncdb.md +44 -16
  139. package/src/docs/templates/bootstrap/CLAUDE.template.md +2 -2
  140. package/src/docs/templates/bootstrap/cursorrules.template.md +7 -5
  141. package/src/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +8 -12
  142. package/src/docs/templates/bootstrap/frontend/app/_layout.template.tsx +75 -52
  143. package/src/docs/templates/bootstrap/frontend/app/login.template.tsx +46 -108
  144. package/src/docs/templates/bootstrap/frontend/app/signup.template.tsx +53 -0
  145. package/src/docs/templates/bootstrap/frontend/lib/betterAuth.template.md +18 -0
  146. package/src/docs/templates/bootstrap/frontend/store/apiClient.template.md +33 -0
  147. package/src/docs/templates/bootstrap/frontend/store/apiSdk.template.md +76 -0
  148. package/src/docs/templates/bootstrap/frontend/store/syncdb.template.md +56 -0
  149. package/src/docs/templates/bootstrap/frontend/utils/index.template.md +0 -4
  150. package/src/docs/upgrades/58.0.0-beta.1.md +504 -0
  151. package/src/docs/upgrades/58.0.0.md +495 -4
  152. package/src/docs/versioned/next/README.md +2 -2
  153. package/src/docs/versioned/next/approval-rubric.md +2 -2
  154. package/src/docs/versioned/next/explanation/admin-interface.md +6 -5
  155. package/src/docs/versioned/next/explanation/admin-plugin-frontend.md +1 -1
  156. package/src/docs/versioned/next/explanation/ai-workflows.md +5 -3
  157. package/src/docs/versioned/next/explanation/announcements/rtk-deprecation.md +16 -11
  158. package/src/docs/versioned/next/explanation/authentication.md +62 -43
  159. package/src/docs/versioned/next/explanation/dependency-management.md +1 -1
  160. package/src/docs/versioned/next/explanation/deployment-baseline.md +1 -1
  161. package/src/docs/versioned/next/explanation/example-coverage.md +2 -2
  162. package/src/docs/versioned/next/explanation/explicit-any-policy.md +5 -6
  163. package/src/docs/versioned/next/explanation/gcp-hosting-architecture.md +1 -1
  164. package/src/docs/versioned/next/explanation/local-first-data.md +11 -9
  165. package/src/docs/versioned/next/explanation/model-router-actions.md +1 -1
  166. package/src/docs/versioned/next/explanation/modular-api-design.md +2 -2
  167. package/src/docs/versioned/next/explanation/no-barrel-imports.md +5 -5
  168. package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +4 -3
  169. package/src/docs/versioned/next/explanation/source-rules.md +2 -2
  170. package/src/docs/versioned/next/explanation/typescript-configuration.md +2 -4
  171. package/src/docs/versioned/next/explanation/versioning-policy.md +3 -3
  172. package/src/docs/versioned/next/how-to/README.md +3 -2
  173. package/src/docs/versioned/next/how-to/add-feature-flags.md +50 -25
  174. package/src/docs/versioned/next/how-to/add-organizations.md +2 -1
  175. package/src/docs/versioned/next/how-to/admin-custom-home.md +8 -2
  176. package/src/docs/versioned/next/how-to/admin-custom-widget.md +0 -1
  177. package/src/docs/versioned/next/how-to/agent-ui-asks.md +6 -6
  178. package/src/docs/versioned/next/how-to/build-admin-screens.md +10 -8
  179. package/src/docs/versioned/next/how-to/build-for-web.md +1 -1
  180. package/src/docs/versioned/next/how-to/call-external-apis.md +2 -2
  181. package/src/docs/versioned/next/how-to/circleci.md +12 -6
  182. package/src/docs/versioned/next/how-to/configure-better-auth.md +114 -60
  183. package/src/docs/versioned/next/how-to/connect-mcp-service-token.md +10 -4
  184. package/src/docs/versioned/next/how-to/create-a-terreno-app.md +14 -2
  185. package/src/docs/versioned/next/how-to/debug-with-mcp.md +8 -13
  186. package/src/docs/versioned/next/how-to/expose-mcp-tools.md +15 -4
  187. package/src/docs/versioned/next/how-to/generate-the-client-sdk.md +33 -0
  188. package/src/docs/versioned/next/how-to/github-actions-ci.md +2 -2
  189. package/src/docs/versioned/next/how-to/in-app-notifications.md +1 -1
  190. package/src/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +318 -447
  191. package/src/docs/versioned/next/how-to/password-reset.md +1 -1
  192. package/src/docs/versioned/next/how-to/product-announcements.md +6 -3
  193. package/src/docs/versioned/next/how-to/rate-limiting.md +38 -16
  194. package/src/docs/versioned/next/how-to/run-mongodb-migrations.md +19 -0
  195. package/src/docs/versioned/next/how-to/run-tests-locally.md +2 -3
  196. package/src/docs/versioned/next/how-to/set-up-social-login.md +1 -1
  197. package/src/docs/versioned/next/how-to/set-up-terreno-mcp.md +2 -2
  198. package/src/docs/versioned/next/how-to/track-upstream-expo.md +1 -1
  199. package/src/docs/versioned/next/how-to/upgrade-banner.md +5 -3
  200. package/src/docs/versioned/next/how-to/upgrade-terreno.md +5 -5
  201. package/src/docs/versioned/next/how-to/use-syncdb-correctly.md +1 -1
  202. package/src/docs/versioned/next/how-to/websocket-integration.md +113 -402
  203. package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
  204. package/src/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +5 -0
  205. package/src/docs/versioned/next/implementationPlans/native-module-baseline.md +29 -5
  206. package/src/docs/versioned/next/implementationPlans/remove-legacy-realtime.md +1 -1
  207. package/src/docs/versioned/next/implementationPlans/remove-rtk.md +185 -0
  208. package/src/docs/versioned/next/reference/README.md +1 -1
  209. package/src/docs/versioned/next/reference/admin-frontend.md +85 -70
  210. package/src/docs/versioned/next/reference/admin-spa.md +10 -4
  211. package/src/docs/versioned/next/reference/ai.md +36 -4
  212. package/src/docs/versioned/next/reference/announcements.md +3 -3
  213. package/src/docs/versioned/next/reference/api.md +39 -24
  214. package/src/docs/versioned/next/reference/cli.md +3 -4
  215. package/src/docs/versioned/next/reference/environment-variables.md +16 -16
  216. package/src/docs/versioned/next/reference/feature-flags.md +48 -7
  217. package/src/docs/versioned/next/reference/jobs.md +2 -2
  218. package/src/docs/versioned/next/reference/legacy/rtk.md +25 -600
  219. package/src/docs/versioned/next/reference/mcp-server.md +441 -1158
  220. package/src/docs/versioned/next/reference/syncdb.md +426 -16
  221. package/src/docs/versioned/next/reference/test.md +28 -3
  222. package/src/docs/versioned/next/reference/ui.md +132 -19
  223. package/src/docs/versioned/next/tasks/native-module-baseline.md +8 -4
  224. package/src/docs/versioned/next/tasks/rate-limiting.md +9 -2
  225. package/src/docs/versioned/next/tasks/remove-legacy-realtime.md +5 -5
  226. package/src/docs/versioned/next/tasks/remove-rtk.md +155 -0
  227. package/dist/docs/guidelines/rtk/guidelines/core.md +0 -26
  228. package/dist/docs/resources/rtk.md +0 -181
  229. package/dist/docs/templates/bootstrap/frontend/openapi-config.template.md +0 -16
  230. package/dist/docs/templates/bootstrap/frontend/scripts/generate-sdk.template.md +0 -49
  231. package/dist/docs/templates/bootstrap/frontend/store/appState.template.md +0 -45
  232. package/dist/docs/templates/bootstrap/frontend/store/errors.template.md +0 -51
  233. package/dist/docs/templates/bootstrap/frontend/store/index.template.md +0 -86
  234. package/dist/docs/templates/bootstrap/frontend/store/openApiSdk.template.md +0 -49
  235. package/dist/docs/templates/bootstrap/frontend/store/sdk.template.md +0 -80
  236. package/src/docs/guidelines/rtk/guidelines/core.md +0 -26
  237. package/src/docs/resources/rtk.md +0 -181
  238. package/src/docs/templates/bootstrap/frontend/openapi-config.template.md +0 -16
  239. package/src/docs/templates/bootstrap/frontend/scripts/generate-sdk.template.md +0 -49
  240. package/src/docs/templates/bootstrap/frontend/store/appState.template.md +0 -45
  241. package/src/docs/templates/bootstrap/frontend/store/errors.template.md +0 -51
  242. package/src/docs/templates/bootstrap/frontend/store/index.template.md +0 -86
  243. package/src/docs/templates/bootstrap/frontend/store/openApiSdk.template.md +0 -49
  244. package/src/docs/templates/bootstrap/frontend/store/sdk.template.md +0 -80
@@ -4,7 +4,7 @@ Set up Better Auth as the **default** authentication provider for new Terreno ap
4
4
 
5
5
  ## Overview
6
6
 
7
- Better Auth is the recommended authentication system for new Terreno frontends. Register `BetterAuthApp` on the backend, set `AUTH_PROVIDER=better-auth`, and wire `createBetterAuthClient` + `generateBetterAuthSlice` on the client. Pair with `betterAuthAdapter` when using `@terreno/syncdb`.
7
+ Better Auth is the recommended authentication system for new Terreno frontends. Register `BetterAuthApp` on the backend, set `AUTH_PROVIDER=better-auth`, and on the client create the client with `createBetterAuthClient` and wrap the app in `SessionProvider`, both from `@terreno/syncdb/auth`. Pass the same client to `betterAuthAdapter` for `createSyncDb` and the API client.
8
8
 
9
9
  JWT/Passport remains available for legacy deployments (`AUTH_PROVIDER=jwt`). Both can run in parallel during migration.
10
10
 
@@ -378,17 +378,22 @@ const userSchema = new mongoose.Schema(
378
378
  ### 1. Create Better Auth Client
379
379
 
380
380
  ``````typescript
381
- import {createBetterAuthClient} from "@terreno/rtk";
381
+ // lib/betterAuth.ts
382
+ import {createBetterAuthClient} from "@terreno/syncdb/auth";
383
+ import {baseUrl} from "@terreno/syncdb/config";
382
384
 
383
385
  // `scheme` is the app's deep-link scheme (required).
384
386
  export const authClient = createBetterAuthClient({
385
- baseURL: process.env.EXPO_PUBLIC_API_URL || "http://localhost:4000",
386
- scheme: "yourapp",
387
+ baseURL: baseUrl,
388
+ scheme: "yourapp", // app.json "scheme", for OAuth deep links
389
+ storagePrefix: "yourapp",
387
390
  });
388
391
  ``````
389
392
 
390
- On web the client authenticates with Better Auth's session cookie. When the web frontend and
391
- the API are on different sites, use [bearer mode](#frontend-and-api-on-different-sites).
393
+ The client stores its session in `expo-secure-store` on native and AsyncStorage on web.
394
+ Install them in the app with `bunx expo install expo-secure-store @react-native-async-storage/async-storage`.
395
+
396
+ Install them in the app with `bunx expo install expo-secure-store @react-native-async-storage/async-storage`.
392
397
 
393
398
  A cookie-authenticated `POST`, `PUT`, `PATCH`, or `DELETE` to any Terreno route is
394
399
  authenticated only when its `Origin` (or, without one, its `Referer`) is in `trustedOrigins` or
@@ -406,7 +411,7 @@ the matching Better Auth client plugins and their typed methods:
406
411
 
407
412
  ``````typescript
408
413
  import {router} from "expo-router";
409
- import {createBetterAuthClient} from "@terreno/rtk";
414
+ import {createBetterAuthClient} from "@terreno/syncdb/auth";
410
415
 
411
416
  export const authClient = createBetterAuthClient({
412
417
  baseURL: process.env.EXPO_PUBLIC_API_URL || "http://localhost:4000",
@@ -447,27 +452,54 @@ Notes:
447
452
  - **Server first.** A client feature only adds client methods. Turn the feature on in
448
453
  `BetterAuthConfig` too, or its calls answer 404.
449
454
 
450
- ### 2. Add Session Redux Slice
455
+ ### 2. Provide the Session
456
+
457
+ Wrap the app in `SessionProvider` and read the session with `useSession()`. No Redux store is
458
+ needed.
459
+
460
+ ``````tsx
461
+ // app/_layout.tsx
462
+ import {SessionProvider, useSession} from "@terreno/syncdb/auth";
463
+ import {authClient} from "@/lib/betterAuth";
464
+ import {syncDb} from "@/store/syncdb";
465
+
466
+ const RootLayout = (): React.ReactElement => (
467
+ <SessionProvider authClient={authClient} syncDbs={[syncDb]}>
468
+ <RootNavigator />
469
+ </SessionProvider>
470
+ );
471
+
472
+ const RootNavigator = (): React.ReactElement => {
473
+ const {userId, isLoading} = useSession();
474
+ if (isLoading) {
475
+ return <Spinner />;
476
+ }
477
+ return userId ? <AppTabs /> : <LoginScreen />;
478
+ };
479
+ ``````
480
+
481
+ The provider reads the session on start and follows Better Auth's session signal, so a
482
+ sign-in or sign-out updates `useSession()` on its own. `logout()` from `useSession()` signs
483
+ out of Better Auth, signs out each `syncDbs` client (create it with `wipeOnSignOut: true` to
484
+ wipe local data), runs `onLogout`, and clears the session.
485
+
486
+ After an email sign-in, call `refresh()` to resolve the user right away:
451
487
 
452
488
  ``````typescript
453
- import {generateBetterAuthSlice} from "@terreno/rtk";
454
- import {configureStore} from "@reduxjs/toolkit";
455
- import {authClient} from "./authClient";
456
- import {api} from "./sdk"; // the app's generated RTK Query API
457
-
458
- // Purge the SDK's cached responses on logout or user switch.
459
- const betterAuth = generateBetterAuthSlice({apisToReset: [api], authClient});
460
-
461
- export const store = configureStore({
462
- reducer: {
463
- betterAuth: betterAuth.reducer, // selectors read `state.betterAuth`
464
- // ... other reducers
465
- },
466
- middleware: (getDefault) => getDefault().concat(...betterAuth.middleware),
467
- });
489
+ const {refresh} = useSession();
468
490
 
469
- // Call after sign-in, sign-out, and at app startup to copy the session into Redux
470
- void betterAuth.syncSession(store.dispatch);
491
+ const result = await authClient.signIn.email({email, password});
492
+ if (!result.error) {
493
+ await refresh();
494
+ }
495
+ ``````
496
+
497
+ For `@terreno/syncdb`, build the auth provider from the same client:
498
+
499
+ ``````typescript
500
+ import {betterAuthAdapter, bridgeBetterAuthReactClient} from "@terreno/syncdb/auth";
501
+
502
+ export const authProvider = betterAuthAdapter(bridgeBetterAuthReactClient(authClient));
471
503
  ``````
472
504
 
473
505
  ### 3. Add Social Login UI
@@ -476,7 +508,7 @@ Use the SocialLoginButton component:
476
508
 
477
509
  ``````typescript
478
510
  import {SocialLoginButton, Box} from "@terreno/ui";
479
- import {authClient} from "@/store/authClient";
511
+ import {authClient} from "@/lib/betterAuth";
480
512
 
481
513
  const LoginScreen = () => {
482
514
  return (
@@ -524,7 +556,7 @@ Better Auth's `lastLoginMethod`, which reads a backend cookie that a cross-site
524
556
  see.
525
557
 
526
558
  ``````typescript
527
- import {createRememberedAccountsStore, toLoginAccountOptions, useRememberedAccounts} from "@terreno/rtk";
559
+ import {createRememberedAccountsStore, toLoginAccountOptions, useRememberedAccounts} from "@terreno/syncdb/auth";
528
560
  import {LoginScreen} from "@terreno/ui";
529
561
 
530
562
  // One store per app, at module scope.
@@ -606,7 +638,7 @@ only the sign-in methods the server enables, and it records each sign-in in the
606
638
  [remembered accounts](#4-remember-accounts-on-this-device) store.
607
639
 
608
640
  ``````typescript
609
- import {createRememberedAccountsStore, TerrenoLoginScreen} from "@terreno/rtk";
641
+ import {createRememberedAccountsStore, TerrenoLoginScreen} from "@terreno/syncdb/auth";
610
642
  import {useLocalSearchParams, useRouter} from "expo-router";
611
643
 
612
644
  export const rememberedAccounts = createRememberedAccountsStore({rememberIdentity: false});
@@ -670,18 +702,19 @@ What it does:
670
702
  the screen has to see the returned session to record it, and it navigates on by itself. Pass
671
703
  `onStepChange` to catch the screen landing on its `login` step while your app already holds a
672
704
  session (the live-session check failed), and navigate away there; example-frontend's
673
- `app/login.tsx` does both, and skips re-syncing Redux in `onSignedIn` when it already holds the
674
- user.
675
- - **Signing out.** Dispatch `generateBetterAuthSlice`'s `logout()`. It keeps the session until
676
- `authClient.signOut()` answers, then clears it, so the login screen never opens while the old
677
- session is still live. Meanwhile `selectBetterAuthIsSigningOut` is true: show it on the
678
- sign-out control. `logout()` leaves `isLoading` alone, so the screen stays put; if your
679
- navigator shows a spinner on `selectBetterAuthIsLoading`, show it only while no user is
680
- loaded (`isLoading && !userId`), or a session refresh would remount the navigator on its
681
- first tab. A sign-out that cannot reach the server leaves a cookie or native session in place
682
- and sets the slice's `error` (`SIGN_OUT_FAILED_MESSAGE`); show it. Stop anything that calls the
683
- API with the session first: example-frontend's `logout` in `store/index.ts` stops syncdb,
684
- then dispatches `logout()`, and its profile screen shows both.
705
+ `app/login.tsx` does both, and skips `refresh()` in `onSignedIn` when the session already holds
706
+ the user.
707
+ - **Signing out.** Call `logout()` from `useSession()`. It keeps the session until
708
+ `authClient.signOut()` answers, then signs out each `syncDbs` client (wiping local data when
709
+ `wipeOnSignOut` is set) and clears the session, so the login screen never opens while the old
710
+ session is still live. Meanwhile `isSigningOut` is true: show it on the sign-out control.
711
+ `logout()` leaves `isLoading` alone, so the screen stays put; if your navigator shows a
712
+ spinner on `isLoading`, show it only while no user is loaded (`isLoading && !userId`), or a
713
+ session refresh would remount the navigator on its first tab. A sign-out that cannot reach the
714
+ server (or that the server refuses, or that outlasts `signOutTimeoutMs`, 10 seconds by default)
715
+ leaves a cookie or native session in place, wipes nothing, and sets `error` to
716
+ `SIGN_OUT_FAILED_MESSAGE`; show it. A bearer client that has dropped its token before the
717
+ request signs out locally. example-frontend's profile screen shows both states.
685
718
  - **Sign-up.** The sign-up link hides when the server's sign-up is closed (`signUp: false`).
686
719
  - **No email and password.** When the server has `emailPassword` off, the form, the Sign in
687
720
  button, and the forgot-password link are left out (`LoginScreen` with `fields={[]}`), and a
@@ -765,7 +798,7 @@ every card to the Better Auth client. Each card shows only when the server's
765
798
  [`/terreno/methods`](../reference/api.md#better-auth-authentication) turns its feature on.
766
799
 
767
800
  ``````typescript
768
- import {TerrenoAccountSecurityScreen} from "@terreno/rtk";
801
+ import {TerrenoAccountSecurityScreen} from "@terreno/syncdb/auth";
769
802
  import {useLocalSearchParams} from "expo-router";
770
803
 
771
804
  const Security = (): React.ReactElement => {
@@ -869,10 +902,11 @@ Safari block it. The user signs in and is signed out on the next request.
869
902
  Use bearer mode in that case. Keep cookie mode when the frontend and API share a site.
870
903
 
871
904
  ``````typescript
872
- import {createBetterAuthClient} from "@terreno/rtk";
905
+ import {createBetterAuthClient} from "@terreno/syncdb/auth";
906
+ import {baseUrl} from "@terreno/syncdb/config";
873
907
 
874
908
  export const authClient = createBetterAuthClient({
875
- baseURL: process.env.EXPO_PUBLIC_API_URL || "http://localhost:4000",
909
+ baseURL: baseUrl,
876
910
  scheme: "yourapp",
877
911
  webAuth: "bearer",
878
912
  });
@@ -904,14 +938,23 @@ Content-Security-Policy. `localStorage` is readable by any XSS on the frontend's
904
938
  outlives the tab, so a stolen or forgotten token stays usable after the person closes it.
905
939
 
906
940
  Read the stored token outside the client, without a network call, with
907
- `getBetterAuthBearerToken({storagePrefix?, bearerStorage?})`. Pass the same options the client
908
- was created with.
941
+ `getBetterAuthBearerToken({storagePrefix?, bearerStorage?})` from `@terreno/syncdb/auth`. Pass
942
+ the same options the client was created with. Pass it to `betterAuthAdapter` as
943
+ `getBearerToken` so the shared `authProvider` reads the token locally instead of calling
944
+ `get-session` on every request:
945
+
946
+ ``````typescript
947
+ import {betterAuthAdapter, bridgeBetterAuthReactClient, getBetterAuthBearerToken} from "@terreno/syncdb/auth";
948
+
949
+ export const authProvider = betterAuthAdapter(bridgeBetterAuthReactClient(authClient), {
950
+ getBearerToken: () => getBetterAuthBearerToken({storagePrefix: "yourapp"}),
951
+ });
952
+ ``````
909
953
 
910
954
  example-frontend shows the whole setup. `EXPO_PUBLIC_BETTER_AUTH_WEB_BEARER=true` turns on
911
955
  bearer mode in `lib/betterAuth.ts`. `store/syncdb.ts` passes the stored token to
912
- `betterAuthAdapter` as `getBearerToken`, and `store/index.ts` registers that adapter with
913
- `setTokenSource` before it creates the store, so RTK Query, the socket and MCP tools send the
914
- same token. `e2e/crossSiteBearer.spec.ts` signs in from `localhost:8082` to an API on
956
+ `betterAuthAdapter` as `getBearerToken`, and that one `authProvider` feeds syncdb (and its
957
+ socket), the request client, and MCP tools, so they all send the same token. `e2e/crossSiteBearer.spec.ts` signs in from `localhost:8082` to an API on
915
958
  `127.0.0.1:4000` with every `set-cookie` header stripped, then reloads.
916
959
 
917
960
  ### Server requirements
@@ -938,7 +981,7 @@ same token. `e2e/crossSiteBearer.spec.ts` signs in from `localhost:8082` to an A
938
981
  ### Social sign-in in bearer mode
939
982
 
940
983
  The server adds a single-use, three-minute token to the OAuth callback's redirect, in the URL
941
- fragment, and the web app exchanges it for the bearer. rtk binds each exchange to a random
984
+ fragment, and the web app exchanges it for the bearer. syncdb binds each exchange to a random
942
985
  nonce the tab stored when it started the sign-in, so a token planted in a link is never sent.
943
986
 
944
987
  1. On the server, list the web app's origin and the one page that reads the token. The origin
@@ -965,7 +1008,7 @@ nonce the tab stored when it started the sign-in, so a token planted in a link i
965
1008
  navigation, never with `fetch`, an `<img>`, or an `<iframe>`:
966
1009
 
967
1010
  ``````typescript
968
- import {signInSocialWithHandoff} from "@terreno/rtk";
1011
+ import {signInSocialWithHandoff} from "@terreno/syncdb/auth";
969
1012
 
970
1013
  <SocialLoginButton
971
1014
  provider="google"
@@ -988,10 +1031,12 @@ nonce the tab stored when it started the sign-in, so a token planted in a link i
988
1031
  before Sentry, analytics, or other third-party scripts start:
989
1032
 
990
1033
  ``````typescript
991
- import {completeBetterAuthOAuthHandoff} from "@terreno/rtk";
1034
+ import {completeBetterAuthOAuthHandoff} from "@terreno/syncdb/auth";
992
1035
 
993
- await completeBetterAuthOAuthHandoff({client: authClient});
994
- await betterAuth.syncSession(store.dispatch);
1036
+ const stored = await completeBetterAuthOAuthHandoff({client: authClient});
1037
+ if (stored) {
1038
+ await refresh(); // useSession().refresh(): SessionProvider read the session before the exchange
1039
+ }
995
1040
  initSentry();
996
1041
  ``````
997
1042
 
@@ -1005,7 +1050,10 @@ nonce the tab stored when it started the sign-in, so a token planted in a link i
1005
1050
 
1006
1051
  4. Show sign-in errors from the query. A failed start or callback comes back with
1007
1052
  `?error=provider_not_found`, `?error=sign_in_failed`, or one of Better Auth's own `error=`
1008
- codes. The function resolves `false` and leaves `error` in the URL.
1053
+ codes. The function resolves `false` and leaves `error` in the URL. On better-auth 1.6 (the
1054
+ version Terreno 58 pins), a generic OAuth provider's own error (such as `access_denied`)
1055
+ goes to the API's `{basePath}/error` page instead of `errorCallbackURL`.
1056
+ No token is issued either way.
1009
1057
 
1010
1058
  The return page must not redirect, on the server or in the browser, before the function has
1011
1059
  run. A browser carries the fragment through a redirect that has none of its own, so a redirect
@@ -1018,14 +1066,14 @@ the handoff only, so a token never goes to a page on the visitor's own machine,
1018
1066
  start when no other origin is left in `CORS_ORIGINS`. CORS and `trustedOrigins` keep them.
1019
1067
  `app/login.tsx` renders `TerrenoLoginScreen` with `callbackURL="/login"` in bearer mode, so its
1020
1068
  social buttons start with `signInSocialWithHandoff` and come back to the same screen, which finds
1021
- the session and records the method. `app/_layout.tsx` syncs the session only after the exchange
1069
+ the session and records the method. `app/_layout.tsx` refreshes the session only after the exchange
1022
1070
  resolves, and leaves a signed-in user on `/login` so the screen can record the sign-in before it
1023
1071
  navigates on.
1024
1072
 
1025
1073
  In an Expo Router app, run the exchange from the entry file, not from a layout. Expo Router
1026
1074
  copies the URL, fragment included, as soon as it is imported, and writes that copy back into
1027
1075
  the address bar when it routes, which would put `ott` and `handoff` back. Importing
1028
- `@terreno/rtk` imports Expo Router too (through `@terreno/ui`). example-frontend's `index.js`
1076
+ `@terreno/ui` imports Expo Router too. example-frontend's `index.js`
1029
1077
  first imports `lib/oauthHandoffUrl.ts`, which has no imports and hides `handoff` and `ott` from
1030
1078
  the URL, then `lib/oauthHandoff.ts`, which puts the URL back and calls
1031
1079
  `completeBetterAuthOAuthHandoff` in the same synchronous step, then `expo-router/entry`.
@@ -1049,12 +1097,12 @@ must refuse.
1049
1097
  A signed-in user links Google, GitHub, or a generic OAuth provider from the Security screen. In
1050
1098
  cookie mode `authClient.linkSocial` does this. In bearer mode it can't: its
1051
1099
  `POST /link-social` fetch comes from another site, so the OAuth state cookie it needs on the
1052
- API's origin is never set. Use `linkSocialWithHandoff` from `@terreno/rtk` instead. It needs
1100
+ API's origin is never set. Use `linkSocialWithHandoff` from `@terreno/syncdb/auth` instead. It needs
1053
1101
  the same `oauthHandoff` server config as social sign-in, and account linking must be on
1054
1102
  (`accountLinking.mode` other than `never`).
1055
1103
 
1056
1104
  ``````typescript
1057
- import {linkSocialWithHandoff} from "@terreno/rtk";
1105
+ import {linkSocialWithHandoff} from "@terreno/syncdb/auth";
1058
1106
 
1059
1107
  const {error} = await linkSocialWithHandoff({
1060
1108
  callbackURL: "/settings/security", // any page on a web origin; sent as an absolute URL
@@ -1125,7 +1173,7 @@ const sessionStorageOrDefault = (): Storage | undefined => {
1125
1173
  };
1126
1174
 
1127
1175
  export const authClient = createBetterAuthClient({
1128
- baseURL: process.env.EXPO_PUBLIC_API_URL || "http://localhost:4000",
1176
+ baseURL: baseUrl,
1129
1177
  bearerStorage: sessionStorageOrDefault(),
1130
1178
  scheme: "yourapp",
1131
1179
  webAuth: "bearer",
@@ -1176,6 +1224,11 @@ Verify the callback URLs in your OAuth provider settings match your `BETTER_AUTH
1176
1224
 
1177
1225
  Check that `trustedOrigins` in your Better Auth config includes your app's deep link scheme (e.g., `"yourapp://"`).
1178
1226
 
1227
+ On native, if every request fails before it is sent after an app update, the stored cookie jar
1228
+ may hold an entry the Expo plugin cannot read. `createBetterAuthClient` drops such entries on
1229
+ read and logs `Discarded … unreadable Better Auth cookie entry`; sign in again to restore the
1230
+ session.
1231
+
1179
1232
  ### Social login opens browser but doesn't redirect back
1180
1233
 
1181
1234
  Ensure your mobile app has the proper deep link configuration in `app.json`:
@@ -1220,5 +1273,6 @@ so new accounts cannot be created through the legacy `/auth/signup`.
1220
1273
 
1221
1274
  - [Authentication Architecture](../explanation/authentication.md)
1222
1275
  - [@terreno/api Reference](../reference/api.md#better-auth)
1223
- - [@terreno/rtk Reference (legacy)](../reference/legacy/rtk.md#better-auth-integration)
1276
+ - [@terreno/syncdb Reference: Auth](../reference/syncdb.md#auth)
1277
+ - [Upgrade from @terreno/rtk to @terreno/syncdb](migrate-rtk-to-syncdb.md)
1224
1278
  - [Better Auth Documentation](https://better-auth.com/)
@@ -35,13 +35,13 @@ Cap is **10** active tokens per user. List rows show prefix (`mcp_` + eight hex
35
35
  Use a session or JWT. A service token cannot mint another token.
36
36
 
37
37
  ```bash
38
- curl -X POST "$API/mcp/service-tokens" \
38
+ curl -X POST "$API/mcp/service-tokens/create" \
39
39
  -H "Authorization: Bearer $JWT" \
40
40
  -H "Content-Type: application/json" \
41
41
  -d '{"name":"Perplexity"}'
42
42
  ```
43
43
 
44
- Read `data.token` and `data.mcpUrl` from the JSON. List and revoke never return `token`. Do not log the secret.
44
+ Read `data.token` and `data.mcpUrl` from the JSON. Only this create response carries `token`. List, read, revoke, and the synced `mcp/service-tokens` collection never return `token` or `tokenHash`. Do not log the secret.
45
45
 
46
46
  ## 4. Perplexity custom connector
47
47
 
@@ -104,11 +104,17 @@ The token acts as the owning user on **MCP only**. It cannot mint or list tokens
104
104
 
105
105
  ## 7. Revoke
106
106
 
107
- - **Owner:** Profile → MCP connections → **Revoke** on the row (`DELETE /mcp/service-tokens/:id`).
108
- - **Admin:** Admin → MCP service tokens (`/admin/mcp-service-tokens`). Create and update are off. Delete sets `revokedAt`; it does not hard-delete the row.
107
+ - **Owner:** Profile → MCP connections → **Revoke** on the row (`POST /mcp/service-tokens/:id/revoke`).
108
+ - **Admin:** Admin → MCP service tokens (`/admin/mcp-service-tokens`). Create and update are off. Delete sets `revokedAt`; it does not hard-delete or tombstone the row.
109
+
110
+ The token list is a synced collection (`mcp/service-tokens`, owner-scoped), so a revoke from another device or the admin panel shows up on the owner's list as a `revokedAt` update.
109
111
 
110
112
  Revoked and expired keys fail `tools/call` immediately. Disabled user accounts are refused the same way as over HTTP.
111
113
 
114
+ ## Upgrading from 57.x
115
+
116
+ 58.0.0 gives `McpServiceToken` String ids. Before deploying, add the `mcp-service-token-string-ids` framework migration to your `migrations/` directory and apply it. Existing tokens keep working and keep their ids as hex strings. See [Run MongoDB migrations](run-mongodb-migrations.md#framework-migrations).
117
+
112
118
  A password reset, Better Auth password change, or "sign out everywhere" (`revoke-sessions` / `revoke-other-sessions`) bumps the user's `tokenEpoch` and ends every key minted before it. The keys show as revoked in the list; mint a new one for each client you still use.
113
119
 
114
120
  To put `/mcp` on the public internet behind a Cloudflare Tunnel, see [Expose an MCP server safely](expose-mcp-server-safely.md).
@@ -58,7 +58,7 @@ cd .. && bunx create-terreno-app my-app --yes
58
58
  | Path | Purpose |
59
59
  | --- | --- |
60
60
  | `backend/` | Express/Mongoose API (`@terreno/api`, Better Auth, admin, sync) |
61
- | `frontend/` | Expo universal app (`@terreno/ui`, `@terreno/syncdb`, `@terreno/rtk`) |
61
+ | `frontend/` | Expo universal app (`@terreno/ui`, `@terreno/syncdb`). No Redux: session from `@terreno/syncdb/auth`, requests through `store/apiClient.ts`, generated hooks in `store/apiSdk.ts` |
62
62
  | `Dockerfile` | Consumer backend image (`backend/` only — not the Terreno monorepo) |
63
63
  | `.dockerignore` | Excludes local env secrets, dependencies, and build output from the image context |
64
64
  | `backend/.env`, `frontend/.env` | Gitignored local-dev defaults (written on scaffold). `backend/.env` sets `NODE_ENV=development`, which turns on the dev-only `POST /__terreno/browser-logs` route |
@@ -69,6 +69,18 @@ cd .. && bunx create-terreno-app my-app --yes
69
69
 
70
70
  Generated `@terreno/*` dependencies pin to `^<create-terreno-app version>` at scaffold time.
71
71
 
72
+ ### Frontend data and session wiring
73
+
74
+ | File | What it does |
75
+ | --- | --- |
76
+ | `frontend/lib/betterAuth.ts` | `createBetterAuthClient` from `@terreno/syncdb/auth`, pointed at `baseUrl` from `@terreno/syncdb/config` |
77
+ | `frontend/store/syncdb.ts` | `authProvider` (Better Auth session token) and the `syncDb` client for synced collections |
78
+ | `frontend/store/apiClient.ts` | `createApiClient` from `@terreno/syncdb/api` with the same `authProvider`, `App-Version` / `App-Platform` headers, and `getAdminAuthHeaders` for `AdminProvider` |
79
+ | `frontend/store/apiSdk.ts` | Typed hooks for non-synced routes (`useGetAuthMeQuery`, `usePatchAuthMeMutation`, ...). The scaffold ships the `/auth/me` hooks; `bun run sdk` regenerates the file for every route |
80
+ | `frontend/app/_layout.tsx` | `ApiClientProvider` + `SessionProvider` (`useSession()` gives `userId`, `isLoading`, `refresh`, `logout`) + `SyncDbProvider`; starts `syncDb` after login |
81
+
82
+ `bun run sdk` runs the `api-sdk` script: `terreno-syncdb-codegen --schema $OPENAPI_URL --api-out ./store/apiSdk.ts` (default schema `http://localhost:4000/openapi.json`). Never edit `apiSdk.ts` by hand.
83
+
72
84
  ## 2. Install dependencies
73
85
 
74
86
  ```bash
@@ -122,7 +134,7 @@ Health check: `curl http://localhost:4000/health` → `"healthy":true`.
122
134
  Terminal 2 — web UI (port `8082`):
123
135
 
124
136
  ```bash
125
- (cd frontend && bun run sdk) # after backend is up; regenerates OpenAPI hooks
137
+ (cd frontend && bun run sdk) # after backend is up; regenerates store/apiSdk.ts
126
138
  (cd frontend && bun run web)
127
139
  ```
128
140
 
@@ -399,26 +399,21 @@ terreno logs --entries 100 --level error --sources backend,browser,metro,app
399
399
 
400
400
  ### Inspect client state
401
401
 
402
- Check authentication and non-synced RTK Query cache state:
402
+ Client state lives in `@terreno/syncdb`: synced collections in the local store, and the session in
403
+ `SessionProvider`. There is no Redux store to inspect (the `get_rtk_state` tool and
404
+ `terreno state --slice` were removed with `@terreno/rtk` in Terreno 58). Use the SyncDB tools in
405
+ the next step for data, and `read_logs` / `last_error` above for failed request-client calls.
403
406
 
404
- ```json
405
- {"name":"get_client_state","arguments":{"slice":"rtk","query":"todos"}}
406
- ```
407
-
408
- The tool reads `globalThis.__TERRENO_STORE__` registered by the app, using CDP when the MCP process
409
- cannot access the app heap directly. It also detects a SyncDB client created with `debug: true`, and
410
- its `layer` field reports what it found: `rtk`, `syncdb`, `syncdb+rtk` (both payloads returned), or
411
- `none` (with a setup hint). On web it returns `none`, as shown in step 5. `get_rtk_state` is a
412
- deprecated alias for one release. `slice: "auth"` prefers the Better Auth slice and falls back to
413
- legacy JWT auth; pass `betterAuth` to request that exact slice.
407
+ CLI equivalent of `get_syncdb_state`:
414
408
 
415
409
  Sensitive fields whose names include `password`, `token`, `secret`, `authorization`, or `cookie` are
416
- returned as `[REDACTED]`; use this summary to inspect cache state, never to retrieve credentials.
410
+ returned as `[REDACTED]` in MCP summaries; use them to inspect state, never to retrieve credentials.
411
+
417
412
 
418
413
  The CLI equivalent is:
419
414
 
420
415
  ```bash
421
- terreno state --slice rtk --query todos
416
+ terreno state --collection todos
422
417
  ```
423
418
 
424
419
  ### Inspect and change SyncDB state
@@ -71,10 +71,21 @@ import {getMCPTools} from "@terreno/ai";
71
71
  const tools = getMCPTools(req.user);
72
72
  ```
73
73
 
74
- `useMCPTools()` from `@terreno/rtk` uses the official MCP v2 client with automatic
75
- version negotiation. It no longer constructs JSON-RPC or parses SSE responses by
76
- hand; the SDK supplies the `2026-07-28` `_meta` envelope and required
77
- `Mcp-Method` / `Mcp-Name` routing headers.
74
+ To list the signed-in user's tools in an app, use `useMCPTools` from
75
+ `@terreno/syncdb/app` with the same auth provider you pass to `createSyncDb`:
76
+
77
+ ```typescript
78
+ import {useMCPTools} from "@terreno/syncdb/app";
79
+ import {authProvider} from "@/store/syncdb";
80
+
81
+ const {tools, isLoading, error, refetch} = useMCPTools({authProvider});
82
+ ```
83
+
84
+ The hook reads the token from `authProvider.getToken()` on every fetch, so Better Auth
85
+ sessions work as well as JWT. It uses the official MCP v2 client with automatic version
86
+ negotiation; the SDK supplies the `2026-07-28` `_meta` envelope and the required
87
+ `Mcp-Method` / `Mcp-Name` routing headers. Install `@modelcontextprotocol/client` in the app (optional peer of
88
+ `@terreno/syncdb`).
78
89
 
79
90
  ## Naming tools
80
91
 
@@ -0,0 +1,33 @@
1
+ # Generate the client SDK
2
+
3
+ Run this after any backend change to routes, models, permissions, or OpenAPI docs. The
4
+ backend must serve `/openapi.json` (Terreno `TerrenoApp` / `setupServer` does).
5
+
6
+ 1. Start the backend: `bun run backend:dev` (port 4000).
7
+ 2. Generate both SDK files from the app's frontend package:
8
+
9
+ ```bash
10
+ bunx terreno-syncdb-codegen \
11
+ --schema http://localhost:4000/openapi.json \
12
+ --out ./store/syncDbSdk.ts \
13
+ --api-out ./store/apiSdk.ts \
14
+ --config ./syncdb-codegen.json
15
+ ```
16
+
17
+ 3. Commit both generated files. Never edit them by hand.
18
+
19
+ | File | Holds | Use for |
20
+ |------|-------|---------|
21
+ | `store/syncDbSdk.ts` | Collection hooks + `SYNC_COLLECTIONS` | Synced collections (`useTodos`, `useCreateTodo`) |
22
+ | `store/apiSdk.ts` | Typed query/mutation hooks + request builders | Every other route (`useGetAuthMeQuery`, `usePostAuthForgotPasswordMutation`) |
23
+
24
+ A route missing from `apiSdk.ts` is missing from the OpenAPI spec. Document it in the
25
+ backend (modelRouter actions are documented automatically; hand-written routes use
26
+ `createOpenApiBuilder`) and regenerate. To leave routes out, add `excludePaths` to
27
+ `syncdb-codegen.json`:
28
+
29
+ ```json
30
+ {"excludePaths": ["/admin/", "^/internal/"]}
31
+ ```
32
+
33
+ Reference: [`@terreno/syncdb` codegen](../reference/syncdb.md#codegen).
@@ -19,8 +19,8 @@ PR builds set `DOCS_PREVIEW=true` and pass `--no-minify`. Both PR and
19
19
  | Versioned docs (`57.1.0`, `0.30.0`, …) | Omitted | Prebuilt archives unpacked under `/<version>/` |
20
20
  | JS minify | Off | On |
21
21
  | Local search index | Skipped | Built |
22
- | Generated API + component MDX | Restored from cache when `api`/`rtk`/`ui` hashes match | Same cache, then full generate on miss |
23
- | TypeDoc workspace `tsc` | Once per generate (api+rtk deps share a process) | Same |
22
+ | Generated API + component MDX | Restored from cache when `api`/`ui` hashes match | Same cache, then full generate on miss |
23
+ | TypeDoc workspace `tsc` | Once per generate | Same |
24
24
  | Rspack cache (`node_modules/.cache/rspack`) | Restored per `pull_request` vs `push` | Separate production key |
25
25
 
26
26
  Do not rely on `/57.1.0/…` URLs in a PR deploy preview.
@@ -73,7 +73,7 @@ does not skip later channels.
73
73
 
74
74
  ## 4. Sync collections on the client
75
75
 
76
- Regenerate syncdb hooks (not RTK CRUD) for `notifications` and `notification-preferences`:
76
+ Regenerate syncdb collection hooks for `notifications` and `notification-preferences`:
77
77
 
78
78
  ```bash
79
79
  cd example-frontend