@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.
- 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 +23 -3
- package/README.md +73 -3
- package/dist/api.d.ts +68 -1
- package/dist/api.js +139 -4
- package/dist/api.test.js +906 -2
- package/dist/auth.js +3 -1
- package/dist/errors.js +14 -11
- package/dist/example.js +7 -7
- package/dist/githubAuth.test.js +3 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- 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/plugins.test.js +3 -3
- package/dist/terrenoPlugin.d.ts +4 -0
- package/dist/terrenoPlugin.js +2 -0
- package/dist/tests.js +34 -24
- package/package.json +4 -1
- package/src/__snapshots__/openApi.test.ts.snap +399 -0
- package/src/__snapshots__/openApiBuilder.test.ts.snap +108 -0
- package/src/api.test.ts +743 -2
- package/src/api.ts +209 -3
- package/src/auth.ts +3 -1
- package/src/errors.ts +14 -11
- package/src/example.ts +7 -7
- package/src/githubAuth.test.ts +3 -3
- package/src/index.ts +2 -0
- 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/plugins.test.ts +3 -3
- package/src/terrenoPlugin.ts +5 -0
- package/src/tests.ts +34 -24
- package/.cursorrules +0 -107
- package/.windsurfrules +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/dist/api.js
CHANGED
|
@@ -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;
|