@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.
- package/CHANGELOG.md +43 -0
- package/README.md +57 -3
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +17 -16
- package/dist/bootstrap.js.map +1 -1
- package/dist/docs/guidelines/admin-frontend/guidelines/core.md +6 -5
- package/dist/docs/guidelines/ui/guidelines/core.md +1 -1
- package/dist/docs/prompts/debug.md +6 -4
- package/dist/docs/prompts/screen.md +11 -17
- package/dist/docs/resources/overview.md +5 -3
- package/dist/docs/resources/patterns.md +157 -238
- package/dist/docs/resources/syncdb.md +44 -16
- package/dist/docs/templates/bootstrap/CLAUDE.template.md +2 -2
- package/dist/docs/templates/bootstrap/cursorrules.template.md +7 -5
- package/dist/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +8 -12
- package/dist/docs/templates/bootstrap/frontend/app/_layout.template.tsx +75 -52
- package/dist/docs/templates/bootstrap/frontend/app/login.template.tsx +46 -108
- package/dist/docs/templates/bootstrap/frontend/app/signup.template.tsx +53 -0
- package/dist/docs/templates/bootstrap/frontend/lib/betterAuth.template.md +18 -0
- package/dist/docs/templates/bootstrap/frontend/store/apiClient.template.md +33 -0
- package/dist/docs/templates/bootstrap/frontend/store/apiSdk.template.md +76 -0
- package/dist/docs/templates/bootstrap/frontend/store/syncdb.template.md +56 -0
- package/dist/docs/templates/bootstrap/frontend/utils/index.template.md +0 -4
- package/dist/docs/upgrades/58.0.0-beta.1.md +504 -0
- package/dist/docs/upgrades/58.0.0.md +495 -4
- package/dist/docs/versioned/next/README.md +2 -2
- package/dist/docs/versioned/next/approval-rubric.md +2 -2
- package/dist/docs/versioned/next/explanation/admin-interface.md +6 -5
- package/dist/docs/versioned/next/explanation/admin-plugin-frontend.md +1 -1
- package/dist/docs/versioned/next/explanation/ai-workflows.md +5 -3
- package/dist/docs/versioned/next/explanation/announcements/rtk-deprecation.md +16 -11
- package/dist/docs/versioned/next/explanation/authentication.md +62 -43
- package/dist/docs/versioned/next/explanation/dependency-management.md +1 -1
- package/dist/docs/versioned/next/explanation/deployment-baseline.md +1 -1
- package/dist/docs/versioned/next/explanation/example-coverage.md +2 -2
- package/dist/docs/versioned/next/explanation/explicit-any-policy.md +5 -6
- package/dist/docs/versioned/next/explanation/gcp-hosting-architecture.md +1 -1
- package/dist/docs/versioned/next/explanation/local-first-data.md +11 -9
- package/dist/docs/versioned/next/explanation/model-router-actions.md +1 -1
- package/dist/docs/versioned/next/explanation/modular-api-design.md +2 -2
- package/dist/docs/versioned/next/explanation/no-barrel-imports.md +5 -5
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +4 -3
- package/dist/docs/versioned/next/explanation/source-rules.md +2 -2
- package/dist/docs/versioned/next/explanation/typescript-configuration.md +2 -4
- package/dist/docs/versioned/next/explanation/versioning-policy.md +3 -3
- package/dist/docs/versioned/next/how-to/README.md +3 -2
- package/dist/docs/versioned/next/how-to/add-feature-flags.md +50 -25
- package/dist/docs/versioned/next/how-to/add-organizations.md +2 -1
- package/dist/docs/versioned/next/how-to/admin-custom-home.md +8 -2
- package/dist/docs/versioned/next/how-to/admin-custom-widget.md +0 -1
- package/dist/docs/versioned/next/how-to/agent-ui-asks.md +6 -6
- package/dist/docs/versioned/next/how-to/build-admin-screens.md +10 -8
- package/dist/docs/versioned/next/how-to/build-for-web.md +1 -1
- package/dist/docs/versioned/next/how-to/call-external-apis.md +2 -2
- package/dist/docs/versioned/next/how-to/circleci.md +12 -6
- package/dist/docs/versioned/next/how-to/configure-better-auth.md +114 -60
- package/dist/docs/versioned/next/how-to/connect-mcp-service-token.md +10 -4
- package/dist/docs/versioned/next/how-to/create-a-terreno-app.md +14 -2
- package/dist/docs/versioned/next/how-to/debug-with-mcp.md +8 -13
- package/dist/docs/versioned/next/how-to/expose-mcp-tools.md +15 -4
- package/dist/docs/versioned/next/how-to/generate-the-client-sdk.md +33 -0
- package/dist/docs/versioned/next/how-to/github-actions-ci.md +2 -2
- package/dist/docs/versioned/next/how-to/in-app-notifications.md +1 -1
- package/dist/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +318 -447
- package/dist/docs/versioned/next/how-to/password-reset.md +1 -1
- package/dist/docs/versioned/next/how-to/product-announcements.md +6 -3
- package/dist/docs/versioned/next/how-to/rate-limiting.md +38 -16
- package/dist/docs/versioned/next/how-to/run-mongodb-migrations.md +19 -0
- package/dist/docs/versioned/next/how-to/run-tests-locally.md +2 -3
- package/dist/docs/versioned/next/how-to/set-up-social-login.md +1 -1
- package/dist/docs/versioned/next/how-to/set-up-terreno-mcp.md +2 -2
- package/dist/docs/versioned/next/how-to/track-upstream-expo.md +1 -1
- package/dist/docs/versioned/next/how-to/upgrade-banner.md +5 -3
- package/dist/docs/versioned/next/how-to/upgrade-terreno.md +5 -5
- package/dist/docs/versioned/next/how-to/use-syncdb-correctly.md +1 -1
- package/dist/docs/versioned/next/how-to/websocket-integration.md +113 -402
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +5 -0
- package/dist/docs/versioned/next/implementationPlans/native-module-baseline.md +29 -5
- package/dist/docs/versioned/next/implementationPlans/remove-legacy-realtime.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/remove-rtk.md +185 -0
- package/dist/docs/versioned/next/reference/README.md +1 -1
- package/dist/docs/versioned/next/reference/admin-frontend.md +85 -70
- package/dist/docs/versioned/next/reference/admin-spa.md +10 -4
- package/dist/docs/versioned/next/reference/ai.md +36 -4
- package/dist/docs/versioned/next/reference/announcements.md +3 -3
- package/dist/docs/versioned/next/reference/api.md +39 -24
- package/dist/docs/versioned/next/reference/cli.md +3 -4
- package/dist/docs/versioned/next/reference/environment-variables.md +16 -16
- package/dist/docs/versioned/next/reference/feature-flags.md +48 -7
- package/dist/docs/versioned/next/reference/jobs.md +2 -2
- package/dist/docs/versioned/next/reference/legacy/rtk.md +25 -600
- package/dist/docs/versioned/next/reference/mcp-server.md +441 -1158
- package/dist/docs/versioned/next/reference/syncdb.md +426 -16
- package/dist/docs/versioned/next/reference/test.md +28 -3
- package/dist/docs/versioned/next/reference/ui.md +132 -19
- package/dist/docs/versioned/next/tasks/native-module-baseline.md +8 -4
- package/dist/docs/versioned/next/tasks/rate-limiting.md +9 -2
- package/dist/docs/versioned/next/tasks/remove-legacy-realtime.md +5 -5
- package/dist/docs/versioned/next/tasks/remove-rtk.md +155 -0
- package/dist/local/localTools.d.ts.map +1 -1
- package/dist/local/localTools.js +3 -54
- package/dist/local/localTools.js.map +1 -1
- package/dist/local/tools/runtime.d.ts +0 -21
- package/dist/local/tools/runtime.d.ts.map +1 -1
- package/dist/local/tools/runtime.js +0 -176
- package/dist/local/tools/runtime.js.map +1 -1
- package/dist/local/tools/syncDb.d.ts +0 -11
- package/dist/local/tools/syncDb.d.ts.map +1 -1
- package/dist/local/tools/syncDb.js +1 -5
- package/dist/local/tools/syncDb.js.map +1 -1
- package/dist/packageGuidelines.d.ts +3 -2
- package/dist/packageGuidelines.d.ts.map +1 -1
- package/dist/packageGuidelines.js +4 -11
- package/dist/packageGuidelines.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +17 -18
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +1 -8
- package/dist/resources.js.map +1 -1
- package/dist/search/chunker.d.ts +1 -1
- package/dist/search/chunker.d.ts.map +1 -1
- package/dist/search/inferPackages.d.ts +1 -1
- package/dist/search/inferPackages.js +5 -5
- package/dist/search/inferPackages.js.map +1 -1
- package/dist/tools.d.ts +6 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +126 -119
- package/dist/tools.js.map +1 -1
- package/package.json +6 -6
- package/src/docs/guidelines/admin-frontend/guidelines/core.md +6 -5
- package/src/docs/guidelines/ui/guidelines/core.md +1 -1
- package/src/docs/prompts/debug.md +6 -4
- package/src/docs/prompts/screen.md +11 -17
- package/src/docs/resources/overview.md +5 -3
- package/src/docs/resources/patterns.md +157 -238
- package/src/docs/resources/syncdb.md +44 -16
- package/src/docs/templates/bootstrap/CLAUDE.template.md +2 -2
- package/src/docs/templates/bootstrap/cursorrules.template.md +7 -5
- package/src/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +8 -12
- package/src/docs/templates/bootstrap/frontend/app/_layout.template.tsx +75 -52
- package/src/docs/templates/bootstrap/frontend/app/login.template.tsx +46 -108
- package/src/docs/templates/bootstrap/frontend/app/signup.template.tsx +53 -0
- package/src/docs/templates/bootstrap/frontend/lib/betterAuth.template.md +18 -0
- package/src/docs/templates/bootstrap/frontend/store/apiClient.template.md +33 -0
- package/src/docs/templates/bootstrap/frontend/store/apiSdk.template.md +76 -0
- package/src/docs/templates/bootstrap/frontend/store/syncdb.template.md +56 -0
- package/src/docs/templates/bootstrap/frontend/utils/index.template.md +0 -4
- package/src/docs/upgrades/58.0.0-beta.1.md +504 -0
- package/src/docs/upgrades/58.0.0.md +495 -4
- package/src/docs/versioned/next/README.md +2 -2
- package/src/docs/versioned/next/approval-rubric.md +2 -2
- package/src/docs/versioned/next/explanation/admin-interface.md +6 -5
- package/src/docs/versioned/next/explanation/admin-plugin-frontend.md +1 -1
- package/src/docs/versioned/next/explanation/ai-workflows.md +5 -3
- package/src/docs/versioned/next/explanation/announcements/rtk-deprecation.md +16 -11
- package/src/docs/versioned/next/explanation/authentication.md +62 -43
- package/src/docs/versioned/next/explanation/dependency-management.md +1 -1
- package/src/docs/versioned/next/explanation/deployment-baseline.md +1 -1
- package/src/docs/versioned/next/explanation/example-coverage.md +2 -2
- package/src/docs/versioned/next/explanation/explicit-any-policy.md +5 -6
- package/src/docs/versioned/next/explanation/gcp-hosting-architecture.md +1 -1
- package/src/docs/versioned/next/explanation/local-first-data.md +11 -9
- package/src/docs/versioned/next/explanation/model-router-actions.md +1 -1
- package/src/docs/versioned/next/explanation/modular-api-design.md +2 -2
- package/src/docs/versioned/next/explanation/no-barrel-imports.md +5 -5
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +4 -3
- package/src/docs/versioned/next/explanation/source-rules.md +2 -2
- package/src/docs/versioned/next/explanation/typescript-configuration.md +2 -4
- package/src/docs/versioned/next/explanation/versioning-policy.md +3 -3
- package/src/docs/versioned/next/how-to/README.md +3 -2
- package/src/docs/versioned/next/how-to/add-feature-flags.md +50 -25
- package/src/docs/versioned/next/how-to/add-organizations.md +2 -1
- package/src/docs/versioned/next/how-to/admin-custom-home.md +8 -2
- package/src/docs/versioned/next/how-to/admin-custom-widget.md +0 -1
- package/src/docs/versioned/next/how-to/agent-ui-asks.md +6 -6
- package/src/docs/versioned/next/how-to/build-admin-screens.md +10 -8
- package/src/docs/versioned/next/how-to/build-for-web.md +1 -1
- package/src/docs/versioned/next/how-to/call-external-apis.md +2 -2
- package/src/docs/versioned/next/how-to/circleci.md +12 -6
- package/src/docs/versioned/next/how-to/configure-better-auth.md +114 -60
- package/src/docs/versioned/next/how-to/connect-mcp-service-token.md +10 -4
- package/src/docs/versioned/next/how-to/create-a-terreno-app.md +14 -2
- package/src/docs/versioned/next/how-to/debug-with-mcp.md +8 -13
- package/src/docs/versioned/next/how-to/expose-mcp-tools.md +15 -4
- package/src/docs/versioned/next/how-to/generate-the-client-sdk.md +33 -0
- package/src/docs/versioned/next/how-to/github-actions-ci.md +2 -2
- package/src/docs/versioned/next/how-to/in-app-notifications.md +1 -1
- package/src/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +318 -447
- package/src/docs/versioned/next/how-to/password-reset.md +1 -1
- package/src/docs/versioned/next/how-to/product-announcements.md +6 -3
- package/src/docs/versioned/next/how-to/rate-limiting.md +38 -16
- package/src/docs/versioned/next/how-to/run-mongodb-migrations.md +19 -0
- package/src/docs/versioned/next/how-to/run-tests-locally.md +2 -3
- package/src/docs/versioned/next/how-to/set-up-social-login.md +1 -1
- package/src/docs/versioned/next/how-to/set-up-terreno-mcp.md +2 -2
- package/src/docs/versioned/next/how-to/track-upstream-expo.md +1 -1
- package/src/docs/versioned/next/how-to/upgrade-banner.md +5 -3
- package/src/docs/versioned/next/how-to/upgrade-terreno.md +5 -5
- package/src/docs/versioned/next/how-to/use-syncdb-correctly.md +1 -1
- package/src/docs/versioned/next/how-to/websocket-integration.md +113 -402
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/src/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +5 -0
- package/src/docs/versioned/next/implementationPlans/native-module-baseline.md +29 -5
- package/src/docs/versioned/next/implementationPlans/remove-legacy-realtime.md +1 -1
- package/src/docs/versioned/next/implementationPlans/remove-rtk.md +185 -0
- package/src/docs/versioned/next/reference/README.md +1 -1
- package/src/docs/versioned/next/reference/admin-frontend.md +85 -70
- package/src/docs/versioned/next/reference/admin-spa.md +10 -4
- package/src/docs/versioned/next/reference/ai.md +36 -4
- package/src/docs/versioned/next/reference/announcements.md +3 -3
- package/src/docs/versioned/next/reference/api.md +39 -24
- package/src/docs/versioned/next/reference/cli.md +3 -4
- package/src/docs/versioned/next/reference/environment-variables.md +16 -16
- package/src/docs/versioned/next/reference/feature-flags.md +48 -7
- package/src/docs/versioned/next/reference/jobs.md +2 -2
- package/src/docs/versioned/next/reference/legacy/rtk.md +25 -600
- package/src/docs/versioned/next/reference/mcp-server.md +441 -1158
- package/src/docs/versioned/next/reference/syncdb.md +426 -16
- package/src/docs/versioned/next/reference/test.md +28 -3
- package/src/docs/versioned/next/reference/ui.md +132 -19
- package/src/docs/versioned/next/tasks/native-module-baseline.md +8 -4
- package/src/docs/versioned/next/tasks/rate-limiting.md +9 -2
- package/src/docs/versioned/next/tasks/remove-legacy-realtime.md +5 -5
- package/src/docs/versioned/next/tasks/remove-rtk.md +155 -0
- package/dist/docs/guidelines/rtk/guidelines/core.md +0 -26
- package/dist/docs/resources/rtk.md +0 -181
- package/dist/docs/templates/bootstrap/frontend/openapi-config.template.md +0 -16
- package/dist/docs/templates/bootstrap/frontend/scripts/generate-sdk.template.md +0 -49
- package/dist/docs/templates/bootstrap/frontend/store/appState.template.md +0 -45
- package/dist/docs/templates/bootstrap/frontend/store/errors.template.md +0 -51
- package/dist/docs/templates/bootstrap/frontend/store/index.template.md +0 -86
- package/dist/docs/templates/bootstrap/frontend/store/openApiSdk.template.md +0 -49
- package/dist/docs/templates/bootstrap/frontend/store/sdk.template.md +0 -80
- package/src/docs/guidelines/rtk/guidelines/core.md +0 -26
- package/src/docs/resources/rtk.md +0 -181
- package/src/docs/templates/bootstrap/frontend/openapi-config.template.md +0 -16
- package/src/docs/templates/bootstrap/frontend/scripts/generate-sdk.template.md +0 -49
- package/src/docs/templates/bootstrap/frontend/store/appState.template.md +0 -45
- package/src/docs/templates/bootstrap/frontend/store/errors.template.md +0 -51
- package/src/docs/templates/bootstrap/frontend/store/index.template.md +0 -86
- package/src/docs/templates/bootstrap/frontend/store/openApiSdk.template.md +0 -49
- 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
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
391
|
-
|
|
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/
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
470
|
-
|
|
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 "@/
|
|
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/
|
|
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/
|
|
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
|
|
674
|
-
user.
|
|
675
|
-
- **Signing out.**
|
|
676
|
-
`authClient.signOut()` answers, then
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
loaded (`isLoading && !userId`), or a
|
|
681
|
-
first tab. A sign-out that cannot reach the
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
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/
|
|
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/
|
|
905
|
+
import {createBetterAuthClient} from "@terreno/syncdb/auth";
|
|
906
|
+
import {baseUrl} from "@terreno/syncdb/config";
|
|
873
907
|
|
|
874
908
|
export const authClient = createBetterAuthClient({
|
|
875
|
-
baseURL:
|
|
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
|
|
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 `
|
|
913
|
-
|
|
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.
|
|
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/
|
|
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/
|
|
1034
|
+
import {completeBetterAuthOAuthHandoff} from "@terreno/syncdb/auth";
|
|
992
1035
|
|
|
993
|
-
await completeBetterAuthOAuthHandoff({client: authClient});
|
|
994
|
-
|
|
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`
|
|
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/
|
|
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/
|
|
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/
|
|
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:
|
|
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/
|
|
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
|
|
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 (`
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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]
|
|
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 --
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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`/`
|
|
23
|
-
| TypeDoc workspace `tsc` | Once per generate
|
|
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
|
|
76
|
+
Regenerate syncdb collection hooks for `notifications` and `notification-preferences`:
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
79
|
cd example-frontend
|