@classytic/mongokit 3.6.3 → 3.7.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.
Files changed (33) hide show
  1. package/dist/{PaginationEngine-CunXkR9p.mjs → PaginationEngine-CPmZv7Ds.mjs} +8 -5
  2. package/dist/actions/index.d.mts +1 -1
  3. package/dist/actions/index.mjs +1 -1
  4. package/dist/ai/index.d.mts +23 -1
  5. package/dist/ai/index.mjs +194 -12
  6. package/dist/{cursor-CHToazHy.mjs → cursor-DZ9JSoMM.mjs} +11 -7
  7. package/dist/error-Lw9GEAro.mjs +46 -0
  8. package/dist/{index-BSRSsRRx.d.mts → index-C-qZUqv8.d.mts} +1 -1
  9. package/dist/index.d.mts +31 -9
  10. package/dist/index.mjs +53 -12
  11. package/dist/logger-DJ7egMnd.mjs +30 -0
  12. package/dist/{mongooseToJsonSchema-MlaD3C0B.mjs → mongooseToJsonSchema-DUwXPStK.mjs} +25 -21
  13. package/dist/{mongooseToJsonSchema-D2YjHo7W.d.mts → mongooseToJsonSchema-Du-UopRK.d.mts} +18 -2
  14. package/dist/pagination/PaginationEngine.d.mts +3 -1
  15. package/dist/pagination/PaginationEngine.mjs +1 -1
  16. package/dist/plugins/index.d.mts +2 -2
  17. package/dist/plugins/index.mjs +2 -2
  18. package/dist/query/primitives/coercion.d.mts +1 -1
  19. package/dist/query/primitives/coercion.mjs +1 -1
  20. package/dist/query/primitives/indexes.d.mts +1 -1
  21. package/dist/{sort-C-BJEWUZ.mjs → sort-ffe-9JBg.mjs} +19 -4
  22. package/dist/{types-DiQfDesD.d.mts → types-BgdeBXI1.d.mts} +68 -0
  23. package/dist/{update-AVfKWNGt.mjs → update-BDsQ3cdy.mjs} +2 -1
  24. package/dist/utils/index.d.mts +2 -2
  25. package/dist/utils/index.mjs +5 -4
  26. package/dist/{validation-chain.plugin-BsFzKVnO.d.mts → validation-chain.plugin-Be9rG04B.d.mts} +25 -2
  27. package/dist/{validation-chain.plugin-7A5qGEQq.mjs → validation-chain.plugin-CEyJssZl.mjs} +129 -17
  28. package/package.json +8 -3
  29. package/dist/error-Bpbi_NKo.mjs +0 -63
  30. /package/dist/{coercion-B19MD38s.d.mts → coercion-oM8G4b6m.d.mts} +0 -0
  31. /package/dist/{field-selection-C5o7jyyA.mjs → field-selection-dI0m4RBs.mjs} +0 -0
  32. /package/dist/{id-resolution-LZ-cCwR5.mjs → id-resolution-e4BT9zAV.mjs} +0 -0
  33. /package/dist/{indexes-qIBCZ3mY.d.mts → indexes-C26GNZRU.d.mts} +0 -0
package/dist/index.mjs CHANGED
@@ -1,13 +1,14 @@
1
- import { a as warn, n as parseDuplicateKeyError, r as configureLogger, t as createError } from "./error-Bpbi_NKo.mjs";
2
- import { y as LookupBuilder } from "./update-AVfKWNGt.mjs";
1
+ import { r as warn, t as configureLogger } from "./logger-DJ7egMnd.mjs";
2
+ import { y as LookupBuilder } from "./update-BDsQ3cdy.mjs";
3
+ import { n as parseDuplicateKeyError, t as createError } from "./error-Lw9GEAro.mjs";
3
4
  import { t as actions_exports } from "./actions/index.mjs";
4
- import { t as PaginationEngine } from "./PaginationEngine-CunXkR9p.mjs";
5
- import { A as auditTrailPlugin, C as HOOK_PRIORITY, D as AggregationBuilder, E as withTransaction, M as aggregateHelpersPlugin, O as batchOperationsPlugin, S as cachePlugin, T as isTransactionUnsupported, _ as dateSequentialId, a as uniqueField, b as sequentialId, c as subdocumentPlugin, d as multiTenantPlugin, f as mongoOperationsPlugin, g as customIdPlugin, h as elasticSearchPlugin, i as requireField, j as auditLogPlugin, k as AuditTrailQuery, l as softDeletePlugin, m as fieldFilterPlugin, n as blockIf, o as validationChainPlugin, p as methodRegistryPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as observabilityPlugin, v as getNextSequence, w as Repository, x as cascadePlugin, y as prefixedId } from "./validation-chain.plugin-7A5qGEQq.mjs";
5
+ import { t as PaginationEngine } from "./PaginationEngine-CPmZv7Ds.mjs";
6
+ import { A as AuditTrailQuery, C as cachePlugin, D as withTransaction, E as isTransactionUnsupported, M as auditLogPlugin, N as aggregateHelpersPlugin, O as AggregationBuilder, S as cascadePlugin, T as Repository, _ as customIdPlugin, a as uniqueField, b as prefixedId, c as createTenantContext, d as observabilityPlugin, f as multiTenantPlugin, g as elasticSearchPlugin, h as fieldFilterPlugin, i as requireField, j as auditTrailPlugin, k as batchOperationsPlugin, l as subdocumentPlugin, m as methodRegistryPlugin, n as blockIf, o as validationChainPlugin, p as mongoOperationsPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as dateSequentialId, w as HOOK_PRIORITY, x as sequentialId, y as getNextSequence } from "./validation-chain.plugin-CEyJssZl.mjs";
6
7
  import { isGeoOperator, parseGeoFilter } from "./query/primitives/geo.mjs";
7
- import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "./field-selection-C5o7jyyA.mjs";
8
+ import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "./field-selection-dI0m4RBs.mjs";
8
9
  import { buildFieldTypeMap, coerceFieldValue, coerceHeuristic } from "./query/primitives/coercion.mjs";
9
10
  import { extractSchemaIndexes } from "./query/primitives/indexes.mjs";
