@terreno/api 0.0.11 → 0.0.12

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/CLAUDE.md ADDED
@@ -0,0 +1,107 @@
1
+ # @terreno/api
2
+
3
+ REST API framework built on Express/Mongoose, styled after Django REST Framework.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ bun run compile # Compile TypeScript
9
+ bun run dev # Watch mode
10
+ bun run test # Run tests
11
+ bun run lint # Lint code
12
+ bun run lint:fix # Fix lint issues
13
+ ```
14
+
15
+ ## Architecture
16
+
17
+ ### modelRouter
18
+
19
+ Automatically creates RESTful CRUD APIs for Mongoose models with built-in permissions, population, filtering, and lifecycle hooks.
20
+
21
+ ```typescript
22
+ import {modelRouter, modelRouterOptions, Permissions} from "@terreno/api";
23
+
24
+ const router = modelRouter(YourModel, {
25
+ permissions: {
26
+ list: [Permissions.IsAuthenticated],
27
+ create: [Permissions.IsAuthenticated],
28
+ read: [Permissions.IsOwner],
29
+ update: [Permissions.IsOwner],
30
+ delete: [], // Disabled
31
+ },
32
+ sort: "-created",
33
+ queryFields: ["_id", "type", "name"],
34
+ });
35
+ ```
36
+
37
+ ### Custom Routes
38
+
39
+ For non-CRUD endpoints, use the OpenAPI builder:
40
+
41
+ ```typescript
42
+ import {asyncHandler, authenticateMiddleware, createOpenApiBuilder} from "@terreno/api";
43
+
44
+ router.get("/yourRoute/:id", [
45
+ authenticateMiddleware(),
46
+ createOpenApiBuilder(options)
47
+ .withTags(["yourTag"])
48
+ .withSummary("Brief summary")
49
+ .withPathParameter("id", {type: "string"})
50
+ .withResponse(200, {data: {type: "object"}})
51
+ .build(),
52
+ ], asyncHandler(async (req, res) => {
53
+ return res.json({data: result});
54
+ }));
55
+ ```
56
+
57
+ ## Conventions
58
+
59
+ ### Error Handling
60
+ - Throw `APIError` with appropriate status codes: `throw new APIError({status: 400, title: "Message"})`
61
+ - Services should throw user-friendly errors
62
+
63
+ ### Mongoose
64
+ - Do not use `Model.findOne` - use `Model.findExactlyOne` or `Model.findOneOrThrow`
65
+ - Define statics/methods by direct assignment: `schema.methods = {bar() {}}`
66
+ - All model types live in `src/modelInterfaces.ts`
67
+
68
+ ### User Type Casting
69
+ - In API routes: `req.user` is `UserDocument | undefined`
70
+ - In @terreno/api callbacks: cast with `const user = u as unknown as UserDocument`
71
+ - Never use `as any as UserDocument`
72
+
73
+ ### Logging
74
+ - Use `logger.info/warn/error/debug` for permanent logs (not `console.log`)
75
+
76
+ ### Testing
77
+ - Use bun test with expect for testing
78
+ - Use existing manual mocks from `src/__mocks__/`
79
+ - Never mock @terreno/api or models
80
+
81
+ ## Model Type Generation
82
+
83
+ When creating/modifying Mongoose models, update `src/modelInterfaces.ts`:
84
+
85
+ ```typescript
86
+ export type YourModelMethods = {
87
+ customMethod: (this: YourModelDocument, param: string) => Promise<void>;
88
+ };
89
+
90
+ export type YourModelStatics = DefaultStatics<YourModelDocument> & {
91
+ customStatic: (this: YourModelModel, param: string) => Promise<YourModelDocument>;
92
+ };
93
+
94
+ export type YourModelModel = DefaultModel<YourModelDocument> & YourModelStatics;
95
+ export type YourModelSchema = mongoose.Schema<YourModelDocument, YourModelModel, YourModelMethods>;
96
+ export type YourModelDocument = DefaultDoc & YourModelMethods & {
97
+ fieldName: string;
98
+ };
99
+ ```
100
+
101
+ ## SDK Generation
102
+
103
+ After modifying routes, regenerate the SDK:
104
+
105
+ ```bash
106
+ bun run sdk
107
+ ```
package/biome.jsonc CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "root": false,
2
+ "root": true,
3
3
  "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
4
4
  "extends": ["../biome.jsonc"],
5
5
  "files": {
package/bunfig.toml CHANGED
@@ -1,6 +1,7 @@
1
1
  [test]
2
2
  preload = ["./src/tests/bunSetup.ts"]
3
3
  root = "./src"
4
- coverageExclude = ["dist/**"]
5
- # Note: No coverageThreshold set - tests will not fail on low coverage
4
+ coverage = true
5
+ coverageExclude = ["dist/**", "**/*.test.ts", "**/tests/**"]
6
+ coverageThreshold = { line = 80, function = 80 }
6
7
 
@@ -0,0 +1 @@
1
+ export {};