@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
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
# @terreno/rtk Documentation (legacy)
|
|
2
|
-
|
|
3
|
-
> **Deprecated for data synchronization** as of `56.0.0`. Use `@terreno/syncdb` for collection CRUD. This resource documents RTK for OpenAPI SDK codegen, Better Auth session Redux, feature flags, and sockets during the support window. See [migrate-rtk-to-syncdb.md](https://github.com/TerrenoLabs/terreno/blob/master/docs/how-to/migrate-rtk-to-syncdb.md).
|
|
4
|
-
|
|
5
|
-
Redux Toolkit Query utilities for frontends connecting to @terreno/api backends.
|
|
6
|
-
|
|
7
|
-
## Key Exports
|
|
8
|
-
|
|
9
|
-
- `emptyApi` - Base RTK Query API configured with axios
|
|
10
|
-
- `authSlice` - Redux slice for auth state
|
|
11
|
-
- `generateProfileEndpoints` - Auth endpoint builder
|
|
12
|
-
- Token utilities: `getTokenExpirationTimes()`, `getFriendlyExpirationInfo()`, `getAuthToken()`
|
|
13
|
-
|
|
14
|
-
## Setup
|
|
15
|
-
|
|
16
|
-
### Store Configuration
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
import { configureStore } from "@reduxjs/toolkit";
|
|
20
|
-
import { emptyApi, authSlice } from "@terreno/rtk";
|
|
21
|
-
import { openApiSdk } from "./openApiSdk";
|
|
22
|
-
|
|
23
|
-
export const store = configureStore({
|
|
24
|
-
reducer: {
|
|
25
|
-
[openApiSdk.reducerPath]: openApiSdk.reducer,
|
|
26
|
-
auth: authSlice.reducer,
|
|
27
|
-
},
|
|
28
|
-
middleware: (getDefaultMiddleware) =>
|
|
29
|
-
getDefaultMiddleware().concat(openApiSdk.middleware),
|
|
30
|
-
});
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### SDK Generation
|
|
34
|
-
|
|
35
|
-
The SDK is auto-generated from your backend's OpenAPI spec:
|
|
36
|
-
|
|
37
|
-
```typescript
|
|
38
|
-
// openApiSdk.ts - AUTO-GENERATED, DO NOT EDIT
|
|
39
|
-
import { emptyApi } from "@terreno/rtk";
|
|
40
|
-
|
|
41
|
-
export const openApiSdk = emptyApi.injectEndpoints({
|
|
42
|
-
endpoints: (build) => ({
|
|
43
|
-
getUsers: build.query<User[], GetUsersParams>({
|
|
44
|
-
query: (params) => ({ url: "/users", params }),
|
|
45
|
-
}),
|
|
46
|
-
createUser: build.mutation<User, CreateUserBody>({
|
|
47
|
-
query: (body) => ({ url: "/users", method: "POST", body }),
|
|
48
|
-
}),
|
|
49
|
-
}),
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
export const { useGetUsersQuery, useCreateUserMutation } = openApiSdk;
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Using the SDK
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
import { useGetUsersQuery, useCreateUserMutation } from "@/store/openApiSdk";
|
|
59
|
-
|
|
60
|
-
const UserList = () => {
|
|
61
|
-
const { data: users, isLoading, error } = useGetUsersQuery({ limit: 10 });
|
|
62
|
-
const [createUser, { isLoading: isCreating }] = useCreateUserMutation();
|
|
63
|
-
|
|
64
|
-
const handleCreate = async () => {
|
|
65
|
-
try {
|
|
66
|
-
const newUser = await createUser({ name: "John", email: "john@example.com" }).unwrap();
|
|
67
|
-
console.info("Created user:", newUser);
|
|
68
|
-
} catch (err) {
|
|
69
|
-
console.error("Failed to create user:", err);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
if (isLoading) return <Text>Loading...</Text>;
|
|
74
|
-
if (error) return <Text>Error loading users</Text>;
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<Box>
|
|
78
|
-
{users?.map((user) => (
|
|
79
|
-
<Text key={user.id}>{user.name}</Text>
|
|
80
|
-
))}
|
|
81
|
-
<Button text="Add User" onClick={handleCreate} loading={isCreating} />
|
|
82
|
-
</Box>
|
|
83
|
-
);
|
|
84
|
-
};
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Authentication
|
|
88
|
-
|
|
89
|
-
### Login
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
import { useEmailLoginMutation } from "@/store/openApiSdk";
|
|
93
|
-
import { useAppDispatch } from "@/store/index";
|
|
94
|
-
import { authSlice } from "@terreno/rtk";
|
|
95
|
-
|
|
96
|
-
const LoginScreen = () => {
|
|
97
|
-
const [email, setEmail] = useState("");
|
|
98
|
-
const [password, setPassword] = useState("");
|
|
99
|
-
const [emailLogin, { isLoading, error }] = useEmailLoginMutation();
|
|
100
|
-
const dispatch = useAppDispatch();
|
|
101
|
-
|
|
102
|
-
const handleLogin = async () => {
|
|
103
|
-
try {
|
|
104
|
-
const result = await emailLogin({ email, password }).unwrap();
|
|
105
|
-
// Auth state is automatically updated
|
|
106
|
-
} catch (err) {
|
|
107
|
-
console.error("Login failed:", err);
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<Box padding={4} gap={3}>
|
|
113
|
-
<EmailField label="Email" value={email} onChangeText={setEmail} />
|
|
114
|
-
<PasswordField label="Password" value={password} onChangeText={setPassword} />
|
|
115
|
-
<Button text="Login" onClick={handleLogin} loading={isLoading} />
|
|
116
|
-
</Box>
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Auth State
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
import { useAppSelector } from "@/store/appState";
|
|
125
|
-
|
|
126
|
-
const Component = () => {
|
|
127
|
-
const userId = useAppSelector((state) => state.auth.userId);
|
|
128
|
-
const isAuthenticated = !!userId;
|
|
129
|
-
|
|
130
|
-
// ...
|
|
131
|
-
};
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Logout
|
|
135
|
-
|
|
136
|
-
```typescript
|
|
137
|
-
import { LOGOUT_ACTION_TYPE } from "@terreno/rtk";
|
|
138
|
-
|
|
139
|
-
const handleLogout = () => {
|
|
140
|
-
dispatch({ type: LOGOUT_ACTION_TYPE });
|
|
141
|
-
};
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Token Management
|
|
145
|
-
|
|
146
|
-
Tokens are automatically managed:
|
|
147
|
-
- Stored in `expo-secure-store` (mobile) or AsyncStorage (web)
|
|
148
|
-
- Auto-refresh with exponential backoff
|
|
149
|
-
- Mutex-protected to prevent race conditions
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
import { getAuthToken, getTokenExpirationTimes } from "@terreno/rtk";
|
|
153
|
-
|
|
154
|
-
// Get current token
|
|
155
|
-
const token = await getAuthToken();
|
|
156
|
-
|
|
157
|
-
// Check expiration
|
|
158
|
-
const { accessTokenExpiry, refreshTokenExpiry } = getTokenExpirationTimes(token);
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
## Platform Detection
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
import { IsWeb, IsNative } from "@terreno/rtk";
|
|
165
|
-
|
|
166
|
-
if (IsWeb) {
|
|
167
|
-
// Web-specific code
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (IsNative) {
|
|
171
|
-
// Mobile-specific code
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## Best Practices
|
|
176
|
-
|
|
177
|
-
1. **Never use axios directly** - Always use generated SDK hooks
|
|
178
|
-
2. **Don't modify generated SDK** - It's auto-generated from OpenAPI spec
|
|
179
|
-
3. **Use .unwrap()** for mutations to get the result or throw error
|
|
180
|
-
4. **Handle loading and error states** in your UI
|
|
181
|
-
5. **Use TypeScript** - The SDK provides full type safety
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type {ConfigFile} from "@rtk-query/codegen-openapi";
|
|
2
|
-
|
|
3
|
-
const config: ConfigFile = {
|
|
4
|
-
apiFile: "@terreno/rtk",
|
|
5
|
-
apiImport: "emptySplitApi",
|
|
6
|
-
argSuffix: "Args",
|
|
7
|
-
exportName: "openapi",
|
|
8
|
-
flattenArg: true,
|
|
9
|
-
hooks: true,
|
|
10
|
-
outputFile: "./store/openApiSdk.ts",
|
|
11
|
-
responseSuffix: "Res",
|
|
12
|
-
schemaFile: process.env.OPENAPI_URL ?? "http://localhost:4000/openapi.json",
|
|
13
|
-
tag: true,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export default config;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
import {exec} from "node:child_process";
|
|
4
|
-
import {existsSync, readFileSync, writeFileSync} from "node:fs";
|
|
5
|
-
import {join} from "node:path";
|
|
6
|
-
|
|
7
|
-
const cliPath = join(
|
|
8
|
-
__dirname,
|
|
9
|
-
"..",
|
|
10
|
-
"node_modules",
|
|
11
|
-
"@rtk-query",
|
|
12
|
-
"codegen-openapi",
|
|
13
|
-
"lib",
|
|
14
|
-
"bin",
|
|
15
|
-
"cli.mjs"
|
|
16
|
-
);
|
|
17
|
-
const configPath = join(__dirname, "..", "openapi-config.ts");
|
|
18
|
-
const tsConfigPath = join(__dirname, "..", "tsconfig.codegen.json");
|
|
19
|
-
|
|
20
|
-
const command = `TS_NODE_PROJECT=${tsConfigPath} tsx ${cliPath} ${configPath}`;
|
|
21
|
-
|
|
22
|
-
exec(command, (error, _stdout, stderr) => {
|
|
23
|
-
if (error) {
|
|
24
|
-
console.error(`Error: ${error.message}`);
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
if (stderr) {
|
|
28
|
-
console.error(`stderr: ${stderr}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const sdkPath = join(__dirname, "..", "store", "openApiSdk.ts");
|
|
32
|
-
|
|
33
|
-
if (existsSync(sdkPath)) {
|
|
34
|
-
let content = readFileSync(sdkPath, "utf8");
|
|
35
|
-
content = content.replace(/^export const \{\} = injectedRtkApi;\n?/m, "");
|
|
36
|
-
writeFileSync(sdkPath, content, "utf8");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
exec(
|
|
40
|
-
"bunx biome check --unsafe --write store/openApiSdk.ts",
|
|
41
|
-
{cwd: join(__dirname, "..")},
|
|
42
|
-
(formatError) => {
|
|
43
|
-
if (formatError) {
|
|
44
|
-
console.error(`Formatting error: ${formatError.message}`);
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {createSlice, type PayloadAction} from "@reduxjs/toolkit";
|
|
2
|
-
import type {RootState} from "@terreno/rtk";
|
|
3
|
-
import {type TypedUseSelectorHook, useSelector} from "react-redux";
|
|
4
|
-
|
|
5
|
-
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
|
6
|
-
|
|
7
|
-
export type AppState = {
|
|
8
|
-
darkMode: boolean;
|
|
9
|
-
language: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const initialState: AppState = {
|
|
13
|
-
darkMode: false,
|
|
14
|
-
language: "en",
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const appStateSlice = createSlice({
|
|
18
|
-
initialState,
|
|
19
|
-
name: "appState",
|
|
20
|
-
reducers: {
|
|
21
|
-
resetAppState: () => initialState,
|
|
22
|
-
setDarkMode: (state, action: PayloadAction<boolean>) => {
|
|
23
|
-
state.darkMode = action.payload;
|
|
24
|
-
},
|
|
25
|
-
setLanguage: (state, action: PayloadAction<string>) => {
|
|
26
|
-
state.language = action.payload;
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
export const {setDarkMode, setLanguage, resetAppState} = appStateSlice.actions;
|
|
32
|
-
|
|
33
|
-
export const useSelectDarkMode = (): boolean => {
|
|
34
|
-
return useAppSelector((state: RootState): boolean => {
|
|
35
|
-
return state.appState.darkMode;
|
|
36
|
-
});
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const useSelectLanguage = (): string => {
|
|
40
|
-
return useAppSelector((state: RootState): string => {
|
|
41
|
-
return state.appState.language;
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export default appStateSlice.reducer;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type {Middleware} from "@reduxjs/toolkit";
|
|
2
|
-
import {useToast} from "@terreno/ui";
|
|
3
|
-
|
|
4
|
-
const ignoredErrors = [
|
|
5
|
-
"Password or username is incorrect",
|
|
6
|
-
"Token refresh failed with 401",
|
|
7
|
-
"Failed to refresh token",
|
|
8
|
-
];
|
|
9
|
-
|
|
10
|
-
// biome-ignore lint/suspicious/noExplicitAny: Generic middleware
|
|
11
|
-
export const rtkQueryErrorMiddleware: Middleware = () => (next) => (action: any) => {
|
|
12
|
-
if (action?.error && action?.payload) {
|
|
13
|
-
const errorMessage =
|
|
14
|
-
action.payload?.data?.title ??
|
|
15
|
-
action.payload?.data?.message ??
|
|
16
|
-
action.payload?.error ??
|
|
17
|
-
JSON.stringify(action.payload);
|
|
18
|
-
|
|
19
|
-
let endpointInfo = "unknown endpoint";
|
|
20
|
-
if (action.meta?.baseQueryMeta?.request?.method && action.meta?.baseQueryMeta?.request?.url) {
|
|
21
|
-
endpointInfo = `${action.meta.baseQueryMeta.request.url} ${action.meta.baseQueryMeta.request.method}`;
|
|
22
|
-
} else if (action.meta?.arg?.endpointName) {
|
|
23
|
-
endpointInfo = `${action.meta.arg.endpointName} rejected ${action.meta.arg.type || ""}`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const message = `${endpointInfo.trim()}: ${errorMessage}`;
|
|
27
|
-
console.debug(message);
|
|
28
|
-
|
|
29
|
-
if (action.payload.status === 404 || action.payload.status === 401) {
|
|
30
|
-
return next(action);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const shouldIgnore = ignoredErrors.some((err) => errorMessage.includes(err));
|
|
34
|
-
if (!shouldIgnore) {
|
|
35
|
-
console.warn(message);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return next(action);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const useSentryAndToast = (): ((errorMessage: string) => void) => {
|
|
43
|
-
const toast = useToast();
|
|
44
|
-
return (error: string): void => {
|
|
45
|
-
if (!error) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
toast.error(error);
|
|
49
|
-
console.warn(`Error: ${error}`);
|
|
50
|
-
};
|
|
51
|
-
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
2
|
-
import {combineReducers, configureStore} from "@reduxjs/toolkit";
|
|
3
|
-
import {generateAuthSlice} from "@terreno/rtk";
|
|
4
|
-
import {DateTime} from "luxon";
|
|
5
|
-
import {useDispatch} from "react-redux";
|
|
6
|
-
import type {Storage} from "redux-persist";
|
|
7
|
-
import {persistReducer, persistStore} from "redux-persist";
|
|
8
|
-
|
|
9
|
-
import appState from "./appState";
|
|
10
|
-
import {rtkQueryErrorMiddleware} from "./errors";
|
|
11
|
-
import {terrenoApi} from "./sdk";
|
|
12
|
-
|
|
13
|
-
const authSlice = generateAuthSlice(terrenoApi);
|
|
14
|
-
|
|
15
|
-
export const {logout} = authSlice;
|
|
16
|
-
|
|
17
|
-
const createSafeStorage = (): Storage => {
|
|
18
|
-
return {
|
|
19
|
-
getItem: async (key: string): Promise<string | null> => {
|
|
20
|
-
if (typeof window !== "undefined") {
|
|
21
|
-
return AsyncStorage.getItem(key);
|
|
22
|
-
}
|
|
23
|
-
return null;
|
|
24
|
-
},
|
|
25
|
-
removeItem: async (key: string): Promise<void> => {
|
|
26
|
-
if (typeof window !== "undefined") {
|
|
27
|
-
return AsyncStorage.removeItem(key);
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
setItem: async (key: string, value: string): Promise<void> => {
|
|
31
|
-
if (typeof window !== "undefined") {
|
|
32
|
-
return AsyncStorage.setItem(key, value);
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const persistConfig = {
|
|
39
|
-
blacklist: ["terreno-rtk"],
|
|
40
|
-
key: "root",
|
|
41
|
-
storage: createSafeStorage(),
|
|
42
|
-
timeout: 0,
|
|
43
|
-
version: 1,
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const rootReducer = combineReducers({
|
|
47
|
-
appState,
|
|
48
|
-
auth: authSlice.authReducer,
|
|
49
|
-
"terreno-rtk": terrenoApi.reducer,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
|
53
|
-
|
|
54
|
-
const store = configureStore({
|
|
55
|
-
devTools: process.env.NODE_ENV !== "production" && {
|
|
56
|
-
name: `App-${
|
|
57
|
-
typeof window !== "undefined"
|
|
58
|
-
// biome-ignore lint/suspicious/noAssignInExpressions: Window name assignment
|
|
59
|
-
? window.name || ((window.name = `Window-${DateTime.now().toFormat("HH:mm:ss")}`))
|
|
60
|
-
: "Unknown"
|
|
61
|
-
}`,
|
|
62
|
-
},
|
|
63
|
-
middleware: (getDefaultMiddleware) => {
|
|
64
|
-
return getDefaultMiddleware({
|
|
65
|
-
immutableCheck: false,
|
|
66
|
-
serializableCheck: false,
|
|
67
|
-
thunk: true,
|
|
68
|
-
}).concat([
|
|
69
|
-
...authSlice.middleware,
|
|
70
|
-
// biome-ignore lint/suspicious/noExplicitAny: RTK Query middleware typing
|
|
71
|
-
terrenoApi.middleware as any,
|
|
72
|
-
rtkQueryErrorMiddleware,
|
|
73
|
-
// biome-ignore lint/suspicious/noExplicitAny: Middleware array typing
|
|
74
|
-
]) as any;
|
|
75
|
-
},
|
|
76
|
-
reducer: persistedReducer,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
export const persistor = persistStore(store);
|
|
80
|
-
|
|
81
|
-
export type RootState = ReturnType<typeof store.getState>;
|
|
82
|
-
export type AppDispatch = typeof store.dispatch;
|
|
83
|
-
|
|
84
|
-
export const useAppDispatch: () => AppDispatch = useDispatch;
|
|
85
|
-
|
|
86
|
-
export default store;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// THIS FILE IS AUTO-GENERATED. DO NOT EDIT.
|
|
2
|
-
// Run "bun run sdk" to regenerate this file from the backend OpenAPI spec.
|
|
3
|
-
|
|
4
|
-
import {emptySplitApi as api} from "@terreno/rtk";
|
|
5
|
-
export const addTagTypes = ["Users", "Auth"] as const;
|
|
6
|
-
const injectedRtkApi = api
|
|
7
|
-
.enhanceEndpoints({
|
|
8
|
-
addTagTypes,
|
|
9
|
-
})
|
|
10
|
-
.injectEndpoints({
|
|
11
|
-
endpoints: (build) => ({
|
|
12
|
-
emailLogin: build.mutation<EmailLoginRes, EmailLoginArgs>({
|
|
13
|
-
query: (queryArg) => ({
|
|
14
|
-
body: queryArg,
|
|
15
|
-
method: "POST",
|
|
16
|
-
url: `/auth/login`,
|
|
17
|
-
}),
|
|
18
|
-
}),
|
|
19
|
-
emailSignUp: build.mutation<EmailSignUpRes, EmailSignUpArgs>({
|
|
20
|
-
query: (queryArg) => ({
|
|
21
|
-
body: queryArg,
|
|
22
|
-
method: "POST",
|
|
23
|
-
url: `/auth/signup`,
|
|
24
|
-
}),
|
|
25
|
-
}),
|
|
26
|
-
}),
|
|
27
|
-
overrideExisting: false,
|
|
28
|
-
});
|
|
29
|
-
export {injectedRtkApi as openapi};
|
|
30
|
-
export type EmailLoginArgs = {
|
|
31
|
-
email: string;
|
|
32
|
-
password: string;
|
|
33
|
-
};
|
|
34
|
-
export type EmailLoginRes = {
|
|
35
|
-
token: string;
|
|
36
|
-
refreshToken: string;
|
|
37
|
-
userId: string;
|
|
38
|
-
};
|
|
39
|
-
export type EmailSignUpArgs = {
|
|
40
|
-
email: string;
|
|
41
|
-
password: string;
|
|
42
|
-
name: string;
|
|
43
|
-
};
|
|
44
|
-
export type EmailSignUpRes = {
|
|
45
|
-
token: string;
|
|
46
|
-
refreshToken: string;
|
|
47
|
-
userId: string;
|
|
48
|
-
};
|
|
49
|
-
export const {useEmailLoginMutation, useEmailSignUpMutation} = injectedRtkApi;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import {generateTags} from "@terreno/rtk";
|
|
2
|
-
import startCase from "lodash/startCase";
|
|
3
|
-
|
|
4
|
-
import {addTagTypes, openapi} from "./openApiSdk";
|
|
5
|
-
|
|
6
|
-
export interface ProfileResponse {
|
|
7
|
-
data: {
|
|
8
|
-
_id: string;
|
|
9
|
-
id: string;
|
|
10
|
-
email: string;
|
|
11
|
-
name: string;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface UpdateProfileRequest {
|
|
16
|
-
name?: string;
|
|
17
|
-
email?: string;
|
|
18
|
-
/** Required by the server when `email` changes the mailbox. */
|
|
19
|
-
currentPassword?: string;
|
|
20
|
-
password?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const terrenoApi = openapi
|
|
24
|
-
.injectEndpoints({
|
|
25
|
-
endpoints: (builder) => ({
|
|
26
|
-
getMe: builder.query<ProfileResponse, void>({
|
|
27
|
-
providesTags: ["profile"],
|
|
28
|
-
query: () => ({
|
|
29
|
-
method: "GET",
|
|
30
|
-
url: "/auth/me",
|
|
31
|
-
}),
|
|
32
|
-
}),
|
|
33
|
-
patchMe: builder.mutation<ProfileResponse, UpdateProfileRequest>({
|
|
34
|
-
invalidatesTags: ["profile"],
|
|
35
|
-
query: (body) => ({
|
|
36
|
-
body,
|
|
37
|
-
method: "PATCH",
|
|
38
|
-
url: "/auth/me",
|
|
39
|
-
}),
|
|
40
|
-
}),
|
|
41
|
-
}),
|
|
42
|
-
})
|
|
43
|
-
.enhanceEndpoints({
|
|
44
|
-
addTagTypes: ["profile"],
|
|
45
|
-
endpoints: {
|
|
46
|
-
...generateTags(openapi, [...addTagTypes]),
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
export const {
|
|
51
|
-
useEmailLoginMutation,
|
|
52
|
-
useEmailSignUpMutation,
|
|
53
|
-
useGetMeQuery,
|
|
54
|
-
usePatchMeMutation,
|
|
55
|
-
} = terrenoApi;
|
|
56
|
-
export * from "./openApiSdk";
|
|
57
|
-
|
|
58
|
-
type OpenApiEndpoints = Record<string, unknown>;
|
|
59
|
-
|
|
60
|
-
export const getSdkHook = (
|
|
61
|
-
modelName: string,
|
|
62
|
-
type: "list" | "read" | "create" | "update" | "remove"
|
|
63
|
-
): Record<string, unknown> => {
|
|
64
|
-
const modelPath = startCase(modelName).replace(/\s/g, "");
|
|
65
|
-
const endpoints = openapi.endpoints as OpenApiEndpoints;
|
|
66
|
-
switch (type) {
|
|
67
|
-
case "list":
|
|
68
|
-
return endpoints[`get${modelPath}`] as Record<string, unknown>;
|
|
69
|
-
case "read":
|
|
70
|
-
return endpoints[`get${modelPath}ById`] as Record<string, unknown>;
|
|
71
|
-
case "create":
|
|
72
|
-
return endpoints[`post${modelPath}`] as Record<string, unknown>;
|
|
73
|
-
case "update":
|
|
74
|
-
return endpoints[`patch${modelPath}ById`] as Record<string, unknown>;
|
|
75
|
-
case "remove":
|
|
76
|
-
return endpoints[`delete${modelPath}ById`] as Record<string, unknown>;
|
|
77
|
-
default:
|
|
78
|
-
throw new Error(`Invalid SDK hook: ${modelName}/${type}`);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
### @terreno/rtk
|
|
2
|
-
|
|
3
|
-
Redux Toolkit Query integration:
|
|
4
|
-
|
|
5
|
-
- **generateAuthSlice**: Creates auth reducer and middleware with JWT handling
|
|
6
|
-
- **emptyApi**: Base RTK Query API for code generation
|
|
7
|
-
- **Platform utilities**: Secure token storage (expo-secure-store for native, AsyncStorage for web)
|
|
8
|
-
|
|
9
|
-
Key imports:
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
import {generateAuthSlice} from "@terreno/rtk";
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Always use generated SDK hooks — never use `axios` or `request` directly:
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
// Correct
|
|
19
|
-
import {useGetYourRouteQuery} from "@/store/openApiSdk";
|
|
20
|
-
const {data, isLoading, error} = useGetYourRouteQuery({id: "value"});
|
|
21
|
-
|
|
22
|
-
// Wrong - don't use axios directly
|
|
23
|
-
// const result = await axios.get("/api/yourRoute/value");
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
**No barrel imports** in app store code — import hooks from `@/store/sdk` or `@/store/openApiSdk`, not `@/store`. See `docs/explanation/no-barrel-imports.md`.
|