@terreno/api 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +28 -2
- package/dist/api.js +20 -7
- package/dist/betterAuth.d.ts +91 -0
- package/dist/betterAuth.js +8 -0
- package/dist/betterAuth.test.d.ts +1 -0
- package/dist/betterAuth.test.js +181 -0
- package/dist/betterAuthApp.d.ts +22 -0
- package/dist/betterAuthApp.js +38 -0
- package/dist/betterAuthApp.test.d.ts +1 -0
- package/dist/betterAuthApp.test.js +242 -0
- package/dist/betterAuthSetup.d.ts +60 -0
- package/dist/betterAuthSetup.js +278 -0
- package/dist/betterAuthSetup.test.d.ts +1 -0
- package/dist/betterAuthSetup.test.js +684 -0
- package/dist/expressServer.js +3 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/terrenoApp.d.ts +189 -0
- package/dist/terrenoApp.js +352 -0
- package/dist/terrenoApp.test.d.ts +1 -0
- package/dist/terrenoApp.test.js +264 -0
- package/dist/terrenoPlugin.d.ts +34 -0
- package/package.json +6 -3
- package/src/api.ts +61 -3
- package/src/betterAuth.test.ts +160 -0
- package/src/betterAuth.ts +104 -0
- package/src/betterAuthApp.test.ts +114 -0
- package/src/betterAuthApp.ts +60 -0
- package/src/betterAuthSetup.test.ts +485 -0
- package/src/betterAuthSetup.ts +251 -0
- package/src/expressServer.ts +5 -6
- package/src/index.ts +4 -0
- package/src/openApiValidator.ts +1 -1
- package/src/terrenoApp.test.ts +201 -0
- package/src/terrenoApp.ts +347 -0
- package/src/terrenoPlugin.ts +34 -0
- package/.claude/CLAUDE.local.md +0 -204
- package/.cursor/rules/00-root.mdc +0 -338
- package/.github/copilot-instructions.md +0 -333
- package/AGENTS.md +0 -333
package/AGENTS.md
DELETED
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
# Terreno
|
|
2
|
-
|
|
3
|
-
A monorepo containing shared packages for building full-stack applications with React Native and Express/Mongoose.
|
|
4
|
-
|
|
5
|
-
## Packages
|
|
6
|
-
|
|
7
|
-
- **api/** - REST API framework built on Express/Mongoose (`@terreno/api`)
|
|
8
|
-
- **ui/** - React Native UI component library (`@terreno/ui`)
|
|
9
|
-
- **rtk/** - Redux Toolkit Query utilities for API backends (`@terreno/rtk`)
|
|
10
|
-
- **mcp-server/** - MCP server for AI assistant integration (`@terreno/mcp-server`)
|
|
11
|
-
- **demo/** - Demo app for showcasing and testing UI components
|
|
12
|
-
- **example-frontend/** - Example Expo app demonstrating full stack usage
|
|
13
|
-
- **example-backend/** - Example Express backend using @terreno/api
|
|
14
|
-
|
|
15
|
-
## Development
|
|
16
|
-
|
|
17
|
-
Uses [Bun](https://bun.sh/) as the package manager.
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
bun install # Install dependencies
|
|
21
|
-
bun run compile # Compile all packages
|
|
22
|
-
bun run lint # Lint all packages
|
|
23
|
-
bun run lint:fix # Fix lint issues
|
|
24
|
-
bun run test # Run tests in api and ui
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Package-specific commands
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
bun run api:test # Test API package
|
|
31
|
-
bun run ui:test # Test UI package
|
|
32
|
-
bun run demo:start # Start demo app
|
|
33
|
-
bun run frontend:web # Start frontend example
|
|
34
|
-
bun run backend:dev # Start backend example
|
|
35
|
-
bun run mcp:build # Build MCP server
|
|
36
|
-
bun run mcp:start # Start MCP server
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## How the Packages Work Together
|
|
40
|
-
|
|
41
|
-
The three core packages form a complete full-stack framework:
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
BACKEND
|
|
45
|
-
@terreno/api
|
|
46
|
-
- Mongoose models with modelRouter -> CRUD endpoints
|
|
47
|
-
- Built-in auth (JWT + Passport)
|
|
48
|
-
- Automatic OpenAPI spec generation
|
|
49
|
-
|
|
|
50
|
-
/openapi.json
|
|
51
|
-
|
|
|
52
|
-
RTK Query SDK Codegen
|
|
53
|
-
|
|
|
54
|
-
FRONTEND
|
|
55
|
-
@terreno/rtk
|
|
56
|
-
- Generated hooks from OpenAPI spec
|
|
57
|
-
- Auth slice with JWT token management
|
|
58
|
-
- Automatic token refresh
|
|
59
|
-
+
|
|
60
|
-
@terreno/ui
|
|
61
|
-
- React Native components (Box, Button, TextField, etc.)
|
|
62
|
-
- TerrenoProvider for theming
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Integration Flow
|
|
66
|
-
|
|
67
|
-
1. **Backend (api)**: Define Mongoose models, use `modelRouter` to create CRUD endpoints with permissions
|
|
68
|
-
2. **OpenAPI Generation**: `setupServer` automatically generates `/openapi.json`
|
|
69
|
-
3. **SDK Codegen**: Frontend runs `bun run sdk` to generate RTK Query hooks from OpenAPI spec
|
|
70
|
-
4. **Frontend (rtk + ui)**: Use generated hooks with UI components for type-safe API calls
|
|
71
|
-
|
|
72
|
-
## Example Apps (Keep These Updated!)
|
|
73
|
-
|
|
74
|
-
The `example-frontend/` and `example-backend/` directories serve as both documentation and integration tests. When adding features to api, ui, or rtk:
|
|
75
|
-
|
|
76
|
-
1. **Add examples** demonstrating new features
|
|
77
|
-
2. **Update SDK** after backend changes: `cd example-frontend && bun run sdk`
|
|
78
|
-
3. **Verify integration** by running both examples together
|
|
79
|
-
|
|
80
|
-
### Running the Full Stack
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
# Terminal 1: Start backend
|
|
84
|
-
bun run backend:dev
|
|
85
|
-
|
|
86
|
-
# Terminal 2: Start frontend
|
|
87
|
-
bun run frontend:web
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Code Style
|
|
91
|
-
|
|
92
|
-
### TypeScript/JavaScript
|
|
93
|
-
- Use ES module syntax and TypeScript for all code
|
|
94
|
-
- Prefer interfaces over types; avoid enums, use maps
|
|
95
|
-
- Prefer const arrow functions over `function` keyword
|
|
96
|
-
- Use descriptive variable names with auxiliary verbs (e.g., `isLoading`)
|
|
97
|
-
- Use camelCase directories (e.g., `components/authWizard`)
|
|
98
|
-
- Favor named exports
|
|
99
|
-
- Use the RORO pattern (Receive an Object, Return an Object)
|
|
100
|
-
|
|
101
|
-
### Dates and Time
|
|
102
|
-
- Always use Luxon instead of Date or dayjs
|
|
103
|
-
|
|
104
|
-
### Error Handling
|
|
105
|
-
- Check error conditions at start of functions and return early
|
|
106
|
-
- Limit nested if statements
|
|
107
|
-
- Use multiline syntax with curly braces for all conditionals
|
|
108
|
-
|
|
109
|
-
### Testing
|
|
110
|
-
- Use bun test with expect for testing
|
|
111
|
-
|
|
112
|
-
### Logging
|
|
113
|
-
- Frontend: Use `console.info`, `console.debug`, `console.warn`, or `console.error` for permanent logs
|
|
114
|
-
- Backend: Use `logger.info/warn/error/debug` for permanent logs
|
|
115
|
-
- Use `console.log` only for debugging (to be removed)
|
|
116
|
-
|
|
117
|
-
### Development Practices
|
|
118
|
-
- Don't apologize for errors: fix them
|
|
119
|
-
- Prioritize modularity, DRY, performance, and security
|
|
120
|
-
- Focus on readability over performance
|
|
121
|
-
- Write complete, functional code without TODOs when possible
|
|
122
|
-
- Comments should describe purpose, not effect
|
|
123
|
-
|
|
124
|
-
## Package Reference
|
|
125
|
-
|
|
126
|
-
### @terreno/api
|
|
127
|
-
|
|
128
|
-
REST API framework providing:
|
|
129
|
-
|
|
130
|
-
- **modelRouter**: Auto-generates CRUD endpoints for Mongoose models
|
|
131
|
-
- **Permissions**: `IsAuthenticated`, `IsOwner`, `IsAdmin`, `IsAuthenticatedOrReadOnly`
|
|
132
|
-
- **Query Filters**: `OwnerQueryFilter` for filtering list queries by owner
|
|
133
|
-
- **setupServer**: Express server setup with auth, OpenAPI, and middleware
|
|
134
|
-
- **APIError**: Standardized error handling
|
|
135
|
-
- **logger**: Winston-based logging
|
|
136
|
-
|
|
137
|
-
Key imports:
|
|
138
|
-
```typescript
|
|
139
|
-
import {
|
|
140
|
-
modelRouter,
|
|
141
|
-
setupServer,
|
|
142
|
-
Permissions,
|
|
143
|
-
OwnerQueryFilter,
|
|
144
|
-
APIError,
|
|
145
|
-
logger,
|
|
146
|
-
asyncHandler,
|
|
147
|
-
authenticateMiddleware,
|
|
148
|
-
} from "@terreno/api";
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
#### modelRouter Usage
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
import {modelRouter, modelRouterOptions, Permissions} from "@terreno/api";
|
|
155
|
-
|
|
156
|
-
const router = modelRouter(YourModel, {
|
|
157
|
-
permissions: {
|
|
158
|
-
list: [Permissions.IsAuthenticated],
|
|
159
|
-
create: [Permissions.IsAuthenticated],
|
|
160
|
-
read: [Permissions.IsOwner],
|
|
161
|
-
update: [Permissions.IsOwner],
|
|
162
|
-
delete: [], // Disabled
|
|
163
|
-
},
|
|
164
|
-
sort: "-created",
|
|
165
|
-
queryFields: ["_id", "type", "name"],
|
|
166
|
-
});
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
#### Custom Routes
|
|
170
|
-
|
|
171
|
-
For non-CRUD endpoints, use the OpenAPI builder:
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
import {asyncHandler, authenticateMiddleware, createOpenApiBuilder} from "@terreno/api";
|
|
175
|
-
|
|
176
|
-
router.get("/yourRoute/:id", [
|
|
177
|
-
authenticateMiddleware(),
|
|
178
|
-
createOpenApiBuilder(options)
|
|
179
|
-
.withTags(["yourTag"])
|
|
180
|
-
.withSummary("Brief summary")
|
|
181
|
-
.withPathParameter("id", {type: "string"})
|
|
182
|
-
.withResponse(200, {data: {type: "object"}})
|
|
183
|
-
.build(),
|
|
184
|
-
], asyncHandler(async (req, res) => {
|
|
185
|
-
return res.json({data: result});
|
|
186
|
-
}));
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
#### API Conventions
|
|
190
|
-
|
|
191
|
-
- Throw `APIError` with appropriate status codes: `throw new APIError({status: 400, title: "Message"})`
|
|
192
|
-
- Do not use `Model.findOne` - use `Model.findExactlyOne` or `Model.findOneOrThrow`
|
|
193
|
-
- Define statics/methods by direct assignment: `schema.methods = {bar() {}}`
|
|
194
|
-
- All model types live in `src/modelInterfaces.ts`
|
|
195
|
-
- In routes: `req.user` is `UserDocument | undefined`
|
|
196
|
-
- In @terreno/api callbacks: cast with `const user = u as unknown as UserDocument`
|
|
197
|
-
|
|
198
|
-
### @terreno/ui
|
|
199
|
-
|
|
200
|
-
React Native component library with 88+ components:
|
|
201
|
-
|
|
202
|
-
- **Layout**: Box, Page, SplitPage, Card
|
|
203
|
-
- **Forms**: TextField, SelectField, DateTimeField, CheckBox
|
|
204
|
-
- **Display**: Text, Heading, Badge, DataTable
|
|
205
|
-
- **Actions**: Button, IconButton, Link
|
|
206
|
-
- **Feedback**: Spinner, Modal, Toast
|
|
207
|
-
- **Theming**: TerrenoProvider, useTheme
|
|
208
|
-
|
|
209
|
-
Key imports:
|
|
210
|
-
```typescript
|
|
211
|
-
import {
|
|
212
|
-
Box,
|
|
213
|
-
Button,
|
|
214
|
-
Card,
|
|
215
|
-
Page,
|
|
216
|
-
Text,
|
|
217
|
-
TextField,
|
|
218
|
-
TerrenoProvider,
|
|
219
|
-
} from "@terreno/ui";
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
#### UI Component Examples
|
|
223
|
-
|
|
224
|
-
Layout with Box:
|
|
225
|
-
```typescript
|
|
226
|
-
<Box direction="row" padding={4} gap={2} alignItems="center">
|
|
227
|
-
<Text>Content</Text>
|
|
228
|
-
<Button text="Action" />
|
|
229
|
-
</Box>
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
Buttons:
|
|
233
|
-
```typescript
|
|
234
|
-
<Button
|
|
235
|
-
text="Submit"
|
|
236
|
-
variant="primary" // 'primary' | 'secondary' | 'outline' | 'ghost'
|
|
237
|
-
onClick={handleSubmit}
|
|
238
|
-
loading={isLoading}
|
|
239
|
-
iconName="check"
|
|
240
|
-
/>
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
Forms:
|
|
244
|
-
```typescript
|
|
245
|
-
<TextField
|
|
246
|
-
label="Email"
|
|
247
|
-
value={email}
|
|
248
|
-
onChangeText={setEmail}
|
|
249
|
-
error={emailError}
|
|
250
|
-
helperText="Enter a valid email"
|
|
251
|
-
/>
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Modals:
|
|
255
|
-
```typescript
|
|
256
|
-
<Modal
|
|
257
|
-
title="Confirm Action"
|
|
258
|
-
visible={isVisible}
|
|
259
|
-
primaryButtonText="Confirm"
|
|
260
|
-
secondaryButtonText="Cancel"
|
|
261
|
-
onDismiss={() => setIsVisible(false)}
|
|
262
|
-
onPrimaryAction={handleConfirm}
|
|
263
|
-
>
|
|
264
|
-
<Text>Are you sure?</Text>
|
|
265
|
-
</Modal>
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
#### UI Common Pitfalls
|
|
269
|
-
|
|
270
|
-
- Don't use inline styles when theme values are available
|
|
271
|
-
- Don't use raw `View`/`Text` when `Box`/@terreno/ui `Text` are available
|
|
272
|
-
- Don't forget loading and error states
|
|
273
|
-
- Don't use `style` prop when equivalent props exist (`padding`, `margin`)
|
|
274
|
-
- Never modify `openApiSdk.ts` manually
|
|
275
|
-
|
|
276
|
-
### @terreno/rtk
|
|
277
|
-
|
|
278
|
-
Redux Toolkit Query integration:
|
|
279
|
-
|
|
280
|
-
- **generateAuthSlice**: Creates auth reducer and middleware with JWT handling
|
|
281
|
-
- **emptyApi**: Base RTK Query API for code generation
|
|
282
|
-
- **Platform utilities**: Secure token storage (expo-secure-store for native, AsyncStorage for web)
|
|
283
|
-
|
|
284
|
-
Key imports:
|
|
285
|
-
```typescript
|
|
286
|
-
import {generateAuthSlice} from "@terreno/rtk";
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
Always use generated SDK hooks - never use `axios` or `request` directly:
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
// Correct
|
|
293
|
-
import {useGetYourRouteQuery} from "@/store/openApiSdk";
|
|
294
|
-
const {data, isLoading, error} = useGetYourRouteQuery({id: "value"});
|
|
295
|
-
|
|
296
|
-
// Wrong - don't use axios directly
|
|
297
|
-
// const result = await axios.get("/api/yourRoute/value");
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
## React Best Practices (Frontend Packages)
|
|
301
|
-
|
|
302
|
-
- Use functional components with `React.FC` type
|
|
303
|
-
- Import hooks directly: `import {useEffect, useMemo} from 'react'`
|
|
304
|
-
- Always provide return types for functions
|
|
305
|
-
- Add explanatory comment above each `useEffect`
|
|
306
|
-
- Wrap callbacks in `useCallback`
|
|
307
|
-
- Prefer const arrow functions
|
|
308
|
-
- Use inline styles over `StyleSheet.create`
|
|
309
|
-
- Use Luxon for date operations
|
|
310
|
-
- Place static content and interfaces at beginning of file
|
|
311
|
-
- Minimize `use client`, `useEffect`, and `setState`
|
|
312
|
-
- Always support React-Native Web
|
|
313
|
-
|
|
314
|
-
## CI/CD Workflows
|
|
315
|
-
|
|
316
|
-
### Required Secret Validation
|
|
317
|
-
|
|
318
|
-
GitHub Actions workflows that use secrets or environment variables must validate all required variables are set before using them. Add a validation step early in the job that fails fast with a clear error message listing any missing variables.
|
|
319
|
-
|
|
320
|
-
```yaml
|
|
321
|
-
- name: Validate required secrets
|
|
322
|
-
run: |
|
|
323
|
-
missing=()
|
|
324
|
-
if [ -z "$VAR_NAME" ]; then missing+=("VAR_NAME"); fi
|
|
325
|
-
if [ ${#missing[@]} -ne 0 ]; then
|
|
326
|
-
echo "::error::Missing required secrets: ${missing[*]}"
|
|
327
|
-
exit 1
|
|
328
|
-
fi
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Dependency Management
|
|
332
|
-
|
|
333
|
-
Uses [Bun Catalogs](https://bun.sh/docs/install/catalogs) - shared versions defined in root `package.json` under `catalog`. Reference with `catalog:` in workspace packages.
|