@classytic/mongokit 3.1.1 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -297,6 +297,94 @@ const repo = new Repository(UserModel, [
297
297
  ]);
298
298
  ```
299
299
 
300
+ ### MongoDB Operations Plugin
301
+
302
+ The `mongoOperationsPlugin` adds MongoDB-specific atomic operations like `increment`, `upsert`, `pushToArray`, etc.
303
+
304
+ #### Basic Usage (No TypeScript Autocomplete)
305
+
306
+ ```javascript
307
+ import { Repository, methodRegistryPlugin, mongoOperationsPlugin } from '@classytic/mongokit';
308
+
309
+ const repo = new Repository(ProductModel, [
310
+ methodRegistryPlugin(), // Required first
311
+ mongoOperationsPlugin()
312
+ ]);
313
+
314
+ // Works at runtime but TypeScript doesn't provide autocomplete
315
+ await repo.increment(productId, 'views', 1);
316
+ await repo.upsert({ sku: 'ABC' }, { name: 'Product', price: 99 });
317
+ ```
318
+
319
+ #### With TypeScript Type Safety (Recommended)
320
+
321
+ For full TypeScript autocomplete and type checking, use the `MongoOperationsMethods` type:
322
+
323
+ ```typescript
324
+ import { Repository, methodRegistryPlugin, mongoOperationsPlugin } from '@classytic/mongokit';
325
+ import type { MongoOperationsMethods } from '@classytic/mongokit';
326
+
327
+ // 1. Create your repository class
328
+ class ProductRepo extends Repository<IProduct> {
329
+ // Add custom methods here
330
+ async findBySku(sku: string) {
331
+ return this.getByQuery({ sku });
332
+ }
333
+ }
334
+
335
+ // 2. Create type helper for autocomplete
336
+ type ProductRepoWithPlugins = ProductRepo & MongoOperationsMethods<IProduct>;
337
+
338
+ // 3. Instantiate with type assertion
339
+ const repo = new ProductRepo(ProductModel, [
340
+ methodRegistryPlugin(),
341
+ mongoOperationsPlugin()
342
+ ]) as ProductRepoWithPlugins;
343
+
344
+ // 4. Now TypeScript provides full autocomplete and type checking!
345
+ await repo.increment(productId, 'views', 1); // ✅ Autocomplete works
346
+ await repo.upsert({ sku: 'ABC' }, { name: 'Product' }); // ✅ Type-safe
347
+ await repo.pushToArray(productId, 'tags', 'featured'); // ✅ Validated
348
+ await repo.findBySku('ABC'); // ✅ Custom methods too
349
+ ```
350
+
351
+ **Available operations:**
352
+ - `upsert(query, data, opts)` - Create or find document
353
+ - `increment(id, field, value, opts)` - Atomically increment field
354
+ - `decrement(id, field, value, opts)` - Atomically decrement field
355
+ - `pushToArray(id, field, value, opts)` - Add to array
356
+ - `pullFromArray(id, field, value, opts)` - Remove from array
357
+ - `addToSet(id, field, value, opts)` - Add unique value to array
358
+ - `setField(id, field, value, opts)` - Set field value
359
+ - `unsetField(id, fields, opts)` - Remove field(s)
360
+ - `renameField(id, oldName, newName, opts)` - Rename field
361
+ - `multiplyField(id, field, multiplier, opts)` - Multiply numeric field
362
+ - `setMin(id, field, value, opts)` - Set to min (if current > value)
363
+ - `setMax(id, field, value, opts)` - Set to max (if current < value)
364
+
365
+ ### Plugin Type Safety
366
+
367
+ Plugin methods are added at runtime. Use `WithPlugins<TDoc, TRepo>` for TypeScript autocomplete:
368
+
369
+ ```typescript
370
+ import type { WithPlugins } from '@classytic/mongokit';
371
+
372
+ class UserRepo extends Repository<IUser> {}
373
+
374
+ const repo = new UserRepo(Model, [
375
+ methodRegistryPlugin(),
376
+ mongoOperationsPlugin(),
377
+ // ... other plugins
378
+ ]) as WithPlugins<IUser, UserRepo>;
379
+
380
+ // Full TypeScript autocomplete!
381
+ await repo.increment(id, 'views', 1);
382
+ await repo.restore(id);
383
+ await repo.invalidateCache(id);
384
+ ```
385
+
386
+ **Individual plugin types:** `MongoOperationsMethods<T>`, `BatchOperationsMethods`, `AggregateHelpersMethods`, `SubdocumentMethods<T>`, `SoftDeleteMethods<T>`, `CacheMethods`
387
+
300
388
  ## Event System
301
389
 
302
390
  ```javascript
