@terreno/api 0.0.18 → 0.1.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.
Files changed (48) hide show
  1. package/.claude/CLAUDE.local.md +204 -0
  2. package/.cursor/rules/00-root.mdc +338 -0
  3. package/.github/copilot-instructions.md +333 -0
  4. package/AGENTS.md +23 -3
  5. package/README.md +73 -3
  6. package/dist/api.d.ts +68 -1
  7. package/dist/api.js +139 -4
  8. package/dist/api.test.js +906 -2
  9. package/dist/auth.js +3 -1
  10. package/dist/errors.js +14 -11
  11. package/dist/example.js +7 -7
  12. package/dist/githubAuth.test.js +3 -3
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +2 -0
  15. package/dist/openApi.test.js +8 -5
  16. package/dist/openApiBuilder.d.ts +69 -1
  17. package/dist/openApiBuilder.js +109 -5
  18. package/dist/openApiValidator.d.ts +296 -0
  19. package/dist/openApiValidator.js +698 -0
  20. package/dist/openApiValidator.test.d.ts +1 -0
  21. package/dist/openApiValidator.test.js +346 -0
  22. package/dist/plugins.test.js +3 -3
  23. package/dist/terrenoPlugin.d.ts +4 -0
  24. package/dist/terrenoPlugin.js +2 -0
  25. package/dist/tests.js +34 -24
  26. package/package.json +4 -1
  27. package/src/__snapshots__/openApi.test.ts.snap +399 -0
  28. package/src/__snapshots__/openApiBuilder.test.ts.snap +108 -0
  29. package/src/api.test.ts +743 -2
  30. package/src/api.ts +209 -3
  31. package/src/auth.ts +3 -1
  32. package/src/errors.ts +14 -11
  33. package/src/example.ts +7 -7
  34. package/src/githubAuth.test.ts +3 -3
  35. package/src/index.ts +2 -0
  36. package/src/openApi.test.ts +8 -5
  37. package/src/openApiBuilder.ts +188 -15
  38. package/src/openApiValidator.test.ts +241 -0
  39. package/src/openApiValidator.ts +860 -0
  40. package/src/plugins.test.ts +3 -3
  41. package/src/terrenoPlugin.ts +5 -0
  42. package/src/tests.ts +34 -24
  43. package/.cursorrules +0 -107
  44. package/.windsurfrules +0 -107
  45. package/dist/response.d.ts +0 -0
  46. package/dist/response.js +0 -1
  47. package/index.ts +0 -1
  48. package/src/response.ts +0 -0
