@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
@@ -1,28 +1,33 @@
1
- # RTK deprecation announcement (draft)
1
+ # RTK removal announcement (draft)
2
2
 
3
3
  **Do not post until maintainers review.** Target: GitHub Discussions → Announcements.
4
4
 
5
5
  ---
6
6
 
7
- ## `@terreno/rtk` data sync is deprecated — migrate to `@terreno/syncdb`
7
+ ## `@terreno/rtk` and Redux are removed in Terreno 58
8
8
 
9
- Starting with **56.0.0**, Terreno's default frontend data path is **local-first** via [`@terreno/syncdb`](https://github.com/TerrenoLabs/terreno/blob/master/docs/reference/syncdb.md). Collection reads and writes apply to an on-device store first; the server reconciles over the sync protocol. This replaces RTK Query hooks for CRUD lists and mutations.
9
+ Terreno **58.0.0** deletes `@terreno/rtk` and every Redux dependency. [`@terreno/syncdb`](https://github.com/TerrenoLabs/terreno/blob/master/docs/reference/syncdb.md) is now the only frontend data and session layer. `@terreno/rtk` is not published for 58.
10
10
 
11
11
  ### What changed
12
12
 
13
- - **New:** `@terreno/syncdb` — `useQuery`, `useMutate`, offline outbox, conflict resolution, sync status UX
14
- - **Deprecated:** RTK Query hooks for synced collections (`useGetTodosQuery`, `usePostTodosMutation`, manual optimistic updates)
15
- - **Unchanged:** `bun run sdk` still generates the OpenAPI SDK for auth, profile, admin, AI, and other non-synced routes
13
+ - **Collections:** `useQuery` / `useMutate` read and write a local-first store (unchanged since 56).
14
+ - **Every other route** (`/auth/me`, modelRouter actions, AI, consents, announcements): a request client in `@terreno/syncdb/api` with typed hooks generated by `terreno-syncdb-codegen --api-out`. Hook names match the old RTK codegen.
15
+ - **Session:** `SessionProvider` + `useSession()` from `@terreno/syncdb/auth` (Better Auth, or `jwtAuthAdapter` for JWT backends).
16
+ - **Flags and pushes:** ride the syncdb socket (`@terreno/syncdb/flags`, `useSocketEvent`). One socket per app.
17
+ - **App utilities:** base URLs in `@terreno/syncdb/config`; upgrade check, permissions, dev logger, and MCP tools in `@terreno/syncdb/app`.
18
+ - **Backend:** `GptHistory` and `McpServiceToken` are synced collections with String ids. Two data migrations ship with 58.
16
19
 
17
20
  ### What you need to do
18
21
 
19
- 1. **By next major:** move collection screens from RTK Query to syncdb. `@terreno/rtk` will not publish in the next major line.
20
- 2. **Support window:** `@terreno/rtk` continues to publish with a deprecation notice through the **current major** (56.x beta and stable 0.x).
21
- 3. **Recommended order:** migrate to **Better Auth** first, then syncdb per screen ([migration guide](https://github.com/TerrenoLabs/terreno/blob/master/docs/how-to/migrate-rtk-to-syncdb.md)).
22
+ 1. Run the `GptHistory` and `McpServiceToken` migrations before deploying 58 frontends.
23
+ 2. Follow the [upgrade guide](https://github.com/TerrenoLabs/terreno/blob/master/docs/how-to/migrate-rtk-to-syncdb.md). It maps every removed export to its replacement.
24
+ 3. Remove `@terreno/rtk`, `@reduxjs/toolkit`, `react-redux`, `redux-persist`, and `@rtk-query/codegen-openapi` from the app.
22
25
 
23
- ### Why local-first
26
+ Apps that stay on 57.x keep `@terreno/rtk` 57.x.
24
27
 
25
- Instant UI, durable offline writes, and simpler screen code — at the cost of explicit conflict and sync-status handling. See [local-first data](https://github.com/TerrenoLabs/terreno/blob/master/docs/explanation/local-first-data.md).
28
+ ### Why
29
+
30
+ One data layer means one socket, one auth provider, and one cache for every request. See [local-first data](https://github.com/TerrenoLabs/terreno/blob/master/docs/explanation/local-first-data.md).
26
31
 
27
32
  ### Questions
28
33
 
@@ -6,9 +6,9 @@ Understanding how authentication works in @terreno/api — Better Auth sessions
6
6
 
7
7
  **Better Auth is the default path** for new Terreno apps. It provides session-based authentication with MongoDB storage, built-in social OAuth (Google, GitHub, Apple), and clean integration with `@terreno/syncdb` (`betterAuthAdapter`, `RealtimeApp` socket sessions).
8
8
 
9
- Set `AUTH_PROVIDER=better-auth` and register `BetterAuthApp` on the server. On the client, use `createBetterAuthClient` + `generateBetterAuthSlice` from `@terreno/rtk` for session Redux state, then wire `betterAuthAdapter` into `createSyncDb`.
9
+ Set `AUTH_PROVIDER=better-auth` and register `BetterAuthApp` on the server. On the client, use `createBetterAuthClient` and `SessionProvider` / `useSession()` from `@terreno/syncdb/auth` for session state (React context, no Redux), then wire `betterAuthAdapter` into `createSyncDb` and the API client.
10
10
 
11
- **JWT/Passport (legacy)** remains supported through the current major release line for existing deployments. It uses stateless tokens, Passport strategies (email/password, GitHub OAuth, anonymous), and manual token refresh via `@terreno/rtk`. New projects should not start on JWT unless they have a specific requirement (custom token contracts, non-cookie clients, or a phased migration).
11
+ **JWT/Passport (legacy)** remains supported through the current major release line for existing deployments. It uses stateless tokens, Passport strategies (email/password, GitHub OAuth, anonymous), and client-side token refresh via `jwtAuthAdapter` from `@terreno/syncdb/auth`. New projects should not start on JWT unless they have a specific requirement (custom token contracts, non-cookie clients, or a phased migration).
12
12
 
13
13
  Both systems can run in parallel during migration (`AUTH_PROVIDER` selects the primary path; legacy JWT routes stay available).
14
14
 
@@ -23,7 +23,7 @@ Both systems can run in parallel during migration (`AUTH_PROVIDER` selects the p
23
23
  | `@terreno/syncdb` local-first data | Non-cookie API clients only |
24
24
  | Socket sessions via `RealtimeApp` | Gradual migration in progress |
25
25
 
26
- **Setup:** [Configure Better Auth](../how-to/configure-better-auth.md). **Data layer:** migrate auth before or with syncdb — see [Migrate from RTK to syncdb](../how-to/migrate-rtk-to-syncdb.md) §7.
26
+ **Setup:** [Configure Better Auth](../how-to/configure-better-auth.md). **Data layer:** migrate auth before or with syncdb — see [Upgrade from @terreno/rtk to @terreno/syncdb](../how-to/migrate-rtk-to-syncdb.md) §3–4.
27
27
 
28
28
  ## Authentication Strategies
29
29
 
@@ -68,7 +68,7 @@ the `X-Terreno-Auth-Challenge` header instead:
68
68
  never set a session cookie, and a tampered value fails Better Auth's signature check (the 2FA
69
69
  verify answers 401, a passkey verify 400 `CHALLENGE_NOT_FOUND`, and a tampered trust value
70
70
  just asks for the second factor).
71
- 4. rtk's bearer mode stores the header under `${storagePrefix}_auth_challenge` in the same
71
+ 4. `@terreno/syncdb/auth`'s bearer mode stores the header under `${storagePrefix}_auth_challenge` in the same
72
72
  `bearerStorage` as the bearer token. It never stores a token from a response that asks for a
73
73
  second factor. It drops the 2FA challenge and `dont_remember` after a successful verify, and
74
74
  everything but the trust-device value on sign-out. The trust-device value stays until the server
@@ -147,7 +147,7 @@ short-lived cookie. The callback rejects a response without matching state.
147
147
 
148
148
  ### MCP service tokens (opt-in, `/mcp` only)
149
149
 
150
- Personal `mcp_` keys for remote MCP clients (Perplexity, Cursor JSON config) that cannot hold a session cookie. `TerrenoApp` must set `mcpServiceTokens`. Users mint keys from `POST /mcp/service-tokens` or **Profile → MCP connections**. The plaintext secret is returned **once**; the database stores SHA-256 `tokenHash`.
150
+ Personal `mcp_` keys for remote MCP clients (Perplexity, Cursor JSON config) that cannot hold a session cookie. `TerrenoApp` must set `mcpServiceTokens`. Users mint keys from `POST /mcp/service-tokens/create` or **Profile → MCP connections**. The plaintext secret is returned **once**; the database stores SHA-256 `tokenHash`.
151
151
 
152
152
  `extractUserFromHeaders` on `/mcp` tries a `mcp_` Bearer first, then Better Auth, then JWT. A match loads the owning `User` and updates `lastUsedAt`. Revoked, expired, or disabled-user keys resolve to no user, and so does a key minted before the user's last password reset or session revocation (`tokenEpoch` changed since it was issued). MCP OAuth grants end the same way. The same Bearer is ignored on REST, sync, admin, and on the mint/list/revoke routes (a key cannot mint another key).
153
153
 
@@ -210,19 +210,21 @@ modelRouter(Model, {
210
210
 
211
211
  ### Token Payload
212
212
 
213
- Access tokens contain:
213
+ Access and refresh tokens contain:
214
214
 
215
215
  ``````json
216
216
  {
217
- "sub": "507f1f77bcf86cd799439011", // User ID
218
- "admin": false, // Admin status
219
- "iat": 1709000000, // Issued at (timestamp)
220
- "exp": 1709000900, // Expires at (timestamp)
221
- "iss": "your-app-name" // Issuer (from TOKEN_ISSUER env var)
217
+ "id": "507f1f77bcf86cd799439011", // User ID (the frontend reads the signed-in user from it)
218
+ "sid": "4f9c…", // Session ID, kept across refreshes
219
+ "te": 0, // User token epoch; bumping it revokes refresh tokens
220
+ "iat": 1709000000, // Issued at (timestamp)
221
+ "exp": 1709000900, // Expires at (timestamp)
222
+ "iss": "your-app-name" // Issuer (from TOKEN_ISSUER env var)
222
223
  }
223
224
  ``````
224
225
 
225
- Customize the payload with `authOptions.generateJWTPayload`:
226
+ Add claims with `authOptions.generateJWTPayload`. `id`, `sid`, and `te` always win over
227
+ custom claims:
226
228
 
227
229
  ``````typescript
228
230
  setupServer({
@@ -238,42 +240,58 @@ setupServer({
238
240
 
239
241
  ### Token Refresh Flow
240
242
 
241
- 1. Access token expires (after 15 minutes)
242
- 2. API request returns `401 Unauthorized`
243
- 3. Frontend middleware detects 401
244
- 4. Frontend calls `POST /auth/refresh_token` with refresh token
245
- 5. Backend validates refresh token
246
- 6. Backend issues new access token and refresh token
247
- 7. Frontend retries original request with new token
243
+ 1. Before each request, the frontend checks the stored access token. With under two minutes
244
+ left (or already expired), it calls `POST /auth/refresh_token` with the refresh token first.
245
+ 2. If a request still returns `401 Unauthorized`, the frontend refreshes and retries the
246
+ request once.
247
+ 3. The backend verifies the refresh token and the user's token epoch, then returns a new
248
+ access and refresh token pair (`{data: {token, refreshToken}}`).
249
+ 4. Concurrent requests share one refresh call.
250
+ 5. If the backend rejects the refresh, the frontend clears both tokens and signs out. A
251
+ network failure or timeout keeps the session and the current token.
248
252
 
249
- This is handled automatically by @terreno/rtk's `emptyApi` configuration.
253
+ `jwtAuthAdapter` from `@terreno/syncdb/auth` does this for the syncdb request client and
254
+ `createSyncDb` (it replaces `@terreno/rtk`'s `emptyApi` base query).
250
255
 
251
256
  ## Frontend Integration
252
257
 
253
- ### Redux Store Setup (with @terreno/rtk)
258
+ ### Session State (Better Auth)
254
259
 
255
- ``````typescript
256
- import {generateAuthSlice} from "@terreno/rtk";
257
- import {configureStore} from "@reduxjs/toolkit";
258
- import {openapi} from "./openApiSdk";
260
+ `@terreno/syncdb/auth` owns the frontend session. One Better Auth client feeds three
261
+ consumers:
259
262
 
260
- const {authReducer, middleware, logout} = generateAuthSlice(openapi);
263
+ - `SessionProvider` / `useSession()` — `{userId, user, isLoading, isAuthenticated, error,
264
+ logout, refresh}` for screens and routing.
265
+ - `betterAuthAdapter(bridgeBetterAuthReactClient(client))` — the `AuthProvider` that
266
+ `createSyncDb` and the API client use for bearer tokens and 401 refresh.
267
+ - The Better Auth client itself — `signIn.email`, `signIn.social`, password reset.
261
268
 
262
- export const store = configureStore({
263
- reducer: {
264
- auth: authReducer,
265
- [openapi.reducerPath]: openapi.reducer,
266
- },
267
- middleware: (getDefault) =>
268
- getDefault().concat(openapi.middleware, ...middleware),
269
- });
270
- ``````
269
+ The session store reads `getSession()` on start and then follows Better Auth's session atom,
270
+ which fires after sign-in, sign-out, and user switches. A failed background read keeps the
271
+ current session: a network blip is not a logout. `logout()` signs out of Better Auth, signs
272
+ out syncdb clients (which wipe local data when created with `wipeOnSignOut`), runs the app's
273
+ `onLogout`, and clears the session. This replaces the `@terreno/rtk` Better Auth Redux slice.
274
+ See [syncdb reference: Auth](../reference/syncdb.md#auth).
275
+
276
+ ### Session State (JWT, legacy)
277
+
278
+ JWT apps use the same `SessionProvider` / `useSession()` with a different session source.
279
+ `jwtAuthAdapter({baseUrl})` returns one object that is both:
280
+
281
+ - the `AuthProvider` for `createSyncDb` and `createApiClient` (bearer token, refresh before
282
+ expiry, refresh on 401), and
283
+ - the `source` for `SessionProvider` (it pushes every sign-in and sign-out to the session).
284
+
285
+ `useJwtAuth({adapter})` gives screens `login`, `signup`, `googleLogin`, `resetPassword`, and
286
+ `logout`, plus `isAuthenticating` and `error`. `logout` goes through the `SessionProvider`, so
287
+ syncdb clients sign out and `onLogout` runs. The signed-in user is the `id` claim of the stored
288
+ token (`user` is `{id}`); load the profile from `/auth/me`. A refresh the server rejects signs
289
+ the session out on its own. This replaces `@terreno/rtk`'s `generateAuthSlice` and Redux store.
290
+ See [syncdb reference: JWT auth](../reference/syncdb.md#jwt-auth-legacy).
271
291
 
272
- **What this provides:**
273
- - Automatic token storage (SecureStore on mobile, AsyncStorage on web)
274
- - Token refresh middleware
275
- - Login/logout state management
276
- - Auth header injection for all API requests
292
+ `getTokenExpirationTimes()` and `shouldShowStillThereModal()` read the stored tokens for
293
+ "are you still there?" prompts (the modal shows with 65 seconds or less left on the refresh
294
+ token).
277
295
 
278
296
  ### Token Storage
279
297
 
@@ -286,7 +304,8 @@ export const store = configureStore({
286
304
  - Falls back to localStorage
287
305
  - SSR-safe (checks `typeof window`)
288
306
 
289
- **Storage keys:**
307
+ **Storage keys** (the same keys `@terreno/rtk` used, so signed-in users stay signed in after
308
+ the move):
290
309
  - `AUTH_TOKEN` — Access token
291
310
  - `REFRESH_TOKEN` — Refresh token
292
311
 
@@ -368,7 +387,7 @@ address is the signal that lets the owner react. Status codes and messages are i
368
387
  - Use HTTPS in production
369
388
  - Validate token issuer (`TOKEN_ISSUER`)
370
389
  - Set appropriate token expiration times
371
- - Enable `TerrenoApp` `rateLimit` so login/signup/refresh use the stricter `auth` bucket (20 / 15 min). See [Rate limiting](../how-to/rate-limiting.md).
390
+ - `TerrenoApp` rate limiting (on by default) puts login/signup/refresh in the stricter `auth` bucket (20 / 15 min). Keep it on and pass `trustProxy: 1` on Cloud Run. See [Rate limiting](../how-to/rate-limiting.md).
372
391
  - Keep login/signup/refresh reachable when the client still sends an expired access JWT. Those three routes skip JWT verification; `/auth/me` and other APIs still 401.
373
392
  - Log authentication failures
374
393
 
@@ -538,4 +557,4 @@ See [Receive inbound webhooks](../how-to/inbound-webhooks.md).
538
557
  - [Add GitHub OAuth](../how-to/add-github-oauth.md)
539
558
  - [Create a model](../how-to/create-a-model.md)
540
559
  - [API reference](../reference/api.md)
541
- - [@terreno/rtk reference (legacy)](../reference/legacy/rtk.md)
560
+ - [Upgrade from @terreno/rtk to @terreno/syncdb](../how-to/migrate-rtk-to-syncdb.md)
@@ -76,7 +76,7 @@ JavaScript packages, GitHub Actions, and a few Expo JS-only names may update. Me
76
76
  | `github-actions` | `github-actions` at `/` |
77
77
  | `root` | `bun` at `/` (root catalog and root tools) |
78
78
  | `backend` | `bun` under api, ai, backends, … |
79
- | `frontend` | `bun` under ui, rtk, demo, apps, … |
79
+ | `frontend` | `bun` under ui, syncdb, admin-frontend, demo, apps, … |
80
80
 
81
81
  Frontend ignores catalog-managed names so those fixes land once, in the root catalog. Root ignores fingerprint-skip names, so a security fix for a native/Expo package never opens a PR; handle it by hand in a release. `dependabot-auto-merge.yml` approves patch and minor Dependabot PRs and enables squash auto-merge, so those security PRs merge when required checks pass. A semver-major security PR (or a group containing one) gets no approval or auto-merge and waits for a human. When one fails because the fix needs code changes, fold the bump into the rolling PR ([Update dependencies](../how-to/update-dependencies.md)); never push to the `dependabot/*` branch.
82
82
 
@@ -32,7 +32,7 @@ Use [MongoDB Atlas](https://www.mongodb.com/atlas) or a single-node replica set
32
32
 
33
33
  **3 — Short-lived serverless timeouts**
34
34
 
35
- The RTK/socket client enables reconnection (`reconnection: true`, `reconnectionAttempts: 5` in `rtk/src/socket.ts`). When the backend drops idle connections (for example Cloud Run's default 300s request timeout), clients reconnect but realtime state may lag until the new socket attaches.
35
+ The syncdb socket client enables reconnection (`reconnection: true` in `syncdb/src/sync/socketTransport.ts`). When the backend drops idle connections (for example Cloud Run's default 300s request timeout), clients reconnect and catch up from their sync cursors, but deltas may lag until the new socket attaches.
36
36
 
37
37
  **5 — Build-time API URL**
38
38
 
@@ -19,8 +19,8 @@ that file (and its imports) to a working example. Gaps stay explicit.
19
19
  | UI blocks | yes — `uiBlocks` with `repair: true`, `exportDataset`, and the opt-in `scaleStepper` and `toggleChecklist` callbacks in `example-backend/src/ai/hostActions.ts`, wired from `example-backend/src/api/ai.ts`; `todoStats` in `example-backend/src/ai/tools.ts` stores a `ref` dataset; `findPhotos` in the same file cites the generated photo library, and `example-backend/src/api/photoLibrary.ts` signs its URLs | yes — `example-frontend/app/(tabs)/ai.tsx` (`uiBlocks`, dataset and action hooks, `hostActions` includes `exportDataset`, `scaleStepper`, and `toggleChecklist`, `resolveImage` resolves `file:` photo ids through `useLazyPhotoLibraryUrlQuery`) | e2e mocks a document with one inline and one `ref` chart. A second e2e test stores the Sunday roast reply (`blocks/src/fixtures/golden/sunday-roast.yaml` with `file:` photo ids) in a real `GptHistory`, streams it from the mocked model, and runs the stepper and checklist through the real `POST /gpt/actions`; photo URLs come from the real `GET /photoLibrary/:id/url`, and only the image download is stubbed (`example-frontend/e2e/helpers/seedGptHistory.ts`). Steps: [agent-ui-blocks.md](../how-to/agent-ui-blocks.md). |
20
20
  | Agent asks | yes — `asks: {approvals}` in `example-backend/src/api/ai.ts`, with the per-request `deleteCompletedTodos` approval tool from `example-backend/src/api/todoTools.ts`; it also passes `chat` to `addGptHistoryRoutes` for the headless `pendingAsks` and `turn` endpoints; keyless scripted agent with short compact-surface replies in `example-backend/src/api/demoAgent.ts` | yes — `example-frontend/app/(tabs)/ai.tsx` (`onAskSubmit`, `askErrors`), helpers in `example-frontend/lib/gptAsks.ts` | Without `GEMINI_API_KEY`, "Help me pick a plan" asks a `choice` in chat, "Pick toppings" asks a `select: "many"` `choice` with an Other field, "Send the weekly report" and "Archive old chats" ask a `confirm` (the second `destructive`), "Draft an announcement" asks a `markdown` edit of a draft, "Fill in the invoice details" asks a `form` with eight typed fields, "Upload a receipt" asks for `files`, sent as uploads when `GCS_BUCKET` is set and as data URLs otherwise, and "Delete my completed todos" calls `deleteCompletedTodos`, which runs only after the user approves the server's destructive approval card. e2e: `example-frontend/e2e/ai-chat.spec.ts`. Small clients: the curl walkthrough in the how-to and the demo's watch-sized `SimpleAskCard` story. Steps: [agent-ui-asks.md](../how-to/agent-ui-asks.md). |
21
21
  | AI structured output | no | no | `@terreno/ai` supports structured generation; the example only streams chat. Recorded gap — not claimed by a current tutorial. |
22
- | Feature flags + live updates | yes — `FeatureFlagsApp` in `example-backend/src/server.ts`, seed `example-backend/src/scripts/seed-feature-flags.ts` | yes — `useTerrenoFeatureFlags` in `example-frontend/app/_layout.tsx` | Socket-backed live updates share the realtime connection. |
23
- | Websockets / realtime | yes — `RealtimeApp` in `example-backend/src/server.ts`, `example-backend/src/websockets.ts` | yes — `useSocketConnection` in `example-frontend/app/_layout.tsx` | Sync deltas also use the socket (`SyncApp` + `@terreno/syncdb`). |
22
+ | Feature flags + live updates | yes — `FeatureFlagsApp` in `example-backend/src/server.ts`, seed `example-backend/src/scripts/seed-feature-flags.ts` | yes — `useTerrenoFeatureFlags` (`@terreno/syncdb/flags`) in `example-frontend/app/_layout.tsx` | `featureFlagsChanged` pushes ride the syncdb socket; the app opens one socket. |
23
+ | Websockets / realtime | yes — `RealtimeApp` in `example-backend/src/server.ts`, `example-backend/src/websockets.ts` | yes — the `syncDb` client socket (`example-frontend/store/syncdb.ts`) | Sync deltas and app events (`useSocketEvent`) share the one syncdb socket (`SyncApp` + `@terreno/syncdb`). |
24
24
  | Consent forms | yes — `example-backend/src/consentDefinitions.ts`, seed scripts | yes — `example-frontend/app/(tabs)/documents.tsx` (Consents section), admin `example-frontend/app/admin/consent-forms/` | First-login flow is covered by e2e (`example-frontend/e2e/consents.spec.ts`). |
25
25
  | Product announcements | yes — `AnnouncementsApp` in `example-backend/src/server.ts`, release upload token via `ANNOUNCEMENTS_UPLOAD_TOKEN`, seed `example-backend/src/scripts/seed-announcements.ts`, sample release pack `example-backend/announcements/releases/1.14.0/` with `bun run announcements:pack` | yes — `AnnouncementNavigator` in `example-frontend/app/_layout.tsx` and admin announcement routes | Seeded examples are drafts, so fresh databases do not interrupt sign-in. Release packs support multiple Markdown surfaces and idempotent draft or explicit live API import. |
26
26
  | What's new banner | n/a — generated from `CHANGELOG.md` by `bun run whats-new:generate` | yes — `WhatsNewBanner` in `example-frontend/components/SyncTodosScreen.tsx`, data in `example-frontend/constants/whatsNew.generated.json` | `bun run check:whats-new` keeps the data in sync with each release. |
@@ -15,8 +15,7 @@ Prefer `unknown` (and narrow) or a precise type. Use `as unknown as T` over `as
15
15
  Explicit `any` is acceptable only at **framework or library boundaries** where types are not expressible in TypeScript today, for example:
16
16
 
17
17
  - Mongoose model boundaries that inspect consumer-defined schemas (`api/src/populate.ts`)
18
- - RTK Query `Api<any, any, any, any>` in generic middleware (`rtk/src/offlineMiddleware.ts`)
19
- - Dynamic RTK hook lookup where endpoint names are not statically known (`admin-frontend`)
18
+ - Dynamic lookups where member names are not statically known
20
19
  - Test mocks with type-erased doubles (`*.test.ts`, `*.isolated.tsx`)
21
20
 
22
21
  Every allowed use must be **lint-clean** and **documented** (see below).
@@ -38,15 +37,15 @@ The audit script (`bun run check:explicit-any`) classifies each explicit `any`:
38
37
  When `any` cannot be removed, add **both** comments on the line above (or a file header for tests):
39
38
 
40
39
  ```typescript
41
- // noExplicitAny: RTK Query generates hook names dynamically; not statically expressible
42
- // biome-ignore lint/suspicious/noExplicitAny: dynamic hook lookup on RTK Query enhanced API
43
- const hook = (api as any)[`useGet${name}Query`];
40
+ // noExplicitAny: plugin methods are registered at runtime; names are not statically known
41
+ // biome-ignore lint/suspicious/noExplicitAny: dynamic method lookup on a runtime-registered plugin
42
+ const handler = (plugin as any)[`handle${name}`];
44
43
  ```
45
44
 
46
45
  For test files with many mocks, a file-level header is fine:
47
46
 
48
47
  ```typescript
49
- // noExplicitAny: test mocks use type-erased RTK Query API doubles
48
+ // noExplicitAny: test mocks use type-erased request client doubles
50
49
  // biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
51
50
  ```
52
51
 
@@ -191,7 +191,7 @@ gs://bucket/
191
191
 
192
192
  ### Production Deploy
193
193
 
194
- 1. **Trigger**: Push to `master` branch with changes to `demo/**`, `ui/**`, `example-frontend/**`, `rtk/**`
194
+ 1. **Trigger**: Push to `master` branch with changes to `demo/**`, `ui/**`, `example-frontend/**`, `syncdb/**`
195
195
  2. **Build**: GitHub Actions runs `bun run export` to generate static files
196
196
  3. **Ensure negative caching disabled**: Update backend bucket to prevent cached 404s
197
197
  4. **Upload**:
@@ -1,6 +1,6 @@
1
1
  # Local-first data in Terreno
2
2
 
3
- Terreno's default frontend data path is **local-first**: the on-device store is what your UI reads and writes, and the server reconciles changes asynchronously. This is a different mental model from request/response fetching with RTK Query.
3
+ Terreno's default frontend data path is **local-first**: the on-device store is what your UI reads and writes, and the server reconciles changes asynchronously. This is a different mental model from request/response fetching.
4
4
 
5
5
  ## What local-first means here
6
6
 
@@ -10,8 +10,8 @@ There is no server-first mode and no opt-in flag: if you use syncdb, you adopt t
10
10
 
11
11
  ## Mental model shift
12
12
 
13
- | Server-first (RTK Query) | Local-first (syncdb) |
14
- |--------------------------|----------------------|
13
+ | Server-first (request/response) | Local-first (syncdb) |
14
+ |---------------------------------|----------------------|
15
15
  | UI reads from cache filled by HTTP | UI reads from the local store |
16
16
  | Writes call the API, then invalidate/refetch | Writes apply locally, then reconcile |
17
17
  | Loading spinners track request lifecycle | Sync status tracks outbox + connectivity |
@@ -27,10 +27,12 @@ Think **apply locally, then reconcile** instead of **request, wait, update cache
27
27
  3. **Refetch orchestration** — `invalidatesTags`, `refetch()`, and list/detail cache coordination after mutations.
28
28
  4. **Treating the network as the read path** — list screens blocked on `isLoading` for every navigation.
29
29
 
30
- RTK Query remains appropriate for **non-synced generated** endpoints such as
31
- `/auth/me` and AI routes. Built-in admin RPC stays request/response through its
32
- host-bound fetch client; ObjectId/API-only admin CRUD keeps RTK compatibility in
33
- Terreno 57.
30
+ Routes that are not collections — `/auth/me`, modelRouter actions, AI, consents —
31
+ stay request/response. They go through the syncdb request client
32
+ (`@terreno/syncdb/api`) and its generated hooks in `store/apiSdk.ts`, which share the
33
+ sync client's `AuthProvider`. Built-in admin RPC and ObjectId/API-only admin CRUD use
34
+ admin-frontend's host-bound fetch client. Terreno 58 removed `@terreno/rtk` and Redux;
35
+ syncdb is the only frontend data layer.
34
36
 
35
37
  ## What you start doing
36
38
 
@@ -54,12 +56,12 @@ belong in `queryCollections` instead.
54
56
 
55
57
  **Gains:** instant UI, offline writes with a durable outbox, simpler screen code, and one write path on the server (sync and REST share `modelRouter`).
56
58
 
57
- **Costs:** larger conceptual surface (conflicts, sync status, local storage), mandatory replica-set MongoDB for realtime, and migration work for existing RTK Query screens.
59
+ **Costs:** larger conceptual surface (conflicts, sync status, local storage), mandatory replica-set MongoDB for realtime, and migration work for screens that fetched collections over request/response.
58
60
 
59
61
  Server-first fetching is simpler when you only need online CRUD with no offline requirement — but Terreno's blessed path for collection data is local-first.
60
62
 
61
63
  ## Related docs
62
64
 
63
65
  - [syncdb reference](../reference/syncdb.md) — API ground truth
64
- - [Migrate from RTK to syncdb](../how-to/migrate-rtk-to-syncdb.md) — step-by-step migration
66
+ - [Upgrade from @terreno/rtk to @terreno/syncdb](../how-to/migrate-rtk-to-syncdb.md) — the Terreno 58 upgrade path
65
67
  - [Authentication architecture](authentication.md) — Better Auth + socket sessions
@@ -128,7 +128,7 @@ Instance actions load the document by `id` before the handler runs. Missing docu
128
128
  When `openApi` is configured on the router (automatic with `TerrenoApp` and `setupServer`), each action is documented on first route registration. Operations use:
129
129
 
130
130
  - **Tag** — model collection name by default; override with `action.tag`.
131
- - **operationId** — `{tag}_{actionName}` (e.g. `todos_markComplete`) for stable RTK Query hook names after SDK regeneration.
131
+ - **operationId** — `{tag}_{actionName}` (e.g. `todos_markComplete`) for stable generated hook names (`store/apiSdk.ts`) after SDK regeneration.
132
132
 
133
133
  Request/response schemas are derived from Zod when `body`, `query`, or `response` are set. Successful responses are documented as `{data: ...}` to match the wire format.
134
134
 
@@ -160,9 +160,9 @@ With TerrenoApp, an "app" is just a function that receives the `TerrenoApp` inst
160
160
 
161
161
  #### 6. One collection catalog for surfaces
162
162
 
163
- `modelRouter` registers each collection once in an in-memory **collection catalog** keyed by route path (for example `/todos`). The record holds the Mongoose model, `ModelRouterOptions`, and which surfaces are active (`mcp`, `realtime`, `sync`). TerrenoApp option enrichment calls `replaceCollectionOptions` once per path after RBAC injects `accessControl`.
163
+ `modelRouter` registers each collection once in an in-memory **collection catalog** keyed by route path (for example `/todos`). The record holds the Mongoose model, `ModelRouterOptions`, and which surfaces are active (`mcp`, `sync`). TerrenoApp option enrichment calls `replaceCollectionOptions` once per path after RBAC injects `accessControl`.
164
164
 
165
- MCP, realtime, and sync read **views** of that catalog — they do not keep separate option arrays. `registerMCPModel`, `registerRealtime`, `registerSync`, and the `update*RegistryOptions` helpers remain as wrappers for tests and legacy callers. `clearMCPRegistry`, `clearRealtimeRegistry`, and `clearSyncRegistry` clear the **whole** catalog so tests cannot leave a stale MCP entry after a sync-only clear.
165
+ MCP and sync read **views** of that catalog — they do not keep separate option arrays. `registerMCPModel`, `registerSync`, and the `update*RegistryOptions` helpers remain as wrappers for tests and legacy callers. `clearMCPRegistry` and `clearSyncRegistry` clear the **whole** catalog so tests cannot leave a stale MCP entry after a sync-only clear. The legacy realtime surface (`modelRouter` `realtime`, `registerRealtime`, `clearRealtimeRegistry`) was removed in Terreno 58.
166
166
 
167
167
  Custom MCP tools stay on a separate list; they are not collections. Sync schema validation and index enqueue still run when a collection first opts into `sync`.
168
168
 
@@ -10,7 +10,7 @@ Terreno avoids **barrel imports** — imports that resolve through an `index.ts`
10
10
 
11
11
  ## Allowed
12
12
 
13
- - **Published package APIs** — cross-package imports like `@terreno/api`, `@terreno/ui`, and `@terreno/rtk` use each package's public `src/index` entry. That is intentional.
13
+ - **Published package APIs** — cross-package imports like `@terreno/api`, `@terreno/ui`, and `@terreno/syncdb/react` use each package's public entry (`src/index` or a declared subpath export). That is intentional.
14
14
  - **Package public entry files** — `api/src/index.ts`, `ui/src/index.tsx`, etc. may re-export for npm consumers. Do not import those barrels from *inside* the same package.
15
15
  - **Expo Router routes** — `app/**/index.tsx` files are route entries, not barrels.
16
16
 
@@ -29,12 +29,12 @@ import {User} from "../models/user";
29
29
  ```
30
30
 
31
31
  ```typescript
32
- // Bad — store/index.ts was a barrel of sdk/appState/utils
33
- import {useGetMeQuery} from "@/store";
32
+ // Bad — a directory barrel
33
+ import {useGetAuthMeQuery} from "@/store";
34
34
 
35
35
  // Good
36
- import {useGetMeQuery} from "@/store/sdk";
37
- import store, {useAppDispatch} from "@/store/index";
36
+ import {useGetAuthMeQuery} from "@/store/apiSdk";
37
+ import {syncDb} from "@/store/syncdb";
38
38
  ```
39
39
 
40
40
  ## Enforcement
@@ -554,7 +554,7 @@ org-admins manage only the current org. Invites and billing are design-only plac
554
554
  - **Implementation plan:** [org-management-ui.md](https://github.com/TerrenoLabs/terreno/blob/master/docs/implementationPlans/org-management-ui.md)
555
555
  - **Tasks:** [org-management-ui.md](https://github.com/TerrenoLabs/terreno/blob/master/docs/tasks/org-management-ui.md)
556
556
  - **RTK flag:** Partial — custom non-synced routes use the generated SDK;
557
- ObjectId admin compatibility may use `useAdminApi` in Terreno 57, while
557
+ ObjectId admin CRUD uses the admin fetch client (`useAdminModelApi`), while
558
558
  eligible String-`_id` CRUD uses windowed syncdb
559
559
  - **Depends on:** rbac-permissions
560
560
 
@@ -871,9 +871,10 @@ Shipping this work **closes** https://github.com/TerrenoLabs/terreno/issues/1186
871
871
  **Labels:** `area:api`, `type:feature`
872
872
  **Project fields:** Area=`api`, Target=`Released`, Impact=`Feature`, IP=`rate-limiting`, Status=`Shipped`
873
873
 
874
- Adds opt-in HTTP rate limiting to `@terreno/api`: per-user or per-IP keys, stricter
874
+ Adds HTTP rate limiting to `@terreno/api`: per-user or per-IP keys, stricter
875
875
  auth/OTP buckets (including login), memory Redis or Mongo stores, and 429 rate-limit
876
- headers. Default is off until Terreno 58. Sync mutation nacks stay a separate limiter.
876
+ headers. Opt-in in 57.x; on by default from Terreno 58 (`rateLimit: false` turns it off).
877
+ Sync mutation nacks stay a separate limiter.
877
878
 
878
879
  Shipping this work **closes** https://github.com/TerrenoLabs/terreno/issues/1187.
879
880
 
@@ -6,13 +6,13 @@ file (or a new hit in an existing file) that would trip them.
6
6
 
7
7
  ## Scope
8
8
 
9
- `{api,ui,rtk,ai,admin-backend,admin-frontend,example-backend}/src/**/*.{ts,tsx}`
9
+ `{api,ui,ai,admin-backend,admin-frontend,example-backend}/src/**/*.{ts,tsx}`
10
10
 
11
11
  `example-frontend` and `demo` are listed in the original align glob but have no `src/`
12
12
  tree (`app/`, `components/`, `stories/` instead), so this scanner does not cover them.
13
13
 
14
14
  Skipped: tests (`*.test.*`, `*.spec.*`, `*.isolated.*`, `__tests__`), generated SDKs
15
- (`openApiSdk.ts`, `*OpenApiSdk.ts`), declaration files (`*.d.ts`), `node_modules`, `dist`,
15
+ (`openApiSdk.ts`, `*OpenApiSdk.ts`, `*.gen.ts`), declaration files (`*.d.ts`), `node_modules`, `dist`,
16
16
  and test harness files such as `bunSetup.ts`.
17
17
 
18
18
  ## Rules
@@ -10,7 +10,7 @@ TypeScript 7 removes.
10
10
  | --- | --- | --- | --- | --- |
11
11
  | Node library | `api`, `ai`, `admin-backend`, `announcements`, `api-health`, `blocks`, `comms`, `feature-flags`, `jobs`, `test`, `admin-spa` server (`tsconfig.server.json`) | `nodenext` | `es2023` | CommonJS `dist/` |
12
12
  | Node ESM tool | `mcp-server`, `create-terreno-app` | `nodenext` | `es2023` | ESM `dist/` (`"type": "module"`) |
13
- | Frontend library | `ui`, `admin-frontend`, `rtk`, `syncdb` | `esnext` + `moduleResolution: bundler` | `es2022` | ESM `dist/` for Metro |
13
+ | Frontend library | `ui`, `admin-frontend`, `syncdb` | `esnext` + `moduleResolution: bundler` | `es2022` | ESM `dist/` for Metro |
14
14
  | Bun CLI | `cli` | `esnext` + `moduleResolution: bundler` + `customConditions: ["bun"]` | `es2022` | ESM `dist/` for Bun |
15
15
  | Expo app | `example-frontend`, `demo`, `admin-spa` | extends `expo/tsconfig.base` | from Expo | nothing (`noEmit`) |
16
16
  | Bun app | `example-backend` | `preserve` | `esnext` | nothing (`noEmit`) |
@@ -41,6 +41,4 @@ their `tsconfig.json`, so an `extends` into a repo-root base would ship a broken
41
41
  | `target: es5`, `downlevelIteration` | Deprecated. No supported runtime needs ES5 output. |
42
42
  | `esModuleInterop`, `allowSyntheticDefaultImports`, `forceConsistentCasingInFileNames` | Already `true` by default in TypeScript 6. Setting them to `false` is deprecated. |
43
43
 
44
- `create-terreno-app` scaffolds follow the Expo app and Bun app profiles. Its
45
- `tsconfig.codegen.json` pairs `module: commonjs` with `moduleResolution: bundler`, because
46
- the RTK codegen CLI forces CommonJS when it registers `ts-node`.
44
+ `create-terreno-app` scaffolds follow the Expo app and Bun app profiles.
@@ -4,9 +4,9 @@ All published `@terreno/*` packages share one version. Upgrade them together. Mi
4
4
 
5
5
  ## Lockstep
6
6
 
7
- A git tag `X.Y.Z` (no `v` prefix) is the version for every package that `.github/workflows/publish-on-tag.yml` publishes: `api`, `test`, `ui`, `rtk`, `admin-backend`, `admin-frontend`, `admin-spa`, `blocks`, `ai`, `api-health`, `comms`, `feature-flags`, `mcp`, `syncdb`. Publish jobs read that tag; they do not pick per-package versions.
7
+ A git tag `X.Y.Z` (no `v` prefix) is the version for every package that `.github/workflows/publish-on-tag.yml` publishes: `api`, `test`, `ui`, `admin-backend`, `admin-frontend`, `admin-spa`, `blocks`, `ai`, `api-health`, `comms`, `feature-flags`, `mcp`, `syncdb`. Publish jobs read that tag; they do not pick per-package versions.
8
8
 
9
- Inside the monorepo, packages depend on each other with `workspace:*` (for example `@terreno/rtk` → `@terreno/ui`). On npm they are released at the same number. `@terreno/ui` also pins Expo-line peers (`react-native` `~0.86.0` on the 57 line). Installing `@terreno/ui@57` next to Expo 54 is outside support, same as mixing `@terreno/api@57` with `@terreno/ui@0.31`.
9
+ Inside the monorepo, packages depend on each other with `workspace:*` (for example `@terreno/admin-frontend` → `@terreno/ui`). On npm they are released at the same number. `@terreno/ui` also pins Expo-line peers (`react-native` `0.88.0` on the 58 line). Installing `@terreno/ui@58` next to Expo 57 is outside support, same as mixing `@terreno/api@58` with `@terreno/ui@57`.
10
10
 
11
11
  ## Pre-1.0 (and Expo-aligned majors)
12
12
 
@@ -18,7 +18,7 @@ From 56 onward the **major** tracks the Expo SDK major (`56.x`, `57.x`). That is
18
18
 
19
19
  A public API marked deprecated stays available for **at least three minor releases** on the current major (example: deprecated in `57.1.0` → still present in `57.2.0` and `57.3.0`). Removal happens in a later minor or the next major, always with an upgrade note.
20
20
 
21
- Worked example: `@terreno/rtk` collection CRUD was deprecated in `56.0.0` (restated in `57.1.0`). The package still publishes on 57.x for the OpenAPI SDK, Better Auth Redux, feature flags, and sockets. It will not ship in the **next major**. Migrate collection screens with [migrate-rtk-to-syncdb.md](../how-to/migrate-rtk-to-syncdb.md) as a separate operation from a routine version bump.
21
+ Worked example: `@terreno/rtk` collection CRUD was deprecated in `56.0.0` (restated in `57.1.0`). The package published through 57.x and was removed in `58.0.0`, with `@terreno/syncdb` taking over its request client, session, flags, and app utilities. Upgrading across 58 follows [migrate-rtk-to-syncdb.md](../how-to/migrate-rtk-to-syncdb.md).
22
22
 
23
23
  ## Where to read changes
24
24
 
@@ -22,7 +22,7 @@ Problem-oriented, practical steps. Use these when you know what you want to do.
22
22
  - [Run tests locally](run-tests-locally.md) — Map every CircleCI test job to a Cursor Cloud / laptop command
23
23
  - [GitHub Actions CI](github-actions-ci.md) — Cut PR runtime: docs previews, compile-once e2e, pinned Bun
24
24
  - [Add feature flags](add-feature-flags.md) — Add feature flags, A/B testing, and OpenFeature migration
25
- - [Rate limiting](rate-limiting.md) — Opt-in HTTP limiter on `TerrenoApp` (memory or Redis)
25
+ - [Rate limiting](rate-limiting.md) — Default-on HTTP limiter on `TerrenoApp` (memory, Redis, or Mongo; `rateLimit: false` turns it off)
26
26
  - [Receive inbound webhooks](inbound-webhooks.md) — HMAC, Stripe, Twilio, and SendGrid signatures on `WebhooksApp`
27
27
  - [Durable background jobs](background-jobs.md) — `@terreno/jobs`: enqueue, workers, schedules, Cloud Tasks / Vercel Queues
28
28
  - [Create a Mongoose model](create-a-model.md) — Define models with proper conventions
@@ -59,9 +59,10 @@ Problem-oriented, practical steps. Use these when you know what you want to do.
59
59
  - [Show loading skeletons](show-loading-skeletons.md) — `loading`, `loadingComponent`, and `loadingAnimation` on Box, Card, charts, and Page; `withLoading` for custom components
60
60
  - [Compose charts in a dashboard grid](charts-and-dashboards.md) — `LineChart` / `BarChart` / `AreaChart` / `DonutChart` inside `Card`s in `DashboardGrid` (ops-dashboard scorecards and spans: [dashboard-chart-parity](../implementationPlans/dashboard-chart-parity.md))
61
61
  - [Compare rendered chart snapshots](compare-chart-rendered-snapshots.md) — PNG goldens for the chart visual gallery, not JSON snapshots
62
- - [Migrate from @terreno/rtk to @terreno/syncdb](migrate-rtk-to-syncdb.md) — Move data sync to the local-first layer
62
+ - [Upgrade from @terreno/rtk to @terreno/syncdb (Terreno 58)](migrate-rtk-to-syncdb.md) — Remove `@terreno/rtk` and Redux; every removed export mapped to its replacement
63
63
  - [Use syncdb correctly](use-syncdb-correctly.md) — Serial snapshot startup, outbox-halting 403s, phantom creates, conflicts, and other library behavior apps must handle
64
64
  - [Generate a REST CLI from OpenAPI](generate-a-rest-cli.md) — Scaffold `terreno generate rest-cli` for an app API
65
+ - [Generate the client SDK](generate-the-client-sdk.md) — `terreno-syncdb-codegen` writes collection hooks and typed request hooks from OpenAPI
65
66
  - [In-app notifications](in-app-notifications.md) — Register `NotificationsApp`, syncdb inbox, and UI bell
66
67
  - [Add organizations](add-organizations.md) — Opt into Membership-backed tenancy, RBAC, admin, and seeded examples
67
68
  - [Add a GPT chat mascot](add-gpt-chat-mascot.md) — Optional consumer-owned character on empty `GPTChat`