@@ -1,3 +1,3 @@
1
- export { b as aggregate, c as create, _ as deleteActions, r as read, u as update } from '../index-C2NCVxJK.js';
1
+ export { b as aggregate, c as create, _ as deleteActions, r as read, u as update } from '../index-BXSSv1pW.js';
2
2
  import 'mongoose';
3
- import '../types-DA0rs2Jh.js';
3
+ import '../types-B5Uv6Ak7.js';
@@ -1,5 +1,5 @@
1
1
  import { PipelineStage, ClientSession, Model } from 'mongoose';
2
- import { A as AnyDocument, y as CreateOptions, k as ObjectId, x as OperationOptions, S as SelectSpec, e as PopulateSpec, f as SortSpec, l as UpdateOptions, E as UpdateWithValidationResult, B as UpdateManyResult, z as DeleteResult, a6 as GroupResult, a7 as MinMaxResult } from './types-DA0rs2Jh.js';
2
+ import { A as AnyDocument, y as CreateOptions, k as ObjectId, x as OperationOptions, S as SelectSpec, e as PopulateSpec, f as SortSpec, l as UpdateOptions, E as UpdateWithValidationResult, B as UpdateManyResult, z as DeleteResult, a6 as GroupResult, a7 as MinMaxResult } from './types-B5Uv6Ak7.js';
3
3
 
