@classytic/mongokit 3.1.6 → 3.2.1

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.
@@ -1,5 +1,5 @@
1
1
  import { PipelineStage, ClientSession, Model } from 'mongoose';
2
- import { A as AnyDocument, y as CreateOptions, k as ObjectId, x as OperationOptions, S as SelectSpec, e as PopulateSpec, f as SortSpec, l as UpdateOptions, E as UpdateWithValidationResult, B as UpdateManyResult, z as DeleteResult, a6 as GroupResult, a7 as MinMaxResult } from './types-B5Uv6Ak7.js';
2
+ import { A as AnyDocument, v as CreateOptions, j as ObjectId, u as OperationOptions, S as SelectSpec, e as PopulateSpec, f as SortSpec, U as UpdateOptions, y as UpdateWithValidationResult, x as UpdateManyResult, w as DeleteResult, a5 as GroupResult, a6 as MinMaxResult } from './types-Jni1KgkP.js';
3
3
 
4
4
  /**
5
5
  * LookupBuilder - MongoDB $lookup Utility
@@ -59,6 +59,8 @@ interface LookupOptions {
59
59
  options?: {
60
60
  session?: ClientSession;
61
61
  };
62
+ /** Sanitize pipeline stages (default: true). Set false only for trusted server-side pipelines */
63
+ sanitize?: boolean;
62
64
  }
63
65
  /**
64
66
  * Fluent builder for MongoDB $lookup aggregation stage
@@ -160,6 +162,15 @@ declare class LookupBuilder {
160
162
  * ```
161
163
  */
162
164
  static nested(lookups: LookupOptions[]): PipelineStage[];
165
+ /**
166
+ * Sanitize pipeline stages by blocking dangerous stages and operators.
167
+ * Used internally by build() and available for external use (e.g., aggregate.ts).
168
+ */
169
+ static sanitizePipeline(stages: PipelineStage[]): PipelineStage[];
170
+ /**
171
+ * Recursively remove dangerous operators from an expression object.
172
+ */
173
+ private static _sanitizeDeep;
163
174
  }
164
175
 
165
176
  /**
@@ -349,6 +360,7 @@ declare namespace update$1 {
349
360
  */
350
361
  declare function deleteById(Model: Model<any>, id: string | ObjectId, options?: {
351
362
  session?: ClientSession;
363
+ query?: Record<string, unknown>;
352
364
  }): Promise<DeleteResult>;
