@terreno/api 0.11.7 → 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.
@@ -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 function isOpenApiValidatorConfigured(): boolean;
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 function configureOpenApiValidator(config?: Partial<OpenApiValidatorConfig>): void;
104
+ export declare const configureOpenApiValidator: (config?: Partial<OpenApiValidatorConfig>) => void;
105
105
  /**
106
106
  * Get the current global validator configuration.
107
107
  */
108
- export declare function getOpenApiValidatorConfig(): OpenApiValidatorConfig;
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 function resetOpenApiValidatorConfig(): void;
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 function validateRequestBody(schema: Record<string, OpenApiSchemaProperty>, options?: RequestBodyValidatorOptions): (req: Request, res: Response, next: NextFunction) => void;
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 function validateQueryParams(schema: Record<string, OpenApiSchemaProperty>, options?: QueryValidatorOptions): (req: Request, res: Response, next: NextFunction) => void;
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 function createValidator(options: CreateValidatorOptions): (req: Request, res: Response, next: NextFunction) => void;
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 function validateResponseData(data: unknown, schema: Record<string, OpenApiSchemaProperty>): {
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 function getSchemaFromModel<T>(model: Model<T>): Record<string, OpenApiSchemaProperty>;
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 function validateModelRequestBody<T>(model: Model<T>, options?: RequestBodyValidatorOptions): (req: Request, res: Response, next: NextFunction) => void;
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 function createModelValidators<T>(model: Model<T>, options?: ModelRouterValidationOptions): {
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 function buildQuerySchemaFromFields<T>(model: Model<T>, queryFields?: string[]): Record<string, OpenApiSchemaProperty>;
296
+ export declare const buildQuerySchemaFromFields: <T>(model: Model<T>, queryFields?: string[]) => Record<string, OpenApiSchemaProperty>;
@@ -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 = 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 isOpenApiValidatorConfigured() {
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 configureOpenApiValidator(config) {
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 getOpenApiValidatorConfig() {
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 resetOpenApiValidatorConfig() {
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 getAjvInstance() {
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 hashSchema(schema) {
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 sanitizeSchemaForAjv(schema) {
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 getValidator(schema) {
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 formatValidationErrors(errors) {
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 propertiesToSchema(properties, requiredFields) {
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 validateRequestBody(schema, options) {
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 validateQueryParams(schema, options) {
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 createValidator(options) {
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 validateResponseData(data, schema) {
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 getSchemaFromModel(model) {
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 getRequiredFieldsFromModel(model) {
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 validateModelRequestBody(model, options) {
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 createModelValidators(model, options) {
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 buildQuerySchemaFromFields(model, queryFields) {
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;
@@ -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;
@@ -25,11 +25,11 @@ interface BackgroundTaskLog {
25
25
  level: "info" | "warn" | "error";
26
26
  message: string;
27
27
  }
28
- export type BackgroundTaskMethods = {
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 type BackgroundTaskDocument = Document & BackgroundTaskMethods & {
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 type BackgroundTaskStatics = {
46
+ }
47
+ export interface BackgroundTaskStatics {
48
48
  checkCancellation: (taskId: string) => Promise<void>;
49
- };
50
- export type BackgroundTaskModel = Model<BackgroundTaskDocument, Record<string, never>, BackgroundTaskMethods> & BackgroundTaskStatics;
49
+ }
50
+ export interface BackgroundTaskModel extends Model<BackgroundTaskDocument, Record<string, never>, BackgroundTaskMethods>, BackgroundTaskStatics {
51
+ }
51
52
  export declare const BackgroundTask: BackgroundTaskModel;
52
53
  export {};
@@ -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, mod, SecretManagerServiceClient, _a;
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*/, 4];
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 Error("GcpSecretProvider requires @google-cloud/secret-manager. Install it with: bun add @google-cloud/secret-manager");
165
- case 4: return [2 /*return*/, this.client];
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 ((error_1 === null || error_1 === void 0 ? void 0 : error_1.code) === 5) {
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
@@ -104,5 +104,5 @@
104
104
  "updateSnapshot": "bun test --update-snapshots"
105
105
  },
106
106
  "types": "dist/index.d.ts",
107
- "version": "0.11.7"
107
+ "version": "0.11.8"
108
108
  }
@@ -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 type ConfigurationModel<T extends object> = Model<T> & ConfigurationStatics<T>;
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
- // Intentional unfiltered findOnechecking if any singleton document exists
146
- const existing = await (this.constructor as Model<unknown>).findOne({});
149
+ // Cheap existence checkno 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
- let config = await this.findOne({});
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
- config = new this();
182
- await config.save();
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 findOne and create,
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 this.findOne({});
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.toObject();
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;