4
4
  /**
5
5
  * LookupBuilder - MongoDB $lookup Utility
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { i as PaginationResult, A as AnyDocument, j as PluginType, P as PaginationConfig, R as RepositoryOptions, k as ObjectId, S as SelectSpec, e as PopulateSpec, f as SortSpec$2, a as OffsetPaginationResult, b as KeysetPaginationResult, l as UpdateOptions, d as AggregatePaginationResult, W as WithTransactionOptions, m as RepositoryContext, H as HttpError } from './types-DA0rs2Jh.js';
2
- export { c as AggregatePaginationOptions, n as AnyModel, C as CacheAdapter, a9 as CacheOperationOptions, a8 as CacheOptions, aa as CacheStats, ac as CascadeOptions, ab as CascadeRelation, v as CreateInput, y as CreateOptions, h as CrudSchemas, $ as DecodedCursor, D as DeepPartial, z as DeleteResult, X as EventHandlers, Y as EventPayload, Q as EventPhase, F as FieldPreset, Z as FieldRules, a6 as GroupResult, p as HookMode, I as InferDocument, q as InferRawDoc, _ as JsonSchema, t as KeysOfType, K as KeysetPaginationOptions, a2 as Logger, a7 as MinMaxResult, N as NonNullableFields, O as OffsetPaginationOptions, x as OperationOptions, r as PartialBy, G as Plugin, J as PluginFunction, T as RepositoryEvent, L as RepositoryInstance, M as RepositoryOperation, s as RequiredBy, g as SchemaBuilderOptions, a4 as SoftDeleteFilterMode, a3 as SoftDeleteOptions, a5 as SoftDeleteRepository, o as SortDirection, u as Strict, w as UpdateInput, B as UpdateManyResult, E as UpdateWithValidationResult, U as UserContext, a1 as ValidationChainOptions, V as ValidationResult, a0 as ValidatorDefinition } from './types-DA0rs2Jh.js';
1
+ import { i as PaginationResult, A as AnyDocument, j as PluginType, P as PaginationConfig, R as RepositoryOptions, k as ObjectId, S as SelectSpec, e as PopulateSpec, f as SortSpec$2, a as OffsetPaginationResult, b as KeysetPaginationResult, l as UpdateOptions, d as AggregatePaginationResult, W as WithTransactionOptions, m as RepositoryContext, H as HttpError } from './types-B5Uv6Ak7.js';
2
+ export { c as AggregatePaginationOptions, ad as AllPluginMethods, n as AnyModel, C as CacheAdapter, a9 as CacheOperationOptions, a8 as CacheOptions, aa as CacheStats, ac as CascadeOptions, ab as CascadeRelation, v as CreateInput, y as CreateOptions, h as CrudSchemas, $ as DecodedCursor, D as DeepPartial, z as DeleteResult, X as EventHandlers, Y as EventPayload, Q as EventPhase, F as FieldPreset, Z as FieldRules, a6 as GroupResult, p as HookMode, I as InferDocument, q as InferRawDoc, _ as JsonSchema, t as KeysOfType, K as KeysetPaginationOptions, a2 as Logger, a7 as MinMaxResult, N as NonNullableFields, O as OffsetPaginationOptions, x as OperationOptions, r as PartialBy, G as Plugin, J as PluginFunction, T as RepositoryEvent, L as RepositoryInstance, M as RepositoryOperation, s as RequiredBy, g as SchemaBuilderOptions, a4 as SoftDeleteFilterMode, a3 as SoftDeleteOptions, a5 as SoftDeleteRepository, o as SortDirection, u as Strict, w as UpdateInput, B as UpdateManyResult, E as UpdateWithValidationResult, U as UserContext, a1 as ValidationChainOptions, V as ValidationResult, a0 as ValidatorDefinition, ae as WithPlugins } from './types-B5Uv6Ak7.js';
3
3
  import * as mongoose from 'mongoose';
4
4
  import { PipelineStage, Expression, Model, ClientSession, PopulateOptions } from 'mongoose';
5
5
  import { PaginationEngine } from './pagination/PaginationEngine.js';
6
- import { L as LookupOptions, a as LookupBuilder } from './index-C2NCVxJK.js';
7
- export { i as actions } from './index-C2NCVxJK.js';
8
- export { aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin } from './plugins/index.js';
9
- export { d as buildCrudSchemasFromModel, b as buildCrudSchemasFromMongooseSchema, j as createError, c as createFieldPreset, k as createMemoryCache, f as filterResponseData, g as getFieldsForUser, e as getImmutableFields, a as getMongooseProjection, h as getSystemManagedFields, i as isFieldUpdateAllowed, v as validateUpdateBody } from './mongooseToJsonSchema-BKMxPbPp.js';
6
+ import { L as LookupOptions, a as LookupBuilder } from './index-BXSSv1pW.js';
7
+ export { i as actions } from './index-BXSSv1pW.js';
8
+ export { AggregateHelpersMethods, BatchOperationsMethods, CacheMethods, MongoOperationsMethods, SoftDeleteMethods, SubdocumentMethods, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin } from './plugins/index.js';
9
+ export { d as buildCrudSchemasFromModel, b as buildCrudSchemasFromMongooseSchema, j as createError, c as createFieldPreset, k as createMemoryCache, f as filterResponseData, g as getFieldsForUser, e as getImmutableFields, a as getMongooseProjection, h as getSystemManagedFields, i as isFieldUpdateAllowed, v as validateUpdateBody } from './mongooseToJsonSchema-Cc5AwuDu.js';
10
10
 
11
11
  /**
12
12
  * Framework-Agnostic Controller Interfaces
package/dist/index.js CHANGED
@@ -1073,7 +1073,7 @@ var Repository = class {
1073
1073
  if (typeof options.onFallback === "function") {
1074
1074
  options.onFallback(err);
1075
1075
  }
1076
- if (started && session.inTransaction()) {
1076
+ if (started) {
1077
1077
  try {
1078
1078
  await session.abortTransaction();
1079
1079
  } catch {
@@ -1081,8 +1081,11 @@ var Repository = class {
1081
1081
  }
1082
1082
  return await callback(null);
1083
1083
  }
1084
- if (started && session.inTransaction()) {
1085
- await session.abortTransaction();
1084
+ if (started) {
1085
+ try {
1086
+ await session.abortTransaction();
1087
+ } catch {
1088
+ }
1086
1089
  }
1087
1090
  throw err;
1088
1091
  } finally {
@@ -1,4 +1,4 @@
1
- import { U as UserContext, F as FieldPreset, H as HttpError, C as CacheAdapter, g as SchemaBuilderOptions, h as CrudSchemas, V as ValidationResult } from './types-DA0rs2Jh.js';
1
+ import { U as UserContext, F as FieldPreset, H as HttpError, C as CacheAdapter, g as SchemaBuilderOptions, h as CrudSchemas, V as ValidationResult } from './types-B5Uv6Ak7.js';
2
2
  import mongoose__default, { Schema } from 'mongoose';
3
3
 
4
4
  /**
@@ -1,5 +1,5 @@
1
1
  import { Model } from 'mongoose';
2
- import { A as AnyDocument, P as PaginationConfig, O as OffsetPaginationOptions, a as OffsetPaginationResult, K as KeysetPaginationOptions, b as KeysetPaginationResult, c as AggregatePaginationOptions, d as AggregatePaginationResult } from '../types-DA0rs2Jh.js';
2
+ import { A as AnyDocument, P as PaginationConfig, O as OffsetPaginationOptions, a as OffsetPaginationResult, K as KeysetPaginationOptions, b as KeysetPaginationResult, c as AggregatePaginationOptions, d as AggregatePaginationResult } from '../types-B5Uv6Ak7.js';
3
3
 
4
4
  /**
5
5
  * Pagination Engine
@@ -1,5 +1,5 @@
1
- import { F as FieldPreset, G as Plugin, a2 as Logger, a3 as SoftDeleteOptions, L as RepositoryInstance, a0 as ValidatorDefinition, a1 as ValidationChainOptions, m as RepositoryContext, a8 as CacheOptions, ac as CascadeOptions } from '../types-DA0rs2Jh.js';
2
- import 'mongoose';
1
+ import { F as FieldPreset, G as Plugin, a2 as Logger, a3 as SoftDeleteOptions, k as ObjectId, f as SortSpec, S as SelectSpec, e as PopulateSpec, a as OffsetPaginationResult, L as RepositoryInstance, a0 as ValidatorDefinition, a1 as ValidationChainOptions, m as RepositoryContext, a8 as CacheOptions, aa as CacheStats, ac as CascadeOptions } from '../types-B5Uv6Ak7.js';
2
+ import { ClientSession } from 'mongoose';
3
3
 
4
4
  /**
5
5
  * Field Filter Plugin
@@ -92,6 +92,53 @@ declare function auditLogPlugin(logger: Logger): Plugin;
92
92
  * ```
93
93
  */
