@classytic/mongokit 3.2.0 → 3.2.2

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 (48) hide show
  1. package/README.md +470 -193
  2. package/dist/actions/index.d.mts +9 -0
  3. package/dist/actions/index.mjs +15 -0
  4. package/dist/aggregate-BAi4Do-X.mjs +767 -0
  5. package/dist/aggregate-CCHI7F51.d.mts +269 -0
  6. package/dist/ai/index.d.mts +125 -0
  7. package/dist/ai/index.mjs +203 -0
  8. package/dist/cache-keys-C8Z9B5sw.mjs +204 -0
  9. package/dist/chunk-DQk6qfdC.mjs +18 -0
  10. package/dist/create-BuO6xt0v.mjs +55 -0
  11. package/dist/custom-id.plugin-B_zIs6gE.mjs +1818 -0
  12. package/dist/custom-id.plugin-BzZI4gnE.d.mts +893 -0
  13. package/dist/index.d.mts +1012 -0
  14. package/dist/index.mjs +1906 -0
  15. package/dist/limits-DsNeCx4D.mjs +299 -0
  16. package/dist/logger-D8ily-PP.mjs +51 -0
  17. package/dist/mongooseToJsonSchema-COdDEkIJ.mjs +317 -0
  18. package/dist/{mongooseToJsonSchema-CaRF_bCN.d.ts → mongooseToJsonSchema-Wbvjfwkn.d.mts} +16 -89
  19. package/dist/pagination/PaginationEngine.d.mts +93 -0
  20. package/dist/pagination/PaginationEngine.mjs +196 -0
  21. package/dist/plugins/index.d.mts +3 -0
  22. package/dist/plugins/index.mjs +3 -0
  23. package/dist/types-D-gploPr.d.mts +1241 -0
  24. package/dist/utils/{index.d.ts → index.d.mts} +14 -21
  25. package/dist/utils/index.mjs +5 -0
  26. package/package.json +21 -21
  27. package/dist/actions/index.d.ts +0 -3
  28. package/dist/actions/index.js +0 -5
  29. package/dist/ai/index.d.ts +0 -175
  30. package/dist/ai/index.js +0 -206
  31. package/dist/chunks/chunk-2ZN65ZOP.js +0 -93
  32. package/dist/chunks/chunk-44KXLGPO.js +0 -388
  33. package/dist/chunks/chunk-DEVXDBRL.js +0 -1226
  34. package/dist/chunks/chunk-I7CWNAJB.js +0 -46
  35. package/dist/chunks/chunk-JWUAVZ3L.js +0 -8
  36. package/dist/chunks/chunk-UE2IEXZJ.js +0 -306
  37. package/dist/chunks/chunk-URLJFIR7.js +0 -22
  38. package/dist/chunks/chunk-VWKIKZYF.js +0 -737
  39. package/dist/chunks/chunk-WSFCRVEQ.js +0 -7
  40. package/dist/index-BDn5fSTE.d.ts +0 -516
  41. package/dist/index.d.ts +0 -1422
  42. package/dist/index.js +0 -1893
  43. package/dist/pagination/PaginationEngine.d.ts +0 -117
  44. package/dist/pagination/PaginationEngine.js +0 -3
  45. package/dist/plugins/index.d.ts +0 -922
  46. package/dist/plugins/index.js +0 -6
  47. package/dist/types-Jni1KgkP.d.ts +0 -780
  48. package/dist/utils/index.js +0 -5