@@ -0,0 +1,333 @@
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.
package/AGENTS.md CHANGED
@@ -7,13 +7,14 @@ A monorepo containing shared packages for building full-stack applications with
7
7
  - **api/** - REST API framework built on Express/Mongoose (`@terreno/api`)
8
8
  - **ui/** - React Native UI component library (`@terreno/ui`)
9
9
  - **rtk/** - Redux Toolkit Query utilities for API backends (`@terreno/rtk`)
10
+ - **mcp-server/** - MCP server for AI assistant integration (`@terreno/mcp-server`)
10
11
  - **demo/** - Demo app for showcasing and testing UI components
11
12
  - **example-frontend/** - Example Expo app demonstrating full stack usage
12
13
  - **example-backend/** - Example Express backend using @terreno/api
13
14
 
14
15
  ## Development
15
16
 
16
- Uses [Bun](https://bun.sh/) as the package manager. Use `yarn` commands, not `npm`.
17
+ Uses [Bun](https://bun.sh/) as the package manager.
17
18
 
18
19
  ```bash
19
20
  bun install # Install dependencies
@@ -31,6 +32,8 @@ bun run ui:test # Test UI package
31
32
  bun run demo:start # Start demo app
32
33
  bun run frontend:web # Start frontend example
33
34
  bun run backend:dev # Start backend example
35
+ bun run mcp:build # Build MCP server
36
+ bun run mcp:start # Start MCP server
34
37
  ```
35
38
 
36
39
  ## How the Packages Work Together
@@ -68,10 +71,10 @@ The three core packages form a complete full-stack framework:
68
71
 
69
72
  ## Example Apps (Keep These Updated!)
70
73
 
71
- The `frontend-example/` and `backend-example/` directories serve as both documentation and integration tests. When adding features to api, ui, or rtk:
74
+ The `example-frontend/` and `example-backend/` directories serve as both documentation and integration tests. When adding features to api, ui, or rtk:
72
75
 
73
76
  1. **Add examples** demonstrating new features
74
- 2. **Update SDK** after backend changes: `cd frontend-example && bun run sdk`
77
+ 2. **Update SDK** after backend changes: `cd example-frontend && bun run sdk`
75
78
  3. **Verify integration** by running both examples together
76
79
 
77
80
  ### Running the Full Stack
@@ -308,6 +311,23 @@ const {data, isLoading, error} = useGetYourRouteQuery({id: "value"});
308
311
  - Minimize `use client`, `useEffect`, and `setState`
309
312
  - Always support React-Native Web
310
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
+
311
331
  ## Dependency Management
312
332
 
313
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.
package/README.md CHANGED
@@ -9,6 +9,14 @@ These APIs integrate with @terreno/rtk to create consistent types on the fronten
9
9
  and backend, and automatically generated React hooks to fetch, query, and modify
10
10
  model instances.
11
11
 
12
+ ## Features
13
+
14
+ - **modelRouter** — Automatic CRUD endpoints for Mongoose models
15
+ - **Authentication** — JWT with email/password and GitHub OAuth support
16
+ - **Permissions** — Fine-grained access control (IsAuthenticated, IsOwner, IsAdmin, etc.)
17
+ - **OpenAPI** — Automatic spec generation from models and routes
18
+ - **Logging** — Winston-based logging with Google Cloud and Sentry support
19
+
12
20
  ## Getting started
13
21
 
14
22
  To install:
@@ -46,12 +54,25 @@ const eventSchema = new Schema({
46
54
  Assuming we have a model:
47
55
 
48
56
  const foodSchema = new Schema<Food>({
49
- name: String,
50
- hidden: {type: Boolean, default: false},
51
- ownerId: {type: "ObjectId", ref: "User"},
57
+ name: {
58
+ description: "Name of the food item",
59
+ type: String,
60
+ },
61
+ hidden: {
62
+ description: "Whether the food is hidden from the list",
63
+ type: Boolean,
64
+ default: false,
65
+ },
66
+ ownerId: {
67
+ description: "The user who added this food",
68
+ type: "ObjectId",
69
+ ref: "User",
70
+ },
52
71
  });
53
72
  export const FoodModel = model("Food", foodSchema);
54
73
 
74
+ **Important:** Every field must include a `description` property. This requirement ensures that the auto-generated OpenAPI specification and SDK have meaningful documentation for all fields.
75
+
55
76
  We can expose this model as an API like this:
56
77
 
57
78
  import express from "express";
@@ -99,6 +120,55 @@ Now we can perform operations on the Food model in a standard REST way. We've al
99
120
 
100
121
  You can create your own permissions functions. Check permissions.ts for some examples of how to write them.
101
122
 
123
+ ## Authentication
124
+
125
+ @terreno/api includes built-in authentication with JWT and OAuth support.
126
+
127
+ ### Email/Password Authentication
128
+
129
+ Built-in email/password authentication using `passport-local-mongoose`:
130
+
131
+ ```typescript
132
+ import {setupServer} from "@terreno/api";
133
+ import {User} from "./models/user";
134
+
135
+ setupServer({
136
+ userModel: User,
137
+ addRoutes: (router) => {
138
+ // Your routes here
139
+ },
140
+ });
141
+ ```
142
+
143
+ This automatically adds:
144
+ - `POST /auth/signup` — User registration
145
+ - `POST /auth/login` — Authentication
146
+ - `POST /auth/refresh_token` — Token refresh
147
+ - `GET /auth/me` — Get current user
148
+ - `PATCH /auth/me` — Update current user
149
+
150
+ ### GitHub OAuth
151
+
152
+ Add GitHub OAuth login to your API:
153
+
154
+ ```typescript
155
+ import {githubUserPlugin, setupServer} from "@terreno/api";
156
+
157
+ // Add GitHub fields to user schema
158
+ userSchema.plugin(githubUserPlugin);
159
+
160
+ setupServer({
161
+ userModel: User,
162
+ githubAuth: {
163
+ clientId: process.env.GITHUB_CLIENT_ID!,
164
+ clientSecret: process.env.GITHUB_CLIENT_SECRET!,
165
+ callbackURL: process.env.GITHUB_CALLBACK_URL!,
166
+ },
167
+ });
168
+ ```
169
+
170
+ **Learn more:** See the [GitHub OAuth how-to guide](../docs/how-to/add-github-oauth.md) for complete setup instructions.
171
+
102
172
  ## Sentry
103
173
  To enable Sentry, create a "src/sentryInstrumment.ts" file in your project.
104
174
 
package/dist/api.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import express, { type NextFunction, type Request, type Response } from "express";
2
2
  import mongoose, { type Document, type Model } from "mongoose";
3
3
  import { type User } from "./auth";
4
+ import { type ModelRouterValidationOptions } from "./openApiValidator";
4
5
  import { type RESTPermissions } from "./permissions";
5
6
  import type { PopulatePath } from "./populate";
6
7
  import { type TerrenoTransformer } from "./transformers";
@@ -203,6 +204,19 @@ export interface ModelRouterOptions<T> {
203
204
  * that you want to be documented and typed in the SDK.
204
205
  */