94
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
+ }
95
142
 
96
143
  /**
97
144
  * Method Registry Plugin
@@ -178,16 +225,189 @@ declare function uniqueField(field: string, errorMessage?: string): ValidatorDef
178
225
  /**
179
226
  * MongoDB operations plugin
180
227
  *
181
- * @example
182
- * const repo = new Repository(Model, [
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, [
183
239
  * methodRegistryPlugin(),
184
240
  * mongoOperationsPlugin(),
185
241
  * ]);
186
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!
187
266
  * await repo.increment(productId, 'views', 1);
267
+ * await repo.upsert({ sku: 'ABC' }, { name: 'Product', price: 99 });
188
268
  * await repo.pushToArray(productId, 'tags', 'featured');
269
+ * ```
189
270
  */
190
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
+ }
191
411
 
192
412
  /**
193
413
  * Batch Operations Plugin
@@ -207,6 +427,57 @@ declare function mongoOperationsPlugin(): Plugin;
207
427
  * await repo.deleteMany({ status: 'deleted' });
208
428
  */
209
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
+ }
210
481
 
211
482
  /**
212
483
  * Aggregate Helpers Plugin
@@ -226,6 +497,76 @@ declare function batchOperationsPlugin(): Plugin;
226
497
  * const total = await repo.sum('amount', { status: 'completed' });
227
498
  */