@@ -0,0 +1,1012 @@
1
+ import { $ as SchemaBuilderOptions, A as KeysetPaginationOptions, B as PaginationResult, C as GroupResult, D as InferRawDoc, E as InferDocument, F as ObjectId, G as PopulateSpec, H as Plugin, I as OffsetPaginationOptions, J as RepositoryEvent, K as ReadPreferenceType, L as OffsetPaginationResult, M as Logger, N as MinMaxResult, O as JsonSchema, P as NonNullableFields, Q as RequiredBy, R as OperationOptions, S as FieldRules, St as LookupOptions, T as HttpError, U as PluginFunction, V as PartialBy, W as PluginType, X as RepositoryOperation, Y as RepositoryInstance, Z as RepositoryOptions, _ as DeleteResult, _t as IController, a as AnyModel, at as SortSpec, b as EventPhase, bt as IResponseFormatter, c as CacheOptions, ct as UpdateManyResult, d as CascadeRelation, dt as UserContext, et as SelectSpec, f as CreateInput, ft as ValidationChainOptions, g as DeepPartial, gt as WithTransactionOptions, h as DecodedCursor, ht as WithPlugins, i as AnyDocument, it as SortDirection, j as KeysetPaginationResult, k as KeysOfType, l as CacheStats, lt as UpdateOptions, m as CrudSchemas, mt as ValidatorDefinition, n as AggregatePaginationResult, nt as SoftDeleteOptions, o as CacheAdapter, ot as Strict, p as CreateOptions, pt as ValidationResult, q as RepositoryContext, r as AllPluginMethods, rt as SoftDeleteRepository, s as CacheOperationOptions, st as UpdateInput, t as AggregatePaginationOptions, tt as SoftDeleteFilterMode, u as CascadeOptions, ut as UpdateWithValidationResult, v as EventHandlers, vt as IControllerResponse, w as HookMode, x as FieldPreset, xt as LookupBuilder, y as EventPayload, yt as IRequestContext, z as PaginationConfig } from "./types-D-gploPr.mjs";
2
+ import "./aggregate-CCHI7F51.mjs";
3
+ import { t as index_d_exports } from "./actions/index.mjs";
4
+ import { PaginationEngine } from "./pagination/PaginationEngine.mjs";
5
+ import { A as blockIf, B as timestampPlugin, C as AggregateHelpersMethods, D as MongoOperationsMethods, E as batchOperationsPlugin, I as methodRegistryPlugin, L as SoftDeleteMethods, M as requireField, N as uniqueField, O as mongoOperationsPlugin, P as validationChainPlugin, R as softDeletePlugin, S as subdocumentPlugin, T as BatchOperationsMethods, V as fieldFilterPlugin, _ as multiTenantPlugin, a as SequentialIdOptions, b as cachePlugin, c as getNextSequence, d as ElasticSearchOptions, f as elasticSearchPlugin, g as MultiTenantOptions, h as observabilityPlugin, i as PrefixedIdOptions, j as immutableField, k as autoInject, l as prefixedId, m as OperationMetric, n as DateSequentialIdOptions, o as customIdPlugin, p as ObservabilityOptions, r as IdGenerator, s as dateSequentialId, t as CustomIdOptions, u as sequentialId, v as cascadePlugin, w as aggregateHelpersPlugin, x as SubdocumentMethods, y as CacheMethods, z as auditLogPlugin } from "./custom-id.plugin-BzZI4gnE.mjs";
6
+ import { a as isFieldUpdateAllowed, c as configureLogger, d as filterResponseData, f as getFieldsForUser, i as getSystemManagedFields, l as createError, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as getMongooseProjection, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as createFieldPreset } from "./mongooseToJsonSchema-Wbvjfwkn.mjs";
7
+ import * as mongoose$1 from "mongoose";
8
+ import { ClientSession, Expression, Model, PipelineStage, PopulateOptions } from "mongoose";
9
+
10
+ //#region src/query/AggregationBuilder.d.ts
11
+ /** Options for $vectorSearch stage (Atlas only) */
12
+ interface VectorSearchOptions {
13
+ /** Atlas Search index name */
14
+ index: string;
15
+ /** Field path containing the vector embedding */
16
+ path: string;
17
+ /** Query vector to search against */
18
+ queryVector: number[];
19
+ /** Number of candidates to consider (higher = more accurate, slower) */
20
+ numCandidates?: number;
21
+ /** Max results to return */
22
+ limit: number;
23
+ /** Pre-filter documents before vector search */
24
+ filter?: Record<string, unknown>;
25
+ /** Use exact search instead of ANN (slower but precise) */
26
+ exact?: boolean;
27
+ }
28
+ /** Result from build() including execution options */
29
+ interface AggregationPlan {
30
+ pipeline: PipelineStage[];
31
+ allowDiskUse: boolean;
32
+ }
33
+ type SortOrder = 1 | -1 | 'asc' | 'desc';
34
+ type SortSpec$2 = Record<string, SortOrder>;
35
+ type ProjectionSpec = Record<string, 0 | 1 | Expression>;
36
+ type GroupSpec = {
37
+ _id: string | Record<string, unknown> | null;
38
+ [key: string]: unknown;
39
+ };
40
+ /**
41
+ * Fluent builder for MongoDB aggregation pipelines
42
+ * Optimized for complex queries at scale
43
+ */
44
+ declare class AggregationBuilder {
45
+ private pipeline;
46
+ private _diskUse;
47
+ /**
48
+ * Get the current pipeline
49
+ */
50
+ get(): PipelineStage[];
51
+ /**
52
+ * Build and return the final pipeline
53
+ */
54
+ build(): PipelineStage[];
55
+ /**
56
+ * Build pipeline with execution options (allowDiskUse, etc.)
57
+ */
58
+ plan(): AggregationPlan;
59
+ /**
60
+ * Build and execute the pipeline against a model
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const results = await new AggregationBuilder()
65
+ * .match({ status: 'active' })
66
+ * .allowDiskUse()
67
+ * .exec(MyModel);
68
+ * ```
69
+ */
70
+ exec<T = unknown>(model: Model<any>, session?: mongoose$1.ClientSession): Promise<T[]>;
71
+ /**
72
+ * Reset the pipeline
73
+ */
74
+ reset(): this;
75
+ /**
76
+ * Add a raw pipeline stage
77
+ */
78
+ addStage(stage: PipelineStage): this;
79
+ /**
80
+ * Add multiple raw pipeline stages
81
+ */
82
+ addStages(stages: PipelineStage[]): this;
83
+ /**
84
+ * $match - Filter documents
85
+ * IMPORTANT: Place $match as early as possible for performance
86
+ */
87
+ match(query: Record<string, unknown>): this;
88
+ /**
89
+ * $project - Include/exclude fields or compute new fields
90
+ */
91
+ project(projection: ProjectionSpec): this;
92
+ /**
93
+ * $group - Group documents and compute aggregations
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * .group({
98
+ * _id: '$department',
99
+ * count: { $sum: 1 },
100
+ * avgSalary: { $avg: '$salary' }
101
+ * })
102
+ * ```
103
+ */
104
+ group(groupSpec: GroupSpec): this;
105
+ /**
106
+ * $sort - Sort documents
107
+ */
108
+ sort(sortSpec: SortSpec$2 | string): this;
109
+ /**
110
+ * $limit - Limit number of documents
111
+ */
112
+ limit(count: number): this;
113
+ /**
114
+ * $skip - Skip documents
115
+ */
116
+ skip(count: number): this;
117
+ /**
118
+ * $unwind - Deconstruct array field
119
+ */
120
+ unwind(path: string, preserveNullAndEmptyArrays?: boolean): this;
121
+ /**
122
+ * $addFields - Add new fields or replace existing fields
123
+ */
124
+ addFields(fields: Record<string, unknown>): this;
125
+ /**
126
+ * $set - Alias for $addFields
127
+ */
128
+ set(fields: Record<string, unknown>): this;
129
+ /**
130
+ * $unset - Remove fields
131
+ */
132
+ unset(fields: string | string[]): this;
133
+ /**
134
+ * $replaceRoot - Replace the root document
135
+ */
136
+ replaceRoot(newRoot: string | Record<string, unknown>): this;
137
+ /**
138
+ * $lookup - Join with another collection (simple form)
139
+ *
140
+ * @param from - Collection to join with
141
+ * @param localField - Field from source collection
142
+ * @param foreignField - Field from target collection
143
+ * @param as - Output field name
144
+ * @param single - Unwrap array to single object
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * // Join employees with departments by slug
149
+ * .lookup('departments', 'deptSlug', 'slug', 'department', true)
150
+ * ```
151
+ */
152
+ lookup(from: string, localField: string, foreignField: string, as?: string, single?: boolean): this;
153
+ /**
154
+ * $lookup - Join with another collection (advanced form with pipeline)
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * .lookupWithPipeline({
159
+ * from: 'products',
160
+ * localField: 'productIds',
161
+ * foreignField: 'sku',
162
+ * as: 'products',
163
+ * pipeline: [
164
+ * { $match: { status: 'active' } },
165
+ * { $project: { name: 1, price: 1 } }
166
+ * ]
167
+ * })
168
+ * ```
169
+ */
170
+ lookupWithPipeline(options: LookupOptions): this;
171
+ /**
172
+ * Multiple lookups at once
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * .multiLookup([
177
+ * { from: 'departments', localField: 'deptSlug', foreignField: 'slug', single: true },
178
+ * { from: 'managers', localField: 'managerId', foreignField: '_id', single: true }
179
+ * ])
180
+ * ```
181
+ */
182
+ multiLookup(lookups: LookupOptions[]): this;
183
+ /**
184
+ * $facet - Process multiple aggregation pipelines in a single stage
185
+ * Useful for computing multiple aggregations in parallel
186
+ *
187
+ * @example
188
+ * ```typescript
189
+ * .facet({
190
+ * totalCount: [{ $count: 'count' }],
191
+ * avgPrice: [{ $group: { _id: null, avg: { $avg: '$price' } } }],
192
+ * topProducts: [{ $sort: { sales: -1 } }, { $limit: 10 }]
193
+ * })
194
+ * ```
195
+ */
196
+ facet(facets: Record<string, PipelineStage[]>): this;
197
+ /**
198
+ * $bucket - Categorize documents into buckets
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * .bucket({
203
+ * groupBy: '$price',
204
+ * boundaries: [0, 50, 100, 200],
205
+ * default: 'Other',
206
+ * output: {
207
+ * count: { $sum: 1 },
208
+ * products: { $push: '$name' }
209
+ * }
210
+ * })
211
+ * ```
212
+ */
213
+ bucket(options: {
214
+ groupBy: string | Expression;
215
+ boundaries: unknown[];
216
+ default?: string;
217
+ output?: Record<string, unknown>;
218
+ }): this;
219
+ /**
220
+ * $bucketAuto - Automatically determine bucket boundaries
221
+ */
222
+ bucketAuto(options: {
223
+ groupBy: string | Expression;
224
+ buckets: number;
225
+ output?: Record<string, unknown>;
226
+ granularity?: string;
227
+ }): this;
228
+ /**
229
+ * $setWindowFields - Perform window functions (MongoDB 5.0+)
230
+ * Useful for rankings, running totals, moving averages
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * .setWindowFields({
235
+ * partitionBy: '$department',
236
+ * sortBy: { salary: -1 },
237
+ * output: {
238
+ * rank: { $rank: {} },
239
+ * runningTotal: { $sum: '$salary', window: { documents: ['unbounded', 'current'] } }
240
+ * }
241
+ * })
242
+ * ```
243
+ */
244
+ setWindowFields(options: {
245
+ partitionBy?: string | Expression;
246
+ sortBy?: SortSpec$2;
247
+ output: Record<string, unknown>;
248
+ }): this;
249
+ /**
250
+ * $unionWith - Combine results from multiple collections (MongoDB 4.4+)
251
+ *
252
+ * @example
253
+ * ```typescript
254
+ * .unionWith({
255
+ * coll: 'archivedOrders',
256
+ * pipeline: [{ $match: { year: 2024 } }]
257
+ * })
258
+ * ```
259
+ */
260
+ unionWith(options: {
261
+ coll: string;
262
+ pipeline?: PipelineStage[];
263
+ }): this;
264
+ /**
265
+ * $densify - Fill gaps in data (MongoDB 5.1+)
266
+ * Useful for time series data with missing points
267
+ */
268
+ densify(options: {
269
+ field: string;
270
+ range: {
271
+ step: number;
272
+ unit?: 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
273
+ bounds: 'full' | 'partition' | [unknown, unknown];
274
+ };
275
+ }): this;
276
+ /**
277
+ * $fill - Fill null or missing field values (MongoDB 5.3+)
278
+ */
279
+ fill(options: {
280
+ sortBy?: SortSpec$2;
281
+ output: Record<string, {
282
+ method: 'linear' | 'locf' | 'value';
283
+ value?: unknown;
284
+ }>;
285
+ }): this;
286
+ /**
287
+ * Enable allowDiskUse for large aggregations that exceed 100MB memory limit
288
+ *
289
+ * @example
290
+ * ```typescript
291
+ * const results = await new AggregationBuilder()
292
+ * .match({ status: 'active' })
293
+ * .group({ _id: '$category', total: { $sum: '$amount' } })
294
+ * .allowDiskUse()
295
+ * .exec(Model);
296
+ * ```
297
+ */
298
+ allowDiskUse(enable?: boolean): this;
299
+ /**
300
+ * Paginate - Add skip and limit for offset-based pagination
301
+ */
302
+ paginate(page: number, limit: number): this;
303
+ /**
304
+ * Count total documents (useful with $facet for pagination metadata)
305
+ */
306
+ count(outputField?: string): this;
307
+ /**
308
+ * Sample - Randomly select N documents
309
+ */
310
+ sample(size: number): this;
311
+ /**
312
+ * Out - Write results to a collection
313
+ */
314
+ out(collection: string): this;
315
+ /**
316
+ * Merge - Merge results into a collection
317
+ */
318
+ merge(options: string | {
319
+ into: string;
320
+ on?: string | string[];
321
+ whenMatched?: string;
322
+ whenNotMatched?: string;
323
+ }): this;
324
+ /**
325
+ * GeoNear - Perform geospatial queries
326
+ */
327
+ geoNear(options: {
328
+ near: {
329
+ type: 'Point';
330
+ coordinates: [number, number];
331
+ };
332
+ distanceField: string;
333
+ maxDistance?: number;
334
+ query?: Record<string, unknown>;
335
+ spherical?: boolean;
336
+ }): this;
337
+ /**
338
+ * GraphLookup - Perform recursive search (graph traversal)
339
+ */
340
+ graphLookup(options: {
341
+ from: string;
342
+ startWith: string | Expression;
343
+ connectFromField: string;
344
+ connectToField: string;
345
+ as: string;
346
+ maxDepth?: number;
347
+ depthField?: string;
348
+ restrictSearchWithMatch?: Record<string, unknown>;
349
+ }): this;
350
+ /**
351
+ * $search - Atlas Search full-text search (Atlas only)
352
+ *
353
+ * @example
354
+ * ```typescript
355
+ * .search({
356
+ * index: 'default',
357
+ * text: {
358
+ * query: 'laptop computer',
359
+ * path: ['title', 'description'],
360
+ * fuzzy: { maxEdits: 2 }
361
+ * }
362
+ * })
363
+ * ```
364
+ */
365
+ search(options: {
366
+ index?: string;
367
+ text?: {
368
+ query: string;
369
+ path: string | string[];
370
+ fuzzy?: {
371
+ maxEdits?: number;
372
+ prefixLength?: number;
373
+ };
374
+ score?: {
375
+ boost?: {
376
+ value?: number;
377
+ };
378
+ };
379
+ };
380
+ compound?: {
381
+ must?: unknown[];
382
+ mustNot?: unknown[];
383
+ should?: unknown[];
384
+ filter?: unknown[];
385
+ };
386
+ autocomplete?: unknown;
387
+ near?: unknown;
388
+ range?: unknown;
389
+ }): this;
390
+ /**
391
+ * $searchMeta - Get Atlas Search metadata (Atlas only)
392
+ */
393
+ searchMeta(options: Record<string, unknown>): this;
394
+ /**
395
+ * $vectorSearch - Semantic similarity search using vector embeddings (Atlas only)
396
+ *
397
+ * Requires an Atlas Vector Search index on the target field.
398
+ * Must be the first stage in the pipeline.
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * const results = await new AggregationBuilder()
403
+ * .vectorSearch({
404
+ * index: 'vector_index',
405
+ * path: 'embedding',
406
+ * queryVector: await getEmbedding('running shoes'),
407
+ * limit: 10,
408
+ * numCandidates: 100,
409
+ * filter: { category: 'footwear' }
410
+ * })
411
+ * .project({ embedding: 0, score: { $meta: 'vectorSearchScore' } })
412
+ * .exec(ProductModel);
413
+ * ```
414
+ */
415
+ vectorSearch(options: VectorSearchOptions): this;
416
+ /**
417
+ * Add vectorSearchScore as a field after $vectorSearch
418
+ * Convenience for `.addFields({ score: { $meta: 'vectorSearchScore' } })`
419
+ */
420
+ withVectorScore(fieldName?: string): this;
421
+ /**
422
+ * Create a builder from an existing pipeline
423
+ */
424
+ static from(pipeline: PipelineStage[]): AggregationBuilder;
425
+ /**
426
+ * Create a builder with initial match stage
427
+ */
428
+ static startWith(query: Record<string, unknown>): AggregationBuilder;
429
+ }
430
+ //#endregion
431
+ //#region src/Repository.d.ts
432
+ type HookListener = (data: any) => void | Promise<void>;
433
+ /**
434
+ * Production-grade repository for MongoDB
435
+ * Event-driven, plugin-based, with smart pagination
436
+ */
437
+ declare class Repository<TDoc = AnyDocument> {
438
+ readonly Model: Model<TDoc>;
439
+ readonly model: string;
440
+ readonly _hooks: Map<string, HookListener[]>;
441
+ readonly _pagination: PaginationEngine<TDoc>;
442
+ private readonly _hookMode;
443
+ [key: string]: unknown;
444
+ private _hasTextIndex;
445
+ constructor(Model: Model<TDoc, any, any, any>, plugins?: PluginType[], paginationConfig?: PaginationConfig, options?: RepositoryOptions);
446
+ /**
447
+ * Register a plugin
448
+ */
449
+ use(plugin: PluginType): this;
450
+ /**
451
+ * Register event listener
452
+ */
453
+ on(event: string, listener: HookListener): this;
454
+ /**
455
+ * Remove a specific event listener
456
+ */
457
+ off(event: string, listener: HookListener): this;
458
+ /**
459
+ * Remove all listeners for an event, or all listeners entirely
460
+ */
461
+ removeAllListeners(event?: string): this;
462
+ /**
463
+ * Emit event (sync - for backwards compatibility)
464
+ */
465
+ emit(event: string, data: unknown): void;
466
+ /**
467
+ * Emit event and await all async handlers
468
+ */
469
+ emitAsync(event: string, data: unknown): Promise<void>;
470
+ private _emitHook;
471
+ private _emitErrorHook;
472
+ /**
473
+ * Create single document
474
+ */
475
+ create(data: Record<string, unknown>, options?: {
476
+ session?: ClientSession;
477
+ }): Promise<TDoc>;
478
+ /**
479
+ * Create multiple documents
480
+ */
481
+ createMany(dataArray: Record<string, unknown>[], options?: {
482
+ session?: ClientSession;
483
+ ordered?: boolean;
484
+ }): Promise<TDoc[]>;
485
+ /**
486
+ * Get document by ID
487
+ */
488
+ getById(id: string | ObjectId, options?: {
489
+ select?: SelectSpec;
490
+ populate?: PopulateSpec;
491
+ populateOptions?: PopulateOptions[];
492
+ lean?: boolean;
493
+ session?: ClientSession;
494
+ throwOnNotFound?: boolean;
495
+ skipCache?: boolean;
496
+ cacheTtl?: number;
497
+ readPreference?: ReadPreferenceType;
498
+ }): Promise<TDoc | null>;
499
+ /**
500
+ * Get single document by query
501
+ */
502
+ getByQuery(query: Record<string, unknown>, options?: {
503
+ select?: SelectSpec;
504
+ populate?: PopulateSpec;
505
+ populateOptions?: PopulateOptions[];
506
+ lean?: boolean;
507
+ session?: ClientSession;
508
+ throwOnNotFound?: boolean;
509
+ skipCache?: boolean;
510
+ cacheTtl?: number;
511
+ readPreference?: ReadPreferenceType;
512
+ }): Promise<TDoc | null>;
513
+ /**
514
+ * Unified pagination - auto-detects offset vs keyset based on params
515
+ *
516
+ * Auto-detection logic:
517
+ * - If params has 'cursor' or 'after' → uses keyset pagination (stream)
518
+ * - If params has 'pagination' or 'page' → uses offset pagination (paginate)
519
+ * - Else → defaults to offset pagination with page=1
520
+ *
521
+ * @example
522
+ * // Offset pagination (page-based)
523
+ * await repo.getAll({ page: 1, limit: 50, filters: { status: 'active' } });
524
+ * await repo.getAll({ pagination: { page: 2, limit: 20 } });
525
+ *
526
+ * // Keyset pagination (cursor-based)
527
+ * await repo.getAll({ cursor: 'eyJ2Ij...', limit: 50 });
528
+ * await repo.getAll({ after: 'eyJ2Ij...', sort: { createdAt: -1 } });
529
+ *
530
+ * // Simple query (defaults to page 1)
531
+ * await repo.getAll({ filters: { status: 'active' } });
532
+ *
533
+ * // Skip cache for fresh data
534
+ * await repo.getAll({ filters: { status: 'active' } }, { skipCache: true });
535
+ */
536
+ getAll(params?: {
537
+ filters?: Record<string, unknown>;
538
+ sort?: SortSpec | string;
539
+ cursor?: string;
540
+ after?: string;
541
+ page?: number;
542
+ pagination?: {
543
+ page?: number;
544
+ limit?: number;
545
+ };
546
+ limit?: number;
547
+ search?: string;
548
+ mode?: "offset" | "keyset";
549
+ hint?: string | Record<string, 1 | -1>;
550
+ maxTimeMS?: number;
551
+ countStrategy?: "exact" | "estimated" | "none";
552
+ readPreference?: ReadPreferenceType; /** Advanced populate options (from QueryParser or Arc's BaseController) */
553
+ populateOptions?: PopulateOptions[];
554
+ }, options?: {
555
+ select?: SelectSpec;
556
+ populate?: PopulateSpec;
557
+ populateOptions?: PopulateOptions[];
558
+ lean?: boolean;
559
+ session?: ClientSession;
560
+ skipCache?: boolean;
561
+ cacheTtl?: number;
562
+ readPreference?: ReadPreferenceType;
563
+ }): Promise<OffsetPaginationResult<TDoc> | KeysetPaginationResult<TDoc>>;
564
+ /**
565
+ * Get or create document
566
+ */
567
+ getOrCreate(query: Record<string, unknown>, createData: Record<string, unknown>, options?: {
568
+ session?: ClientSession;
569
+ }): Promise<TDoc | null>;
570
+ /**
571
+ * Count documents
572
+ */
573
+ count(query?: Record<string, unknown>, options?: {
574
+ session?: ClientSession;
575
+ readPreference?: ReadPreferenceType;
576
+ }): Promise<number>;
577
+ /**
578
+ * Check if document exists
579
+ */
580
+ exists(query: Record<string, unknown>, options?: {
581
+ session?: ClientSession;
582
+ readPreference?: ReadPreferenceType;
583
+ }): Promise<{
584
+ _id: unknown;
585
+ } | null>;
586
+ /**
587
+ * Update document by ID
588
+ */
589
+ update(id: string | ObjectId, data: Record<string, unknown>, options?: UpdateOptions): Promise<TDoc>;
590
+ /**
591
+ * Delete document by ID
592
+ */
593
+ delete(id: string | ObjectId, options?: {
594
+ session?: ClientSession;
595
+ }): Promise<{
596
+ success: boolean;
597
+ message: string;
598
+ }>;
599
+ /**
600
+ * Execute aggregation pipeline
601
+ */
602
+ aggregate<TResult = unknown>(pipeline: PipelineStage[], options?: {
603
+ session?: ClientSession;
604
+ }): Promise<TResult[]>;
605
+ /**
606
+ * Aggregate pipeline with pagination
607
+ * Best for: Complex queries, grouping, joins
608
+ */
609
+ aggregatePaginate(options?: AggregatePaginationOptions): Promise<AggregatePaginationResult<TDoc>>;
610
+ /**
611
+ * Get distinct values
612
+ */
613
+ distinct<T = unknown>(field: string, query?: Record<string, unknown>, options?: {
614
+ session?: ClientSession;
615
+ }): Promise<T[]>;
616
+ /**
617
+ * Query with custom field lookups ($lookup)
618
+ * Best for: Joins on slugs, SKUs, codes, or other indexed custom fields
619
+ *
620
+ * @example
621
+ * ```typescript
622
+ * // Join employees with departments using slug instead of ObjectId
623
+ * const employees = await employeeRepo.lookupPopulate({
624
+ * filters: { status: 'active' },
625
+ * lookups: [
626
+ * {
627
+ * from: 'departments',
628
+ * localField: 'departmentSlug',
629
+ * foreignField: 'slug',
630
+ * as: 'department',
631
+ * single: true
632
+ * }
633
+ * ],
634
+ * sort: '-createdAt',
635
+ * page: 1,
636
+ * limit: 50
637
+ * });
638
+ * ```
639
+ */
640
+ lookupPopulate(options: {
641
+ filters?: Record<string, unknown>;
642
+ lookups: LookupOptions[];
643
+ sort?: SortSpec | string;
644
+ page?: number;
645
+ limit?: number;
646
+ select?: SelectSpec;
647
+ session?: ClientSession;
648
+ readPreference?: ReadPreferenceType;
649
+ }): Promise<{
650
+ data: TDoc[];
651
+ total?: number;
652
+ page?: number;
653
+ limit?: number;
654
+ }>;
655
+ /**
656
+ * Create an aggregation builder for this model
657
+ * Useful for building complex custom aggregations
658
+ *
659
+ * @example
660
+ * ```typescript
661
+ * const pipeline = repo.buildAggregation()
662
+ * .match({ status: 'active' })
663
+ * .lookup('departments', 'deptSlug', 'slug', 'department', true)
664
+ * .group({ _id: '$department', count: { $sum: 1 } })
665
+ * .sort({ count: -1 })
666
+ * .build();
667
+ *
668
+ * const results = await repo.Model.aggregate(pipeline);
669
+ * ```
670
+ */
671
+ buildAggregation(): AggregationBuilder;
672
+ /**
673
+ * Create a lookup builder
674
+ * Useful for building $lookup stages independently
675
+ *
676
+ * @example
677
+ * ```typescript
678
+ * const lookupStages = repo.buildLookup('departments')
679
+ * .localField('deptSlug')
680
+ * .foreignField('slug')
681
+ * .as('department')
682
+ * .single()
683
+ * .build();
684
+ *
685
+ * const pipeline = [
686
+ * { $match: { status: 'active' } },
687
+ * ...lookupStages
688
+ * ];
689
+ * ```
690
+ */
691
+ buildLookup(from?: string): LookupBuilder;
692
+ /**
693
+ * Execute callback within a transaction with automatic retry on transient failures.
694
+ *
695
+ * Uses the MongoDB driver's `session.withTransaction()` which automatically retries
696
+ * on `TransientTransactionError` and `UnknownTransactionCommitResult`.
697
+ *
698
+ * The callback always receives a `ClientSession`. When `allowFallback` is true
699
+ * and the MongoDB deployment doesn't support transactions (e.g., standalone),
700
+ * the callback runs without a transaction on the same session.
701
+ *
702
+ * @param callback - Receives a `ClientSession` to pass to repository operations
703
+ * @param options.allowFallback - Run without transaction on standalone MongoDB (default: false)
704
+ * @param options.onFallback - Called when falling back to non-transactional execution
705
+ * @param options.transactionOptions - MongoDB driver transaction options (readConcern, writeConcern, etc.)
706
+ *
707
+ * @example
708
+ * ```typescript
709
+ * const result = await repo.withTransaction(async (session) => {
710
+ * const order = await repo.create({ total: 100 }, { session });
711
+ * await paymentRepo.create({ orderId: order._id }, { session });
712
+ * return order;
713
+ * });
714
+ *
715
+ * // With fallback for standalone/dev environments
716
+ * await repo.withTransaction(callback, {
717
+ * allowFallback: true,
718
+ * onFallback: (err) => logger.warn('Running without transaction', err),
719
+ * });
720
+ * ```
721
+ */
722
+ withTransaction<T>(callback: (session: ClientSession) => Promise<T>, options?: WithTransactionOptions): Promise<T>;
723
+ private _isTransactionUnsupported;
724
+ /**
725
+ * Execute custom query with event emission
726
+ */
727
+ _executeQuery<T>(buildQuery: (Model: Model<TDoc>) => Promise<T>): Promise<T>;
728
+ /**
729
+ * Build operation context and run before hooks
730
+ */
731
+ _buildContext(operation: string, options: Record<string, unknown>): Promise<RepositoryContext>;
732
+ /**
733
+ * Parse sort string or object
734
+ */
735
+ _parseSort(sort: SortSpec | string | undefined): SortSpec;
736
+ /**
737
+ * Parse populate specification
738
+ */
739
+ _parsePopulate(populate: PopulateSpec | undefined): string[] | PopulateOptions[];
740
+ /**
741
+ * Handle errors with proper HTTP status codes
742
+ */
743
+ _handleError(error: Error): HttpError;
744
+ }
745
+ //#endregion
746
+ //#region src/query/QueryParser.d.ts
747
+ type SortSpec$1 = Record<string, 1 | -1>;
748
+ type FilterQuery = Record<string, unknown>;
749
+ /**
750
+ * Mongoose-compatible populate option
751
+ * Supports advanced populate with select, match, limit, sort, and nested populate
752
+ *
753
+ * @example
754
+ * ```typescript
755
+ * // URL: ?populate[author][select]=name,email&populate[author][match][active]=true
756
+ * // Generates: { path: 'author', select: 'name email', match: { active: true } }
757
+ * ```
758
+ */
759
+ interface PopulateOption {
760
+ /** Field path to populate */
761
+ path: string;
762
+ /** Fields to select (space-separated) */
763
+ select?: string;
764
+ /** Filter conditions for populated documents */
765
+ match?: Record<string, unknown>;
766
+ /** Query options (limit, sort, skip) */
767
+ options?: {
768
+ limit?: number;
769
+ sort?: SortSpec$1;
770
+ skip?: number;
771
+ };
772
+ /** Nested populate configuration */
773
+ populate?: PopulateOption;
774
+ }
775
+ /** Parsed query result with optional lookup configuration */
776
+ interface ParsedQuery {
777
+ /** MongoDB filter query */
778
+ filters: FilterQuery;
779
+ /** Sort specification */
780
+ sort?: SortSpec$1;
781
+ /** Fields to populate (simple comma-separated string) */
782
+ populate?: string;
783
+ /**
784
+ * Advanced populate options (Mongoose-compatible)
785
+ * When this is set, `populate` will be undefined
786
+ * @example [{ path: 'author', select: 'name email' }]
787
+ */
788
+ populateOptions?: PopulateOption[];
789
+ /** Page number for offset pagination */
790
+ page?: number;
791
+ /** Cursor for keyset pagination */
792
+ after?: string;
793
+ /** Limit */
794
+ limit: number;
795
+ /** Full-text search query */
796
+ search?: string;
797
+ /** Lookup configurations for custom field joins */
798
+ lookups?: LookupOptions[];
799
+ /** Aggregation pipeline stages (advanced) */
800
+ aggregation?: PipelineStage[];
801
+ /** Select/project fields */
802
+ select?: Record<string, 0 | 1>;
803
+ }
804
+ /** Search mode for query parser */
805
+ type SearchMode = "text" | "regex";
806
+ interface QueryParserOptions {
807
+ /** Maximum allowed regex pattern length (default: 500) */
808
+ maxRegexLength?: number;
809
+ /** Maximum allowed text search query length (default: 200) */
810
+ maxSearchLength?: number;
811
+ /** Maximum allowed filter depth (default: 10) */
812
+ maxFilterDepth?: number;
813
+ /** Maximum allowed limit value (default: 1000) */
814
+ maxLimit?: number;
815
+ /** Additional operators to block */
816
+ additionalDangerousOperators?: string[];
817
+ /** Enable lookup parsing (default: true) */
818
+ enableLookups?: boolean;
819
+ /** Enable aggregation parsing (default: false - requires explicit opt-in) */
820
+ enableAggregations?: boolean;
821
+ /**
822
+ * Search mode (default: 'text')
823
+ * - 'text': Uses MongoDB $text search (requires text index)
824
+ * - 'regex': Uses $or with $regex across searchFields (no index required)
825
+ */
826
+ searchMode?: SearchMode;
827
+ /**
828
+ * Fields to search when searchMode is 'regex'
829
+ * Required when searchMode is 'regex'
830
+ * @example ['name', 'description', 'sku', 'tags']
831
+ */
832
+ searchFields?: string[];
833
+ /**
834
+ * Whitelist of collection names allowed in lookups.
835
+ * When set, only these collections can be used in $lookup stages.
836
+ * When undefined, all collection names are allowed.
837
+ * @example ['departments', 'categories', 'users']
838
+ */
839
+ allowedLookupCollections?: string[];
840
+ /** Allowed fields for filtering. If set, ignores unknown fields. */
841
+ allowedFilterFields?: string[];
842
+ /** Allowed fields for sorting. If set, ignores unknown fields. */
843
+ allowedSortFields?: string[];
844
+ }
845
+ /**
846
+ * Modern Query Parser
847
+ * Converts URL parameters to MongoDB queries with $lookup support
848
+ */
849
+ declare class QueryParser {
850
+ private readonly options;
851
+ private readonly operators;
852
+ private readonly dangerousOperators;
853
+ /**
854
+ * Regex patterns that can cause catastrophic backtracking (ReDoS attacks)
855
+ * Detects:
856
+ * - Quantifiers: {n,m}
857
+ * - Possessive quantifiers: *+, ++, ?+
858
+ * - Nested quantifiers: (a+)+, (a*)*
859
+ * - Backreferences: \1, \2, etc.
860
+ * - Complex character classes: [...]...[...]
861
+ */
862
+ private readonly dangerousRegexPatterns;
863
+ constructor(options?: QueryParserOptions);
864
+ /**
865
+ * Parse URL query parameters into MongoDB query format
866
+ *
867
+ * @example
868
+ * ```typescript
869
+ * // URL: ?status=active&lookup[department][foreignField]=slug&sort=-createdAt&page=1
870
+ * const query = parser.parse(req.query);
871
+ * // Returns: { filters: {...}, lookups: [...], sort: {...}, page: 1 }
872
+ * ```
873
+ */
874
+ parse(query: Record<string, unknown> | null | undefined): ParsedQuery;
875
+ /**
876
+ * Parse lookup configurations from URL parameters
877
+ *
878
+ * Supported formats:
879
+ * 1. Simple: ?lookup[department]=slug
880
+ * → Join with 'departments' collection on slug field
881
+ *
882
+ * 2. Detailed: ?lookup[department][localField]=deptSlug&lookup[department][foreignField]=slug
883
+ * → Full control over join configuration
884
+ *
885
+ * 3. Multiple: ?lookup[department]=slug&lookup[category]=categorySlug
886
+ * → Multiple lookups
887
+ *
888
+ * @example
889
+ * ```typescript
890
+ * // URL: ?lookup[department][localField]=deptSlug&lookup[department][foreignField]=slug&lookup[department][single]=true
891
+ * const lookups = parser._parseLookups({
892
+ * department: { localField: 'deptSlug', foreignField: 'slug', single: 'true' }
893
+ * });
894
+ * // Returns: [{ from: 'departments', localField: 'deptSlug', foreignField: 'slug', single: true }]
895
+ * ```
896
+ */
897
+ private _parseLookups;
898
+ /**
899
+ * Parse a single lookup configuration
900
+ */
901
+ private _parseSingleLookup;
902
+ /**
903
+ * Parse aggregation pipeline from URL (advanced feature)
904
+ *
905
+ * @example
906
+ * ```typescript
907
+ * // URL: ?aggregate[group][_id]=$status&aggregate[group][count]=$sum:1
908
+ * const pipeline = parser._parseAggregation({
909
+ * group: { _id: '$status', count: '$sum:1' }
910
+ * });
911
+ * ```
912
+ */
913
+ private _parseAggregation;
914
+ /**
915
+ * Parse select/project fields
916
+ *
917
+ * @example
918
+ * ```typescript
919
+ * // URL: ?select=name,email,-password
920
+ * // Returns: { name: 1, email: 1, password: 0 }
921
+ * ```
922
+ */
923
+ private _parseSelect;
924
+ /**
925
+ * Parse populate parameter - handles both simple string and advanced object format
926
+ *
927
+ * @example
928
+ * ```typescript
929
+ * // Simple: ?populate=author,category
930
+ * // Returns: { simplePopulate: 'author,category', populateOptions: undefined }
931
+ *
932
+ * // Advanced: ?populate[author][select]=name,email
933
+ * // Returns: { simplePopulate: undefined, populateOptions: [{ path: 'author', select: 'name email' }] }
934
+ * ```
935
+ */
936
+ private _parsePopulate;
937
+ /**
938
+ * Parse a single populate configuration
939
+ */
940
+ private _parseSinglePopulate;
941
+ /**
942
+ * Convert populate match values (handles boolean strings, etc.)
943
+ */
944
+ private _convertPopulateMatch;
945
+ /**
946
+ * Parse filter parameters
947
+ */
948
+ private _parseFilters;
949
+ /**
950
+ * Handle operator syntax: field[operator]=value
951
+ */
952
+ private _handleOperatorSyntax;
953
+ /**
954
+ * Handle bracket syntax with object value
955
+ */
956
+ private _handleBracketSyntax;
957
+ private _parseSort;
958
+ private _toMongoOperator;
959
+ private _createSafeRegex;
960
+ private _escapeRegex;
961
+ /**
962
+ * Sanitize $match configuration to prevent dangerous operators
963
+ * Recursively filters out operators like $where, $function, $accumulator
964
+ */
965
+ private _sanitizeMatchConfig;
966
+ /**
967
+ * Sanitize pipeline stages for use in $lookup.
968
+ * Blocks dangerous stages ($out, $merge, etc.) and recursively sanitizes
969
+ * operator expressions within $match, $addFields, and $set stages.
970
+ */
971
+ private _sanitizePipeline;
972
+ /**
973
+ * Recursively sanitize expression objects, blocking dangerous operators
974
+ * like $where, $function, $accumulator inside $addFields/$set stages.
975
+ */
976
+ private _sanitizeExpressions;
977
+ private _sanitizeSearch;
978
+ /**
979
+ * Build regex-based multi-field search filters
980
+ * Creates an $or query with case-insensitive regex across all searchFields
981
+ *
982
+ * @example
983
+ * // searchFields: ['name', 'description', 'sku']
984
+ * // search: 'azure'
985
+ * // Returns: [
986
+ * // { name: { $regex: /azure/i } },
987
+ * // { description: { $regex: /azure/i } },
988
+ * // { sku: { $regex: /azure/i } }
989
+ * // ]
990
+ */
991
+ private _buildRegexSearch;
992
+ private _convertValue;
993
+ private _parseOr;
994
+ private _enhanceWithBetween;
995
+ private _pluralize;
996
+ private _capitalize;
997
+ }
998
+ //#endregion
999
+ //#region src/index.d.ts
1000
+ /**
1001
+ * Factory function to create a repository instance
1002
+ *
1003
+ * @param Model - Mongoose model
1004
+ * @param plugins - Array of plugins to apply
1005
+ * @returns Repository instance
1006
+ *
1007
+ * @example
1008
+ * const userRepo = createRepository(UserModel, [timestampPlugin()]);
1009
+ */
1010
+ declare function createRepository<TDoc>(Model: mongoose$1.Model<TDoc, any, any, any>, plugins?: PluginType[], paginationConfig?: PaginationConfig, options?: RepositoryOptions): Repository<TDoc>;
1011
+ //#endregion
1012
+ export { type AggregateHelpersMethods, type AggregatePaginationOptions, type AggregatePaginationResult, AggregationBuilder, type AllPluginMethods, type AnyDocument, type AnyModel, type BatchOperationsMethods, type CacheAdapter, type CacheMethods, type CacheOperationOptions, type CacheOptions, type CacheStats, type CascadeOptions, type CascadeRelation, type CreateInput, type CreateOptions, type CrudSchemas, type CustomIdOptions, type DateSequentialIdOptions, type DecodedCursor, type DeepPartial, type DeleteResult, type ElasticSearchOptions, type EventHandlers, type EventPayload, type EventPhase, type FieldPreset, type FieldRules, type FilterQuery, type GroupResult, type HookMode, type HttpError, type IController, type IControllerResponse, type IRequestContext, type IResponseFormatter, type IdGenerator, type InferDocument, type InferRawDoc, type JsonSchema, type KeysOfType, type KeysetPaginationOptions, type KeysetPaginationResult, type Logger, LookupBuilder, type LookupOptions, type MinMaxResult, type MongoOperationsMethods, type MultiTenantOptions, type NonNullableFields, type ObjectId, type ObservabilityOptions, type OffsetPaginationOptions, type OffsetPaginationResult, type OperationMetric, type OperationOptions, type PaginationConfig, PaginationEngine, type PaginationResult, type ParsedQuery, type PartialBy, type Plugin, type PluginFunction, type PluginType, type PopulateOption, type PopulateSpec, type PrefixedIdOptions, QueryParser, type QueryParserOptions, type ReadPreferenceType, Repository, Repository as default, type RepositoryContext, type RepositoryEvent, type RepositoryInstance, type RepositoryOperation, type RepositoryOptions, type RequiredBy, type SchemaBuilderOptions, type SearchMode, type SelectSpec, type SequentialIdOptions, type SoftDeleteFilterMode, type SoftDeleteMethods, type SoftDeleteOptions, type SoftDeleteRepository, type SortDirection, type SortSpec, type Strict, type SubdocumentMethods, type UpdateInput, type UpdateManyResult, type UpdateOptions, type UpdateWithValidationResult, type UserContext, type ValidationChainOptions, type ValidationResult, type ValidatorDefinition, type WithPlugins, type WithTransactionOptions, index_d_exports as actions, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, configureLogger, createError, createFieldPreset, createMemoryCache, createRepository, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getImmutableFields, getMongooseProjection, getNextSequence, getSystemManagedFields, immutableField, isFieldUpdateAllowed, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validateUpdateBody, validationChainPlugin };