10
- import { a as isFieldUpdateAllowed, i as getSystemManagedFields, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-MlaD3C0B.mjs";
11
+ import { a as isFieldUpdateAllowed, i as getSystemManagedFields, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-DUwXPStK.mjs";
11
12
  //#region src/query/QueryParser.ts
12
13
  /**
13
14
  * Modern Query Parser
@@ -48,15 +49,47 @@ var QueryParser = class {
48
49
  */
49
50
  _schemaIndexes;
50
51
  /**
51
- * Regex patterns that can cause catastrophic backtracking (ReDoS attacks)
52
- * Detects:
52
+ * Regex patterns that can cause catastrophic backtracking (ReDoS attacks).
53
+ * Detects common footguns:
53
54
  * - Quantifiers: {n,m}
54
55
  * - Possessive quantifiers: *+, ++, ?+
55
56
  * - Nested quantifiers: (a+)+, (a*)*
56
57
  * - Backreferences: \1, \2, etc.
57
58
  * - Complex character classes: [...]...[...]
59
+ *
60
+ * This pattern detector is FAIL-SAFE (on match, the input is escaped), but
61
+ * it is not exhaustive. {@link _regexComplexityExceedsBudget} complements
62
+ * it with a deterministic static complexity budget so patterns that happen
63
+ * to evade the detector still fail over when their unbounded-quantifier
64
+ * density is pathological.
58
65
  */
59
66
  dangerousRegexPatterns = /(\{[0-9,]+\}|\*\+|\+\+|\?\+|(\(.+\))\+|\(\?:|\\[0-9]|(\[.+\]).+(\[.+\]))/;
67
+ /**
68
+ * Static complexity budget for user-supplied regex patterns.
69
+ * Returns `true` if the pattern crosses a budget that empirically correlates
70
+ * with ReDoS risk — independent of the heuristic regex detector.
71
+ *
72
+ * Budget components (any single threshold crossed → over budget):
73
+ * - unbounded quantifiers (`*`, `+`, `?`) — hard cap 20
74
+ * - nested groups `(` — hard cap 8
75
+ * - alternations `|` — hard cap 10
76
+ * - combined: (quantifiers * groups) — hard cap 40
77
+ *
78
+ * These thresholds are intentionally permissive for legitimate queries and
79
+ * tight enough to refuse known-pathological patterns like `(a+)+b` with
80
+ * heavy repetition.
81
+ */
82
+ _regexComplexityExceedsBudget(patternStr) {
83
+ const stripped = patternStr.replace(/\\[^\\]/g, "");
84
+ const unboundedQuantifiers = (stripped.match(/[*+?]/g) ?? []).length;
85
+ const groups = (stripped.match(/\(/g) ?? []).length;
86
+ const alternations = (stripped.match(/\|/g) ?? []).length;
87
+ if (unboundedQuantifiers > 20) return true;
88
+ if (groups > 8) return true;
89
+ if (alternations > 10) return true;
90
+ if (unboundedQuantifiers * groups > 40) return true;
91
+ return false;
92
+ }
60
93
  constructor(options = {}) {
61
94
  this.options = {
62
95
  maxRegexLength: options.maxRegexLength ?? 500,
@@ -770,6 +803,10 @@ var QueryParser = class {
770
803
  warn("[mongokit] Potentially dangerous regex pattern, escaping");
771
804
  return new RegExp(this._escapeRegex(patternStr), flags);
772
805
  }
806
+ if (this._regexComplexityExceedsBudget(patternStr)) {
807
+ warn("[mongokit] Regex complexity budget exceeded, escaping");
808
+ return new RegExp(this._escapeRegex(patternStr), flags);
809
+ }
773
810
  try {
774
811
  return new RegExp(patternStr, flags);
775
812
  } catch {
@@ -783,7 +820,11 @@ var QueryParser = class {
783
820
  * Sanitize $match configuration to prevent dangerous operators
784
821
  * Recursively filters out operators like $where, $function, $accumulator
785
822
  */
786
- _sanitizeMatchConfig(config) {
823
+ _sanitizeMatchConfig(config, depth = 0) {
824
+ if (depth > this.options.maxFilterDepth) {
825
+ warn(`[mongokit] $match sanitize depth ${depth} exceeds maximum ${this.options.maxFilterDepth}, truncating branch`);
826
+ return {};
827
+ }
787
828
  const sanitized = {};
788
829
  const logicalArrayOps = new Set([
789
830
  "$or",
@@ -795,10 +836,10 @@ var QueryParser = class {
795
836
  warn(`[mongokit] Blocked dangerous operator in aggregation: ${key}`);
796
837
  continue;
797
838
  }
798
- if (value && typeof value === "object" && !Array.isArray(value)) sanitized[key] = this._sanitizeMatchConfig(value);
839
+ if (value && typeof value === "object" && !Array.isArray(value)) sanitized[key] = this._sanitizeMatchConfig(value, depth + 1);
799
840
  else if (Array.isArray(value)) {
800
841
  const sanitizedArray = value.map((item) => {
801
- if (item && typeof item === "object" && !Array.isArray(item)) return this._sanitizeMatchConfig(item);
842
+ if (item && typeof item === "object" && !Array.isArray(item)) return this._sanitizeMatchConfig(item, depth + 1);
802
843
  return item;
803
844
  });
804
845
  if (logicalArrayOps.has(key)) {
@@ -945,4 +986,4 @@ function createRepository(Model, plugins = [], paginationConfig = {}, options =
945
986
  }
946
987
  var src_default = Repository;
947
988
  //#endregion
948
- export { AggregationBuilder, AuditTrailQuery, HOOK_PRIORITY, LookupBuilder, PaginationEngine, QueryParser, Repository, actions_exports as actions, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, configureLogger, createError, createFieldPreset, createMemoryCache, createRepository, customIdPlugin, dateSequentialId, src_default as default, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getImmutableFields, getMongooseProjection, getNextSequence, getSystemManagedFields, immutableField, isFieldUpdateAllowed, isTransactionUnsupported, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, parseDuplicateKeyError, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validateUpdateBody, validationChainPlugin, withTransaction };
989
+ export { AggregationBuilder, AuditTrailQuery, HOOK_PRIORITY, LookupBuilder, PaginationEngine, QueryParser, Repository, actions_exports as actions, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, configureLogger, createError, createFieldPreset, createMemoryCache, createRepository, createTenantContext, customIdPlugin, dateSequentialId, src_default as default, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getImmutableFields, getMongooseProjection, getNextSequence, getSystemManagedFields, immutableField, isFieldUpdateAllowed, isTransactionUnsupported, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, parseDuplicateKeyError, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validateUpdateBody, validationChainPlugin, withTransaction };
@@ -0,0 +1,30 @@
1
+ //#region src/utils/logger.ts
2
+ const noop = () => {};
3
+ let current = {
4
+ warn: console.warn.bind(console),
5
+ debug: noop
6
+ };
7
+ /**
8
+ * Configure the internal logger.
9
+ * Pass `false` to silence all output.
10
+ */
11
+ function configureLogger(config) {
12
+ if (config === false) current = {
13
+ warn: noop,
14
+ debug: noop
15
+ };
16
+ else current = {
17
+ ...current,
18
+ ...config
19
+ };
20
+ }
21
+ /** Emit a warning — security blocks, config issues, performance hints */
22
+ function warn(message, ...args) {
23
+ current.warn(message, ...args);
24
+ }
25
+ /** Emit debug info — only visible when debug is enabled */
26
+ function debug(message, ...args) {
27
+ current.debug(message, ...args);
28
+ }
29
+ //#endregion
30
+ export { debug as n, warn as r, configureLogger as t };
@@ -1,4 +1,4 @@
1
- import { n as isObjectIdInstance } from "./id-resolution-LZ-cCwR5.mjs";
1
+ import { n as isObjectIdInstance } from "./id-resolution-e4BT9zAV.mjs";
2
2
  import mongoose from "mongoose";
3
3
  //#region src/utils/memory-cache.ts
4
4
  /**
@@ -245,10 +245,10 @@ function buildJsonSchemaFromPaths(mongooseSchema, options) {
245
245
  }
246
246
  for (const [rootField, fieldPaths] of rootFields.entries()) if (fieldPaths.length === 1 && fieldPaths[0].path === rootField) {
247
247
  const schemaType = fieldPaths[0].schemaType;
248
- properties[rootField] = schemaTypeToJsonSchema(schemaType);
248
+ properties[rootField] = schemaTypeToJsonSchema(schemaType, options);
249
249
  if (schemaType.isRequired && !isSoftRequired(rootField, schemaType)) required.push(rootField);
250
250
  } else {
251
- const nestedSchema = buildNestedJsonSchema(fieldPaths, rootField);
251
+ const nestedSchema = buildNestedJsonSchema(fieldPaths, rootField, options);
252
252
  properties[rootField] = nestedSchema.schema;
253
253
  if (nestedSchema.required) required.push(rootField);
254
254
  }
@@ -271,14 +271,14 @@ function buildJsonSchemaFromPaths(mongooseSchema, options) {
271
271
  /**
272
272
  * Build nested JSON schema from dot-notation paths
273
273
  */
274
- function buildNestedJsonSchema(fieldPaths, rootField) {
274
+ function buildNestedJsonSchema(fieldPaths, rootField, options = {}) {
275
275
  const properties = {};
276
276
  const required = [];
277
277
  let hasRequiredFields = false;
278
278
  for (const { path, schemaType } of fieldPaths) {
279
279
  const parts = path.substring(rootField.length + 1).split(".");
280
280
  if (parts.length === 1) {
281
- properties[parts[0]] = schemaTypeToJsonSchema(schemaType);
281
+ properties[parts[0]] = schemaTypeToJsonSchema(schemaType, options);
282
282
  if (schemaType.isRequired) {
283
283
  required.push(parts[0]);
284
284
  hasRequiredFields = true;
@@ -292,7 +292,7 @@ function buildNestedJsonSchema(fieldPaths, rootField) {
292
292
  const nestedObj = properties[fieldName];
293
293
  if (!nestedObj.properties) nestedObj.properties = {};
294
294
  const deepPath = parts.slice(1).join(".");
295
- nestedObj.properties[deepPath] = schemaTypeToJsonSchema(schemaType);
295
+ nestedObj.properties[deepPath] = schemaTypeToJsonSchema(schemaType, options);
296
296
  }
297
297
  }
298
298
  const schema = {
@@ -324,10 +324,10 @@ function buildNestedJsonSchema(fieldPaths, rootField) {
324
324
  * `{ type: 'object', additionalProperties: true }` so we never block a
325
325
  * valid payload with the old `{ type: 'string' }` default.
326
326
  */
327
- function introspectArrayItems(schemaType) {
328
- if (hasInnerSchema(schemaType)) return subSchemaToJsonSchema(schemaType.schema);
327
+ function introspectArrayItems(schemaType, options = {}) {
328
+ if (hasInnerSchema(schemaType)) return subSchemaToJsonSchema(schemaType.schema, options);
329
329
  const caster = schemaType?.caster;
330
- if (caster && typeof caster === "object" && "instance" in caster && caster.instance) return schemaTypeToJsonSchema(caster);
330
+ if (caster && typeof caster === "object" && "instance" in caster && caster.instance) return schemaTypeToJsonSchema(caster, options);
331
331
  const declaredType = schemaType?.options?.type;
332
332
  if (Array.isArray(declaredType) && declaredType.length > 0) {
333
333
  const inner = declaredType[0];
@@ -335,7 +335,7 @@ function introspectArrayItems(schemaType) {
335
335
  type: "object",
336
336
  additionalProperties: true
337
337
  };
338
- return jsonTypeFor(inner, {}, /* @__PURE__ */ new WeakSet());
338
+ return jsonTypeFor(inner, options, /* @__PURE__ */ new WeakSet());
339
339
  }
340
340
  return {
341
341
  type: "object",
@@ -348,7 +348,7 @@ function introspectArrayItems(schemaType) {
348
348
  * does NOT apply create/update field rules — subdocument shape should faithfully
349
349
  * reflect the declared schema, not the top-level CRUD-mode omissions.
350
350
  */
351
- function subSchemaToJsonSchema(subSchema) {
351
+ function subSchemaToJsonSchema(subSchema, options = {}) {
352
352
  const properties = {};
353
353
  const required = [];
354
354
  const paths = subSchema.paths ?? {};
@@ -358,7 +358,7 @@ function subSchemaToJsonSchema(subSchema) {
358
358
  const instance = st.instance;
359
359
  if (!instance || isObjectIdInstance(instance)) continue;
360
360
  }
361
- properties[path] = schemaTypeToJsonSchema(st);
361
+ properties[path] = schemaTypeToJsonSchema(st, options);
362
362
  if (st.isRequired) required.push(path);
363
363
  }
364
364
  const result = {
@@ -371,7 +371,7 @@ function subSchemaToJsonSchema(subSchema) {
371
371
  /**
372
372
  * Convert Mongoose SchemaType to JSON Schema
373
373
  */
374
- function schemaTypeToJsonSchema(schemaType) {
374
+ function schemaTypeToJsonSchema(schemaType, builderOptions = {}) {
375
375
  if (typeof schemaType?.jsonSchema === "function") try {
376
376
  const custom = schemaType.jsonSchema();
377
377
  if (custom && typeof custom === "object") return custom;
@@ -400,16 +400,16 @@ function schemaTypeToJsonSchema(schemaType) {
400
400
  } else if (isObjectIdInstance(instance)) {
401
401
  result.type = "string";
402
402
  result.pattern = "^[0-9a-fA-F]{24}$";
403
- if (typeof options.ref === "string" && options.ref.length > 0) result["x-ref"] = options.ref;
403
+ if (builderOptions.openApiExtensions === true && typeof options.ref === "string" && options.ref.length > 0) result["x-ref"] = options.ref;
404
404
  } else if (instance === "Array") {
405
405
  result.type = "array";
406
- result.items = introspectArrayItems(schemaType);
406
+ result.items = introspectArrayItems(schemaType, builderOptions);
407
407
  } else if (instance === "Map") {
408
408
  result.type = "object";
409
409
  const ofDef = options.of;
410
410
  if (ofDef !== void 0 && ofDef !== null) result.additionalProperties = jsonTypeFor(ofDef, {}, /* @__PURE__ */ new WeakSet());
411
411
  else result.additionalProperties = true;
412
- } else if (hasInnerSchema(schemaType)) return subSchemaToJsonSchema(schemaType.schema);
412
+ } else if (hasInnerSchema(schemaType)) return subSchemaToJsonSchema(schemaType.schema, builderOptions);
413
413
  else {
414
414
  result.type = "object";
415
415
  result.additionalProperties = true;
@@ -511,10 +511,14 @@ function jsonTypeFor(def, options, seen) {
511
511
  additionalProperties: true
512
512
  };
513
513
  }
514
- if (isObjectIdType(typedDef.type)) return {
515
- type: "string",
516
- pattern: "^[0-9a-fA-F]{24}$"
517
- };
514
+ if (isObjectIdType(typedDef.type)) {
515
+ const objIdResult = {
516
+ type: "string",
517
+ pattern: "^[0-9a-fA-F]{24}$"
518
+ };
519
+ if (options?.openApiExtensions === true && typeof typedDef.ref === "string" && typedDef.ref.length > 0) objIdResult["x-ref"] = typedDef.ref;
520
+ return objIdResult;
521
+ }
518
522
  if (isMongooseSchema(typedDef.type)) {
519
523
  const obj = typedDef.type.obj;
520
524
  if (obj && typeof obj === "object") {
@@ -547,7 +551,7 @@ function jsonTypeFor(def, options, seen) {
547
551
  additionalProperties: true
548
552
  };
549
553
  seen.add(def);
550
- return subSchemaToJsonSchema(def);
554
+ return subSchemaToJsonSchema(def, options);
551
555
  }
552
556
  if (isPlainObject(def)) {
553
557
  if (seen.has(def)) return {
@@ -1,4 +1,4 @@
1
- import { T as FieldPreset, _ as CrudSchemas, k as HttpError, ot as SchemaBuilderOptions, s as CacheAdapter, xt as ValidationResult, yt as UserContext } from "./types-DiQfDesD.mjs";
1
+ import { T as FieldPreset, _ as CrudSchemas, k as HttpError, ot as SchemaBuilderOptions, s as CacheAdapter, xt as ValidationResult, yt as UserContext } from "./types-BgdeBXI1.mjs";
2
2
  import mongoose, { Schema } from "mongoose";
3
3
 
4
4
  //#region src/utils/error.d.ts
@@ -15,13 +15,29 @@ import mongoose, { Schema } from "mongoose";
15
15
  * throw createError(403, 'Access denied');
16
16
  */
17
17
  declare function createError(status: number, message: string): HttpError;
18
+ /** Options for parseDuplicateKeyError */
19
+ interface ParseDuplicateKeyOptions {
20
+ /**
21
+ * Include the offending values inline in the error message and under
22
+ * `error.duplicate.values`. Default is `false` because those values can be
23
+ * PII (emails, tokens, phone numbers) and end up in logs/crash reports.
24
+ * Enable in dev or for trusted internal tools only.
25
+ */
26
+ exposeValues?: boolean;
27
+ }
18
28
  /**
19
29
  * Detect and convert a MongoDB E11000 duplicate-key error into
20
30
  * a 409 HttpError with an actionable message.
21
31
  *
32
+ * PII-safe by default: the error message lists only the conflicting field
33
+ * names, never the values. Structured field names are attached under
34
+ * `error.duplicate.fields` for downstream handlers. Pass
35
+ * `{ exposeValues: true }` to opt into including the values (dev or trusted
36
+ * server-to-server contexts only).
37
+ *
22
38
  * Returns `null` when the error is not a duplicate-key error.
23
39
  */
24
- declare function parseDuplicateKeyError(error: unknown): HttpError | null;
40
+ declare function parseDuplicateKeyError(error: unknown, options?: ParseDuplicateKeyOptions): HttpError | null;
25
41
  //#endregion
26
42
  //#region src/utils/field-selection.d.ts
27
43
  /**
@@ -1,4 +1,4 @@
1
- import { F as KeysetPaginationResult, G as PaginationConfig, H as OffsetPaginationOptions, P as KeysetPaginationOptions, U as OffsetPaginationResult, a as AnyDocument, n as AggregatePaginationOptions, r as AggregatePaginationResult } from "../types-DiQfDesD.mjs";
1
+ import { F as KeysetPaginationResult, G as PaginationConfig, H as OffsetPaginationOptions, P as KeysetPaginationOptions, U as OffsetPaginationResult, a as AnyDocument, n as AggregatePaginationOptions, r as AggregatePaginationResult } from "../types-BgdeBXI1.mjs";
2
2
  import { Model } from "mongoose";
3
3
 
4
4
  //#region src/pagination/PaginationEngine.d.ts
@@ -11,6 +11,8 @@ interface ResolvedPaginationConfig {
11
11
  maxPage: number;
12
12
  deepPageThreshold: number;
13
13
  cursorVersion: number;
14
+ minCursorVersion: number;
15
+ strictKeysetSortFields: string[] | undefined;
14
16
  useEstimatedCount: boolean;
15
17
  }
16
18
  /**
@@ -1,2 +1,2 @@
1
- import { t as PaginationEngine } from "../PaginationEngine-CunXkR9p.mjs";
1
+ import { t as PaginationEngine } from "../PaginationEngine-CPmZv7Ds.mjs";
2
2
  export { PaginationEngine };
@@ -1,2 +1,2 @@
1
- import { A as dateSequentialId, B as AuditEntry, C as elasticSearchPlugin, D as PrefixedIdOptions, E as IdGenerator, F as CacheMethods, G as AuditTrailOptions, H as AuditQueryOptions, I as cachePlugin, J as auditLogPlugin, K as AuditTrailQuery, L as BatchOperationsMethods, M as prefixedId, N as sequentialId, O as SequentialIdOptions, P as cascadePlugin, S as ElasticSearchOptions, T as DateSequentialIdOptions, U as AuditQueryResult, V as AuditOperation, W as AuditTrailMethods, X as aggregateHelpersPlugin, Y as AggregateHelpersMethods, _ as MongoOperationsMethods, a as uniqueField, b as methodRegistryPlugin, c as SubdocumentMethods, d as softDeletePlugin, f as ObservabilityOptions, g as multiTenantPlugin, h as MultiTenantOptions, i as requireField, j as getNextSequence, k as customIdPlugin, l as subdocumentPlugin, m as observabilityPlugin, n as blockIf, o as validationChainPlugin, p as OperationMetric, q as auditTrailPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as SoftDeleteMethods, v as mongoOperationsPlugin, w as CustomIdOptions, x as fieldFilterPlugin, y as MethodRegistryRepository, z as batchOperationsPlugin } from "../validation-chain.plugin-BsFzKVnO.mjs";
2
- export { type AggregateHelpersMethods, type AuditEntry, type AuditOperation, type AuditQueryOptions, type AuditQueryResult, type AuditTrailMethods, type AuditTrailOptions, AuditTrailQuery, type BatchOperationsMethods, type CacheMethods, type CustomIdOptions, type DateSequentialIdOptions, type ElasticSearchOptions, type IdGenerator, type MethodRegistryRepository, type MongoOperationsMethods, type MultiTenantOptions, type ObservabilityOptions, type OperationMetric, type PrefixedIdOptions, type SequentialIdOptions, type SoftDeleteMethods, type SubdocumentMethods, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
1
+ import { $ as aggregateHelpersPlugin, A as PrefixedIdOptions, B as BatchOperationsMethods, C as methodRegistryPlugin, D as CustomIdOptions, E as elasticSearchPlugin, F as prefixedId, G as AuditQueryOptions, H as batchOperationsPlugin, I as sequentialId, J as AuditTrailOptions, K as AuditQueryResult, L as cascadePlugin, M as customIdPlugin, N as dateSequentialId, O as DateSequentialIdOptions, P as getNextSequence, Q as AggregateHelpersMethods, R as CacheMethods, S as MethodRegistryRepository, T as ElasticSearchOptions, U as AuditEntry, W as AuditOperation, X as auditTrailPlugin, Y as AuditTrailQuery, Z as auditLogPlugin, _ as observabilityPlugin, a as uniqueField, b as MongoOperationsMethods, c as TenantContext, d as SubdocumentMethods, f as subdocumentPlugin, g as OperationMetric, h as ObservabilityOptions, i as requireField, j as SequentialIdOptions, k as IdGenerator, l as TenantStore, m as softDeletePlugin, n as blockIf, o as validationChainPlugin, p as SoftDeleteMethods, q as AuditTrailMethods, r as immutableField, s as timestampPlugin, t as autoInject, u as createTenantContext, v as MultiTenantOptions, w as fieldFilterPlugin, x as mongoOperationsPlugin, y as multiTenantPlugin, z as cachePlugin } from "../validation-chain.plugin-Be9rG04B.mjs";
2
+ export { type AggregateHelpersMethods, type AuditEntry, type AuditOperation, type AuditQueryOptions, type AuditQueryResult, type AuditTrailMethods, type AuditTrailOptions, AuditTrailQuery, type BatchOperationsMethods, type CacheMethods, type CustomIdOptions, type DateSequentialIdOptions, type ElasticSearchOptions, type IdGenerator, type MethodRegistryRepository, type MongoOperationsMethods, type MultiTenantOptions, type ObservabilityOptions, type OperationMetric, type PrefixedIdOptions, type SequentialIdOptions, type SoftDeleteMethods, type SubdocumentMethods, type TenantContext, type TenantStore, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, createTenantContext, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
@@ -1,2 +1,2 @@
1
- import { A as auditTrailPlugin, M as aggregateHelpersPlugin, O as batchOperationsPlugin, S as cachePlugin, _ as dateSequentialId, a as uniqueField, b as sequentialId, c as subdocumentPlugin, d as multiTenantPlugin, f as mongoOperationsPlugin, g as customIdPlugin, h as elasticSearchPlugin, i as requireField, j as auditLogPlugin, k as AuditTrailQuery, l as softDeletePlugin, m as fieldFilterPlugin, n as blockIf, o as validationChainPlugin, p as methodRegistryPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as observabilityPlugin, v as getNextSequence, x as cascadePlugin, y as prefixedId } from "../validation-chain.plugin-7A5qGEQq.mjs";
2
- export { AuditTrailQuery, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
1
+ import { A as AuditTrailQuery, C as cachePlugin, M as auditLogPlugin, N as aggregateHelpersPlugin, S as cascadePlugin, _ as customIdPlugin, a as uniqueField, b as prefixedId, c as createTenantContext, d as observabilityPlugin, f as multiTenantPlugin, g as elasticSearchPlugin, h as fieldFilterPlugin, i as requireField, j as auditTrailPlugin, k as batchOperationsPlugin, l as subdocumentPlugin, m as methodRegistryPlugin, n as blockIf, o as validationChainPlugin, p as mongoOperationsPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as dateSequentialId, x as sequentialId, y as getNextSequence } from "../validation-chain.plugin-CEyJssZl.mjs";
2
+ export { AuditTrailQuery, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, createTenantContext, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
@@ -1,2 +1,2 @@
1
- import { a as coerceHeuristic, i as coerceFieldValue, n as SchemaPathsLike, o as coerceToType, r as buildFieldTypeMap, s as normalizeMongooseType, t as FieldType } from "../../coercion-B19MD38s.mjs";
1
+ import { a as coerceHeuristic, i as coerceFieldValue, n as SchemaPathsLike, o as coerceToType, r as buildFieldTypeMap, s as normalizeMongooseType, t as FieldType } from "../../coercion-oM8G4b6m.mjs";
2
2
  export { FieldType, SchemaPathsLike, buildFieldTypeMap, coerceFieldValue, coerceHeuristic, coerceToType, normalizeMongooseType };
@@ -1,4 +1,4 @@
1
- import { n as isObjectIdInstance } from "../../id-resolution-LZ-cCwR5.mjs";
1
+ import { n as isObjectIdInstance } from "../../id-resolution-e4BT9zAV.mjs";
2
2
  import mongoose from "mongoose";
3
3
  //#region src/query/primitives/coercion.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { n as SchemaIndexes, r as extractSchemaIndexes, t as IndexableSchema } from "../../indexes-qIBCZ3mY.mjs";
1
+ import { n as SchemaIndexes, r as extractSchemaIndexes, t as IndexableSchema } from "../../indexes-C26GNZRU.mjs";
2
2
  export { IndexableSchema, SchemaIndexes, extractSchemaIndexes };
@@ -21,21 +21,36 @@ function normalizeSort(sort) {
21
21
  return normalized;
22
22
  }
23
23
  /**
24
- * Validates and normalizes sort for keyset pagination
25
- * Auto-adds _id tie-breaker if needed
26
- * Ensures _id direction matches primary field
24
+ * Validates and normalizes sort for keyset pagination.
25
+ * Auto-adds `_id` tie-breaker if needed; ensures `_id` direction matches the
26
+ * primary field.
27
+ *
28
+ * **Known limitation (MongoDB mixed-type sort):** keyset pagination across a
29
+ * field that can hold both typed values (Date, Number) and `null`/`undefined`
30
+ * is lossy — `$lt/$gt` don't cross the type boundary in BSON comparison, so
31
+ * some docs at the null/non-null boundary are unreachable. If your sort field
32
+ * is nullable, either:
33
+ * - sort by `_id` alone (always safe), or
34
+ * - use `allowedPrimaryFields` to lock keyset sort to fields your schema
35
+ * guarantees non-null (see `PaginationConfig.strictKeysetSortFields`).
27
36
  *
28
37
  * @param sort - Sort specification
38
+ * @param allowedPrimaryFields - Optional allowlist of primary (non-_id) sort
39
+ * field names. When set, rejects sorts whose primary field isn't listed.
40
+ * `_id` is always allowed.
29
41
  * @returns Validated and normalized sort
30
42
  * @throws Error if sort is invalid for keyset pagination
31
43
  */
32
- function validateKeysetSort(sort) {
44
+ function validateKeysetSort(sort, allowedPrimaryFields) {
33
45
  const keys = Object.keys(sort);
34
46
  if (keys.length === 0) throw new Error("Keyset pagination requires at least one sort field");
35
47
  if (keys.length === 1 && keys[0] === "_id") return normalizeSort(sort);
36
48
  for (const key of keys) if (sort[key] !== 1 && sort[key] !== -1) throw new Error(`Invalid sort direction for "${key}": must be 1 or -1, got ${sort[key]}`);
37
49
  const nonIdKeys = keys.filter((k) => k !== "_id");
38
50
  const primaryDirection = sort[nonIdKeys[0]];
51
+ if (allowedPrimaryFields && allowedPrimaryFields.length > 0) {
52
+ for (const key of nonIdKeys) if (!allowedPrimaryFields.includes(key)) throw new Error(`Keyset sort field "${key}" is not in the strictKeysetSortFields allowlist. Allowed: ${allowedPrimaryFields.join(", ")}. (See PaginationConfig.strictKeysetSortFields — protects against lossy null/non-null keyset boundaries.)`);
53
+ }
39
54
  for (const key of nonIdKeys) if (sort[key] !== primaryDirection) throw new Error("All sort fields must share the same direction for keyset pagination");
40
55
  if (keys.includes("_id") && sort._id !== primaryDirection) throw new Error("_id direction must match primary field direction");
41
56
  if (!keys.includes("_id")) return normalizeSort({
@@ -570,6 +570,19 @@ interface RepositoryOptions {
570
570
  * Required for regex mode to take effect.
571
571
  */
572
572
  searchFields?: string[];
573
+ /**
574
+ * How to react to a plugin composition that is known to be unsafe.
575
+ * - 'warn' (default): log a warning via the configured logger.
576
+ * - 'throw': fail fast at construction time — recommended for production.
577
+ * - 'off': disable the check entirely.
578
+ *
579
+ * Checks currently enforced:
580
+ * - soft-delete must precede batch-operations (otherwise deleteMany /
581
+ * updateMany skip the soft-delete filter injection).
582
+ * - multi-tenant must precede cache (otherwise cache keys are computed
583
+ * before tenant scoping → cross-tenant cache poisoning risk).
584
+ */
585
+ pluginOrderChecks?: 'warn' | 'throw' | 'off';
573
586
  }
574
587
  /** Pagination configuration */
575
588
  interface PaginationConfig {
@@ -583,6 +596,27 @@ interface PaginationConfig {
583
596
  deepPageThreshold?: number;
584
597
  /** Cursor version for forward compatibility (default: 1) */
585
598
  cursorVersion?: number;
599
+ /**
600
+ * Minimum cursor version accepted. Bump alongside `cursorVersion` when a
601
+ * breaking format change ships so stale client cursors are rejected with a
602
+ * clear error instead of silently paginating from the wrong position.
603
+ * Default: 1 (accept any cursor <= cursorVersion).
604
+ */
605
+ minCursorVersion?: number;
606
+ /**
607
+ * Allowlist of primary sort fields for keyset pagination. When set, any
608
+ * `getAll({ sort })` whose primary (non-_id) field is not in this list
609
+ * throws at validation time.
610
+ *
611
+ * Use this to lock down keyset pagination to fields that are structurally
612
+ * guaranteed non-null in your schema — keyset sort across null/non-null
613
+ * boundaries is lossy (MongoDB's `$lt/$gt` semantics leave a gap at the
614
+ * type boundary, so not every doc is reachable).
615
+ *
616
+ * `_id` is always allowed regardless of this list.
617
+ * Undefined (default) = no allowlist, any sort field accepted.
618
+ */
619
+ strictKeysetSortFields?: string[];
586
620
  /** Use estimatedDocumentCount for faster counts on large collections */
587
621
  useEstimatedCount?: boolean;
588
622
  }
@@ -1079,6 +1113,19 @@ interface SchemaBuilderOptions {
1079
1113
  type: string;
1080
1114
  } | unknown>;
1081
1115
  };
1116
+ /**
1117
+ * Emit OpenAPI vendor extensions (`x-*` keywords like `x-ref` for populated
1118
+ * ObjectId fields). Default: `false`.
1119
+ *
1120
+ * Why opt-in: Ajv's strict mode THROWS on any `x-*` keyword it doesn't
1121
+ * recognize (`strict mode: unknown keyword: "x-ref"`). Consumers validating
1122
+ * request bodies with Ajv strict need a keyword-clean schema; consumers
1123
+ * generating OpenAPI documentation want the vendor extensions. Default is
1124
+ * OFF so Ajv-strict-mode consumers are safe out of the box. Turn ON to
1125
+ * include `x-ref` etc. in the output (typically when feeding the schema
1126
+ * into a docgen tool like @fastify/swagger or redocly).
1127
+ */
1128
+ openApiExtensions?: boolean;
1082
1129
  }
1083
1130
  /** JSON Schema type */
1084
1131
  interface JsonSchema {
@@ -1256,6 +1303,17 @@ interface CacheOptions {
1256
1303
  skipIf?: {
1257
1304
  largeLimit?: number;
1258
1305
  };
1306
+ /**
1307
+ * TTL jitter to mitigate cache stampedes. When many entries share the same
1308
+ * TTL and expire simultaneously, every concurrent reader misses and hammers
1309
+ * the DB at once. Jitter spreads expirations over a window.
1310
+ *
1311
+ * - `number` in [0, 1]: fractional symmetric jitter. `0.1` multiplies the
1312
+ * TTL by a random factor in [0.9, 1.1]. Default: 0 (no jitter).
1313
+ * - `function(ttl)`: full control — receive the configured TTL (seconds),
1314
+ * return the effective TTL (seconds) to store with.
1315
+ */
1316
+ jitter?: number | ((ttlSeconds: number) => number);
1259
1317
  }
1260
1318
  /** Options for cache-aware operations */
1261
1319
  interface CacheOperationOptions {
@@ -1312,6 +1370,16 @@ interface HttpError extends Error {
1312
1370
  validator: string;
1313
1371
  error: string;
1314
1372
  }>;
1373
+ /**
1374
+ * Structured metadata for duplicate-key (E11000) errors. Safe to surface in
1375
+ * logs/audit. Includes the offending field names and a boolean-only mirror
1376
+ * of whether each field had a duplicate value — never the value itself
1377
+ * unless `parseDuplicateKeyError` was called with `{ exposeValues: true }`.
1378
+ */
1379
+ duplicate?: {
1380
+ fields: string[]; /** Only populated when parseDuplicateKeyError was called with exposeValues:true. */
1381
+ values?: Record<string, unknown>;
1382
+ };
1315
1383
  }
1316
1384
  /**
1317
1385
  * Combines all plugin method types into a single type
@@ -1,5 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
2
- import { a as warn, t as createError } from "./error-Bpbi_NKo.mjs";
2
+ import { r as warn } from "./logger-DJ7egMnd.mjs";
3
+ import { t as createError } from "./error-Lw9GEAro.mjs";
3
4
  //#region src/query/LookupBuilder.ts
4
5
  /** Stages that are never valid inside a $lookup pipeline */
5
6
  const BLOCKED_PIPELINE_STAGES = [
@@ -1,5 +1,5 @@
1
- import { Z as PopulateSpec, pt as SortSpec, st as SelectSpec } from "../types-DiQfDesD.mjs";
2
- import { a as isFieldUpdateAllowed, c as configureLogger, d as getFieldsForUser, f as getMongooseProjection, i as getSystemManagedFields, l as createFieldPreset, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as createError, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as filterResponseData } from "../mongooseToJsonSchema-D2YjHo7W.mjs";
1
+ import { Z as PopulateSpec, pt as SortSpec, st as SelectSpec } from "../types-BgdeBXI1.mjs";
2
+ import { a as isFieldUpdateAllowed, c as configureLogger, d as getFieldsForUser, f as getMongooseProjection, i as getSystemManagedFields, l as createFieldPreset, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as createError, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as filterResponseData } from "../mongooseToJsonSchema-Du-UopRK.mjs";
3
3
 
4
4
  //#region src/utils/cache-keys.d.ts
5
5
  /**
@@ -1,5 +1,6 @@
1
- import { r as configureLogger, t as createError } from "../error-Bpbi_NKo.mjs";
2
- import { n as isObjectIdInstance, r as isValidIdForType, t as getSchemaIdType } from "../id-resolution-LZ-cCwR5.mjs";
3
- import { a as byIdKey, c as listQueryKey, i as getMongooseProjection, l as modelPattern, n as filterResponseData, o as byQueryKey, r as getFieldsForUser, s as listPattern, t as createFieldPreset, u as versionKey } from "../field-selection-C5o7jyyA.mjs";
4
- import { a as isFieldUpdateAllowed, i as getSystemManagedFields, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel } from "../mongooseToJsonSchema-MlaD3C0B.mjs";
1
+ import { t as configureLogger } from "../logger-DJ7egMnd.mjs";
2
+ import { t as createError } from "../error-Lw9GEAro.mjs";
3
+ import { n as isObjectIdInstance, r as isValidIdForType, t as getSchemaIdType } from "../id-resolution-e4BT9zAV.mjs";
4
+ import { a as byIdKey, c as listQueryKey, i as getMongooseProjection, l as modelPattern, n as filterResponseData, o as byQueryKey, r as getFieldsForUser, s as listPattern, t as createFieldPreset, u as versionKey } from "../field-selection-dI0m4RBs.mjs";
5
+ import { a as isFieldUpdateAllowed, i as getSystemManagedFields, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel } from "../mongooseToJsonSchema-DUwXPStK.mjs";
5
6
  export { buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, byIdKey, byQueryKey, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getImmutableFields, getMongooseProjection, getSchemaIdType, getSystemManagedFields, isFieldUpdateAllowed, isObjectIdInstance, isValidIdForType, listPattern, listQueryKey, modelPattern, validateUpdateBody, versionKey };
@@ -1,5 +1,6 @@
1
- import { I as Logger, J as Plugin, St as ValidatorDefinition, T as FieldPreset, U as OffsetPaginationResult, V as ObjectId, Z as PopulateSpec, bt as ValidationChainOptions, et as RepositoryContext, f as CascadeOptions, l as CacheOptions, nt as RepositoryInstance, pt as SortSpec, st as SelectSpec, u as CacheStats, ut as SoftDeleteOptions } from "./types-DiQfDesD.mjs";
1
+ import { I as Logger, J as Plugin, St as ValidatorDefinition, T as FieldPreset, U as OffsetPaginationResult, V as ObjectId, Z as PopulateSpec, bt as ValidationChainOptions, et as RepositoryContext, f as CascadeOptions, l as CacheOptions, nt as RepositoryInstance, pt as SortSpec, st as SelectSpec, u as CacheStats, ut as SoftDeleteOptions } from "./types-BgdeBXI1.mjs";
2
2
  import mongoose, { ClientSession } from "mongoose";
3
+ import { AsyncLocalStorage } from "node:async_hooks";
3
4
 
4
5
  //#region src/plugins/aggregate-helpers.plugin.d.ts
5
6
  /**
@@ -1062,6 +1063,28 @@ interface SubdocumentMethods<TDoc> {
1062
1063
  deleteSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, options?: Record<string, unknown>): Promise<TDoc>;
1063
1064
  }
1064
1065
  //#endregion
1066
+ //#region src/plugins/tenant-context.d.ts
1067
+ interface TenantStore {
1068
+ tenantId: string | undefined;
1069
+ [key: string]: unknown;
1070
+ }
1071
+ interface TenantContext {
1072
+ /** Run `fn` with the given tenant store active for its entire async tree. */
1073
+ run<T>(store: TenantStore, fn: () => T): T;
1074
+ /** Current tenant ID, or undefined if no context is active. */
1075
+ getTenantId(): string | undefined;
1076
+ /** Full store for the current context (use for extra per-request metadata). */
1077
+ getStore(): TenantStore | undefined;
1078
+ /**
1079
+ * Assert that a tenant context is active; throw otherwise.
1080
+ * Useful in hot paths where a missing tenant must fail loud, not silent.
1081
+ */
1082
+ requireTenantId(): string;
1083
+ /** Underlying AsyncLocalStorage — escape hatch for advanced composition. */
1084
+ readonly storage: AsyncLocalStorage<TenantStore>;
1085
+ }
1086
+ declare function createTenantContext(): TenantContext;
1087
+ //#endregion
1065
1088
  //#region src/plugins/timestamp.plugin.d.ts
1066
1089
  /**
1067
1090
  * Timestamp plugin that auto-injects timestamps
@@ -1110,4 +1133,4 @@ declare function immutableField(field: string): ValidatorDefinition;
1110
1133
  */
1111
1134
  declare function uniqueField(field: string, errorMessage?: string): ValidatorDefinition;
1112
1135
  //#endregion
1113
- export { dateSequentialId as A, AuditEntry as B, elasticSearchPlugin as C, PrefixedIdOptions as D, IdGenerator as E, CacheMethods as F, AuditTrailOptions as G, AuditQueryOptions as H, cachePlugin as I, auditLogPlugin as J, AuditTrailQuery as K, BatchOperationsMethods as L, prefixedId as M, sequentialId as N, SequentialIdOptions as O, cascadePlugin as P, BulkWriteResult as R, ElasticSearchOptions as S, DateSequentialIdOptions as T, AuditQueryResult as U, AuditOperation as V, AuditTrailMethods as W, aggregateHelpersPlugin as X, AggregateHelpersMethods as Y, MongoOperationsMethods as _, uniqueField as a, methodRegistryPlugin as b, SubdocumentMethods as c, softDeletePlugin as d, ObservabilityOptions as f, multiTenantPlugin as g, MultiTenantOptions as h, requireField as i, getNextSequence as j, customIdPlugin as k, subdocumentPlugin as l, observabilityPlugin as m, blockIf as n, validationChainPlugin as o, OperationMetric as p, auditTrailPlugin as q, immutableField as r, timestampPlugin as s, autoInject as t, SoftDeleteMethods as u, mongoOperationsPlugin as v, CustomIdOptions as w, fieldFilterPlugin as x, MethodRegistryRepository as y, batchOperationsPlugin as z };
1136
+ export { aggregateHelpersPlugin as $, PrefixedIdOptions as A, BatchOperationsMethods as B, methodRegistryPlugin as C, CustomIdOptions as D, elasticSearchPlugin as E, prefixedId as F, AuditQueryOptions as G, batchOperationsPlugin as H, sequentialId as I, AuditTrailOptions as J, AuditQueryResult as K, cascadePlugin as L, customIdPlugin as M, dateSequentialId as N, DateSequentialIdOptions as O, getNextSequence as P, AggregateHelpersMethods as Q, CacheMethods as R, MethodRegistryRepository as S, ElasticSearchOptions as T, AuditEntry as U, BulkWriteResult as V, AuditOperation as W, auditTrailPlugin as X, AuditTrailQuery as Y, auditLogPlugin as Z, observabilityPlugin as _, uniqueField as a, MongoOperationsMethods as b, TenantContext as c, SubdocumentMethods as d, subdocumentPlugin as f, OperationMetric as g, ObservabilityOptions as h, requireField as i, SequentialIdOptions as j, IdGenerator as k, TenantStore as l, softDeletePlugin as m, blockIf as n, validationChainPlugin as o, SoftDeleteMethods as p, AuditTrailMethods as q, immutableField as r, timestampPlugin as s, autoInject as t, createTenantContext as u, MultiTenantOptions as v, fieldFilterPlugin as w, mongoOperationsPlugin as x, multiTenantPlugin as y, cachePlugin as z };