228
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
+ }
229
570
 
230
571
  /**
231
572
  * Subdocument Plugin
@@ -245,6 +586,73 @@ declare function aggregateHelpersPlugin(): Plugin;
245
586
  * await repo.updateSubdocument(parentId, 'items', itemId, { name: 'Updated Item' });
246
587
  */
247
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
+ }
248
656
 
249
657
  /**
250
658
  * Cache Plugin
@@ -303,6 +711,55 @@ declare function subdocumentPlugin(): Plugin;
303
711
  * @returns Plugin instance
304
712
  */
305
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
+ }
306
763
 
307
764
  /**
308
765
  * Cascade Delete Plugin
@@ -339,4 +796,4 @@ declare function cachePlugin(options: CacheOptions): Plugin;
339
796
  */
340
797
  declare function cascadePlugin(options: CascadeOptions): Plugin;
341
798
 
342
- export { type MethodRegistryRepository, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
799
+ export { type AggregateHelpersMethods, type BatchOperationsMethods, type CacheMethods, type MethodRegistryRepository, type MongoOperationsMethods, type SoftDeleteMethods, type SubdocumentMethods, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
@@ -646,5 +646,128 @@ interface HttpError extends Error {
646
646
  error: string;
647
647
  }>;
648
648
  }
649
+ /**
650
+ * Combines all plugin method types into a single type
651
+ * Useful when you're using all plugins and want full type safety
652
+ *
653
+ * @example
654
+ * ```typescript
655
+ * import { Repository } from '@classytic/mongokit';
656
+ * import type { AllPluginMethods } from '@classytic/mongokit';
657
+ *
658
+ * class UserRepo extends Repository<IUser> {}
659
+ *
660
+ * const repo = new UserRepo(Model, [...allPlugins]) as UserRepo & AllPluginMethods<IUser>;
661
+ *
662
+ * // TypeScript knows about all plugin methods!
663
+ * await repo.increment(id, 'views', 1);
664
+ * await repo.restore(id);
665
+ * await repo.invalidateCache(id);
666
+ * ```
667
+ *
668
+ * Note: Import the individual plugin method types if you need them:
669
+ * ```typescript
670
+ * import type {
671
+ * MongoOperationsMethods,
672
+ * BatchOperationsMethods,
673
+ * AggregateHelpersMethods,
674
+ * SubdocumentMethods,
675
+ * SoftDeleteMethods,
676
+ * CacheMethods,
677
+ * } from '@classytic/mongokit';
678
+ * ```
679
+ */
680
+ type AllPluginMethods<TDoc> = {
681
+ upsert(query: Record<string, unknown>, data: Record<string, unknown>, options?: Record<string, unknown>): Promise<TDoc>;
682
+ increment(id: string | ObjectId, field: string, value?: number, options?: Record<string, unknown>): Promise<TDoc>;
683
+ decrement(id: string | ObjectId, field: string, value?: number, options?: Record<string, unknown>): Promise<TDoc>;
684
+ pushToArray(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
685
+ pullFromArray(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
686
+ addToSet(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
687
+ setField(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
688
+ unsetField(id: string | ObjectId, fields: string | string[], options?: Record<string, unknown>): Promise<TDoc>;
689
+ renameField(id: string | ObjectId, oldName: string, newName: string, options?: Record<string, unknown>): Promise<TDoc>;
690
+ multiplyField(id: string | ObjectId, field: string, multiplier: number, options?: Record<string, unknown>): Promise<TDoc>;
691
+ setMin(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
692
+ setMax(id: string | ObjectId, field: string, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
693
+ updateMany(query: Record<string, unknown>, data: Record<string, unknown>, options?: {
694
+ session?: ClientSession;
695
+ updatePipeline?: boolean;
696
+ }): Promise<{
697
+ acknowledged: boolean;
698
+ matchedCount: number;
699
+ modifiedCount: number;
700
+ upsertedCount: number;
701
+ upsertedId: unknown;
702
+ }>;
703
+ deleteMany(query: Record<string, unknown>, options?: Record<string, unknown>): Promise<{
704
+ acknowledged: boolean;
705
+ deletedCount: number;
706
+ }>;
707
+ groupBy(field: string, options?: {
708
+ limit?: number;
709
+ session?: unknown;
710
+ }): Promise<Array<{
711
+ _id: unknown;
712
+ count: number;
713
+ }>>;
714
+ sum(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
715
+ average(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
716
+ min(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
717
+ max(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
718
+ addSubdocument(parentId: string | ObjectId, arrayPath: string, subData: Record<string, unknown>, options?: Record<string, unknown>): Promise<TDoc>;
719
+ getSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, options?: {
720
+ lean?: boolean;
721
+ session?: unknown;
722
+ }): Promise<Record<string, unknown>>;
723
+ updateSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, updateData: Record<string, unknown>, options?: {
724
+ session?: unknown;
725
+ }): Promise<TDoc>;
726
+ deleteSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, options?: Record<string, unknown>): Promise<TDoc>;
727
+ restore(id: string | ObjectId, options?: {
728
+ session?: ClientSession;
729
+ }): Promise<TDoc>;
730
+ getDeleted(params?: {
731
+ filters?: Record<string, unknown>;
732
+ sort?: SortSpec | string;
733
+ page?: number;
734
+ limit?: number;
735
+ }, options?: {
736
+ select?: SelectSpec;
737
+ populate?: PopulateSpec;
738
+ lean?: boolean;
739
+ session?: ClientSession;
740
+ }): Promise<OffsetPaginationResult<TDoc>>;
741
+ invalidateCache(id: string): Promise<void>;
742
+ invalidateListCache(): Promise<void>;
743
+ invalidateAllCache(): Promise<void>;
744
+ getCacheStats(): CacheStats;
745
+ resetCacheStats(): void;
746
+ };
747
+ /**
748
+ * Helper type to add all plugin methods to a repository class
749
+ * Cleaner than manually typing the intersection
750
+ *
751
+ * @example
752
+ * ```typescript
753
+ * import { Repository } from '@classytic/mongokit';
754
+ * import type { WithPlugins } from '@classytic/mongokit';
755
+ *
756
+ * class OrderRepo extends Repository<IOrder> {
757
+ * async getCustomerOrders(customerId: string) {
758
+ * return this.getAll({ filters: { customerId } });
759
+ * }
760
+ * }
761
+ *
762
+ * const orderRepo = new OrderRepo(Model, [
763
+ * ...allPlugins
764
+ * ]) as WithPlugins<IOrder, OrderRepo>;
765
+ *
766
+ * // Works: custom methods + plugin methods
767
+ * await orderRepo.getCustomerOrders('123');
768
+ * await orderRepo.increment(orderId, 'total', 100);
769
+ * ```
770
+ */
771
+ type WithPlugins<TDoc, TRepo extends RepositoryInstance = RepositoryInstance> = TRepo & AllPluginMethods<TDoc>;
649
772
 
650
- export type { DecodedCursor as $, AnyDocument as A, UpdateManyResult as B, CacheAdapter as C, DeepPartial as D, UpdateWithValidationResult as E, FieldPreset as F, Plugin as G, HttpError as H, InferDocument as I, PluginFunction as J, KeysetPaginationOptions as K, RepositoryInstance as L, RepositoryOperation as M, NonNullableFields as N, OffsetPaginationOptions as O, PaginationConfig as P, EventPhase as Q, RepositoryOptions as R, SelectSpec as S, RepositoryEvent as T, UserContext as U, ValidationResult as V, WithTransactionOptions as W, EventHandlers as X, EventPayload as Y, FieldRules as Z, JsonSchema as _, OffsetPaginationResult as a, ValidatorDefinition as a0, ValidationChainOptions as a1, Logger as a2, SoftDeleteOptions as a3, SoftDeleteFilterMode as a4, SoftDeleteRepository as a5, GroupResult as a6, MinMaxResult as a7, CacheOptions as a8, CacheOperationOptions as a9, CacheStats as aa, CascadeRelation as ab, CascadeOptions as ac, KeysetPaginationResult as b, AggregatePaginationOptions as c, AggregatePaginationResult as d, PopulateSpec as e, SortSpec as f, SchemaBuilderOptions as g, CrudSchemas as h, PaginationResult as i, PluginType as j, ObjectId as k, UpdateOptions as l, RepositoryContext as m, AnyModel as n, SortDirection as o, HookMode as p, InferRawDoc as q, PartialBy as r, RequiredBy as s, KeysOfType as t, Strict as u, CreateInput as v, UpdateInput as w, OperationOptions as x, CreateOptions as y, DeleteResult as z };
773
+ export type { DecodedCursor as $, AnyDocument as A, UpdateManyResult as B, CacheAdapter as C, DeepPartial as D, UpdateWithValidationResult as E, FieldPreset as F, Plugin as G, HttpError as H, InferDocument as I, PluginFunction as J, KeysetPaginationOptions as K, RepositoryInstance as L, RepositoryOperation as M, NonNullableFields as N, OffsetPaginationOptions as O, PaginationConfig as P, EventPhase as Q, RepositoryOptions as R, SelectSpec as S, RepositoryEvent as T, UserContext as U, ValidationResult as V, WithTransactionOptions as W, EventHandlers as X, EventPayload as Y, FieldRules as Z, JsonSchema as _, OffsetPaginationResult as a, ValidatorDefinition as a0, ValidationChainOptions as a1, Logger as a2, SoftDeleteOptions as a3, SoftDeleteFilterMode as a4, SoftDeleteRepository as a5, GroupResult as a6, MinMaxResult as a7, CacheOptions as a8, CacheOperationOptions as a9, CacheStats as aa, CascadeRelation as ab, CascadeOptions as ac, AllPluginMethods as ad, WithPlugins as ae, KeysetPaginationResult as b, AggregatePaginationOptions as c, AggregatePaginationResult as d, PopulateSpec as e, SortSpec as f, SchemaBuilderOptions as g, CrudSchemas as h, PaginationResult as i, PluginType as j, ObjectId as k, UpdateOptions as l, RepositoryContext as m, AnyModel as n, SortDirection as o, HookMode as p, InferRawDoc as q, PartialBy as r, RequiredBy as s, KeysOfType as t, Strict as u, CreateInput as v, UpdateInput as w, OperationOptions as x, CreateOptions as y, DeleteResult as z };
@@ -1,5 +1,5 @@
1
- export { d as buildCrudSchemasFromModel, b as buildCrudSchemasFromMongooseSchema, j as createError, c as createFieldPreset, k as createMemoryCache, f as filterResponseData, g as getFieldsForUser, e as getImmutableFields, a as getMongooseProjection, h as getSystemManagedFields, i as isFieldUpdateAllowed, v as validateUpdateBody } from '../mongooseToJsonSchema-BKMxPbPp.js';
2
- import { S as SelectSpec, e as PopulateSpec, f as SortSpec } from '../types-DA0rs2Jh.js';
1
+ export { d as buildCrudSchemasFromModel, b as buildCrudSchemasFromMongooseSchema, j as createError, c as createFieldPreset, k as createMemoryCache, f as filterResponseData, g as getFieldsForUser, e as getImmutableFields, a as getMongooseProjection, h as getSystemManagedFields, i as isFieldUpdateAllowed, v as validateUpdateBody } from '../mongooseToJsonSchema-Cc5AwuDu.js';
2
+ import { S as SelectSpec, e as PopulateSpec, f as SortSpec } from '../types-B5Uv6Ak7.js';
3
3
  import 'mongoose';
4
4
 
5
5
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/mongokit",
3
- "version": "3.1.1",
3
+ "version": "3.1.3",
4
4
  "description": "Production-grade MongoDB repositories with zero dependencies - smart pagination, events, and plugins",
5
5
  "type": "module",
6
6
  "sideEffects": false,