@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,893 @@
1
+ import { F as ObjectId, G as PopulateSpec, H as Plugin, L as OffsetPaginationResult, M as Logger, Y as RepositoryInstance, at as SortSpec, c as CacheOptions, et as SelectSpec, ft as ValidationChainOptions, l as CacheStats, mt as ValidatorDefinition, nt as SoftDeleteOptions, q as RepositoryContext, u as CascadeOptions, x as FieldPreset } from "./types-D-gploPr.mjs";
2
+ import mongoose, { ClientSession } from "mongoose";
3
+
4
+ //#region src/plugins/field-filter.plugin.d.ts
5
+ /**
6
+ * Field filter plugin that restricts fields based on user context
7
+ *
8
+ * @example
9
+ * const fieldPreset = {
10
+ * public: ['id', 'name'],
11
+ * authenticated: ['email'],
12
+ * admin: ['createdAt', 'internalNotes']
13
+ * };
14
+ *
15
+ * const repo = new Repository(Model, [fieldFilterPlugin(fieldPreset)]);
16
+ */
17
+ declare function fieldFilterPlugin(fieldPreset: FieldPreset): Plugin;
18
+ //#endregion
19
+ //#region src/plugins/timestamp.plugin.d.ts
20
+ /**
21
+ * Timestamp plugin that auto-injects timestamps
22
+ *
23
+ * @example
24
+ * const repo = new Repository(Model, [timestampPlugin()]);
25
+ */
26
+ declare function timestampPlugin(): Plugin;
27
+ //#endregion
28
+ //#region src/plugins/audit-log.plugin.d.ts
29
+ /**
30
+ * Audit log plugin that logs all repository operations
31
+ *
32
+ * @example
33
+ * const repo = new Repository(Model, [auditLogPlugin(console)]);
34
+ */
35
+ declare function auditLogPlugin(logger: Logger): Plugin;
36
+ //#endregion
37
+ //#region src/plugins/soft-delete.plugin.d.ts
38
+ /**
39
+ * Soft delete plugin
40
+ *
41
+ * @example Basic usage
42
+ * ```typescript
43
+ * const repo = new Repository(Model, [
44
+ * softDeletePlugin({ deletedField: 'deletedAt' })
45
+ * ]);
46
+ *
47
+ * // Delete (soft)
48
+ * await repo.delete(id);
49
+ *
50
+ * // Restore
51
+ * await repo.restore(id);
52
+ *
53
+ * // Get deleted documents
54
+ * await repo.getDeleted({ page: 1, limit: 20 });
55
+ * ```
56
+ *
57
+ * @example With null filter mode (for schemas with default: null)
58
+ * ```typescript
59
+ * // Schema: { deletedAt: { type: Date, default: null } }
60
+ * const repo = new Repository(Model, [
61
+ * softDeletePlugin({
62
+ * deletedField: 'deletedAt',
63
+ * filterMode: 'null', // default - works with default: null
64
+ * })
65
+ * ]);
66
+ * ```
67
+ *
68
+ * @example With TTL for auto-cleanup
69
+ * ```typescript
70
+ * const repo = new Repository(Model, [
71
+ * softDeletePlugin({
72
+ * deletedField: 'deletedAt',
73
+ * ttlDays: 30, // Auto-delete after 30 days
74
+ * })
75
+ * ]);
76
+ * ```
77
+ */
78
+ declare function softDeletePlugin(options?: SoftDeleteOptions): Plugin;
79
+ /**
80
+ * TypeScript interface for soft delete plugin methods
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * import type { SoftDeleteMethods } from '@classytic/mongokit';
85
+ *
86
+ * type UserRepoWithSoftDelete = UserRepo & SoftDeleteMethods<IUser>;
87
+ *
88
+ * const userRepo = new UserRepo(UserModel, [
89
+ * methodRegistryPlugin(),
90
+ * softDeletePlugin({ deletedField: 'deletedAt' }),
91
+ * ]) as UserRepoWithSoftDelete;
92
+ *
93
+ * // TypeScript autocomplete for soft delete methods
94
+ * await userRepo.restore(userId);
95
+ * const deleted = await userRepo.getDeleted({ page: 1, limit: 20 });
96
+ * ```
97
+ */
98
+ interface SoftDeleteMethods<TDoc> {
99
+ /**
100
+ * Restore a soft-deleted document
101
+ * @param id - Document ID to restore
102
+ * @param options - Optional restore options
103
+ * @returns Restored document
104
+ */
105
+ restore(id: string | ObjectId, options?: {
106
+ session?: ClientSession;
107
+ }): Promise<TDoc>;
108
+ /**
109
+ * Get paginated list of soft-deleted documents
110
+ * @param params - Query parameters (filters, sort, pagination)
111
+ * @param options - Query options (select, populate, lean, session)
112
+ * @returns Paginated result of deleted documents
113
+ */
114
+ getDeleted(params?: {
115
+ filters?: Record<string, unknown>;
116
+ sort?: SortSpec | string;
117
+ page?: number;
118
+ limit?: number;
119
+ }, options?: {
120
+ select?: SelectSpec;
121
+ populate?: PopulateSpec;
122
+ lean?: boolean;
123
+ session?: ClientSession;
124
+ }): Promise<OffsetPaginationResult<TDoc>>;
125
+ }
126
+ //#endregion
127
+ //#region src/plugins/method-registry.plugin.d.ts
128
+ /**
129
+ * Extended repository interface with method registry
130
+ */
131
+ interface MethodRegistryRepository extends RepositoryInstance {
132
+ registerMethod(name: string, fn: Function): void;
133
+ hasMethod(name: string): boolean;
134
+ getRegisteredMethods(): string[];
135
+ }
136
+ /**
137
+ * Method registry plugin that enables dynamic method registration
138
+ */
139
+ declare function methodRegistryPlugin(): Plugin;
140
+ //#endregion
141
+ //#region src/plugins/validation-chain.plugin.d.ts
142
+ type OperationType = 'create' | 'createMany' | 'update' | 'delete';
143
+ /**
144
+ * Validation chain plugin
145
+ *
146
+ * @example
147
+ * const repo = new Repository(Model, [
148
+ * validationChainPlugin([
149
+ * requireField('email'),
150
+ * uniqueField('email', 'Email already exists'),
151
+ * blockIf('no-delete-admin', ['delete'], ctx => ctx.data?.role === 'admin', 'Cannot delete admin'),
152
+ * ])
153
+ * ]);
154
+ */
155
+ declare function validationChainPlugin(validators?: ValidatorDefinition[], options?: ValidationChainOptions): Plugin;
156
+ /**
157
+ * Block operation if condition is true
158
+ *
159
+ * @example
160
+ * blockIf('block-library', ['delete'], ctx => ctx.data?.managed, 'Cannot delete managed records')
161
+ */
162
+ declare function blockIf(name: string, operations: OperationType[], condition: (context: RepositoryContext) => boolean, errorMessage: string): ValidatorDefinition;
163
+ /**
164
+ * Require a field to be present
165
+ */
166
+ declare function requireField(field: string, operations?: OperationType[]): ValidatorDefinition;
167
+ /**
168
+ * Auto-inject a value if not present
169
+ */
170
+ declare function autoInject(field: string, getter: (context: RepositoryContext) => unknown, operations?: OperationType[]): ValidatorDefinition;
171
+ /**
172
+ * Make a field immutable (cannot be updated)
173
+ */
174
+ declare function immutableField(field: string): ValidatorDefinition;
175
+ /**
176
+ * Ensure field value is unique
177
+ */
178
+ declare function uniqueField(field: string, errorMessage?: string): ValidatorDefinition;
179
+ //#endregion
180
+ //#region src/plugins/mongo-operations.plugin.d.ts
181
+ /**
182
+ * MongoDB operations plugin
183
+ *
184
+ * Adds MongoDB-specific atomic operations to repositories:
185
+ * - upsert: Create or update document
186
+ * - increment/decrement: Atomic numeric operations
187
+ * - pushToArray/pullFromArray/addToSet: Array operations
188
+ * - setField/unsetField/renameField: Field operations
189
+ * - multiplyField: Multiply numeric field
190
+ * - setMin/setMax: Conditional min/max updates
191
+ *
192
+ * @example Basic usage (no TypeScript autocomplete)
193
+ * ```typescript
194
+ * const repo = new Repository(ProductModel, [
195
+ * methodRegistryPlugin(),
196
+ * mongoOperationsPlugin(),
197
+ * ]);
198
+ *
199
+ * // Works at runtime but TypeScript doesn't know about these methods
200
+ * await (repo as any).increment(productId, 'views', 1);
201
+ * await (repo as any).pushToArray(productId, 'tags', 'featured');
202
+ * ```
203
+ *
204
+ * @example With TypeScript type safety (recommended)
205
+ * ```typescript
206
+ * import { Repository, mongoOperationsPlugin, methodRegistryPlugin } from '@classytic/mongokit';
207
+ * import type { MongoOperationsMethods } from '@classytic/mongokit';
208
+ *
209
+ * class ProductRepo extends Repository<IProduct> {
210
+ * // Add your custom methods here
211
+ * }
212
+ *
213
+ * // Create with type assertion to get autocomplete for plugin methods
214
+ * type ProductRepoWithPlugins = ProductRepo & MongoOperationsMethods<IProduct>;
215
+ *
216
+ * const repo = new ProductRepo(ProductModel, [
217
+ * methodRegistryPlugin(),
218
+ * mongoOperationsPlugin(),
219
+ * ]) as ProductRepoWithPlugins;
220
+ *
221
+ * // Now TypeScript provides autocomplete and type checking!
222
+ * await repo.increment(productId, 'views', 1);
223
+ * await repo.upsert({ sku: 'ABC' }, { name: 'Product', price: 99 });
224
+ * await repo.pushToArray(productId, 'tags', 'featured');
225
+ * ```
226
+ */
227
+ declare function mongoOperationsPlugin(): Plugin;
228
+ /**
229
+ * Type interface for repositories using mongoOperationsPlugin
230
+ *
231
+ * Use this interface to get TypeScript autocomplete and type safety
232
+ * for the methods added by mongoOperationsPlugin.
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * import { Repository, mongoOperationsPlugin, methodRegistryPlugin } from '@classytic/mongokit';
237
+ * import type { MongoOperationsMethods } from '@classytic/mongokit';
238
+ *
239
+ * // Without type safety (base is flexible)
240
+ * class ProductRepo extends Repository<IProduct> {
241
+ * // Can add anything - fully flexible
242
+ * }
243
+ *
244
+ * // With type safety for plugin methods
245
+ * class ProductRepo extends Repository<IProduct> implements MongoOperationsMethods<IProduct> {
246
+ * // TypeScript knows about upsert, increment, decrement, etc.
247
+ * }
248
+ *
249
+ * const repo = new ProductRepo(ProductModel, [
250
+ * methodRegistryPlugin(),
251
+ * mongoOperationsPlugin(),
252
+ * ]);
253
+ *
254
+ * // Now TypeScript provides autocomplete and type checking
255
+ * await repo.increment(productId, 'views', 1);
256
+ * await repo.upsert({ sku: 'ABC' }, { name: 'Product' });
257
+ * ```
258
+ */
259
+ interface MongoOperationsMethods<TDoc> {
260
+ /**
261
+ * Update existing document or insert new one
262
+ * @param query - Query to find document
263
+ * @param data - Data to update or insert
264
+ * @param options - Operation options (session, etc.)
265
+ * @returns Created or updated document
266
+ */
267
+ upsert(query: Record<string, unknown>, data: Record<string, unknown>, options?: Record<string, unknown>): Promise<TDoc>;
268
+ /**
269
+ * Atomically increment numeric field
270
+ * @param id - Document ID
271
+ * @param field - Field name to increment
272
+ * @param value - Value to increment by (default: 1)
273
+ * @param options - Operation options (session, etc.)
274
+ * @returns Updated document
275
+ */
276
+ increment(id: string | ObjectId, field: string, value?: number, options?: Record<string, unknown>): Promise<TDoc>;
277
+ /**
278
+ * Atomically decrement numeric field
279
+ * @param id - Document ID
280
+ * @param field - Field name to decrement
281
+ * @param value - Value to decrement by (default: 1)
282
+ * @param options - Operation options (session, etc.)
283
+ * @returns Updated document
284
+ */
285
+ decrement(id: string | ObjectId, field: string, value?: number, options?: Record<string, unknown>): Promise<TDoc>;
286
+ /**
287
+ * Push value to array field
288
+ * @param id - Document ID
289
+ * @param field - Array field name
290
+ * @param value - Value to push
291
+ * @param options - Operation options (session, etc.)
292
+ * @returns Updated document
293
+ */
294
+ pushToArray(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
295
+ /**
296
+ * Remove value from array field
297
+ * @param id - Document ID
298
+ * @param field - Array field name
299
+ * @param value - Value to remove
300
+ * @param options - Operation options (session, etc.)
301
+ * @returns Updated document
302
+ */
303
+ pullFromArray(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
304
+ /**
305
+ * Add value to array only if not already present (unique)
306
+ * @param id - Document ID
307
+ * @param field - Array field name
308
+ * @param value - Value to add
309
+ * @param options - Operation options (session, etc.)
310
+ * @returns Updated document
311
+ */
312
+ addToSet(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
313
+ /**
314
+ * Set field value (alias for update with $set)
315
+ * @param id - Document ID
316
+ * @param field - Field name
317
+ * @param value - Value to set
318
+ * @param options - Operation options (session, etc.)
319
+ * @returns Updated document
320
+ */
321
+ setField(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
322
+ /**
323
+ * Unset (remove) field from document
324
+ * @param id - Document ID
325
+ * @param fields - Field name or array of field names to remove
326
+ * @param options - Operation options (session, etc.)
327
+ * @returns Updated document
328
+ */
329
+ unsetField(id: string | ObjectId, fields: string | string[], options?: Record<string, unknown>): Promise<TDoc>;
330
+ /**
331
+ * Rename field in document
332
+ * @param id - Document ID
333
+ * @param oldName - Current field name
334
+ * @param newName - New field name
335
+ * @param options - Operation options (session, etc.)
336
+ * @returns Updated document
337
+ */
338
+ renameField(id: string | ObjectId, oldName: string, newName: string, options?: Record<string, unknown>): Promise<TDoc>;
339
+ /**
340
+ * Multiply numeric field by value
341
+ * @param id - Document ID
342
+ * @param field - Field name
343
+ * @param multiplier - Multiplier value
344
+ * @param options - Operation options (session, etc.)
345
+ * @returns Updated document
346
+ */
347
+ multiplyField(id: string | ObjectId, field: string, multiplier: number, options?: Record<string, unknown>): Promise<TDoc>;
348
+ /**
349
+ * Set field to minimum value (only if current value is greater)
350
+ * @param id - Document ID
351
+ * @param field - Field name
352
+ * @param value - Minimum value
353
+ * @param options - Operation options (session, etc.)
354
+ * @returns Updated document
355
+ */
356
+ setMin(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
357
+ /**
358
+ * Set field to maximum value (only if current value is less)
359
+ * @param id - Document ID
360
+ * @param field - Field name
361
+ * @param value - Maximum value
362
+ * @param options - Operation options (session, etc.)
363
+ * @returns Updated document
364
+ */
365
+ setMax(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
366
+ }
367
+ //#endregion
368
+ //#region src/plugins/batch-operations.plugin.d.ts
369
+ /**
370
+ * Batch operations plugin
371
+ *
372
+ * @example
373
+ * const repo = new Repository(Model, [
374
+ * methodRegistryPlugin(),
375
+ * batchOperationsPlugin(),
376
+ * ]);
377
+ *
378
+ * await repo.updateMany({ status: 'pending' }, { status: 'active' });
379
+ * await repo.deleteMany({ status: 'deleted' });
380
+ */
381
+ declare function batchOperationsPlugin(): Plugin;
382
+ /**
383
+ * Type interface for repositories using batchOperationsPlugin
384
+ *
385
+ * @example
386
+ * ```typescript
387
+ * import { Repository, methodRegistryPlugin, batchOperationsPlugin } from '@classytic/mongokit';
388
+ * import type { BatchOperationsMethods } from '@classytic/mongokit';
389
+ *
390
+ * class ProductRepo extends Repository<IProduct> {}
391
+ *
392
+ * type ProductRepoWithBatch = ProductRepo & BatchOperationsMethods;
393
+ *
394
+ * const repo = new ProductRepo(ProductModel, [
395
+ * methodRegistryPlugin(),
396
+ * batchOperationsPlugin(),
397
+ * ]) as ProductRepoWithBatch;
398
+ *
399
+ * // TypeScript autocomplete works!
400
+ * await repo.updateMany({ status: 'pending' }, { status: 'active' });
401
+ * await repo.deleteMany({ status: 'archived' });
402
+ * ```
403
+ */
404
+ interface BatchOperationsMethods {
405
+ /**
406
+ * Update multiple documents matching the query
407
+ * @param query - Query to match documents
408
+ * @param data - Update data
409
+ * @param options - Operation options
410
+ * @returns Update result with matchedCount, modifiedCount, etc.
411
+ */
412
+ updateMany(query: Record<string, unknown>, data: Record<string, unknown>, options?: {
413
+ session?: ClientSession;
414
+ updatePipeline?: boolean;
415
+ }): Promise<{
416
+ acknowledged: boolean;
417
+ matchedCount: number;
418
+ modifiedCount: number;
419
+ upsertedCount: number;
420
+ upsertedId: unknown;
421
+ }>;
422
+ /**
423
+ * Delete multiple documents matching the query
424
+ * @param query - Query to match documents
425
+ * @param options - Operation options
426
+ * @returns Delete result with deletedCount
427
+ */
428
+ deleteMany(query: Record<string, unknown>, options?: Record<string, unknown>): Promise<{
429
+ acknowledged: boolean;
430
+ deletedCount: number;
431
+ }>;
432
+ }
433
+ //#endregion
434
+ //#region src/plugins/aggregate-helpers.plugin.d.ts
435
+ /**
436
+ * Aggregate helpers plugin
437
+ *
438
+ * @example
439
+ * const repo = new Repository(Model, [
440
+ * methodRegistryPlugin(),
441
+ * aggregateHelpersPlugin(),
442
+ * ]);
443
+ *
444
+ * const groups = await repo.groupBy('category');
445
+ * const total = await repo.sum('amount', { status: 'completed' });
446
+ */
447
+ declare function aggregateHelpersPlugin(): Plugin;
448
+ /**
449
+ * Type interface for repositories using aggregateHelpersPlugin
450
+ *
451
+ * @example
452
+ * ```typescript
453
+ * import { Repository, methodRegistryPlugin, aggregateHelpersPlugin } from '@classytic/mongokit';
454
+ * import type { AggregateHelpersMethods } from '@classytic/mongokit';
455
+ *
456
+ * class OrderRepo extends Repository<IOrder> {}
457
+ *
458
+ * type OrderRepoWithAggregates = OrderRepo & AggregateHelpersMethods;
459
+ *
460
+ * const repo = new OrderRepo(OrderModel, [
461
+ * methodRegistryPlugin(),
462
+ * aggregateHelpersPlugin(),
463
+ * ]) as OrderRepoWithAggregates;
464
+ *
465
+ * // TypeScript autocomplete works!
466
+ * const groups = await repo.groupBy('status');
467
+ * const total = await repo.sum('amount', { status: 'completed' });
468
+ * const avg = await repo.average('amount');
469
+ * ```
470
+ */
471
+ interface AggregateHelpersMethods {
472
+ /**
473
+ * Group documents by field value and count occurrences
474
+ * @param field - Field to group by
475
+ * @param options - Operation options
476
+ * @returns Array of groups with _id and count
477
+ */
478
+ groupBy(field: string, options?: {
479
+ limit?: number;
480
+ session?: unknown;
481
+ }): Promise<Array<{
482
+ _id: unknown;
483
+ count: number;
484
+ }>>;
485
+ /**
486
+ * Calculate sum of field values
487
+ * @param field - Field to sum
488
+ * @param query - Filter query
489
+ * @param options - Operation options
490
+ * @returns Sum of field values
491
+ */
492
+ sum(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
493
+ /**
494
+ * Calculate average of field values
495
+ * @param field - Field to average
496
+ * @param query - Filter query
497
+ * @param options - Operation options
498
+ * @returns Average of field values
499
+ */
500
+ average(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
501
+ /**
502
+ * Get minimum field value
503
+ * @param field - Field to get minimum from
504
+ * @param query - Filter query
505
+ * @param options - Operation options
506
+ * @returns Minimum field value
507
+ */
508
+ min(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
509
+ /**
510
+ * Get maximum field value
511
+ * @param field - Field to get maximum from
512
+ * @param query - Filter query
513
+ * @param options - Operation options
514
+ * @returns Maximum field value
515
+ */
516
+ max(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
517
+ }
518
+ //#endregion
519
+ //#region src/plugins/subdocument.plugin.d.ts
520
+ /**
521
+ * Subdocument plugin for managing nested arrays
522
+ *
523
+ * @example
524
+ * const repo = new Repository(Model, [
525
+ * methodRegistryPlugin(),
526
+ * subdocumentPlugin(),
527
+ * ]);
528
+ *
529
+ * await repo.addSubdocument(parentId, 'items', { name: 'Item 1' });
530
+ * await repo.updateSubdocument(parentId, 'items', itemId, { name: 'Updated Item' });
531
+ */
532
+ declare function subdocumentPlugin(): Plugin;
533
+ /**
534
+ * Type interface for repositories using subdocumentPlugin
535
+ *
536
+ * @example
537
+ * ```typescript
538
+ * import { Repository, methodRegistryPlugin, subdocumentPlugin } from '@classytic/mongokit';
539
+ * import type { SubdocumentMethods } from '@classytic/mongokit';
540
+ *
541
+ * class OrderRepo extends Repository<IOrder> {}
542
+ *
543
+ * type OrderRepoWithSubdocs = OrderRepo & SubdocumentMethods<IOrder>;
544
+ *
545
+ * const repo = new OrderRepo(OrderModel, [
546
+ * methodRegistryPlugin(),
547
+ * subdocumentPlugin(),
548
+ * ]) as OrderRepoWithSubdocs;
549
+ *
550
+ * // TypeScript autocomplete works!
551
+ * await repo.addSubdocument(orderId, 'items', { productId: '123', quantity: 2 });
552
+ * await repo.updateSubdocument(orderId, 'items', itemId, { quantity: 5 });
553
+ * await repo.deleteSubdocument(orderId, 'items', itemId);
554
+ * ```
555
+ */
556
+ interface SubdocumentMethods<TDoc> {
557
+ /**
558
+ * Add subdocument to array field
559
+ * @param parentId - Parent document ID
560
+ * @param arrayPath - Path to array field (e.g., 'items', 'addresses')
561
+ * @param subData - Subdocument data
562
+ * @param options - Operation options
563
+ * @returns Updated parent document
564
+ */
565
+ addSubdocument(parentId: string | ObjectId, arrayPath: string, subData: Record<string, unknown>, options?: Record<string, unknown>): Promise<TDoc>;
566
+ /**
567
+ * Get subdocument from array field
568
+ * @param parentId - Parent document ID
569
+ * @param arrayPath - Path to array field
570
+ * @param subId - Subdocument ID
571
+ * @param options - Operation options
572
+ * @returns Subdocument
573
+ */
574
+ getSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, options?: {
575
+ lean?: boolean;
576
+ session?: unknown;
577
+ }): Promise<Record<string, unknown>>;
578
+ /**
579
+ * Update subdocument in array field
580
+ * @param parentId - Parent document ID
581
+ * @param arrayPath - Path to array field
582
+ * @param subId - Subdocument ID
583
+ * @param updateData - Update data
584
+ * @param options - Operation options
585
+ * @returns Updated parent document
586
+ */
587
+ updateSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, updateData: Record<string, unknown>, options?: {
588
+ session?: unknown;
589
+ }): Promise<TDoc>;
590
+ /**
591
+ * Delete subdocument from array field
592
+ * @param parentId - Parent document ID
593
+ * @param arrayPath - Path to array field
594
+ * @param subId - Subdocument ID
595
+ * @param options - Operation options
596
+ * @returns Updated parent document
597
+ */
598
+ deleteSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, options?: Record<string, unknown>): Promise<TDoc>;
599
+ }
600
+ //#endregion
601
+ //#region src/plugins/cache.plugin.d.ts
602
+ /**
603
+ * Cache plugin factory
604
+ *
605
+ * @param options - Cache configuration
606
+ * @returns Plugin instance
607
+ */
608
+ declare function cachePlugin(options: CacheOptions): Plugin;
609
+ /**
610
+ * TypeScript interface for cache plugin methods
611
+ *
612
+ * @example
613
+ * ```typescript
614
+ * import type { CacheMethods } from '@classytic/mongokit';
615
+ *
616
+ * type ProductRepoWithCache = ProductRepo & CacheMethods;
617
+ *
618
+ * const productRepo = new ProductRepo(ProductModel, [
619
+ * methodRegistryPlugin(),
620
+ * cachePlugin({ adapter: redisAdapter, ttl: 60 }),
621
+ * ]) as ProductRepoWithCache;
622
+ *
623
+ * // TypeScript autocomplete for cache methods
624
+ * await productRepo.invalidateCache(productId);
625
+ * await productRepo.invalidateListCache();
626
+ * await productRepo.invalidateAllCache();
627
+ * const stats = productRepo.getCacheStats();
628
+ * productRepo.resetCacheStats();
629
+ * ```
630
+ */
631
+ interface CacheMethods {
632
+ /**
633
+ * Invalidate cache for a specific document
634
+ * Use when document was updated outside this service
635
+ * @param id - Document ID to invalidate
636
+ */
637
+ invalidateCache(id: string): Promise<void>;
638
+ /**
639
+ * Invalidate all list caches for this model
640
+ * Use when bulk changes happened outside this service
641
+ */
642
+ invalidateListCache(): Promise<void>;
643
+ /**
644
+ * Invalidate ALL cache entries for this model
645
+ * Nuclear option - use sparingly
646
+ */
647
+ invalidateAllCache(): Promise<void>;
648
+ /**
649
+ * Get cache statistics for monitoring
650
+ * @returns Cache statistics (hits, misses, sets, invalidations)
651
+ */
652
+ getCacheStats(): CacheStats;
653
+ /**
654
+ * Reset cache statistics
655
+ */
656
+ resetCacheStats(): void;
657
+ }
658
+ //#endregion
659
+ //#region src/plugins/cascade.plugin.d.ts
660
+ /**
661
+ * Cascade delete plugin
662
+ *
663
+ * Deletes related documents after the parent document is deleted.
664
+ * Works with both hard delete and soft delete scenarios.
665
+ *
666
+ * @param options - Cascade configuration
667
+ * @returns Plugin
668
+ */
669
+ declare function cascadePlugin(options: CascadeOptions): Plugin;
670
+ //#endregion
671
+ //#region src/plugins/multi-tenant.plugin.d.ts
672
+ interface MultiTenantOptions {
673
+ /** Field name used for tenant isolation (default: 'organizationId') */
674
+ tenantField?: string;
675
+ /** Context key to read tenant ID from (default: 'organizationId') */
676
+ contextKey?: string;
677
+ /** Throw if tenant ID is missing from context (default: true) */
678
+ required?: boolean;
679
+ /** Operations to skip tenant injection (e.g., for admin/system queries) */
680
+ skipOperations?: string[];
681
+ /**
682
+ * Dynamic skip — receives the context and operation name, returns true to
683
+ * bypass tenant scoping for this call. Use for role-based bypass (e.g.,
684
+ * super admin) without needing a separate repo instance.
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * skipWhen: (context) => context.role === 'superadmin'
689
+ * ```
690
+ */
691
+ skipWhen?: (context: RepositoryContext, operation: string) => boolean;
692
+ /**
693
+ * Resolve tenant ID from external source (e.g., AsyncLocalStorage, CLS).
694
+ * Called when tenant ID is not found in context. If it returns a value,
695
+ * that value is used as the tenant ID without requiring it in context.
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * resolveContext: () => asyncLocalStorage.getStore()?.tenantId
700
+ * ```
701
+ */
702
+ resolveContext?: () => string | undefined;
703
+ }
704
+ declare function multiTenantPlugin(options?: MultiTenantOptions): Plugin;
705
+ //#endregion
706
+ //#region src/plugins/observability.plugin.d.ts
707
+ interface OperationMetric {
708
+ /** Operation name (e.g., 'create', 'getAll', 'update') */
709
+ operation: string;
710
+ /** Model/collection name */
711
+ model: string;
712
+ /** Duration in milliseconds */
713
+ durationMs: number;
714
+ /** Whether the operation succeeded */
715
+ success: boolean;
716
+ /** Error message if failed */
717
+ error?: string;
718
+ /** Timestamp when the operation started */
719
+ startedAt: Date;
720
+ /** User ID if available */
721
+ userId?: string;
722
+ /** Organization ID if available */
723
+ organizationId?: string;
724
+ }
725
+ interface ObservabilityOptions {
726
+ /** Callback invoked after every operation with timing data */
727
+ onMetric: (metric: OperationMetric) => void;
728
+ /** Operations to track (default: all) */
729
+ operations?: string[];
730
+ /** Threshold in ms — only report operations slower than this */
731
+ slowThresholdMs?: number;
732
+ }
733
+ declare function observabilityPlugin(options: ObservabilityOptions): Plugin;
734
+ //#endregion
735
+ //#region src/plugins/elastic.plugin.d.ts
736
+ interface ElasticSearchOptions {
737
+ /** Elasticsearch or OpenSearch client instance */
738
+ client: any;
739
+ /** Index name to perform search against */
740
+ index: string;
741
+ /** Field to extract MongoDB ID from the indexed document (default: '_id') */
742
+ idField?: string;
743
+ }
744
+ declare function elasticSearchPlugin(options: ElasticSearchOptions): Plugin;
745
+ //#endregion
746
+ //#region src/plugins/custom-id.plugin.d.ts
747
+ /**
748
+ * Generator function that produces a unique ID.
749
+ * Receives the full repository context for conditional logic.
750
+ */
751
+ type IdGenerator = (context: RepositoryContext) => string | Promise<string>;
752
+ interface CustomIdOptions {
753
+ /** Field to store the custom ID (default: 'customId') */
754
+ field?: string;
755
+ /** Function to generate the ID. Can be async. */
756
+ generator: IdGenerator;
757
+ /** Only generate if the field is missing/empty (default: true) */
758
+ generateOnlyIfEmpty?: boolean;
759
+ }
760
+ /**
761
+ * Atomically increment and return the next sequence value for a given key.
762
+ * Uses `findOneAndUpdate` with `upsert` + `$inc` — fully atomic even under
763
+ * heavy concurrency.
764
+ *
765
+ * @param counterKey - Unique key identifying this counter (e.g., "Invoice" or "Invoice:2026-02")
766
+ * @param increment - Value to increment by (default: 1)
767
+ * @returns The next sequence number (after increment)
768
+ *
769
+ * @example
770
+ * const seq = await getNextSequence('invoices');
771
+ * // First call → 1, second → 2, ...
772
+ *
773
+ * @example Batch increment for createMany
774
+ * const startSeq = await getNextSequence('invoices', 5);
775
+ * // If current was 10, returns 15 (you use 11, 12, 13, 14, 15)
776
+ */
777
+ declare function getNextSequence(counterKey: string, increment?: number): Promise<number>;
778
+ interface SequentialIdOptions {
779
+ /** Prefix string (e.g., 'INV', 'ORD') */
780
+ prefix: string;
781
+ /** Mongoose model — used to derive the counter key from model name */
782
+ model: mongoose.Model<any>;
783
+ /** Number of digits to pad to (default: 4 → "0001") */
784
+ padding?: number;
785
+ /** Separator between prefix and number (default: '-') */
786
+ separator?: string;
787
+ /** Custom counter key override (default: model.modelName) */
788
+ counterKey?: string;
789
+ }
790
+ /**
791
+ * Generator: Simple sequential counter.
792
+ * Produces IDs like `INV-0001`, `INV-0002`, etc.
793
+ *
794
+ * Uses atomic MongoDB counters — safe under concurrency.
795
+ *
796
+ * @example
797
+ * ```typescript
798
+ * customIdPlugin({
799
+ * field: 'invoiceNumber',
800
+ * generator: sequentialId({ prefix: 'INV', model: InvoiceModel }),
801
+ * })
802
+ * ```
803
+ */
804
+ declare function sequentialId(options: SequentialIdOptions): IdGenerator;
805
+ interface DateSequentialIdOptions {
806
+ /** Prefix string (e.g., 'BILL', 'INV') */
807
+ prefix: string;
808
+ /** Mongoose model — used to derive the counter key */
809
+ model: mongoose.Model<any>;
810
+ /**
811
+ * Partition granularity — counter resets each period.
812
+ * - 'yearly' → BILL-2026-0001, resets every January
813
+ * - 'monthly' → BILL-2026-02-0001, resets every month
814
+ * - 'daily' → BILL-2026-02-20-0001, resets every day
815
+ */
816
+ partition?: 'yearly' | 'monthly' | 'daily';
817
+ /** Number of digits to pad to (default: 4) */
818
+ padding?: number;
819
+ /** Separator (default: '-') */
820
+ separator?: string;
821
+ }
822
+ /**
823
+ * Generator: Date-partitioned sequential counter.
824
+ * Counter resets per period — great for invoice/bill numbering.
825
+ *
826
+ * Produces IDs like:
827
+ * - yearly: `BILL-2026-0001`
828
+ * - monthly: `BILL-2026-02-0001`
829
+ * - daily: `BILL-2026-02-20-0001`
830
+ *
831
+ * @example
832
+ * ```typescript
833
+ * customIdPlugin({
834
+ * field: 'billNumber',
835
+ * generator: dateSequentialId({
836
+ * prefix: 'BILL',
837
+ * model: BillModel,
838
+ * partition: 'monthly',
839
+ * }),
840
+ * })
841
+ * ```
842
+ */
843
+ declare function dateSequentialId(options: DateSequentialIdOptions): IdGenerator;
844
+ interface PrefixedIdOptions {
845
+ /** Prefix string (e.g., 'USR', 'TXN') */
846
+ prefix: string;
847
+ /** Separator (default: '_') */
848
+ separator?: string;
849
+ /** Length of the random suffix (default: 12) */
850
+ length?: number;
851
+ }
852
+ /**
853
+ * Generator: Prefix + random alphanumeric suffix.
854
+ * Does NOT require a database round-trip — purely in-memory.
855
+ *
856
+ * Produces IDs like: `USR_a7b3xk9m2p1q`
857
+ *
858
+ * Good for: user-facing IDs where ordering doesn't matter.
859
+ * Not suitable for sequential numbering.
860
+ *
861
+ * @example
862
+ * ```typescript
863
+ * customIdPlugin({
864
+ * field: 'publicId',
865
+ * generator: prefixedId({ prefix: 'USR', length: 10 }),
866
+ * })
867
+ * ```
868
+ */
869
+ declare function prefixedId(options: PrefixedIdOptions): IdGenerator;
870
+ /**
871
+ * Custom ID plugin — injects generated IDs into documents before creation.
872
+ *
873
+ * @param options - Configuration for ID generation
874
+ * @returns Plugin instance
875
+ *
876
+ * @example
877
+ * ```typescript
878
+ * import { Repository, customIdPlugin, sequentialId } from '@classytic/mongokit';
879
+ *
880
+ * const invoiceRepo = new Repository(InvoiceModel, [
881
+ * customIdPlugin({
882
+ * field: 'invoiceNumber',
883
+ * generator: sequentialId({ prefix: 'INV', model: InvoiceModel }),
884
+ * }),
885
+ * ]);
886
+ *
887
+ * const inv = await invoiceRepo.create({ amount: 100 });
888
+ * console.log(inv.invoiceNumber); // "INV-0001"
889
+ * ```
890
+ */
891
+ declare function customIdPlugin(options: CustomIdOptions): Plugin;
892
+ //#endregion
893
+ export { blockIf as A, timestampPlugin as B, AggregateHelpersMethods as C, MongoOperationsMethods as D, batchOperationsPlugin as E, MethodRegistryRepository as F, methodRegistryPlugin as I, SoftDeleteMethods as L, requireField as M, uniqueField as N, mongoOperationsPlugin as O, validationChainPlugin as P, softDeletePlugin as R, subdocumentPlugin as S, BatchOperationsMethods as T, fieldFilterPlugin as V, multiTenantPlugin as _, SequentialIdOptions as a, cachePlugin as b, getNextSequence as c, ElasticSearchOptions as d, elasticSearchPlugin as f, MultiTenantOptions as g, observabilityPlugin as h, PrefixedIdOptions as i, immutableField as j, autoInject as k, prefixedId as l, OperationMetric as m, DateSequentialIdOptions as n, customIdPlugin as o, ObservabilityOptions as p, IdGenerator as r, dateSequentialId as s, CustomIdOptions as t, sequentialId as u, cascadePlugin as v, aggregateHelpersPlugin as w, SubdocumentMethods as x, CacheMethods as y, auditLogPlugin as z };