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