353
365
  /**
354
366
  * Delete many documents
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { i as PaginationResult, A as AnyDocument, j as PluginType, P as PaginationConfig, R as RepositoryOptions, k as ObjectId, S as SelectSpec, e as PopulateSpec, f as SortSpec$2, a as OffsetPaginationResult, b as KeysetPaginationResult, l as UpdateOptions, d as AggregatePaginationResult, W as WithTransactionOptions, m as RepositoryContext, H as HttpError } from './types-B5Uv6Ak7.js';
2
- export { c as AggregatePaginationOptions, ad as AllPluginMethods, n as AnyModel, C as CacheAdapter, a9 as CacheOperationOptions, a8 as CacheOptions, aa as CacheStats, ac as CascadeOptions, ab as CascadeRelation, v as CreateInput, y as CreateOptions, h as CrudSchemas, $ as DecodedCursor, D as DeepPartial, z as DeleteResult, X as EventHandlers, Y as EventPayload, Q as EventPhase, F as FieldPreset, Z as FieldRules, a6 as GroupResult, p as HookMode, I as InferDocument, q as InferRawDoc, _ as JsonSchema, t as KeysOfType, K as KeysetPaginationOptions, a2 as Logger, a7 as MinMaxResult, N as NonNullableFields, O as OffsetPaginationOptions, x as OperationOptions, r as PartialBy, G as Plugin, J as PluginFunction, T as RepositoryEvent, L as RepositoryInstance, M as RepositoryOperation, s as RequiredBy, g as SchemaBuilderOptions, a4 as SoftDeleteFilterMode, a3 as SoftDeleteOptions, a5 as SoftDeleteRepository, o as SortDirection, u as Strict, w as UpdateInput, B as UpdateManyResult, E as UpdateWithValidationResult, U as UserContext, a1 as ValidationChainOptions, V as ValidationResult, a0 as ValidatorDefinition, ae as WithPlugins } from './types-B5Uv6Ak7.js';
1
+ import { h as PaginationResult, A as AnyDocument, i as PluginType, P as PaginationConfig, R as RepositoryOptions, j as ObjectId, S as SelectSpec, e as PopulateSpec, f as SortSpec$2, a as OffsetPaginationResult, b as KeysetPaginationResult, U as UpdateOptions, d as AggregatePaginationResult, W as WithTransactionOptions, k as RepositoryContext, H as HttpError } from './types-Jni1KgkP.js';
2
+ export { c as AggregatePaginationOptions, ad as AllPluginMethods, l as AnyModel, a7 as CacheAdapter, a9 as CacheOperationOptions, a8 as CacheOptions, aa as CacheStats, ac as CascadeOptions, ab as CascadeRelation, C as CreateInput, v as CreateOptions, Z as CrudSchemas, _ as DecodedCursor, D as DeepPartial, w as DeleteResult, L as EventHandlers, M as EventPayload, G as EventPhase, Q as FieldPreset, T as FieldRules, a5 as GroupResult, n as HookMode, I as InferDocument, o as InferRawDoc, Y as JsonSchema, r as KeysOfType, K as KeysetPaginationOptions, a1 as Logger, a6 as MinMaxResult, N as NonNullableFields, O as OffsetPaginationOptions, u as OperationOptions, p as PartialBy, g as Plugin, B as PluginFunction, J as RepositoryEvent, E as RepositoryInstance, F as RepositoryOperation, q as RequiredBy, X as SchemaBuilderOptions, a3 as SoftDeleteFilterMode, a2 as SoftDeleteOptions, a4 as SoftDeleteRepository, m as SortDirection, s as Strict, t as UpdateInput, x as UpdateManyResult, y as UpdateWithValidationResult, z as UserContext, a0 as ValidationChainOptions, V as ValidationResult, $ as ValidatorDefinition, ae as WithPlugins } from './types-Jni1KgkP.js';
3
3
  import * as mongoose from 'mongoose';
4
- import { PipelineStage, Expression, Model, ClientSession, PopulateOptions } from 'mongoose';
4
+ import { PipelineStage, Model, Expression, ClientSession, PopulateOptions } from 'mongoose';
5
5
  import { PaginationEngine } from './pagination/PaginationEngine.js';
6
- import { L as LookupOptions, a as LookupBuilder } from './index-BXSSv1pW.js';
7
- export { i as actions } from './index-BXSSv1pW.js';
8
- export { AggregateHelpersMethods, BatchOperationsMethods, CacheMethods, MongoOperationsMethods, SoftDeleteMethods, SubdocumentMethods, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin } from './plugins/index.js';
9
- export { d as buildCrudSchemasFromModel, b as buildCrudSchemasFromMongooseSchema, j as createError, c as createFieldPreset, k as createMemoryCache, f as filterResponseData, g as getFieldsForUser, e as getImmutableFields, a as getMongooseProjection, h as getSystemManagedFields, i as isFieldUpdateAllowed, v as validateUpdateBody } from './mongooseToJsonSchema-Cc5AwuDu.js';
6
+ import { L as LookupOptions, a as LookupBuilder } from './index-BDn5fSTE.js';
7
+ export { i as actions } from './index-BDn5fSTE.js';
8
+ export { AggregateHelpersMethods, BatchOperationsMethods, CacheMethods, MongoOperationsMethods, MultiTenantOptions, ObservabilityOptions, OperationMetric, SoftDeleteMethods, SubdocumentMethods, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin } from './plugins/index.js';
9
+ export { d as buildCrudSchemasFromModel, b as buildCrudSchemasFromMongooseSchema, k as configureLogger, j as createError, c as createFieldPreset, l as createMemoryCache, f as filterResponseData, g as getFieldsForUser, e as getImmutableFields, a as getMongooseProjection, h as getSystemManagedFields, i as isFieldUpdateAllowed, v as validateUpdateBody } from './mongooseToJsonSchema-CaRF_bCN.js';
10
10
 
11
11
  /**
12
12
  * Framework-Agnostic Controller Interfaces
@@ -330,35 +330,28 @@ interface IResponseFormatter {
330
330
  paginated<T>(result: PaginationResult<T>): IControllerResponse<PaginationResult<T>>;
331
331
  }
332
332
 
333
- /**
334
- * AggregationBuilder - Fluent MongoDB Aggregation Pipeline Builder
335
- *
336
- * Modern, type-safe builder for complex MongoDB aggregations.
337
- * Supports MongoDB 6+ features with optimized query patterns.
338
- *
339
- * Features:
340
- * - Fluent, chainable API
341
- * - $lookup with custom field joins
342
- * - Faceted search
343
- * - Window functions ($setWindowFields)
344
- * - Atlas Search ($search)
345
- * - Union queries ($unionWith)
346
- * - Full aggregation operator support
347
- *
348
- * @example
349
- * ```typescript
350
- * const pipeline = new AggregationBuilder()
351
- * .match({ status: 'active' })
352
- * .lookup('departments', 'deptSlug', 'slug', 'department', true)
353
- * .sort({ createdAt: -1 })
354
- * .limit(50)
355
- * .project({ password: 0 })
356
- * .build();
357
- *
358
- * const results = await Model.aggregate(pipeline);
359
- * ```
360
- */
361
-
333
+ /** Options for $vectorSearch stage (Atlas only) */
334
+ interface VectorSearchOptions {
335
+ /** Atlas Search index name */
336
+ index: string;
337
+ /** Field path containing the vector embedding */
338
+ path: string;
339
+ /** Query vector to search against */
340
+ queryVector: number[];
341
+ /** Number of candidates to consider (higher = more accurate, slower) */
342
+ numCandidates?: number;
343
+ /** Max results to return */
344
+ limit: number;
345
+ /** Pre-filter documents before vector search */
346
+ filter?: Record<string, unknown>;
347
+ /** Use exact search instead of ANN (slower but precise) */
348
+ exact?: boolean;
349
+ }
350
+ /** Result from build() including execution options */
351
+ interface AggregationPlan {
352
+ pipeline: PipelineStage[];
353
+ allowDiskUse: boolean;
354
+ }
362
355
  type SortOrder = 1 | -1 | 'asc' | 'desc';