205
206
  openApiExtraModelProperties?: any;
207
+ /**
208
+ * Enable runtime validation of request bodies against the OpenAPI schema.
209
+ * When enabled, requests that don't match the documented schema will return 400 errors.
210
+ *
211
+ * Can be set to:
212
+ * - `true`: Enable validation for create and update operations
213
+ * - `false`: Disable validation (default)
214
+ * - Object with `validateCreate` and `validateUpdate` booleans for fine-grained control
215
+ *
216
+ * Note: Global validation can be enabled via `configureOpenApiValidator()`.
217
+ * This option overrides the global setting for this specific router.
218
+ */
219
+ validation?: boolean | ModelRouterValidationOptions;
206
220
  }
207
221
  /**
208
222
  * Create a set of CRUD routes given a Mongoose model and configuration options.
@@ -211,6 +225,59 @@ export interface ModelRouterOptions<T> {
211
225
  * @param options Options for configuring the REST API, such as permissions, transformers, and hooks.
212
226
  */
213
227
  export declare function modelRouter<T>(model: Model<T>, options: ModelRouterOptions<T>): express.Router;
214
- export declare const asyncHandler: (fn: any) => (req: Request, res: Response, next: NextFunction) => Promise<any>;
228
+ /**
229
+ * Options for the asyncHandler function.
230
+ */
231
+ export interface AsyncHandlerOptions {
232
+ /**
233
+ * Schema for validating request body.
234
+ * When provided and validation is enabled, the request body will be validated
235
+ * against this schema before the handler runs.
236
+ */
237
+ bodySchema?: Record<string, import("./openApiBuilder").OpenApiSchemaProperty>;
238
+ /**
239
+ * Schema for validating query parameters.
240
+ * When provided and validation is enabled, query params will be validated
241
+ * against this schema before the handler runs.
242
+ */
243
+ querySchema?: Record<string, import("./openApiBuilder").OpenApiSchemaProperty>;
244
+ /**
245
+ * Override global validation setting for this handler.
246
+ * - `true`: Enable validation regardless of global setting
247
+ * - `false`: Disable validation regardless of global setting
248
+ * - `undefined`: Use global setting
249
+ */
250
+ validate?: boolean;
251
+ }
252
+ /**
253
+ * Wraps async route handlers to properly catch and forward errors.
254
+ *
255
+ * Since Express doesn't handle async routes well, wrap them with this function.
256
+ * Optionally supports integrated request validation.
257
+ *
258
+ * @param fn - The async route handler function
259
+ * @param options - Optional configuration for validation
260
+ * @returns Express middleware function
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * // Basic usage without validation
265
+ * router.post("/users", asyncHandler(async (req, res) => {
266
+ * // handler code
267
+ * }));
268
+ *
269
+ * // With integrated validation
270
+ * router.post("/users", asyncHandler(async (req, res) => {
271
+ * // handler code - body is already validated
272
+ * }, {
273
+ * bodySchema: {
274
+ * name: {type: "string", required: true},
275
+ * email: {type: "string", format: "email", required: true},
276
+ * },
277
+ * validate: true,
278
+ * }));
279
+ * ```
280
+ */
281
+ export declare const asyncHandler: (fn: any, options?: AsyncHandlerOptions) => (req: Request, res: Response, next: NextFunction) => void;
215
282
  export declare const gooseRestRouter: typeof modelRouter;
216
283
  export type GooseRESTOptions<T> = ModelRouterOptions<T>;