@autofleet/sadot 0.13.5 → 0.13.6
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/hooks/hooks.js
CHANGED
|
@@ -31,6 +31,7 @@ const ajv_1 = __importDefault(require("ajv"));
|
|
|
31
31
|
const joi_1 = __importDefault(require("joi"));
|
|
32
32
|
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
33
33
|
const errors_1 = require("@autofleet/errors");
|
|
34
|
+
const ajv_errors_1 = __importDefault(require("ajv-errors"));
|
|
34
35
|
const logger_1 = __importDefault(require("../utils/logger"));
|
|
35
36
|
const ValidatorRepo = __importStar(require("../repository/validator"));
|
|
36
37
|
const DefinitionRepo = __importStar(require("../repository/definition"));
|
|
@@ -48,6 +49,7 @@ const ajv = new ajv_1.default({
|
|
|
48
49
|
$data: true, // Enable $data references
|
|
49
50
|
});
|
|
50
51
|
(0, ajv_formats_1.default)(ajv);
|
|
52
|
+
(0, ajv_errors_1.default)(ajv);
|
|
51
53
|
/**
|
|
52
54
|
* Helper function to manually copy object properties
|
|
53
55
|
* This is more efficient for large objects and avoids excessive object creation
|
|
@@ -88,10 +90,22 @@ const getCompleteCustomFields = async (instance, options) => {
|
|
|
88
90
|
}
|
|
89
91
|
return instance.customFields || {};
|
|
90
92
|
};
|
|
93
|
+
const formatAjvErrors = (errors) => errors.reduce((acc, err) => {
|
|
94
|
+
const basePath = (err.instancePath || '')
|
|
95
|
+
.split('/')
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.join('.')
|
|
98
|
+
.replace(/^after\./, '');
|
|
99
|
+
const missingProp = err.keyword === 'required' ? `.${err.params?.missingProperty}` : '';
|
|
100
|
+
const key = (basePath + missingProp).replace(/^\./, '') || 'root';
|
|
101
|
+
const message = err.message || 'Invalid value';
|
|
102
|
+
acc[key] = message;
|
|
103
|
+
return acc;
|
|
104
|
+
}, {});
|
|
91
105
|
/**
|
|
92
106
|
* Validates the model using custom validators
|
|
93
107
|
*/
|
|
94
|
-
const validateModel = async (instance, options, scopeAttributes, isCreate = false) => {
|
|
108
|
+
const validateModel = async (instance, options, scopeAttributes, modelOptions = {}, isCreate = false) => {
|
|
95
109
|
var _a;
|
|
96
110
|
const modelType = instance.constructor.name;
|
|
97
111
|
logger_1.default.debug('sadot - validating model', { isCreate, modelType });
|
|
@@ -121,6 +135,9 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
|
|
|
121
135
|
validatorsPromise = ValidatorRepo.findAllByModelType(modelType, entityId, {
|
|
122
136
|
transaction: options.transaction,
|
|
123
137
|
attributes: CUSTOM_VALIDATOR_ATTRIBUTES_TO_PULL,
|
|
138
|
+
...(modelOptions.include && {
|
|
139
|
+
include: modelOptions.include?.(entityId),
|
|
140
|
+
}),
|
|
124
141
|
raw: true,
|
|
125
142
|
});
|
|
126
143
|
if (options.transaction) {
|
|
@@ -173,7 +190,10 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
|
|
|
173
190
|
})));
|
|
174
191
|
if (!isValid) {
|
|
175
192
|
const errorDetails = validateSchema.errors?.map((err) => `${err.instancePath || ''} ${err.message || 'Invalid value'}`).join(', ');
|
|
176
|
-
|
|
193
|
+
const formattedErrors = formatAjvErrors(validateSchema.errors);
|
|
194
|
+
throw new errors_1.BadRequest([new Error(`Validation failed for ${modelType}: ${errorDetails}`)], undefined, {
|
|
195
|
+
customError: formattedErrors,
|
|
196
|
+
});
|
|
177
197
|
}
|
|
178
198
|
}
|
|
179
199
|
}
|
|
@@ -202,7 +222,10 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
|
|
|
202
222
|
const errorDetails = validateSchema
|
|
203
223
|
.errors
|
|
204
224
|
?.map((err) => `${err.instancePath || ''} ${err.message || 'Invalid value'}`).join(', ');
|
|
205
|
-
|
|
225
|
+
const formattedErrors = formatAjvErrors(validateSchema.errors);
|
|
226
|
+
throw new errors_1.BadRequest([new Error(`Validation failed for ${modelType}: ${errorDetails}`)], undefined, {
|
|
227
|
+
customError: formattedErrors,
|
|
228
|
+
});
|
|
206
229
|
}
|
|
207
230
|
}
|
|
208
231
|
}
|
|
@@ -270,7 +293,7 @@ const beforeCreate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
|
|
|
270
293
|
throw new errors_2.MissingRequiredCustomFieldError(missingFields);
|
|
271
294
|
}
|
|
272
295
|
// Step 2: Validate the model data (including custom fields)
|
|
273
|
-
await validateModel(instance, options, scopeAttributes, true);
|
|
296
|
+
await validateModel(instance, options, scopeAttributes, modelOptions, true);
|
|
274
297
|
// format date and datetime fields
|
|
275
298
|
formatDates(fieldDefinitions, instance);
|
|
276
299
|
// Step 3: Save custom field values if they exist
|
|
@@ -308,7 +331,7 @@ const beforeUpdate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
|
|
|
308
331
|
modelType, modelOptions, identifiers, options,
|
|
309
332
|
});
|
|
310
333
|
// Step 1: Validate the model data (including custom fields)
|
|
311
|
-
await validateModel(instance, options, scopeAttributes, false);
|
|
334
|
+
await validateModel(instance, options, scopeAttributes, modelOptions, false);
|
|
312
335
|
// format date and datetime fields
|
|
313
336
|
formatDates(fieldDefinitions, instance);
|
|
314
337
|
// Step 2: Update custom field values if they exist
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { Transactionable } from 'sequelize';
|
|
1
|
+
import type { IncludeOptions, Transactionable } from 'sequelize';
|
|
2
2
|
import { CustomValidator } from '../models';
|
|
3
3
|
export interface FindValidatorOptions extends Transactionable {
|
|
4
4
|
withDisabled?: boolean;
|
|
5
5
|
attributes?: string[];
|
|
6
6
|
raw?: boolean;
|
|
7
|
+
include?: IncludeOptions[];
|
|
7
8
|
}
|
|
8
9
|
export interface ValidatorAttributes {
|
|
9
10
|
entityId: string;
|
|
@@ -40,7 +40,9 @@ const findAllByModelType = async (modelType, entityId, options = { withDisabled:
|
|
|
40
40
|
logger_1.default.debug('custom-validator - find all validators by model type');
|
|
41
41
|
return (0, exports.findAll)({
|
|
42
42
|
modelType,
|
|
43
|
-
|
|
43
|
+
...(!options.include && {
|
|
44
|
+
entityId,
|
|
45
|
+
}),
|
|
44
46
|
}, options);
|
|
45
47
|
};
|
|
46
48
|
exports.findAllByModelType = findAllByModelType;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sadot",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"@autofleet/common-types": "^4.4.0",
|
|
32
32
|
"@autofleet/events": "^4.0.0",
|
|
33
33
|
"ajv": "^8.12.0",
|
|
34
|
+
"ajv-errors": "^3.0.0",
|
|
34
35
|
"ajv-formats": "^3.0.1",
|
|
35
36
|
"http-status-codes": "^2.3.0",
|
|
36
37
|
"joi": "^17.7.0",
|
package/src/hooks/hooks.ts
CHANGED
|
@@ -3,6 +3,7 @@ import Ajv from 'ajv';
|
|
|
3
3
|
import Joi from 'joi';
|
|
4
4
|
import addFormats from 'ajv-formats';
|
|
5
5
|
import { BadRequest } from '@autofleet/errors';
|
|
6
|
+
import ajvErrors from 'ajv-errors';
|
|
6
7
|
import logger from '../utils/logger';
|
|
7
8
|
import * as ValidatorRepo from '../repository/validator';
|
|
8
9
|
import * as DefinitionRepo from '../repository/definition';
|
|
@@ -25,6 +26,7 @@ const ajv = new Ajv({
|
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
addFormats(ajv);
|
|
29
|
+
ajvErrors(ajv);
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* Helper function to manually copy object properties
|
|
@@ -76,6 +78,29 @@ const getCompleteCustomFields = async (instance, options): Promise<Record<string
|
|
|
76
78
|
return instance.customFields || {};
|
|
77
79
|
};
|
|
78
80
|
|
|
81
|
+
const formatAjvErrors = (
|
|
82
|
+
errors: {
|
|
83
|
+
instancePath?: string;
|
|
84
|
+
keyword: string;
|
|
85
|
+
message?: string;
|
|
86
|
+
params?: Record<string, any>;
|
|
87
|
+
}[],
|
|
88
|
+
): Record<string, string> => errors.reduce((acc, err) => {
|
|
89
|
+
const basePath = (err.instancePath || '')
|
|
90
|
+
.split('/')
|
|
91
|
+
.filter(Boolean)
|
|
92
|
+
.join('.')
|
|
93
|
+
.replace(/^after\./, '');
|
|
94
|
+
|
|
95
|
+
const missingProp = err.keyword === 'required' ? `.${err.params?.missingProperty}` : '';
|
|
96
|
+
const key = (basePath + missingProp).replace(/^\./, '') || 'root';
|
|
97
|
+
|
|
98
|
+
const message = err.message || 'Invalid value';
|
|
99
|
+
acc[key] = message;
|
|
100
|
+
|
|
101
|
+
return acc;
|
|
102
|
+
}, {} as Record<string, string>);
|
|
103
|
+
|
|
79
104
|
/**
|
|
80
105
|
* Validates the model using custom validators
|
|
81
106
|
*/
|
|
@@ -83,6 +108,7 @@ const validateModel = async (
|
|
|
83
108
|
instance,
|
|
84
109
|
options,
|
|
85
110
|
scopeAttributes: string[],
|
|
111
|
+
modelOptions: ModelOptions = {},
|
|
86
112
|
isCreate = false,
|
|
87
113
|
): Promise<void> => {
|
|
88
114
|
const modelType = instance.constructor.name;
|
|
@@ -124,6 +150,9 @@ const validateModel = async (
|
|
|
124
150
|
{
|
|
125
151
|
transaction: options.transaction,
|
|
126
152
|
attributes: CUSTOM_VALIDATOR_ATTRIBUTES_TO_PULL,
|
|
153
|
+
...(modelOptions.include && {
|
|
154
|
+
include: modelOptions.include?.(entityId),
|
|
155
|
+
}),
|
|
127
156
|
raw: true,
|
|
128
157
|
},
|
|
129
158
|
);
|
|
@@ -189,7 +218,14 @@ const validateModel = async (
|
|
|
189
218
|
const errorDetails = validateSchema.errors?.map((err) =>
|
|
190
219
|
`${(err as any).instancePath || ''} ${(err as any).message || 'Invalid value'}`).join(', ');
|
|
191
220
|
|
|
192
|
-
|
|
221
|
+
const formattedErrors = formatAjvErrors(validateSchema.errors);
|
|
222
|
+
throw new BadRequest(
|
|
223
|
+
[new Error(`Validation failed for ${modelType}: ${errorDetails}`)],
|
|
224
|
+
undefined,
|
|
225
|
+
{
|
|
226
|
+
customError: formattedErrors,
|
|
227
|
+
},
|
|
228
|
+
);
|
|
193
229
|
}
|
|
194
230
|
}
|
|
195
231
|
} else {
|
|
@@ -224,7 +260,14 @@ const validateModel = async (
|
|
|
224
260
|
.errors
|
|
225
261
|
?.map((err) => `${(err as any).instancePath || ''} ${(err as any).message || 'Invalid value'}`).join(', ');
|
|
226
262
|
|
|
227
|
-
|
|
263
|
+
const formattedErrors = formatAjvErrors(validateSchema.errors);
|
|
264
|
+
throw new BadRequest(
|
|
265
|
+
[new Error(`Validation failed for ${modelType}: ${errorDetails}`)],
|
|
266
|
+
undefined,
|
|
267
|
+
{
|
|
268
|
+
customError: formattedErrors,
|
|
269
|
+
},
|
|
270
|
+
);
|
|
228
271
|
}
|
|
229
272
|
}
|
|
230
273
|
}
|
|
@@ -321,7 +364,7 @@ export const beforeCreate = (
|
|
|
321
364
|
}
|
|
322
365
|
|
|
323
366
|
// Step 2: Validate the model data (including custom fields)
|
|
324
|
-
await validateModel(instance, options, scopeAttributes, true);
|
|
367
|
+
await validateModel(instance, options, scopeAttributes, modelOptions, true);
|
|
325
368
|
|
|
326
369
|
// format date and datetime fields
|
|
327
370
|
formatDates(fieldDefinitions, instance);
|
|
@@ -372,7 +415,7 @@ export const beforeUpdate = (
|
|
|
372
415
|
});
|
|
373
416
|
|
|
374
417
|
// Step 1: Validate the model data (including custom fields)
|
|
375
|
-
await validateModel(instance, options, scopeAttributes, false);
|
|
418
|
+
await validateModel(instance, options, scopeAttributes, modelOptions, false);
|
|
376
419
|
|
|
377
420
|
// format date and datetime fields
|
|
378
421
|
formatDates(fieldDefinitions, instance);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Transactionable } from 'sequelize';
|
|
1
|
+
import type { IncludeOptions, Transactionable } from 'sequelize';
|
|
2
2
|
import logger from '../utils/logger';
|
|
3
3
|
import { CustomValidator } from '../models';
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@ export interface FindValidatorOptions extends Transactionable {
|
|
|
6
6
|
withDisabled?: boolean;
|
|
7
7
|
attributes?: string[];
|
|
8
8
|
raw?: boolean;
|
|
9
|
+
include?: IncludeOptions[];
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
// Make sure this interface is compatible with the Sequelize model
|
|
@@ -68,7 +69,9 @@ export const findAllByModelType = async (
|
|
|
68
69
|
return findAll(
|
|
69
70
|
{
|
|
70
71
|
modelType,
|
|
71
|
-
|
|
72
|
+
...(!options.include && {
|
|
73
|
+
entityId,
|
|
74
|
+
}),
|
|
72
75
|
},
|
|
73
76
|
options,
|
|
74
77
|
);
|