363
356
  type SortSpec$1 = Record<string, SortOrder>;
364
357
  type ProjectionSpec = Record<string, 0 | 1 | Expression>;
@@ -372,6 +365,7 @@ type GroupSpec = {
372
365
  */
373
366
  declare class AggregationBuilder {
374
367
  private pipeline;
368
+ private _diskUse;
375
369
  /**
376
370
  * Get the current pipeline
377
371
  */
@@ -380,6 +374,22 @@ declare class AggregationBuilder {
380
374
  * Build and return the final pipeline
381
375
  */
382
376
  build(): PipelineStage[];
377
+ /**
378
+ * Build pipeline with execution options (allowDiskUse, etc.)
379
+ */
380
+ plan(): AggregationPlan;
381
+ /**
382
+ * Build and execute the pipeline against a model
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * const results = await new AggregationBuilder()
387
+ * .match({ status: 'active' })
388
+ * .allowDiskUse()
389
+ * .exec(MyModel);
390
+ * ```
391
+ */
392
+ exec<T = unknown>(model: Model<any>, session?: mongoose.ClientSession): Promise<T[]>;
383
393
  /**
384
394
  * Reset the pipeline
385
395
  */
@@ -595,6 +605,19 @@ declare class AggregationBuilder {
595
605
  value?: unknown;
596
606
  }>;
597
607
  }): this;
608
+ /**
609
+ * Enable allowDiskUse for large aggregations that exceed 100MB memory limit
610
+ *
611
+ * @example
612
+ * ```typescript
613
+ * const results = await new AggregationBuilder()
614
+ * .match({ status: 'active' })
615
+ * .group({ _id: '$category', total: { $sum: '$amount' } })
616
+ * .allowDiskUse()
617
+ * .exec(Model);
618
+ * ```
619
+ */
620
+ allowDiskUse(enable?: boolean): this;
598
621
  /**
599
622
  * Paginate - Add skip and limit for offset-based pagination
600
623
  */
@@ -690,6 +713,33 @@ declare class AggregationBuilder {
690
713
  * $searchMeta - Get Atlas Search metadata (Atlas only)
691
714
  */
692
715
  searchMeta(options: Record<string, unknown>): this;
716
+ /**
717
+ * $vectorSearch - Semantic similarity search using vector embeddings (Atlas only)
718
+ *
719
+ * Requires an Atlas Vector Search index on the target field.
720
+ * Must be the first stage in the pipeline.
721
+ *
722
+ * @example
723
+ * ```typescript
724
+ * const results = await new AggregationBuilder()
725
+ * .vectorSearch({
726
+ * index: 'vector_index',
727
+ * path: 'embedding',
728
+ * queryVector: await getEmbedding('running shoes'),
729
+ * limit: 10,
730
+ * numCandidates: 100,
731
+ * filter: { category: 'footwear' }
732
+ * })
733
+ * .project({ embedding: 0, score: { $meta: 'vectorSearchScore' } })
734
+ * .exec(ProductModel);
735
+ * ```
736
+ */
737
+ vectorSearch(options: VectorSearchOptions): this;
738
+ /**
739
+ * Add vectorSearchScore as a field after $vectorSearch
740
+ * Convenience for `.addFields({ score: { $meta: 'vectorSearchScore' } })`
741
+ */
742
+ withVectorScore(fieldName?: string): this;
693
743
  /**
694
744
  * Create a builder from an existing pipeline
695
745
  */
@@ -748,6 +798,14 @@ declare class Repository<TDoc = AnyDocument> {
748
798
  * Register event listener
749
799
  */
750
800
  on(event: string, listener: HookListener): this;
801
+ /**
802
+ * Remove a specific event listener
803
+ */
804
+ off(event: string, listener: HookListener): this;
805
+ /**
806
+ * Remove all listeners for an event, or all listeners entirely
807
+ */
808
+ removeAllListeners(event?: string): this;
751
809
  /**
752
810
  * Emit event (sync - for backwards compatibility)
753
811
  */
@@ -974,9 +1032,36 @@ declare class Repository<TDoc = AnyDocument> {
974
1032
  */
975
1033
  buildLookup(from?: string): LookupBuilder;
976
1034
  /**
977
- * Execute callback within a transaction
1035
+ * Execute callback within a transaction with automatic retry on transient failures.
1036
+ *
1037
+ * Uses the MongoDB driver's `session.withTransaction()` which automatically retries
1038
+ * on `TransientTransactionError` and `UnknownTransactionCommitResult`.
1039
+ *
1040
+ * The callback always receives a `ClientSession`. When `allowFallback` is true
1041
+ * and the MongoDB deployment doesn't support transactions (e.g., standalone),
1042
+ * the callback runs without a transaction on the same session.
1043
+ *
1044
+ * @param callback - Receives a `ClientSession` to pass to repository operations
1045
+ * @param options.allowFallback - Run without transaction on standalone MongoDB (default: false)
1046
+ * @param options.onFallback - Called when falling back to non-transactional execution
1047
+ * @param options.transactionOptions - MongoDB driver transaction options (readConcern, writeConcern, etc.)
1048
+ *
1049
+ * @example
1050
+ * ```typescript
1051
+ * const result = await repo.withTransaction(async (session) => {
1052
+ * const order = await repo.create({ total: 100 }, { session });
1053
+ * await paymentRepo.create({ orderId: order._id }, { session });
1054
+ * return order;
1055
+ * });
1056
+ *
1057
+ * // With fallback for standalone/dev environments
1058
+ * await repo.withTransaction(callback, {
1059
+ * allowFallback: true,
1060
+ * onFallback: (err) => logger.warn('Running without transaction', err),
1061
+ * });
1062
+ * ```
978
1063
  */
979
- withTransaction<T>(callback: (session: ClientSession | null) => Promise<T>, options?: WithTransactionOptions): Promise<T>;
1064
+ withTransaction<T>(callback: (session: ClientSession) => Promise<T>, options?: WithTransactionOptions): Promise<T>;
980
1065
  private _isTransactionUnsupported;
981
1066
  /**
982
1067
  * Execute custom query with event emission
@@ -1057,9 +1142,11 @@ declare class Repository<TDoc = AnyDocument> {
1057
1142
  *
1058
1143
  * ### Lookup Security
1059
1144
  *
1060
- * Lookups are sanitized by default (collection whitelists, field validation,
1061
- * pipeline/let blocking). For maximum security, use per-collection field allowlists
1062
- * in your controller layer (see BaseController example).
1145
+ * Lookup pipelines are sanitized by default:
1146
+ * - Dangerous stages blocked ($out, $merge, $unionWith, $collStats, $currentOp, $listSessions)
1147
+ * - Dangerous operators blocked inside $match/$addFields/$set ($where, $function, $accumulator, $expr)
1148
+ * - Optional collection whitelist via `allowedLookupCollections`
1149
+ * For maximum security, use per-collection field allowlists in your controller layer.
1063
1150
  *
1064
1151
  * ### Filter Security
1065
1152
  *
@@ -1158,6 +1245,13 @@ interface QueryParserOptions {
1158
1245
  * @example ['name', 'description', 'sku', 'tags']
1159
1246
  */
1160
1247
  searchFields?: string[];
1248
+ /**
1249
+ * Whitelist of collection names allowed in lookups.
1250
+ * When set, only these collections can be used in $lookup stages.
1251
+ * When undefined, all collection names are allowed.
1252
+ * @example ['departments', 'categories', 'users']
1253
+ */
1254
+ allowedLookupCollections?: string[];
1161
1255
  }
1162
1256
  /**
1163
1257
  * Modern Query Parser
@@ -1280,6 +1374,17 @@ declare class QueryParser {
1280
1374
  * Recursively filters out operators like $where, $function, $accumulator
1281
1375
  */
1282
1376
  private _sanitizeMatchConfig;
1377
+ /**
1378
+ * Sanitize pipeline stages for use in $lookup.
1379
+ * Blocks dangerous stages ($out, $merge, etc.) and recursively sanitizes
1380
+ * operator expressions within $match, $addFields, and $set stages.
1381
+ */
1382
+ private _sanitizePipeline;
1383
+ /**
1384
+ * Recursively sanitize expression objects, blocking dangerous operators
1385
+ * like $where, $function, $accumulator inside $addFields/$set stages.
1386
+ */
1387
+ private _sanitizeExpressions;
1283
1388
  private _sanitizeSearch;
1284
1389
  /**
1285
1390
  * Build regex-based multi-field search filters