@terreno/api 0.11.6 → 0.11.8
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/configurationPlugin.d.ts +2 -1
- package/dist/configurationPlugin.js +16 -9
- package/dist/errors.d.ts +6 -6
- package/dist/errors.js +22 -22
- package/dist/errors.test.d.ts +1 -0
- package/dist/errors.test.js +280 -0
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +4 -3
- package/dist/notifiers/zoomNotifier.js +12 -11
- package/dist/openApiCompat.js +2 -1
- package/dist/openApiEtag.d.ts +1 -1
- package/dist/openApiEtag.js +4 -3
- package/dist/openApiValidator.d.ts +12 -12
- package/dist/openApiValidator.js +59 -58
- package/dist/plugins.test.js +22 -0
- package/dist/scriptRunner.d.ts +8 -7
- package/dist/secretProviders.js +17 -7
- package/package.json +1 -1
- package/src/configurationPlugin.ts +18 -9
- package/src/errors.test.ts +302 -0
- package/src/errors.ts +18 -13
- package/src/middleware.ts +6 -2
- package/src/notifiers/zoomNotifier.ts +4 -3
- package/src/openApiCompat.ts +2 -1
- package/src/openApiEtag.ts +2 -2
- package/src/openApiValidator.ts +46 -46
- package/src/plugins.test.ts +29 -0
- package/src/scriptRunner.ts +23 -27
- package/src/secretProviders.ts +27 -9
|
@@ -83,7 +83,7 @@ export interface OpenApiValidatorConfig {
|
|
|
83
83
|
* Check whether `configureOpenApiValidator()` has been called.
|
|
84
84
|
* Validation middleware is a no-op when this returns false.
|
|
85
85
|
*/
|
|
86
|
-
export declare
|
|
86
|
+
export declare const isOpenApiValidatorConfigured: () => boolean;
|
|
87
87
|
/**
|
|
88
88
|
* Configure the global OpenAPI validator settings.
|
|
89
89
|
* Calling this function activates validation — middleware that was previously
|
|
@@ -101,17 +101,17 @@ export declare function isOpenApiValidatorConfigured(): boolean;
|
|
|
101
101
|
* });
|
|
102
102
|
* ```
|
|
103
103
|
*/
|
|
104
|
-
export declare
|
|
104
|
+
export declare const configureOpenApiValidator: (config?: Partial<OpenApiValidatorConfig>) => void;
|
|
105
105
|
/**
|
|
106
106
|
* Get the current global validator configuration.
|
|
107
107
|
*/
|
|
108
|
-
export declare
|
|
108
|
+
export declare const getOpenApiValidatorConfig: () => OpenApiValidatorConfig;
|
|
109
109
|
/**
|
|
110
110
|
* Reset the global validator configuration to defaults.
|
|
111
111
|
* Also resets `isConfigured` to false.
|
|
112
112
|
* Useful for testing.
|
|
113
113
|
*/
|
|
114
|
-
export declare
|
|
114
|
+
export declare const resetOpenApiValidatorConfig: () => void;
|
|
115
115
|
/**
|
|
116
116
|
* Options for the request body validator middleware.
|
|
117
117
|
*/
|
|
@@ -149,7 +149,7 @@ export interface RequestBodyValidatorOptions {
|
|
|
149
149
|
* @param options - Optional configuration for this validator
|
|
150
150
|
* @returns Express middleware function
|
|
151
151
|
*/
|
|
152
|
-
export declare
|
|
152
|
+
export declare const validateRequestBody: (schema: Record<string, OpenApiSchemaProperty>, options?: RequestBodyValidatorOptions) => ((req: Request, res: Response, next: NextFunction) => void);
|
|
153
153
|
/**
|
|
154
154
|
* Options for the query parameter validator middleware.
|
|
155
155
|
*/
|
|
@@ -170,7 +170,7 @@ export interface QueryValidatorOptions {
|
|
|
170
170
|
* @param options - Optional configuration for this validator
|
|
171
171
|
* @returns Express middleware function
|
|
172
172
|
*/
|
|
173
|
-
export declare
|
|
173
|
+
export declare const validateQueryParams: (schema: Record<string, OpenApiSchemaProperty>, options?: QueryValidatorOptions) => ((req: Request, res: Response, next: NextFunction) => void);
|
|
174
174
|
/**
|
|
175
175
|
* Options for creating a combined validation middleware.
|
|
176
176
|
*/
|
|
@@ -205,7 +205,7 @@ export interface CreateValidatorOptions {
|
|
|
205
205
|
* ], handler);
|
|
206
206
|
* ```
|
|
207
207
|
*/
|
|
208
|
-
export declare
|
|
208
|
+
export declare const createValidator: (options: CreateValidatorOptions) => ((req: Request, res: Response, next: NextFunction) => void);
|
|
209
209
|
/**
|
|
210
210
|
* Validates response data against a schema.
|
|
211
211
|
* This is primarily for development/testing to ensure responses match documentation.
|
|
@@ -214,7 +214,7 @@ export declare function createValidator(options: CreateValidatorOptions): (req:
|
|
|
214
214
|
* @param schema - The expected schema
|
|
215
215
|
* @returns Object with valid flag and any errors
|
|
216
216
|
*/
|
|
217
|
-
export declare
|
|
217
|
+
export declare const validateResponseData: (data: unknown, schema: Record<string, OpenApiSchemaProperty>) => {
|
|
218
218
|
valid: boolean;
|
|
219
219
|
errors?: ErrorObject[];
|
|
220
220
|
};
|
|
@@ -226,7 +226,7 @@ export declare function validateResponseData(data: unknown, schema: Record<strin
|
|
|
226
226
|
* @param model - A Mongoose model
|
|
227
227
|
* @returns Schema properties suitable for validation
|
|
228
228
|
*/
|
|
229
|
-
export declare
|
|
229
|
+
export declare const getSchemaFromModel: <T>(model: Model<T>) => Record<string, OpenApiSchemaProperty>;
|
|
230
230
|
/**
|
|
231
231
|
* Creates a request body validator middleware from a Mongoose model.
|
|
232
232
|
* This is a convenience function that combines getSchemaFromModel and validateRequestBody.
|
|
@@ -235,7 +235,7 @@ export declare function getSchemaFromModel<T>(model: Model<T>): Record<string, O
|
|
|
235
235
|
* @param options - Optional configuration for the validator
|
|
236
236
|
* @returns Express middleware function
|
|
237
237
|
*/
|
|
238
|
-
export declare
|
|
238
|
+
export declare const validateModelRequestBody: <T>(model: Model<T>, options?: RequestBodyValidatorOptions) => ((req: Request, res: Response, next: NextFunction) => void);
|
|
239
239
|
/**
|
|
240
240
|
* Options for creating validation middleware for a modelRouter.
|
|
241
241
|
*/
|
|
@@ -281,7 +281,7 @@ export interface ModelRouterValidationOptions {
|
|
|
281
281
|
* @param options - Configuration options
|
|
282
282
|
* @returns Object with create and update validation middleware
|
|
283
283
|
*/
|
|
284
|
-
export declare
|
|
284
|
+
export declare const createModelValidators: <T>(model: Model<T>, options?: ModelRouterValidationOptions) => {
|
|
285
285
|
create: (req: Request, res: Response, next: NextFunction) => void;
|
|
286
286
|
update: (req: Request, res: Response, next: NextFunction) => void;
|
|
287
287
|
};
|
|
@@ -293,4 +293,4 @@ export declare function createModelValidators<T>(model: Model<T>, options?: Mode
|
|
|
293
293
|
* @param queryFields - Array of field names allowed for querying
|
|
294
294
|
* @returns Schema properties suitable for query validation
|
|
295
295
|
*/
|
|
296
|
-
export declare
|
|
296
|
+
export declare const buildQuerySchemaFromFields: <T>(model: Model<T>, queryFields?: string[]) => Record<string, OpenApiSchemaProperty>;
|
package/dist/openApiValidator.js
CHANGED
|
@@ -96,18 +96,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
96
96
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
97
97
|
};
|
|
98
98
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
99
|
-
exports.isOpenApiValidatorConfigured =
|
|
100
|
-
exports.configureOpenApiValidator = configureOpenApiValidator;
|
|
101
|
-
exports.getOpenApiValidatorConfig = getOpenApiValidatorConfig;
|
|
102
|
-
exports.resetOpenApiValidatorConfig = resetOpenApiValidatorConfig;
|
|
103
|
-
exports.validateRequestBody = validateRequestBody;
|
|
104
|
-
exports.validateQueryParams = validateQueryParams;
|
|
105
|
-
exports.createValidator = createValidator;
|
|
106
|
-
exports.validateResponseData = validateResponseData;
|
|
107
|
-
exports.getSchemaFromModel = getSchemaFromModel;
|
|
108
|
-
exports.validateModelRequestBody = validateModelRequestBody;
|
|
109
|
-
exports.createModelValidators = createModelValidators;
|
|
110
|
-
exports.buildQuerySchemaFromFields = buildQuerySchemaFromFields;
|
|
99
|
+
exports.buildQuerySchemaFromFields = exports.createModelValidators = exports.validateModelRequestBody = exports.getSchemaFromModel = exports.validateResponseData = exports.createValidator = exports.validateQueryParams = exports.validateRequestBody = exports.resetOpenApiValidatorConfig = exports.getOpenApiValidatorConfig = exports.configureOpenApiValidator = exports.isOpenApiValidatorConfigured = void 0;
|
|
111
100
|
var ajv_1 = __importDefault(require("ajv"));
|
|
112
101
|
var ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
113
102
|
var mongoose_to_swagger_1 = __importDefault(require("mongoose-to-swagger"));
|
|
@@ -128,9 +117,10 @@ var globalConfig = {
|
|
|
128
117
|
* Check whether `configureOpenApiValidator()` has been called.
|
|
129
118
|
* Validation middleware is a no-op when this returns false.
|
|
130
119
|
*/
|
|
131
|
-
function
|
|
120
|
+
var isOpenApiValidatorConfigured = function () {
|
|
132
121
|
return isConfigured;
|
|
133
|
-
}
|
|
122
|
+
};
|
|
123
|
+
exports.isOpenApiValidatorConfigured = isOpenApiValidatorConfigured;
|
|
134
124
|
/**
|
|
135
125
|
* Configure the global OpenAPI validator settings.
|
|
136
126
|
* Calling this function activates validation — middleware that was previously
|
|
@@ -148,7 +138,7 @@ function isOpenApiValidatorConfigured() {
|
|
|
148
138
|
* });
|
|
149
139
|
* ```
|
|
150
140
|
*/
|
|
151
|
-
function
|
|
141
|
+
var configureOpenApiValidator = function (config) {
|
|
152
142
|
if (config === void 0) { config = {}; }
|
|
153
143
|
isConfigured = true;
|
|
154
144
|
globalConfig = __assign(__assign({}, globalConfig), config);
|
|
@@ -156,19 +146,21 @@ function configureOpenApiValidator(config) {
|
|
|
156
146
|
ajvCache.clear();
|
|
157
147
|
validatorCache.clear();
|
|
158
148
|
logger_1.logger.debug("OpenAPI validator configured: ".concat(JSON.stringify(globalConfig)));
|
|
159
|
-
}
|
|
149
|
+
};
|
|
150
|
+
exports.configureOpenApiValidator = configureOpenApiValidator;
|
|
160
151
|
/**
|
|
161
152
|
* Get the current global validator configuration.
|
|
162
153
|
*/
|
|
163
|
-
function
|
|
154
|
+
var getOpenApiValidatorConfig = function () {
|
|
164
155
|
return __assign({}, globalConfig);
|
|
165
|
-
}
|
|
156
|
+
};
|
|
157
|
+
exports.getOpenApiValidatorConfig = getOpenApiValidatorConfig;
|
|
166
158
|
/**
|
|
167
159
|
* Reset the global validator configuration to defaults.
|
|
168
160
|
* Also resets `isConfigured` to false.
|
|
169
161
|
* Useful for testing.
|
|
170
162
|
*/
|
|
171
|
-
function
|
|
163
|
+
var resetOpenApiValidatorConfig = function () {
|
|
172
164
|
isConfigured = false;
|
|
173
165
|
globalConfig = {
|
|
174
166
|
coerceTypes: true,
|
|
@@ -179,13 +171,14 @@ function resetOpenApiValidatorConfig() {
|
|
|
179
171
|
};
|
|
180
172
|
ajvCache.clear();
|
|
181
173
|
validatorCache.clear();
|
|
182
|
-
}
|
|
174
|
+
};
|
|
175
|
+
exports.resetOpenApiValidatorConfig = resetOpenApiValidatorConfig;
|
|
183
176
|
// Lazy AJV instance cache keyed by coerceTypes + removeAdditional
|
|
184
177
|
var ajvCache = new Map();
|
|
185
178
|
/**
|
|
186
179
|
* Get or create an AJV instance with the current config settings.
|
|
187
180
|
*/
|
|
188
|
-
function
|
|
181
|
+
var getAjvInstance = function () {
|
|
189
182
|
var _a, _b, _c, _d;
|
|
190
183
|
var key = "coerce:".concat((_a = globalConfig.coerceTypes) !== null && _a !== void 0 ? _a : true, ",remove:").concat((_b = globalConfig.removeAdditional) !== null && _b !== void 0 ? _b : true);
|
|
191
184
|
var instance = ajvCache.get(key);
|
|
@@ -202,15 +195,15 @@ function getAjvInstance() {
|
|
|
202
195
|
ajvCache.set(key, instance);
|
|
203
196
|
}
|
|
204
197
|
return instance;
|
|
205
|
-
}
|
|
198
|
+
};
|
|
206
199
|
// Cache compiled validators by schema hash + config key
|
|
207
200
|
var validatorCache = new Map();
|
|
208
201
|
/**
|
|
209
202
|
* Generate a simple hash for a schema to use as a cache key.
|
|
210
203
|
*/
|
|
211
|
-
function
|
|
204
|
+
var hashSchema = function (schema) {
|
|
212
205
|
return JSON.stringify(schema);
|
|
213
|
-
}
|
|
206
|
+
};
|
|
214
207
|
var VALID_JSON_SCHEMA_TYPES = new Set([
|
|
215
208
|
"string",
|
|
216
209
|
"number",
|
|
@@ -229,7 +222,7 @@ var MONGOOSE_TYPE_MAP = {
|
|
|
229
222
|
* Recursively replace non-standard mongoose-to-swagger types with valid JSON Schema types
|
|
230
223
|
* so AJV can compile the schema.
|
|
231
224
|
*/
|
|
232
|
-
function
|
|
225
|
+
var sanitizeSchemaForAjv = function (schema) {
|
|
233
226
|
var e_1, _a;
|
|
234
227
|
if (!schema || typeof schema !== "object") {
|
|
235
228
|
return schema;
|
|
@@ -274,14 +267,14 @@ function sanitizeSchemaForAjv(schema) {
|
|
|
274
267
|
result.additionalProperties = sanitizeSchemaForAjv(result.additionalProperties);
|
|
275
268
|
}
|
|
276
269
|
return result;
|
|
277
|
-
}
|
|
270
|
+
};
|
|
278
271
|
/**
|
|
279
272
|
* Get or create a compiled validator for a schema.
|
|
280
273
|
* Uses the current config so changes take effect on next call.
|
|
281
274
|
* Sanitizes non-standard mongoose-to-swagger types before compilation.
|
|
282
275
|
* Returns null if the schema still cannot be compiled after sanitization.
|
|
283
276
|
*/
|
|
284
|
-
function
|
|
277
|
+
var getValidator = function (schema) {
|
|
285
278
|
var _a, _b;
|
|
286
279
|
var ajv = getAjvInstance();
|
|
287
280
|
var configKey = "coerce:".concat((_a = globalConfig.coerceTypes) !== null && _a !== void 0 ? _a : true, ",remove:").concat((_b = globalConfig.removeAdditional) !== null && _b !== void 0 ? _b : true);
|
|
@@ -301,11 +294,11 @@ function getValidator(schema) {
|
|
|
301
294
|
validatorCache.set(hash, null);
|
|
302
295
|
return null;
|
|
303
296
|
}
|
|
304
|
-
}
|
|
297
|
+
};
|
|
305
298
|
/**
|
|
306
299
|
* Format AJV errors into a human-readable string.
|
|
307
300
|
*/
|
|
308
|
-
function
|
|
301
|
+
var formatValidationErrors = function (errors) {
|
|
309
302
|
return errors
|
|
310
303
|
.map(function (err) {
|
|
311
304
|
var path = err.instancePath || "/";
|
|
@@ -313,13 +306,13 @@ function formatValidationErrors(errors) {
|
|
|
313
306
|
return "".concat(path, ": ").concat(message);
|
|
314
307
|
})
|
|
315
308
|
.join("; ");
|
|
316
|
-
}
|
|
309
|
+
};
|
|
317
310
|
/**
|
|
318
311
|
* Convert OpenApiSchemaProperty to a full OpenApiSchema suitable for AJV.
|
|
319
312
|
* Strips `required` from individual properties (OpenAPI-style) and moves it
|
|
320
313
|
* to the schema-level `required` array (JSON Schema-style) for AJV compatibility.
|
|
321
314
|
*/
|
|
322
|
-
function
|
|
315
|
+
var propertiesToSchema = function (properties, requiredFields) {
|
|
323
316
|
var e_2, _a;
|
|
324
317
|
// Extract required fields from properties that have required: true
|
|
325
318
|
var autoRequired = Object.entries(properties)
|
|
@@ -359,7 +352,7 @@ function propertiesToSchema(properties, requiredFields) {
|
|
|
359
352
|
schema.additionalProperties = false;
|
|
360
353
|
}
|
|
361
354
|
return schema;
|
|
362
|
-
}
|
|
355
|
+
};
|
|
363
356
|
/**
|
|
364
357
|
* Creates middleware that validates the request body against an OpenAPI schema.
|
|
365
358
|
*
|
|
@@ -370,7 +363,7 @@ function propertiesToSchema(properties, requiredFields) {
|
|
|
370
363
|
* @param options - Optional configuration for this validator
|
|
371
364
|
* @returns Express middleware function
|
|
372
365
|
*/
|
|
373
|
-
function
|
|
366
|
+
var validateRequestBody = function (schema, options) {
|
|
374
367
|
var fullSchema = propertiesToSchema(schema, options === null || options === void 0 ? void 0 : options.required);
|
|
375
368
|
return function (req, _res, next) {
|
|
376
369
|
var _a, _b, _c;
|
|
@@ -447,7 +440,8 @@ function validateRequestBody(schema, options) {
|
|
|
447
440
|
}
|
|
448
441
|
next();
|
|
449
442
|
};
|
|
450
|
-
}
|
|
443
|
+
};
|
|
444
|
+
exports.validateRequestBody = validateRequestBody;
|
|
451
445
|
/**
|
|
452
446
|
* Creates middleware that validates query parameters against an OpenAPI schema.
|
|
453
447
|
*
|
|
@@ -455,7 +449,7 @@ function validateRequestBody(schema, options) {
|
|
|
455
449
|
* @param options - Optional configuration for this validator
|
|
456
450
|
* @returns Express middleware function
|
|
457
451
|
*/
|
|
458
|
-
function
|
|
452
|
+
var validateQueryParams = function (schema, options) {
|
|
459
453
|
var fullSchema = propertiesToSchema(schema);
|
|
460
454
|
return function (req, _res, next) {
|
|
461
455
|
var _a, _b, _c, _d;
|
|
@@ -513,7 +507,8 @@ function validateQueryParams(schema, options) {
|
|
|
513
507
|
}
|
|
514
508
|
next();
|
|
515
509
|
};
|
|
516
|
-
}
|
|
510
|
+
};
|
|
511
|
+
exports.validateQueryParams = validateQueryParams;
|
|
517
512
|
/**
|
|
518
513
|
* Creates a combined validation middleware for both body and query parameters.
|
|
519
514
|
*
|
|
@@ -531,12 +526,12 @@ function validateQueryParams(schema, options) {
|
|
|
531
526
|
* ], handler);
|
|
532
527
|
* ```
|
|
533
528
|
*/
|
|
534
|
-
function
|
|
529
|
+
var createValidator = function (options) {
|
|
535
530
|
var bodyValidator = options.body
|
|
536
|
-
? validateRequestBody(options.body, { enabled: options.enabled })
|
|
531
|
+
? (0, exports.validateRequestBody)(options.body, { enabled: options.enabled })
|
|
537
532
|
: null;
|
|
538
533
|
var queryValidator = options.query
|
|
539
|
-
? validateQueryParams(options.query, { enabled: options.enabled })
|
|
534
|
+
? (0, exports.validateQueryParams)(options.query, { enabled: options.enabled })
|
|
540
535
|
: null;
|
|
541
536
|
return function (req, res, next) {
|
|
542
537
|
// Run body validation first
|
|
@@ -562,7 +557,8 @@ function createValidator(options) {
|
|
|
562
557
|
next();
|
|
563
558
|
}
|
|
564
559
|
};
|
|
565
|
-
}
|
|
560
|
+
};
|
|
561
|
+
exports.createValidator = createValidator;
|
|
566
562
|
/**
|
|
567
563
|
* Validates response data against a schema.
|
|
568
564
|
* This is primarily for development/testing to ensure responses match documentation.
|
|
@@ -571,7 +567,7 @@ function createValidator(options) {
|
|
|
571
567
|
* @param schema - The expected schema
|
|
572
568
|
* @returns Object with valid flag and any errors
|
|
573
569
|
*/
|
|
574
|
-
function
|
|
570
|
+
var validateResponseData = function (data, schema) {
|
|
575
571
|
if (!globalConfig.validateResponses) {
|
|
576
572
|
return { valid: true };
|
|
577
573
|
}
|
|
@@ -588,7 +584,8 @@ function validateResponseData(data, schema) {
|
|
|
588
584
|
return { errors: validator.errors, valid: false };
|
|
589
585
|
}
|
|
590
586
|
return { valid: true };
|
|
591
|
-
}
|
|
587
|
+
};
|
|
588
|
+
exports.validateResponseData = validateResponseData;
|
|
592
589
|
var m2sOptions = {
|
|
593
590
|
props: ["readOnly", "required", "enum", "default"],
|
|
594
591
|
};
|
|
@@ -600,19 +597,20 @@ var m2sOptions = {
|
|
|
600
597
|
* @param model - A Mongoose model
|
|
601
598
|
* @returns Schema properties suitable for validation
|
|
602
599
|
*/
|
|
603
|
-
function
|
|
600
|
+
var getSchemaFromModel = function (model) {
|
|
604
601
|
var modelSwagger = (0, mongoose_to_swagger_1.default)(model, m2sOptions);
|
|
605
602
|
(0, populate_1.fixMixedFields)(model.schema, modelSwagger.properties);
|
|
606
603
|
return modelSwagger.properties;
|
|
607
|
-
}
|
|
604
|
+
};
|
|
605
|
+
exports.getSchemaFromModel = getSchemaFromModel;
|
|
608
606
|
/**
|
|
609
607
|
* Extract required field names from a Mongoose model's swagger schema.
|
|
610
608
|
*/
|
|
611
|
-
function
|
|
609
|
+
var getRequiredFieldsFromModel = function (model) {
|
|
612
610
|
var _a;
|
|
613
611
|
var modelSwagger = (0, mongoose_to_swagger_1.default)(model, m2sOptions);
|
|
614
612
|
return (_a = modelSwagger.required) !== null && _a !== void 0 ? _a : [];
|
|
615
|
-
}
|
|
613
|
+
};
|
|
616
614
|
/**
|
|
617
615
|
* Creates a request body validator middleware from a Mongoose model.
|
|
618
616
|
* This is a convenience function that combines getSchemaFromModel and validateRequestBody.
|
|
@@ -621,9 +619,9 @@ function getRequiredFieldsFromModel(model) {
|
|
|
621
619
|
* @param options - Optional configuration for the validator
|
|
622
620
|
* @returns Express middleware function
|
|
623
621
|
*/
|
|
624
|
-
function
|
|
622
|
+
var validateModelRequestBody = function (model, options) {
|
|
625
623
|
var _a, _b;
|
|
626
|
-
var schema = getSchemaFromModel(model);
|
|
624
|
+
var schema = (0, exports.getSchemaFromModel)(model);
|
|
627
625
|
var requiredFields = getRequiredFieldsFromModel(model);
|
|
628
626
|
if ((_a = options === null || options === void 0 ? void 0 : options.excludeFields) === null || _a === void 0 ? void 0 : _a.length) {
|
|
629
627
|
var excluded_1 = new Set(options.excludeFields);
|
|
@@ -633,8 +631,9 @@ function validateModelRequestBody(model, options) {
|
|
|
633
631
|
}));
|
|
634
632
|
requiredFields = requiredFields.filter(function (f) { return !excluded_1.has(f); });
|
|
635
633
|
}
|
|
636
|
-
return validateRequestBody(schema, __assign(__assign({}, options), { required: __spreadArray(__spreadArray([], __read(((_b = options === null || options === void 0 ? void 0 : options.required) !== null && _b !== void 0 ? _b : [])), false), __read(requiredFields), false) }));
|
|
637
|
-
}
|
|
634
|
+
return (0, exports.validateRequestBody)(schema, __assign(__assign({}, options), { required: __spreadArray(__spreadArray([], __read(((_b = options === null || options === void 0 ? void 0 : options.required) !== null && _b !== void 0 ? _b : [])), false), __read(requiredFields), false) }));
|
|
635
|
+
};
|
|
636
|
+
exports.validateModelRequestBody = validateModelRequestBody;
|
|
638
637
|
/**
|
|
639
638
|
* Creates validation middleware for use with modelRouter.
|
|
640
639
|
* Returns an object with middleware for each operation type.
|
|
@@ -643,21 +642,22 @@ function validateModelRequestBody(model, options) {
|
|
|
643
642
|
* @param options - Configuration options
|
|
644
643
|
* @returns Object with create and update validation middleware
|
|
645
644
|
*/
|
|
646
|
-
function
|
|
647
|
-
var schema = getSchemaFromModel(model);
|
|
645
|
+
var createModelValidators = function (model, options) {
|
|
646
|
+
var schema = (0, exports.getSchemaFromModel)(model);
|
|
648
647
|
return {
|
|
649
|
-
create: validateRequestBody(schema, {
|
|
648
|
+
create: (0, exports.validateRequestBody)(schema, {
|
|
650
649
|
enabled: options === null || options === void 0 ? void 0 : options.validateCreate,
|
|
651
650
|
onAdditionalPropertiesRemoved: options === null || options === void 0 ? void 0 : options.onAdditionalPropertiesRemoved,
|
|
652
651
|
onError: options === null || options === void 0 ? void 0 : options.onError,
|
|
653
652
|
}),
|
|
654
|
-
update: validateRequestBody(schema, {
|
|
653
|
+
update: (0, exports.validateRequestBody)(schema, {
|
|
655
654
|
enabled: options === null || options === void 0 ? void 0 : options.validateUpdate,
|
|
656
655
|
onAdditionalPropertiesRemoved: options === null || options === void 0 ? void 0 : options.onAdditionalPropertiesRemoved,
|
|
657
656
|
onError: options === null || options === void 0 ? void 0 : options.onError,
|
|
658
657
|
}),
|
|
659
658
|
};
|
|
660
|
-
}
|
|
659
|
+
};
|
|
660
|
+
exports.createModelValidators = createModelValidators;
|
|
661
661
|
/**
|
|
662
662
|
* Build a query parameter schema from a model's Mongoose schema and queryFields array.
|
|
663
663
|
* Always includes pagination parameters (limit, page, sort).
|
|
@@ -666,10 +666,10 @@ function createModelValidators(model, options) {
|
|
|
666
666
|
* @param queryFields - Array of field names allowed for querying
|
|
667
667
|
* @returns Schema properties suitable for query validation
|
|
668
668
|
*/
|
|
669
|
-
function
|
|
669
|
+
var buildQuerySchemaFromFields = function (model, queryFields) {
|
|
670
670
|
var e_3, _a;
|
|
671
671
|
if (queryFields === void 0) { queryFields = []; }
|
|
672
|
-
var modelSchema = getSchemaFromModel(model);
|
|
672
|
+
var modelSchema = (0, exports.getSchemaFromModel)(model);
|
|
673
673
|
var querySchema = {
|
|
674
674
|
limit: { type: "number" },
|
|
675
675
|
page: { type: "number" },
|
|
@@ -697,4 +697,5 @@ function buildQuerySchemaFromFields(model, queryFields) {
|
|
|
697
697
|
finally { if (e_3) throw e_3.error; }
|
|
698
698
|
}
|
|
699
699
|
return querySchema;
|
|
700
|
-
}
|
|
700
|
+
};
|
|
701
|
+
exports.buildQuerySchemaFromFields = buildQuerySchemaFromFields;
|
package/dist/plugins.test.js
CHANGED
|
@@ -74,6 +74,28 @@ stuffSchema.plugin(plugins_1.findExactlyOne);
|
|
|
74
74
|
stuffSchema.plugin(plugins_1.upsertPlugin);
|
|
75
75
|
stuffSchema.plugin(plugins_1.createdUpdatedPlugin);
|
|
76
76
|
var StuffModel = (0, mongoose_1.model)("Stuff", stuffSchema);
|
|
77
|
+
(0, bun_test_1.describe)("baseUserPlugin", function () {
|
|
78
|
+
(0, bun_test_1.it)("adds admin and email fields to the schema", function () {
|
|
79
|
+
var testSchema = new mongoose_1.Schema({});
|
|
80
|
+
// biome-ignore lint/suspicious/noExplicitAny: test schema
|
|
81
|
+
(0, plugins_1.baseUserPlugin)(testSchema);
|
|
82
|
+
var adminPath = testSchema.path("admin");
|
|
83
|
+
(0, bun_test_1.expect)(adminPath).toBeDefined();
|
|
84
|
+
(0, bun_test_1.expect)(adminPath.options.default).toBe(false);
|
|
85
|
+
var emailPath = testSchema.path("email");
|
|
86
|
+
(0, bun_test_1.expect)(emailPath).toBeDefined();
|
|
87
|
+
(0, bun_test_1.expect)(emailPath.options.index).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
(0, bun_test_1.describe)("firebaseJWTPlugin", function () {
|
|
91
|
+
(0, bun_test_1.it)("adds firebaseId field to the schema", function () {
|
|
92
|
+
var testSchema = new mongoose_1.Schema({});
|
|
93
|
+
(0, plugins_1.firebaseJWTPlugin)(testSchema);
|
|
94
|
+
var firebaseIdPath = testSchema.path("firebaseId");
|
|
95
|
+
(0, bun_test_1.expect)(firebaseIdPath).toBeDefined();
|
|
96
|
+
(0, bun_test_1.expect)(firebaseIdPath.options.index).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
77
99
|
(0, bun_test_1.describe)("createdUpdate", function () {
|
|
78
100
|
(0, bun_test_1.it)("sets created and updated on save", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
79
101
|
var stuff;
|
package/dist/scriptRunner.d.ts
CHANGED
|
@@ -25,11 +25,11 @@ interface BackgroundTaskLog {
|
|
|
25
25
|
level: "info" | "warn" | "error";
|
|
26
26
|
message: string;
|
|
27
27
|
}
|
|
28
|
-
export
|
|
28
|
+
export interface BackgroundTaskMethods {
|
|
29
29
|
addLog: (this: BackgroundTaskDocument, level: "info" | "warn" | "error", message: string) => Promise<void>;
|
|
30
30
|
updateProgress: (this: BackgroundTaskDocument, percentage: number, stage?: string, message?: string) => Promise<void>;
|
|
31
|
-
}
|
|
32
|
-
export
|
|
31
|
+
}
|
|
32
|
+
export interface BackgroundTaskDocument extends Document, BackgroundTaskMethods {
|
|
33
33
|
taskType: string;
|
|
34
34
|
status: "pending" | "running" | "completed" | "failed" | "cancelled";
|
|
35
35
|
progress?: BackgroundTaskProgress;
|
|
@@ -43,10 +43,11 @@ export type BackgroundTaskDocument = Document & BackgroundTaskMethods & {
|
|
|
43
43
|
created: Date;
|
|
44
44
|
updated: Date;
|
|
45
45
|
deleted: boolean;
|
|
46
|
-
}
|
|
47
|
-
export
|
|
46
|
+
}
|
|
47
|
+
export interface BackgroundTaskStatics {
|
|
48
48
|
checkCancellation: (taskId: string) => Promise<void>;
|
|
49
|
-
}
|
|
50
|
-
export
|
|
49
|
+
}
|
|
50
|
+
export interface BackgroundTaskModel extends Model<BackgroundTaskDocument, Record<string, never>, BackgroundTaskMethods>, BackgroundTaskStatics {
|
|
51
|
+
}
|
|
51
52
|
export declare const BackgroundTask: BackgroundTaskModel;
|
|
52
53
|
export {};
|
package/dist/secretProviders.js
CHANGED
|
@@ -86,6 +86,7 @@ var __read = (this && this.__read) || function (o, n) {
|
|
|
86
86
|
};
|
|
87
87
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
88
88
|
exports.GcpSecretProvider = exports.EnvSecretProvider = void 0;
|
|
89
|
+
var errors_1 = require("./errors");
|
|
89
90
|
var logger_1 = require("./logger");
|
|
90
91
|
/**
|
|
91
92
|
* Secret provider that reads secrets from environment variables.
|
|
@@ -143,12 +144,13 @@ var GcpSecretProvider = /** @class */ (function () {
|
|
|
143
144
|
}
|
|
144
145
|
GcpSecretProvider.prototype.getClient = function () {
|
|
145
146
|
return __awaiter(this, void 0, void 0, function () {
|
|
146
|
-
var moduleName,
|
|
147
|
+
var mod, moduleName, _a, SecretManagerServiceClient;
|
|
147
148
|
var _b, _c;
|
|
148
149
|
return __generator(this, function (_d) {
|
|
149
150
|
switch (_d.label) {
|
|
150
151
|
case 0:
|
|
151
|
-
if (!!this.client) return [3 /*break*/,
|
|
152
|
+
if (!!this.client) return [3 /*break*/, 5];
|
|
153
|
+
mod = void 0;
|
|
152
154
|
_d.label = 1;
|
|
153
155
|
case 1:
|
|
154
156
|
_d.trys.push([1, 3, , 4]);
|
|
@@ -156,13 +158,21 @@ var GcpSecretProvider = /** @class */ (function () {
|
|
|
156
158
|
return [4 /*yield*/, Promise.resolve("".concat(/* webpackIgnore: true */ moduleName)).then(function (s) { return __importStar(require(s)); })];
|
|
157
159
|
case 2:
|
|
158
160
|
mod = _d.sent();
|
|
159
|
-
SecretManagerServiceClient = (_b = mod.SecretManagerServiceClient) !== null && _b !== void 0 ? _b : (_c = mod.default) === null || _c === void 0 ? void 0 : _c.SecretManagerServiceClient;
|
|
160
|
-
this.client = new SecretManagerServiceClient();
|
|
161
161
|
return [3 /*break*/, 4];
|
|
162
162
|
case 3:
|
|
163
163
|
_a = _d.sent();
|
|
164
|
-
throw new
|
|
165
|
-
|
|
164
|
+
throw new errors_1.APIError({
|
|
165
|
+
status: 500,
|
|
166
|
+
title: "GcpSecretProvider requires @google-cloud/secret-manager. Install it with: bun add @google-cloud/secret-manager",
|
|
167
|
+
});
|
|
168
|
+
case 4:
|
|
169
|
+
SecretManagerServiceClient = (_b = mod.SecretManagerServiceClient) !== null && _b !== void 0 ? _b : (_c = mod.default) === null || _c === void 0 ? void 0 : _c.SecretManagerServiceClient;
|
|
170
|
+
if (!SecretManagerServiceClient) {
|
|
171
|
+
throw new Error("SecretManagerServiceClient not found in @google-cloud/secret-manager module");
|
|
172
|
+
}
|
|
173
|
+
this.client = new SecretManagerServiceClient();
|
|
174
|
+
_d.label = 5;
|
|
175
|
+
case 5: return [2 /*return*/, this.client];
|
|
166
176
|
}
|
|
167
177
|
});
|
|
168
178
|
});
|
|
@@ -198,7 +208,7 @@ var GcpSecretProvider = /** @class */ (function () {
|
|
|
198
208
|
return [2 /*return*/, typeof payload === "string" ? payload : new TextDecoder().decode(payload)];
|
|
199
209
|
case 4:
|
|
200
210
|
error_1 = _c.sent();
|
|
201
|
-
if (
|
|
211
|
+
if (error_1 instanceof Error && "code" in error_1 && error_1.code === 5) {
|
|
202
212
|
// NOT_FOUND
|
|
203
213
|
logger_1.logger.warn("GcpSecretProvider: secret ".concat(secretName, " not found"));
|
|
204
214
|
return [2 /*return*/, null];
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ import type {Document, Model, Schema} from "mongoose";
|
|
|
2
2
|
|
|
3
3
|
import {APIError} from "./errors";
|
|
4
4
|
import {logger} from "./logger";
|
|
5
|
+
import {type FindOneOrNonePlugin, findOneOrNone} from "./plugins";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Metadata for a secret field discovered by the configuration plugin.
|
|
@@ -100,7 +101,7 @@ export interface ConfigurationStatics<T extends object> {
|
|
|
100
101
|
* const full = await AppConfig.getConfig(); // typed as AppConfigDocument
|
|
101
102
|
* ```
|
|
102
103
|
*/
|
|
103
|
-
export
|
|
104
|
+
export interface ConfigurationModel<T extends object> extends Model<T>, ConfigurationStatics<T> {}
|
|
104
105
|
|
|
105
106
|
// ---------------------------------------------------------------------------
|
|
106
107
|
// Plugin
|
|
@@ -132,6 +133,9 @@ export type ConfigurationModel<T extends object> = Model<T> & ConfigurationStati
|
|
|
132
133
|
export const configurationPlugin = (schema: Schema, options?: ConfigurationPluginOptions): void => {
|
|
133
134
|
const pluginOptions = options ?? {};
|
|
134
135
|
|
|
136
|
+
// Apply findOneOrNone so the singleton lookup avoids bare Model.findOne (idempotent).
|
|
137
|
+
findOneOrNone(schema);
|
|
138
|
+
|
|
135
139
|
// Add a sentinel field with a unique index to enforce singleton at the DB level.
|
|
136
140
|
// All config documents get _singleton: "config", and the unique index prevents duplicates.
|
|
137
141
|
schema.add({
|
|
@@ -142,8 +146,8 @@ export const configurationPlugin = (schema: Schema, options?: ConfigurationPlugi
|
|
|
142
146
|
// Enforce singleton: only one document allowed (application-level guard)
|
|
143
147
|
schema.pre("save", async function () {
|
|
144
148
|
if (this.isNew) {
|
|
145
|
-
//
|
|
146
|
-
const existing = await (this.constructor as Model<unknown>).
|
|
149
|
+
// Cheap existence check — no document needs to be returned.
|
|
150
|
+
const existing = await (this.constructor as Model<unknown>).exists({});
|
|
147
151
|
if (existing) {
|
|
148
152
|
throw new APIError({
|
|
149
153
|
status: 409,
|
|
@@ -173,18 +177,23 @@ export const configurationPlugin = (schema: Schema, options?: ConfigurationPlugi
|
|
|
173
177
|
|
|
174
178
|
// Static: get the singleton configuration document or a value at a path (race-safe via upsert)
|
|
175
179
|
schema.statics.getConfig = async function (key?: string): Promise<unknown> {
|
|
176
|
-
|
|
180
|
+
const findSingleton = (): Promise<Document | null> =>
|
|
181
|
+
(this as unknown as FindOneOrNonePlugin<unknown>).findOneOrNone(
|
|
182
|
+
{}
|
|
183
|
+
) as Promise<Document | null>;
|
|
184
|
+
let config: Document | null = await findSingleton();
|
|
177
185
|
if (!config) {
|
|
178
186
|
try {
|
|
179
187
|
// Use `new` + `save` instead of `create({})` so Mongoose initializes
|
|
180
188
|
// nested subdocument defaults (create({}) skips them).
|
|
181
|
-
|
|
182
|
-
await
|
|
189
|
+
const created = new this();
|
|
190
|
+
await created.save();
|
|
191
|
+
config = created;
|
|
183
192
|
} catch (err: unknown) {
|
|
184
|
-
// If another process created the document between
|
|
193
|
+
// If another process created the document between the lookup and create,
|
|
185
194
|
// the pre-save hook will throw a 409. Just fetch the existing one.
|
|
186
195
|
if ((err as {status?: number})?.status === 409) {
|
|
187
|
-
config = await
|
|
196
|
+
config = await findSingleton();
|
|
188
197
|
} else {
|
|
189
198
|
throw err;
|
|
190
199
|
}
|
|
@@ -197,7 +206,7 @@ export const configurationPlugin = (schema: Schema, options?: ConfigurationPlugi
|
|
|
197
206
|
|
|
198
207
|
// Resolve dot-notation key into the document
|
|
199
208
|
const parts = key.split(".");
|
|
200
|
-
let value: unknown = config
|
|
209
|
+
let value: unknown = config?.toObject();
|
|
201
210
|
for (const part of parts) {
|
|
202
211
|
if (value == null || typeof value !== "object") {
|
|
203
212
|
return undefined;
|