@classytic/mongokit 3.6.4 → 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.
- package/dist/{PaginationEngine-CunXkR9p.mjs → PaginationEngine-CPmZv7Ds.mjs} +8 -5
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +1 -1
- package/dist/ai/index.d.mts +23 -1
- package/dist/ai/index.mjs +194 -12
- package/dist/{cursor-CHToazHy.mjs → cursor-DZ9JSoMM.mjs} +11 -7
- package/dist/error-Lw9GEAro.mjs +46 -0
- package/dist/{index-jzO5hMtF.d.mts → index-C-qZUqv8.d.mts} +1 -1
- package/dist/index.d.mts +31 -9
- package/dist/index.mjs +53 -12
- package/dist/logger-DJ7egMnd.mjs +30 -0
- package/dist/{mongooseToJsonSchema-BlfkI9LC.mjs → mongooseToJsonSchema-DUwXPStK.mjs} +1 -1
- package/dist/{mongooseToJsonSchema-BvD1NDl9.d.mts → mongooseToJsonSchema-Du-UopRK.d.mts} +18 -2
- package/dist/pagination/PaginationEngine.d.mts +3 -1
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/index.mjs +2 -2
- package/dist/query/primitives/coercion.d.mts +1 -1
- package/dist/query/primitives/coercion.mjs +1 -1
- package/dist/query/primitives/indexes.d.mts +1 -1
- package/dist/{sort-C-BJEWUZ.mjs → sort-ffe-9JBg.mjs} +19 -4
- package/dist/{types-BoH1qdHo.d.mts → types-BgdeBXI1.d.mts} +55 -0
- package/dist/{update-AVfKWNGt.mjs → update-BDsQ3cdy.mjs} +2 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +5 -4
- package/dist/{validation-chain.plugin-BXx6Ogpp.d.mts → validation-chain.plugin-Be9rG04B.d.mts} +25 -2
- package/dist/{validation-chain.plugin-7A5qGEQq.mjs → validation-chain.plugin-CEyJssZl.mjs} +129 -17
- package/package.json +8 -3
- package/dist/error-Bpbi_NKo.mjs +0 -63
- /package/dist/{coercion-B19MD38s.d.mts → coercion-oM8G4b6m.d.mts} +0 -0
- /package/dist/{field-selection-C5o7jyyA.mjs → field-selection-dI0m4RBs.mjs} +0 -0
- /package/dist/{id-resolution-LZ-cCwR5.mjs → id-resolution-e4BT9zAV.mjs} +0 -0
- /package/dist/{indexes-qIBCZ3mY.d.mts → indexes-C26GNZRU.d.mts} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { y as LookupBuilder } from "./update-
|
|
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-
|
|
5
|
-
import { A as
|
|
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-
|
|
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-
|
|
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 { T as FieldPreset, _ as CrudSchemas, k as HttpError, ot as SchemaBuilderOptions, s as CacheAdapter, xt as ValidationResult, yt as UserContext } from "./types-
|
|
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-
|
|
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-
|
|
1
|
+
import { t as PaginationEngine } from "../PaginationEngine-CPmZv7Ds.mjs";
|
|
2
2
|
export { PaginationEngine };
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
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 };
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
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-
|
|
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,2 +1,2 @@
|
|
|
1
|
-
import { n as SchemaIndexes, r as extractSchemaIndexes, t as IndexableSchema } from "../../indexes-
|
|
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
|
-
*
|
|
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
|
}
|
|
@@ -1269,6 +1303,17 @@ interface CacheOptions {
|
|
|
1269
1303
|
skipIf?: {
|
|
1270
1304
|
largeLimit?: number;
|
|
1271
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);
|
|
1272
1317
|
}
|
|
1273
1318
|
/** Options for cache-aware operations */
|
|
1274
1319
|
interface CacheOperationOptions {
|
|
@@ -1325,6 +1370,16 @@ interface HttpError extends Error {
|
|
|
1325
1370
|
validator: string;
|
|
1326
1371
|
error: string;
|
|
1327
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
|
+
};
|
|
1328
1383
|
}
|
|
1329
1384
|
/**
|
|
1330
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 {
|
|
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 = [
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Z as PopulateSpec, pt as SortSpec, st as SelectSpec } from "../types-
|
|
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-
|
|
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
|
/**
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { a as
|
|
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 };
|
package/dist/{validation-chain.plugin-BXx6Ogpp.d.mts → validation-chain.plugin-Be9rG04B.d.mts}
RENAMED
|
@@ -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-
|
|
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 {
|
|
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 };
|