@terreno/api 0.0.17 → 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.
- package/.claude/CLAUDE.local.md +204 -0
- package/.cursor/rules/00-root.mdc +338 -0
- package/.github/copilot-instructions.md +333 -0
- package/AGENTS.md +333 -0
- package/README.md +76 -7
- package/biome.jsonc +1 -1
- package/dist/api.d.ts +68 -1
- package/dist/api.js +140 -5
- package/dist/api.query.test.js +1 -1
- package/dist/api.test.js +222 -484
- package/dist/auth.js +3 -1
- package/dist/errors.js +15 -12
- package/dist/example.js +7 -7
- package/dist/expressServer.d.ts +8 -2
- package/dist/expressServer.js +8 -1
- package/dist/githubAuth.d.ts +64 -0
- package/dist/githubAuth.js +293 -0
- package/dist/githubAuth.test.d.ts +1 -0
- package/dist/githubAuth.test.js +351 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/logger.js +1 -1
- package/dist/middleware.js +1 -1
- package/dist/notifiers/googleChatNotifier.js +1 -1
- package/dist/notifiers/googleChatNotifier.test.js +1 -1
- package/dist/notifiers/slackNotifier.js +1 -1
- package/dist/notifiers/slackNotifier.test.js +1 -1
- package/dist/notifiers/zoomNotifier.js +1 -1
- package/dist/notifiers/zoomNotifier.test.js +1 -1
- package/dist/openApi.test.js +8 -5
- package/dist/openApiBuilder.d.ts +69 -1
- package/dist/openApiBuilder.js +109 -5
- package/dist/openApiValidator.d.ts +296 -0
- package/dist/openApiValidator.js +698 -0
- package/dist/openApiValidator.test.d.ts +1 -0
- package/dist/openApiValidator.test.js +346 -0
- package/dist/permissions.js +1 -1
- package/dist/plugins.test.js +3 -3
- package/dist/terrenoPlugin.d.ts +4 -0
- package/dist/terrenoPlugin.js +2 -0
- package/dist/tests/bunSetup.js +2 -2
- package/dist/tests.js +34 -24
- package/package.json +7 -2
- package/src/__snapshots__/openApi.test.ts.snap +399 -0
- package/src/__snapshots__/openApiBuilder.test.ts.snap +108 -0
- package/src/api.query.test.ts +1 -1
- package/src/api.test.ts +161 -374
- package/src/api.ts +210 -4
- package/src/auth.ts +3 -1
- package/src/errors.ts +15 -12
- package/src/example.ts +7 -7
- package/src/expressServer.ts +18 -2
- package/src/githubAuth.test.ts +223 -0
- package/src/githubAuth.ts +335 -0
- package/src/index.ts +3 -0
- package/src/logger.ts +1 -1
- package/src/middleware.ts +1 -1
- package/src/notifiers/googleChatNotifier.test.ts +1 -1
- package/src/notifiers/googleChatNotifier.ts +1 -1
- package/src/notifiers/slackNotifier.test.ts +1 -1
- package/src/notifiers/slackNotifier.ts +1 -1
- package/src/notifiers/zoomNotifier.test.ts +1 -1
- package/src/notifiers/zoomNotifier.ts +1 -1
- package/src/openApi.test.ts +8 -5
- package/src/openApiBuilder.ts +188 -15
- package/src/openApiValidator.test.ts +241 -0
- package/src/openApiValidator.ts +860 -0
- package/src/permissions.ts +1 -1
- package/src/plugins.test.ts +3 -3
- package/src/terrenoPlugin.ts +5 -0
- package/src/tests/bunSetup.ts +2 -2
- package/src/tests.ts +34 -24
- package/CLAUDE.md +0 -107
- package/dist/response.d.ts +0 -0
- package/dist/response.js +0 -1
- package/index.ts +0 -1
- package/src/response.ts +0 -0
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:
|
|
50
|
-
|
|
51
|
-
|
|
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,14 +120,62 @@ 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
|
|
|
105
|
-
|
|
106
|
-
// Include dotenv here at the start if you're including configuration from dot files.
|
|
107
|
-
import "dotenv/config";
|
|
175
|
+
> **Note:** Bun automatically loads `.env` files before your code runs, so there's no need for `dotenv`. Just place a `.env` file in your project root and `process.env` will have your variables available immediately. See [Bun .env docs](https://bun.sh/docs/runtime/env).
|
|
108
176
|
|
|
109
|
-
|
|
177
|
+
```
|
|
178
|
+
import * as Sentry from "@sentry/bun";
|
|
110
179
|
import {nodeProfilingIntegration} from "@sentry/profiling-node";
|
|
111
180
|
|
|
112
181
|
if (process.env.NODE_ENV === "production" && !process.env.SENTRY_DSN) {
|
package/biome.jsonc
CHANGED
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
|
-
|
|
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>;
|
package/dist/api.js
CHANGED
|
@@ -127,7 +127,7 @@ exports.modelRouter = modelRouter;
|
|
|
127
127
|
*
|
|
128
128
|
* @packageDocumentation
|
|
129
129
|
*/
|
|
130
|
-
var Sentry = __importStar(require("@sentry/
|
|
130
|
+
var Sentry = __importStar(require("@sentry/bun"));
|
|
131
131
|
var express_1 = __importDefault(require("express"));
|
|
132
132
|
var cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
133
133
|
var mongoose_1 = __importDefault(require("mongoose"));
|
|
@@ -135,6 +135,7 @@ var auth_1 = require("./auth");
|
|
|
135
135
|
var errors_1 = require("./errors");
|
|
136
136
|
var logger_1 = require("./logger");
|
|
137
137
|
var openApi_1 = require("./openApi");
|
|
138
|
+
var openApiValidator_1 = require("./openApiValidator");
|
|
138
139
|
var permissions_1 = require("./permissions");
|
|
139
140
|
var transformers_1 = require("./transformers");
|
|
140
141
|
var utils_1 = require("./utils");
|
|
@@ -227,6 +228,62 @@ function checkQueryParamAllowed(queryParam, queryParamValue, queryFields) {
|
|
|
227
228
|
//
|
|
228
229
|
// return result;
|
|
229
230
|
// }
|
|
231
|
+
// Helper to determine if validation should be enabled for a specific operation.
|
|
232
|
+
// When options.validation is not set, returns true — the middleware's own
|
|
233
|
+
// isConfigured check will decide whether to actually validate.
|
|
234
|
+
function shouldValidate(options, operation) {
|
|
235
|
+
var _a, _b, _c;
|
|
236
|
+
// Check route-specific validation option first
|
|
237
|
+
if (options.validation !== undefined) {
|
|
238
|
+
if (typeof options.validation === "boolean") {
|
|
239
|
+
return options.validation;
|
|
240
|
+
}
|
|
241
|
+
if (operation === "create") {
|
|
242
|
+
return (_a = options.validation.validateCreate) !== null && _a !== void 0 ? _a : true;
|
|
243
|
+
}
|
|
244
|
+
if (operation === "update") {
|
|
245
|
+
return (_b = options.validation.validateUpdate) !== null && _b !== void 0 ? _b : true;
|
|
246
|
+
}
|
|
247
|
+
return (_c = options.validation.validateQuery) !== null && _c !== void 0 ? _c : true;
|
|
248
|
+
}
|
|
249
|
+
// Default: let middleware's isConfigured check decide
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
// Get body validation middleware if validation is enabled
|
|
253
|
+
function getBodyValidationMiddleware(model, options, operation) {
|
|
254
|
+
var validationOptions = {};
|
|
255
|
+
if (!shouldValidate(options, operation)) {
|
|
256
|
+
validationOptions.enabled = false;
|
|
257
|
+
}
|
|
258
|
+
if (typeof options.validation === "object") {
|
|
259
|
+
if (options.validation.onError) {
|
|
260
|
+
validationOptions.onError = options.validation.onError;
|
|
261
|
+
}
|
|
262
|
+
if (options.validation.onAdditionalPropertiesRemoved) {
|
|
263
|
+
validationOptions.onAdditionalPropertiesRemoved =
|
|
264
|
+
options.validation.onAdditionalPropertiesRemoved;
|
|
265
|
+
}
|
|
266
|
+
var excludeFields = operation === "create"
|
|
267
|
+
? options.validation.excludeFromCreate
|
|
268
|
+
: options.validation.excludeFromUpdate;
|
|
269
|
+
if (excludeFields === null || excludeFields === void 0 ? void 0 : excludeFields.length) {
|
|
270
|
+
validationOptions.excludeFields = excludeFields;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return (0, openApiValidator_1.validateModelRequestBody)(model, validationOptions);
|
|
274
|
+
}
|
|
275
|
+
// Get query validation middleware if validation is enabled
|
|
276
|
+
function getQueryValidationMiddleware(model, options) {
|
|
277
|
+
var querySchema = (0, openApiValidator_1.buildQuerySchemaFromFields)(model, options.queryFields);
|
|
278
|
+
var validationOptions = {};
|
|
279
|
+
if (!shouldValidate(options, "query")) {
|
|
280
|
+
validationOptions.enabled = false;
|
|
281
|
+
}
|
|
282
|
+
if (typeof options.validation === "object" && options.validation.onError) {
|
|
283
|
+
validationOptions.onError = options.validation.onError;
|
|
284
|
+
}
|
|
285
|
+
return (0, openApiValidator_1.validateQueryParams)(querySchema, validationOptions);
|
|
286
|
+
}
|
|
230
287
|
/**
|
|
231
288
|
* Create a set of CRUD routes given a Mongoose model and configuration options.
|
|
232
289
|
*
|
|
@@ -242,10 +299,15 @@ function modelRouter(model, options) {
|
|
|
242
299
|
options.endpoints(router);
|
|
243
300
|
}
|
|
244
301
|
var responseHandler = (_a = options.responseHandler) !== null && _a !== void 0 ? _a : transformers_1.defaultResponseHandler;
|
|
302
|
+
// Always install validation middleware — they are no-ops until configureOpenApiValidator() is called
|
|
303
|
+
var createValidation = getBodyValidationMiddleware(model, options, "create");
|
|
304
|
+
var updateValidation = getBodyValidationMiddleware(model, options, "update");
|
|
305
|
+
var queryValidation = getQueryValidationMiddleware(model, options);
|
|
245
306
|
router.post("/", [
|
|
246
307
|
(0, auth_1.authenticateMiddleware)(options.allowAnonymous),
|
|
247
308
|
(0, openApi_1.createOpenApiMiddleware)(model, options),
|
|
248
309
|
(0, permissions_1.permissionMiddleware)(model, options),
|
|
310
|
+
createValidation,
|
|
249
311
|
], (0, exports.asyncHandler)(function (req, res) { return __awaiter(_this, void 0, void 0, function () {
|
|
250
312
|
var body, error_1, data, error_2, populateQuery, error_3, error_4, serialized, error_5;
|
|
251
313
|
return __generator(this, function (_a) {
|
|
@@ -378,6 +440,7 @@ function modelRouter(model, options) {
|
|
|
378
440
|
(0, auth_1.authenticateMiddleware)(options.allowAnonymous),
|
|
379
441
|
(0, permissions_1.permissionMiddleware)(model, options),
|
|
380
442
|
(0, openApi_1.listOpenApiMiddleware)(model, options),
|
|
443
|
+
queryValidation,
|
|
381
444
|
], (0, exports.asyncHandler)(function (req, res) { return __awaiter(_this, void 0, void 0, function () {
|
|
382
445
|
var query, _a, _b, queryParam, _c, _d, queryParam, queryFilter, error_6, limit, builtQuery, total, populatedQuery, data, error_7, serialized, error_8, more, msg;
|
|
383
446
|
var e_4, _e, e_5, _f;
|
|
@@ -594,6 +657,7 @@ function modelRouter(model, options) {
|
|
|
594
657
|
(0, auth_1.authenticateMiddleware)(options.allowAnonymous),
|
|
595
658
|
(0, openApi_1.patchOpenApiMiddleware)(model, options),
|
|
596
659
|
(0, permissions_1.permissionMiddleware)(model, options),
|
|
660
|
+
updateValidation,
|
|
597
661
|
], (0, exports.asyncHandler)(function (req, res) { return __awaiter(_this, void 0, void 0, function () {
|
|
598
662
|
var doc, body, error_10, prevDoc, error_11, populateQuery, error_12, serialized, error_13;
|
|
599
663
|
var _a;
|
|
@@ -991,10 +1055,81 @@ function modelRouter(model, options) {
|
|
|
991
1055
|
router.use(errors_1.apiErrorMiddleware);
|
|
992
1056
|
return router;
|
|
993
1057
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1058
|
+
/**
|
|
1059
|
+
* Wraps async route handlers to properly catch and forward errors.
|
|
1060
|
+
*
|
|
1061
|
+
* Since Express doesn't handle async routes well, wrap them with this function.
|
|
1062
|
+
* Optionally supports integrated request validation.
|
|
1063
|
+
*
|
|
1064
|
+
* @param fn - The async route handler function
|
|
1065
|
+
* @param options - Optional configuration for validation
|
|
1066
|
+
* @returns Express middleware function
|
|
1067
|
+
*
|
|
1068
|
+
* @example
|
|
1069
|
+
* ```typescript
|
|
1070
|
+
* // Basic usage without validation
|
|
1071
|
+
* router.post("/users", asyncHandler(async (req, res) => {
|
|
1072
|
+
* // handler code
|
|
1073
|
+
* }));
|
|
1074
|
+
*
|
|
1075
|
+
* // With integrated validation
|
|
1076
|
+
* router.post("/users", asyncHandler(async (req, res) => {
|
|
1077
|
+
* // handler code - body is already validated
|
|
1078
|
+
* }, {
|
|
1079
|
+
* bodySchema: {
|
|
1080
|
+
* name: {type: "string", required: true},
|
|
1081
|
+
* email: {type: "string", format: "email", required: true},
|
|
1082
|
+
* },
|
|
1083
|
+
* validate: true,
|
|
1084
|
+
* }));
|
|
1085
|
+
* ```
|
|
1086
|
+
*/
|
|
1087
|
+
var asyncHandler = function (fn, options) {
|
|
1088
|
+
var _a, _b;
|
|
1089
|
+
// If no validation options, return simple handler
|
|
1090
|
+
if (!(options === null || options === void 0 ? void 0 : options.bodySchema) && !(options === null || options === void 0 ? void 0 : options.querySchema)) {
|
|
1091
|
+
return function (req, res, next) {
|
|
1092
|
+
return Promise.resolve(fn(req, res, next)).catch(next);
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
// Import validation functions dynamically to avoid circular deps at module load
|
|
1096
|
+
var _c = require("./openApiValidator"), validateRequestBody = _c.validateRequestBody, validateQueryParams = _c.validateQueryParams, getOpenApiValidatorConfig = _c.getOpenApiValidatorConfig;
|
|
1097
|
+
// Build validation middleware
|
|
1098
|
+
var validators = [];
|
|
1099
|
+
// Determine if validation should be enabled
|
|
1100
|
+
var shouldValidate = (_b = (_a = options.validate) !== null && _a !== void 0 ? _a : getOpenApiValidatorConfig().validateRequests) !== null && _b !== void 0 ? _b : false;
|
|
1101
|
+
if (shouldValidate) {
|
|
1102
|
+
if (options.bodySchema) {
|
|
1103
|
+
validators.push(validateRequestBody(options.bodySchema, { enabled: true }));
|
|
1104
|
+
}
|
|
1105
|
+
if (options.querySchema) {
|
|
1106
|
+
validators.push(validateQueryParams(options.querySchema, { enabled: true }));
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
return function (req, res, next) {
|
|
1110
|
+
// Run validators sequentially, then the handler
|
|
1111
|
+
var runValidators = function (index) {
|
|
1112
|
+
if (index >= validators.length) {
|
|
1113
|
+
// All validators passed, run the actual handler
|
|
1114
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
try {
|
|
1118
|
+
validators[index](req, res, function (err) {
|
|
1119
|
+
if (err) {
|
|
1120
|
+
next(err);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
runValidators(index + 1);
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
catch (err) {
|
|
1127
|
+
next(err);
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
runValidators(0);
|
|
1131
|
+
};
|
|
1132
|
+
};
|
|
998
1133
|
exports.asyncHandler = asyncHandler;
|
|
999
1134
|
// For backwards compatibility with the old names.
|
|
1000
1135
|
exports.gooseRestRouter = modelRouter;
|
package/dist/api.query.test.js
CHANGED
|
@@ -89,7 +89,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
89
89
|
};
|
|
90
90
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
91
91
|
var bun_test_1 = require("bun:test");
|
|
92
|
-
var Sentry = __importStar(require("@sentry/
|
|
92
|
+
var Sentry = __importStar(require("@sentry/bun"));
|
|
93
93
|
var qs_1 = __importDefault(require("qs"));
|
|
94
94
|
var supertest_1 = __importDefault(require("supertest"));
|
|
95
95
|
var api_1 = require("./api");
|