@classytic/mongokit 3.0.0 → 3.0.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.
- package/README.md +251 -846
- package/dist/actions/index.d.ts +2 -2
- package/dist/actions/index.js +13 -2
- package/dist/{index-CgOJ2pqz.d.ts → index-CMCrkd2v.d.ts} +11 -11
- package/dist/index.d.ts +19 -17
- package/dist/index.js +250 -23
- package/dist/{memory-cache-DG2oSSbx.d.ts → memory-cache-Bn_-Kk-0.d.ts} +1 -1
- package/dist/pagination/PaginationEngine.d.ts +1 -1
- package/dist/pagination/PaginationEngine.js +0 -2
- package/dist/plugins/index.d.ts +37 -2
- package/dist/plugins/index.js +181 -4
- package/dist/{types-Nxhmi1aI.d.ts → types-B3dPUKjs.d.ts} +28 -2
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +0 -2
- package/package.json +2 -1
- package/dist/actions/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/pagination/PaginationEngine.js.map +0 -1
- package/dist/plugins/index.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/error.ts","../src/actions/create.ts","../src/actions/read.ts","../src/actions/update.ts","../src/actions/delete.ts","../src/actions/aggregate.ts","../src/pagination/utils/cursor.ts","../src/pagination/utils/sort.ts","../src/pagination/utils/filter.ts","../src/pagination/utils/limits.ts","../src/pagination/PaginationEngine.ts","../src/Repository.ts","../src/utils/field-selection.ts","../src/plugins/field-filter.plugin.ts","../src/plugins/timestamp.plugin.ts","../src/plugins/audit-log.plugin.ts","../src/plugins/soft-delete.plugin.ts","../src/plugins/method-registry.plugin.ts","../src/plugins/validation-chain.plugin.ts","../src/plugins/mongo-operations.plugin.ts","../src/plugins/batch-operations.plugin.ts","../src/plugins/aggregate-helpers.plugin.ts","../src/plugins/subdocument.plugin.ts","../src/utils/cache-keys.ts","../src/plugins/cache.plugin.ts","../src/utils/memory-cache.ts","../src/actions/index.ts","../src/index.ts"],"names":["parsePopulate","result","mongoose","getByQuery","aggregate","update"],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Error Utilities\r\n * \r\n * HTTP-compatible error creation for repository operations\r\n */\r\n\r\nimport type { HttpError } from '../types.js';\r\n\r\n/**\r\n * Creates an error with HTTP status code\r\n *\r\n * @param status - HTTP status code\r\n * @param message - Error message\r\n * @returns Error with status property\r\n * \r\n * @example\r\n * throw createError(404, 'Document not found');\r\n * throw createError(400, 'Invalid input');\r\n * throw createError(403, 'Access denied');\r\n */\r\nexport function createError(status: number, message: string): HttpError {\r\n const error = new Error(message) as HttpError;\r\n error.status = status;\r\n return error;\r\n}\r\n","/**\r\n * Create Actions\r\n * Pure functions for document creation\r\n */\r\n\r\nimport type { Model, ClientSession, SchemaType } from 'mongoose';\r\nimport type { CreateOptions, AnyDocument } from '../types.js';\r\n\r\n/**\r\n * Create single document\r\n */\r\nexport async function create<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n data: Record<string, unknown>,\r\n options: CreateOptions = {}\r\n): Promise<TDoc> {\r\n const document = new Model(data);\r\n await document.save({ session: options.session });\r\n return document as TDoc;\r\n}\r\n\r\n/**\r\n * Create multiple documents\r\n */\r\nexport async function createMany<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n dataArray: Record<string, unknown>[],\r\n options: CreateOptions = {}\r\n): Promise<TDoc[]> {\r\n return Model.insertMany(dataArray, {\r\n session: options.session,\r\n ordered: options.ordered !== false,\r\n }) as Promise<TDoc[]>;\r\n}\r\n\r\n/**\r\n * Create with defaults (useful for initialization)\r\n */\r\nexport async function createDefault<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n overrides: Record<string, unknown> = {},\r\n options: CreateOptions = {}\r\n): Promise<TDoc> {\r\n const defaults: Record<string, unknown> = {};\r\n\r\n // Extract defaults from schema\r\n Model.schema.eachPath((path: string, schemaType: SchemaType) => {\r\n const schemaOptions = schemaType.options as { default?: unknown };\r\n if (schemaOptions.default !== undefined && path !== '_id') {\r\n defaults[path] = typeof schemaOptions.default === 'function'\r\n ? schemaOptions.default()\r\n : schemaOptions.default;\r\n }\r\n });\r\n\r\n return create(Model, { ...defaults, ...overrides }, options);\r\n}\r\n\r\n/**\r\n * Upsert (create or update)\r\n */\r\nexport async function upsert<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: { session?: ClientSession; updatePipeline?: boolean } = {}\r\n): Promise<TDoc | null> {\r\n return Model.findOneAndUpdate(\r\n query,\r\n { $setOnInsert: data },\r\n {\r\n upsert: true,\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n }\r\n );\r\n}\r\n","/**\r\n * Read Actions\r\n * Pure functions for document retrieval\r\n */\r\n\r\nimport type { Model, ClientSession, PopulateOptions } from 'mongoose';\r\nimport { createError } from '../utils/error.js';\r\nimport type { AnyDocument, SelectSpec, PopulateSpec, SortSpec, OperationOptions } from '../types.js';\r\n\r\n/**\r\n * Parse populate specification into consistent format\r\n */\r\nfunction parsePopulate(populate: PopulateSpec | undefined): (string | PopulateOptions)[] {\r\n if (!populate) return [];\r\n if (typeof populate === 'string') {\r\n return populate.split(',').map(p => p.trim());\r\n }\r\n if (Array.isArray(populate)) {\r\n return populate.map(p => typeof p === 'string' ? p.trim() : p);\r\n }\r\n return [populate];\r\n}\r\n\r\n/**\r\n * Get document by ID\r\n *\r\n * @param Model - Mongoose model\r\n * @param id - Document ID\r\n * @param options - Query options\r\n * @returns Document or null\r\n * @throws Error if document not found and throwOnNotFound is true\r\n */\r\nexport async function getById<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n options: OperationOptions = {}\r\n): Promise<TDoc | null> {\r\n // If additional query filters are provided (e.g., soft delete filter), use findOne\r\n const query = options.query\r\n ? Model.findOne({ _id: id, ...options.query })\r\n : Model.findById(id);\r\n\r\n if (options.select) query.select(options.select);\r\n if (options.populate) query.populate(parsePopulate(options.populate));\r\n if (options.lean) query.lean();\r\n if (options.session) query.session(options.session);\r\n\r\n const document = await query.exec();\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document;\r\n}\r\n\r\n/**\r\n * Get document by query\r\n *\r\n * @param Model - Mongoose model\r\n * @param query - MongoDB query\r\n * @param options - Query options\r\n * @returns Document or null\r\n * @throws Error if document not found and throwOnNotFound is true\r\n */\r\nexport async function getByQuery<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n options: OperationOptions = {}\r\n): Promise<TDoc | null> {\r\n const mongoQuery = Model.findOne(query);\r\n\r\n if (options.select) mongoQuery.select(options.select);\r\n if (options.populate) mongoQuery.populate(parsePopulate(options.populate));\r\n if (options.lean) mongoQuery.lean();\r\n if (options.session) mongoQuery.session(options.session);\r\n\r\n const document = await mongoQuery.exec();\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document;\r\n}\r\n\r\n/**\r\n * Get document by query without throwing (returns null if not found)\r\n */\r\nexport async function tryGetByQuery<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n options: Omit<OperationOptions, 'throwOnNotFound'> = {}\r\n): Promise<TDoc | null> {\r\n return getByQuery(Model, query, { ...options, throwOnNotFound: false });\r\n}\r\n\r\n/**\r\n * Get all documents (basic query without pagination)\r\n * For pagination, use Repository.paginate() or Repository.stream()\r\n */\r\nexport async function getAll<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown> = {},\r\n options: {\r\n select?: SelectSpec;\r\n populate?: PopulateSpec;\r\n sort?: SortSpec;\r\n limit?: number;\r\n skip?: number;\r\n lean?: boolean;\r\n session?: ClientSession;\r\n } = {}\r\n): Promise<TDoc[]> {\r\n let mongoQuery = Model.find(query);\r\n\r\n if (options.select) mongoQuery = mongoQuery.select(options.select);\r\n if (options.populate) mongoQuery = mongoQuery.populate(parsePopulate(options.populate));\r\n if (options.sort) mongoQuery = mongoQuery.sort(options.sort);\r\n if (options.limit) mongoQuery = mongoQuery.limit(options.limit);\r\n if (options.skip) mongoQuery = mongoQuery.skip(options.skip);\r\n\r\n mongoQuery = mongoQuery.lean(options.lean !== false);\r\n if (options.session) mongoQuery = mongoQuery.session(options.session);\r\n\r\n return mongoQuery.exec() as Promise<TDoc[]>;\r\n}\r\n\r\n/**\r\n * Get or create document (upsert)\r\n */\r\nexport async function getOrCreate<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n createData: Record<string, unknown>,\r\n options: { session?: ClientSession; updatePipeline?: boolean } = {}\r\n): Promise<TDoc | null> {\r\n return Model.findOneAndUpdate(\r\n query,\r\n { $setOnInsert: createData },\r\n {\r\n upsert: true,\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n }\r\n );\r\n}\r\n\r\n/**\r\n * Count documents matching query\r\n */\r\nexport async function count(\r\n Model: Model<any>,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<number> {\r\n return Model.countDocuments(query).session(options.session ?? null);\r\n}\r\n\r\n/**\r\n * Check if document exists\r\n */\r\nexport async function exists(\r\n Model: Model<any>,\r\n query: Record<string, unknown>,\r\n options: { session?: ClientSession } = {}\r\n): Promise<{ _id: unknown } | null> {\r\n return Model.exists(query).session(options.session ?? null);\r\n}\r\n","/**\r\n * Update Actions\r\n * Pure functions for document updates with optimizations\r\n */\r\n\r\nimport type { Model, ClientSession, PopulateOptions } from 'mongoose';\r\nimport { createError } from '../utils/error.js';\r\nimport type { AnyDocument, UpdateOptions, UpdateManyResult, UpdateWithValidationResult } from '../types.js';\r\n\r\n/**\r\n * Parse populate specification into consistent format\r\n */\r\nfunction parsePopulate(populate: unknown): (string | PopulateOptions)[] {\r\n if (!populate) return [];\r\n if (typeof populate === 'string') {\r\n return populate.split(',').map(p => p.trim());\r\n }\r\n if (Array.isArray(populate)) {\r\n return populate.map(p => typeof p === 'string' ? p.trim() : p as PopulateOptions);\r\n }\r\n return [populate as PopulateOptions];\r\n}\r\n\r\n/**\r\n * Update by ID\r\n */\r\nexport async function update<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n data: Record<string, unknown>,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n const document = await Model.findByIdAndUpdate(id, data, {\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n })\r\n .select(options.select || '')\r\n .populate(parsePopulate(options.populate))\r\n .lean(options.lean ?? false);\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document as TDoc;\r\n}\r\n\r\n/**\r\n * Update with query constraints (optimized)\r\n * Returns null if constraints not met (not an error)\r\n */\r\nexport async function updateWithConstraints<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n data: Record<string, unknown>,\r\n constraints: Record<string, unknown> = {},\r\n options: UpdateOptions = {}\r\n): Promise<TDoc | null> {\r\n const query = { _id: id, ...constraints };\r\n\r\n const document = await Model.findOneAndUpdate(query, data, {\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n })\r\n .select(options.select || '')\r\n .populate(parsePopulate(options.populate))\r\n .lean(options.lean ?? false);\r\n\r\n return document as TDoc | null;\r\n}\r\n\r\n/**\r\n * Validation options for smart update\r\n */\r\ninterface ValidationOptions {\r\n buildConstraints?: (data: Record<string, unknown>) => Record<string, unknown>;\r\n validateUpdate?: (\r\n existing: Record<string, unknown>,\r\n data: Record<string, unknown>\r\n ) => { valid: boolean; message?: string; violations?: Array<{ field: string; reason: string }> };\r\n}\r\n\r\n/**\r\n * Update with validation (smart optimization)\r\n * 1-query on success, 2-queries for detailed errors\r\n */\r\nexport async function updateWithValidation<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n data: Record<string, unknown>,\r\n validationOptions: ValidationOptions = {},\r\n options: UpdateOptions = {}\r\n): Promise<UpdateWithValidationResult<TDoc>> {\r\n const { buildConstraints, validateUpdate } = validationOptions;\r\n\r\n // Try optimized update with constraints\r\n if (buildConstraints) {\r\n const constraints = buildConstraints(data);\r\n const document = await updateWithConstraints(Model, id, data, constraints, options);\r\n\r\n if (document) {\r\n return { success: true, data: document };\r\n }\r\n }\r\n\r\n // Fetch for validation\r\n const existing = await Model.findById(id).select(options.select || '').lean();\r\n\r\n if (!existing) {\r\n return {\r\n success: false,\r\n error: {\r\n code: 404,\r\n message: 'Document not found',\r\n },\r\n };\r\n }\r\n\r\n // Run custom validation\r\n if (validateUpdate) {\r\n const validation = validateUpdate(existing as Record<string, unknown>, data);\r\n if (!validation.valid) {\r\n return {\r\n success: false,\r\n error: {\r\n code: 403,\r\n message: validation.message || 'Update not allowed',\r\n violations: validation.violations,\r\n },\r\n };\r\n }\r\n }\r\n\r\n // Validation passed - perform update\r\n const updated = await update(Model, id, data, options);\r\n return { success: true, data: updated };\r\n}\r\n\r\n/**\r\n * Update many documents\r\n */\r\nexport async function updateMany(\r\n Model: Model<unknown>,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: { session?: ClientSession; updatePipeline?: boolean } = {}\r\n): Promise<UpdateManyResult> {\r\n const result = await Model.updateMany(query, data, {\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n });\r\n\r\n return {\r\n matchedCount: result.matchedCount,\r\n modifiedCount: result.modifiedCount,\r\n };\r\n}\r\n\r\n/**\r\n * Update by query\r\n */\r\nexport async function updateByQuery<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc | null> {\r\n const document = await Model.findOneAndUpdate(query, data, {\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n })\r\n .select(options.select || '')\r\n .populate(parsePopulate(options.populate))\r\n .lean(options.lean ?? false);\r\n\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document as TDoc | null;\r\n}\r\n\r\n/**\r\n * Increment field\r\n */\r\nexport async function increment<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n field: string,\r\n value: number = 1,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n return update(Model, id, { $inc: { [field]: value } }, options);\r\n}\r\n\r\n/**\r\n * Push to array\r\n */\r\nexport async function pushToArray<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n field: string,\r\n value: unknown,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n return update(Model, id, { $push: { [field]: value } }, options);\r\n}\r\n\r\n/**\r\n * Pull from array\r\n */\r\nexport async function pullFromArray<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n field: string,\r\n value: unknown,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n return update(Model, id, { $pull: { [field]: value } }, options);\r\n}\r\n","/**\r\n * Delete Actions\r\n * Pure functions for document deletion\r\n */\r\n\r\nimport type { Model, ClientSession } from 'mongoose';\r\nimport { createError } from '../utils/error.js';\r\nimport type { DeleteResult, AnyDocument } from '../types.js';\r\n\r\n/**\r\n * Delete by ID\r\n */\r\nexport async function deleteById(\r\n Model: Model<any>,\r\n id: string,\r\n options: { session?: ClientSession } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findByIdAndDelete(id).session(options.session ?? null);\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Deleted successfully' };\r\n}\r\n\r\n/**\r\n * Delete many documents\r\n */\r\nexport async function deleteMany(\r\n Model: Model<any>,\r\n query: Record<string, unknown>,\r\n options: { session?: ClientSession } = {}\r\n): Promise<DeleteResult> {\r\n const result = await Model.deleteMany(query).session(options.session ?? null);\r\n\r\n return {\r\n success: true,\r\n count: result.deletedCount,\r\n message: 'Deleted successfully',\r\n };\r\n}\r\n\r\n/**\r\n * Delete by query\r\n */\r\nexport async function deleteByQuery(\r\n Model: Model<any>,\r\n query: Record<string, unknown>,\r\n options: { session?: ClientSession; throwOnNotFound?: boolean } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findOneAndDelete(query).session(options.session ?? null);\r\n\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Deleted successfully' };\r\n}\r\n\r\n/**\r\n * Soft delete (set deleted flag)\r\n */\r\nexport async function softDelete<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n options: { session?: ClientSession; userId?: string } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findByIdAndUpdate(\r\n id,\r\n {\r\n deleted: true,\r\n deletedAt: new Date(),\r\n deletedBy: options.userId,\r\n },\r\n { new: true, session: options.session }\r\n );\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Soft deleted successfully' };\r\n}\r\n\r\n/**\r\n * Restore soft deleted document\r\n */\r\nexport async function restore<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n options: { session?: ClientSession } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findByIdAndUpdate(\r\n id,\r\n {\r\n deleted: false,\r\n deletedAt: null,\r\n deletedBy: null,\r\n },\r\n { new: true, session: options.session }\r\n );\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Restored successfully' };\r\n}\r\n","/**\r\n * Aggregate Actions\r\n * MongoDB aggregation pipeline operations\r\n */\r\n\r\nimport type { Model, ClientSession, PipelineStage } from 'mongoose';\r\nimport type { AnyDocument, LookupOptions, GroupResult, MinMaxResult } from '../types.js';\r\n\r\n/**\r\n * Execute aggregation pipeline\r\n */\r\nexport async function aggregate<TResult = unknown>(\r\n Model: Model<any>,\r\n pipeline: PipelineStage[],\r\n options: { session?: ClientSession } = {}\r\n): Promise<TResult[]> {\r\n const aggregation = Model.aggregate(pipeline);\r\n\r\n if (options.session) {\r\n aggregation.session(options.session);\r\n }\r\n\r\n return aggregation.exec() as Promise<TResult[]>;\r\n}\r\n\r\n/**\r\n * Aggregate with pagination using native MongoDB $facet\r\n * WARNING: $facet results must be <16MB. For larger results (limit >1000),\r\n * consider using Repository.aggregatePaginate() or splitting into separate queries.\r\n */\r\nexport async function aggregatePaginate<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n pipeline: PipelineStage[],\r\n options: { page?: number; limit?: number; session?: ClientSession } = {}\r\n): Promise<{\r\n docs: TDoc[];\r\n total: number;\r\n page: number;\r\n limit: number;\r\n pages: number;\r\n hasNext: boolean;\r\n hasPrev: boolean;\r\n}> {\r\n const page = parseInt(String(options.page || 1), 10);\r\n const limit = parseInt(String(options.limit || 10), 10);\r\n const skip = (page - 1) * limit;\r\n\r\n // 16MB MongoDB document size limit safety check\r\n const SAFE_LIMIT = 1000;\r\n if (limit > SAFE_LIMIT) {\r\n console.warn(\r\n `[mongokit] Large aggregation limit (${limit}). $facet results must be <16MB. ` +\r\n `Consider using Repository.aggregatePaginate() for safer handling of large datasets.`\r\n );\r\n }\r\n\r\n const facetPipeline: PipelineStage[] = [\r\n ...pipeline,\r\n {\r\n $facet: {\r\n docs: [{ $skip: skip }, { $limit: limit }],\r\n total: [{ $count: 'count' }],\r\n },\r\n },\r\n ];\r\n\r\n const aggregation = Model.aggregate(facetPipeline);\r\n if (options.session) {\r\n aggregation.session(options.session);\r\n }\r\n\r\n const [result] = await aggregation.exec() as [{ docs: TDoc[]; total: { count: number }[] }];\r\n const docs = result.docs || [];\r\n const total = result.total[0]?.count || 0;\r\n const pages = Math.ceil(total / limit);\r\n\r\n return {\r\n docs,\r\n total,\r\n page,\r\n limit,\r\n pages,\r\n hasNext: page < pages,\r\n hasPrev: page > 1,\r\n };\r\n}\r\n\r\n/**\r\n * Group documents by field value\r\n */\r\nexport async function groupBy(\r\n Model: Model<any>,\r\n field: string,\r\n options: { limit?: number; session?: ClientSession } = {}\r\n): Promise<GroupResult[]> {\r\n const pipeline: PipelineStage[] = [\r\n { $group: { _id: `$${field}`, count: { $sum: 1 } } },\r\n { $sort: { count: -1 } },\r\n ];\r\n\r\n if (options.limit) {\r\n pipeline.push({ $limit: options.limit });\r\n }\r\n\r\n return aggregate(Model, pipeline, options);\r\n}\r\n\r\n/**\r\n * Count by field values\r\n */\r\nexport async function countBy(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<GroupResult[]> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push(\r\n { $group: { _id: `$${field}`, count: { $sum: 1 } } },\r\n { $sort: { count: -1 } }\r\n );\r\n\r\n return aggregate(Model, pipeline, options);\r\n}\r\n\r\n/**\r\n * Lookup (join) with another collection\r\n */\r\nexport async function lookup<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n lookupOptions: LookupOptions\r\n): Promise<TDoc[]> {\r\n const { from, localField, foreignField, as, pipeline = [], query = {}, options = {} } = lookupOptions;\r\n\r\n const aggPipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n aggPipeline.push({ $match: query });\r\n }\r\n\r\n aggPipeline.push({\r\n $lookup: {\r\n from,\r\n localField,\r\n foreignField,\r\n as,\r\n ...(pipeline.length > 0 ? { pipeline: pipeline as any } : {}),\r\n },\r\n } as any);\r\n\r\n return aggregate(Model, aggPipeline, options);\r\n}\r\n\r\n/**\r\n * Unwind array field\r\n */\r\nexport async function unwind<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n field: string,\r\n options: { preserveEmpty?: boolean; session?: ClientSession } = {}\r\n): Promise<TDoc[]> {\r\n const pipeline: PipelineStage[] = [\r\n {\r\n $unwind: {\r\n path: `$${field}`,\r\n preserveNullAndEmptyArrays: options.preserveEmpty !== false,\r\n },\r\n },\r\n ];\r\n\r\n return aggregate(Model, pipeline, { session: options.session });\r\n}\r\n\r\n/**\r\n * Facet search (multiple aggregations in one query)\r\n */\r\nexport async function facet<TResult = Record<string, unknown[]>>(\r\n Model: Model<any>,\r\n facets: Record<string, PipelineStage[]>,\r\n options: { session?: ClientSession } = {}\r\n): Promise<TResult[]> {\r\n const pipeline: PipelineStage[] = [{ $facet: facets as any } as any];\r\n\r\n return aggregate(Model, pipeline, options);\r\n}\r\n\r\n/**\r\n * Get distinct values\r\n */\r\nexport async function distinct<T = unknown>(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<T[]> {\r\n return Model.distinct(field, query).session(options.session ?? null) as Promise<T[]>;\r\n}\r\n\r\n/**\r\n * Calculate sum\r\n */\r\nexport async function sum(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<number> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push({\r\n $group: {\r\n _id: null,\r\n total: { $sum: `$${field}` },\r\n },\r\n });\r\n\r\n const result = await aggregate<{ total: number }>(Model, pipeline, options);\r\n return result[0]?.total || 0;\r\n}\r\n\r\n/**\r\n * Calculate average\r\n */\r\nexport async function average(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<number> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push({\r\n $group: {\r\n _id: null,\r\n average: { $avg: `$${field}` },\r\n },\r\n });\r\n\r\n const result = await aggregate<{ average: number }>(Model, pipeline, options);\r\n return result[0]?.average || 0;\r\n}\r\n\r\n/**\r\n * Min/Max\r\n */\r\nexport async function minMax(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<MinMaxResult> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push({\r\n $group: {\r\n _id: null,\r\n min: { $min: `$${field}` },\r\n max: { $max: `$${field}` },\r\n },\r\n });\r\n\r\n const result = await aggregate<MinMaxResult>(Model, pipeline, options);\r\n return result[0] || { min: null, max: null };\r\n}\r\n","/**\r\n * Cursor Utilities\r\n * \r\n * Encoding and decoding of cursor tokens for keyset pagination.\r\n * Cursors are base64-encoded JSON containing position data and metadata.\r\n */\r\n\r\nimport mongoose from 'mongoose';\r\nimport type { SortSpec, DecodedCursor, ObjectId, CursorPayload, ValueType } from '../../types.js';\r\n\r\n/**\r\n * Encodes document values and sort metadata into a base64 cursor token\r\n *\r\n * @param doc - Document to extract cursor values from\r\n * @param primaryField - Primary sort field name\r\n * @param sort - Normalized sort specification\r\n * @param version - Cursor version for forward compatibility\r\n * @returns Base64-encoded cursor token\r\n */\r\nexport function encodeCursor(\r\n doc: Record<string, unknown>,\r\n primaryField: string,\r\n sort: SortSpec,\r\n version: number = 1\r\n): string {\r\n const primaryValue = doc[primaryField];\r\n const idValue = doc._id;\r\n\r\n const payload: CursorPayload = {\r\n v: serializeValue(primaryValue),\r\n t: getValueType(primaryValue),\r\n id: serializeValue(idValue) as string,\r\n idType: getValueType(idValue),\r\n sort,\r\n ver: version,\r\n };\r\n\r\n return Buffer.from(JSON.stringify(payload)).toString('base64');\r\n}\r\n\r\n/**\r\n * Decodes a cursor token back into document values and sort metadata\r\n *\r\n * @param token - Base64-encoded cursor token\r\n * @returns Decoded cursor data\r\n * @throws Error if token is invalid or malformed\r\n */\r\nexport function decodeCursor(token: string): DecodedCursor {\r\n try {\r\n const json = Buffer.from(token, 'base64').toString('utf-8');\r\n const payload = JSON.parse(json) as CursorPayload;\r\n\r\n return {\r\n value: rehydrateValue(payload.v, payload.t),\r\n id: rehydrateValue(payload.id, payload.idType) as ObjectId | string,\r\n sort: payload.sort,\r\n version: payload.ver,\r\n };\r\n } catch {\r\n throw new Error('Invalid cursor token');\r\n }\r\n}\r\n\r\n/**\r\n * Validates that cursor sort matches current query sort\r\n *\r\n * @param cursorSort - Sort specification from cursor\r\n * @param currentSort - Sort specification from query\r\n * @throws Error if sorts don't match\r\n */\r\nexport function validateCursorSort(cursorSort: SortSpec, currentSort: SortSpec): void {\r\n const cursorSortStr = JSON.stringify(cursorSort);\r\n const currentSortStr = JSON.stringify(currentSort);\r\n\r\n if (cursorSortStr !== currentSortStr) {\r\n throw new Error('Cursor sort does not match current query sort');\r\n }\r\n}\r\n\r\n/**\r\n * Validates cursor version matches expected version\r\n *\r\n * @param cursorVersion - Version from cursor\r\n * @param expectedVersion - Expected version from config\r\n * @throws Error if versions don't match\r\n */\r\nexport function validateCursorVersion(cursorVersion: number, expectedVersion: number): void {\r\n if (cursorVersion !== expectedVersion) {\r\n throw new Error(`Cursor version ${cursorVersion} does not match expected version ${expectedVersion}`);\r\n }\r\n}\r\n\r\n/**\r\n * Serializes a value for cursor storage\r\n */\r\nfunction serializeValue(value: unknown): string | number | boolean {\r\n if (value instanceof Date) return value.toISOString();\r\n if (value instanceof mongoose.Types.ObjectId) return value.toString();\r\n return value as string | number | boolean;\r\n}\r\n\r\n/**\r\n * Gets the type identifier for a value\r\n */\r\nfunction getValueType(value: unknown): ValueType {\r\n if (value instanceof Date) return 'date';\r\n if (value instanceof mongoose.Types.ObjectId) return 'objectid';\r\n if (typeof value === 'boolean') return 'boolean';\r\n if (typeof value === 'number') return 'number';\r\n if (typeof value === 'string') return 'string';\r\n return 'unknown';\r\n}\r\n\r\n/**\r\n * Rehydrates a serialized value back to its original type\r\n */\r\nfunction rehydrateValue(serialized: unknown, type: ValueType): unknown {\r\n switch (type) {\r\n case 'date':\r\n return new Date(serialized as string);\r\n case 'objectid':\r\n return new mongoose.Types.ObjectId(serialized as string);\r\n case 'boolean':\r\n return Boolean(serialized);\r\n case 'number':\r\n return Number(serialized);\r\n default:\r\n return serialized;\r\n }\r\n}\r\n","/**\r\n * Sort Utilities\r\n * \r\n * Normalization and validation of sort specifications for pagination.\r\n */\r\n\r\nimport type { SortSpec, SortDirection } from '../../types.js';\r\n\r\n/**\r\n * Normalizes sort object to ensure stable key order\r\n * Primary fields first, _id last (not alphabetical)\r\n *\r\n * @param sort - Sort specification\r\n * @returns Normalized sort with stable key order\r\n */\r\nexport function normalizeSort(sort: SortSpec): SortSpec {\r\n const normalized: SortSpec = {};\r\n\r\n Object.keys(sort).forEach(key => {\r\n if (key !== '_id') normalized[key] = sort[key];\r\n });\r\n\r\n if (sort._id !== undefined) {\r\n normalized._id = sort._id;\r\n }\r\n\r\n return normalized;\r\n}\r\n\r\n/**\r\n * Validates and normalizes sort for keyset pagination\r\n * Auto-adds _id tie-breaker if needed\r\n * Ensures _id direction matches primary field\r\n *\r\n * @param sort - Sort specification\r\n * @returns Validated and normalized sort\r\n * @throws Error if sort is invalid for keyset pagination\r\n */\r\nexport function validateKeysetSort(sort: SortSpec): SortSpec {\r\n const keys = Object.keys(sort);\r\n\r\n if (keys.length === 1 && keys[0] !== '_id') {\r\n const field = keys[0];\r\n const direction = sort[field];\r\n return normalizeSort({ [field]: direction, _id: direction });\r\n }\r\n\r\n if (keys.length === 1 && keys[0] === '_id') {\r\n return normalizeSort(sort);\r\n }\r\n\r\n if (keys.length === 2) {\r\n if (!keys.includes('_id')) {\r\n throw new Error('Keyset pagination requires _id as tie-breaker');\r\n }\r\n\r\n const primaryField = keys.find(k => k !== '_id')!;\r\n const primaryDirection = sort[primaryField];\r\n const idDirection = sort._id;\r\n\r\n if (primaryDirection !== idDirection) {\r\n throw new Error('_id direction must match primary field direction');\r\n }\r\n\r\n return normalizeSort(sort);\r\n }\r\n\r\n throw new Error('Keyset pagination only supports single field + _id');\r\n}\r\n\r\n/**\r\n * Inverts sort directions (1 becomes -1, -1 becomes 1)\r\n *\r\n * @param sort - Sort specification\r\n * @returns Inverted sort\r\n */\r\nexport function invertSort(sort: SortSpec): SortSpec {\r\n const inverted: SortSpec = {};\r\n\r\n Object.keys(sort).forEach(key => {\r\n inverted[key] = (sort[key] === 1 ? -1 : 1) as SortDirection;\r\n });\r\n\r\n return inverted;\r\n}\r\n\r\n/**\r\n * Extracts primary sort field (first non-_id field)\r\n *\r\n * @param sort - Sort specification\r\n * @returns Primary field name\r\n */\r\nexport function getPrimaryField(sort: SortSpec): string {\r\n const keys = Object.keys(sort);\r\n return keys.find(k => k !== '_id') || '_id';\r\n}\r\n\r\n/**\r\n * Gets sort direction for a specific field\r\n *\r\n * @param sort - Sort specification\r\n * @param field - Field name\r\n * @returns Sort direction\r\n */\r\nexport function getDirection(sort: SortSpec, field: string): SortDirection | undefined {\r\n return sort[field];\r\n}\r\n","/**\r\n * Filter Utilities\r\n * \r\n * Build MongoDB filters for keyset pagination with proper cursor positioning.\r\n */\r\n\r\nimport type { SortSpec, FilterQuery, AnyDocument, ObjectId } from '../../types.js';\r\n\r\n/**\r\n * Builds MongoDB filter for keyset pagination\r\n * Creates compound $or condition for proper cursor-based filtering\r\n *\r\n * @param baseFilters - Existing query filters\r\n * @param sort - Normalized sort specification\r\n * @param cursorValue - Primary field value from cursor\r\n * @param cursorId - _id value from cursor\r\n * @returns MongoDB filter with keyset condition\r\n *\r\n * @example\r\n * buildKeysetFilter(\r\n * { status: 'active' },\r\n * { createdAt: -1, _id: -1 },\r\n * new Date('2024-01-01'),\r\n * new ObjectId('...')\r\n * )\r\n * // Returns:\r\n * // {\r\n * // status: 'active',\r\n * // $or: [\r\n * // { createdAt: { $lt: Date('2024-01-01') } },\r\n * // { createdAt: Date('2024-01-01'), _id: { $lt: ObjectId('...') } }\r\n * // ]\r\n * // }\r\n */\r\nexport function buildKeysetFilter(\r\n baseFilters: FilterQuery<AnyDocument>,\r\n sort: SortSpec,\r\n cursorValue: unknown,\r\n cursorId: ObjectId | string\r\n): FilterQuery<AnyDocument> {\r\n const primaryField = Object.keys(sort).find(k => k !== '_id') || '_id';\r\n const direction = sort[primaryField];\r\n const operator = direction === 1 ? '$gt' : '$lt';\r\n\r\n return {\r\n ...baseFilters,\r\n $or: [\r\n { [primaryField]: { [operator]: cursorValue } },\r\n {\r\n [primaryField]: cursorValue,\r\n _id: { [operator]: cursorId },\r\n },\r\n ],\r\n } as FilterQuery<AnyDocument>;\r\n}\r\n","/**\r\n * Limit Utilities\r\n * \r\n * Validation and calculation helpers for pagination limits and pages.\r\n */\r\n\r\nimport type { PaginationConfig } from '../../types.js';\r\n\r\n/**\r\n * Validates and sanitizes limit value\r\n * Parses strings to numbers and prevents NaN bugs\r\n *\r\n * @param limit - Requested limit\r\n * @param config - Pagination configuration\r\n * @returns Sanitized limit between 1 and maxLimit\r\n */\r\nexport function validateLimit(limit: number | string, config: PaginationConfig): number {\r\n const parsed = Number(limit);\r\n\r\n if (!Number.isFinite(parsed) || parsed < 1) {\r\n return config.defaultLimit || 10;\r\n }\r\n\r\n return Math.min(Math.floor(parsed), config.maxLimit || 100);\r\n}\r\n\r\n/**\r\n * Validates and sanitizes page number\r\n * Parses strings to numbers and prevents NaN bugs\r\n *\r\n * @param page - Requested page (1-indexed)\r\n * @param config - Pagination configuration\r\n * @returns Sanitized page number >= 1\r\n * @throws Error if page exceeds maxPage\r\n */\r\nexport function validatePage(page: number | string, config: PaginationConfig): number {\r\n const parsed = Number(page);\r\n\r\n if (!Number.isFinite(parsed) || parsed < 1) {\r\n return 1;\r\n }\r\n\r\n const sanitized = Math.floor(parsed);\r\n\r\n if (sanitized > (config.maxPage || 10000)) {\r\n throw new Error(`Page ${sanitized} exceeds maximum ${config.maxPage || 10000}`);\r\n }\r\n\r\n return sanitized;\r\n}\r\n\r\n/**\r\n * Checks if page number should trigger deep pagination warning\r\n *\r\n * @param page - Current page number\r\n * @param threshold - Warning threshold\r\n * @returns True if warning should be shown\r\n */\r\nexport function shouldWarnDeepPagination(page: number, threshold: number): boolean {\r\n return page > threshold;\r\n}\r\n\r\n/**\r\n * Calculates number of documents to skip for offset pagination\r\n *\r\n * @param page - Page number (1-indexed)\r\n * @param limit - Documents per page\r\n * @returns Number of documents to skip\r\n */\r\nexport function calculateSkip(page: number, limit: number): number {\r\n return (page - 1) * limit;\r\n}\r\n\r\n/**\r\n * Calculates total number of pages\r\n *\r\n * @param total - Total document count\r\n * @param limit - Documents per page\r\n * @returns Total number of pages\r\n */\r\nexport function calculateTotalPages(total: number, limit: number): number {\r\n return Math.ceil(total / limit);\r\n}\r\n","/**\r\n * Pagination Engine\r\n * \r\n * Production-grade pagination for MongoDB with support for:\r\n * - Offset pagination (page-based) - Best for small datasets, random page access\r\n * - Keyset pagination (cursor-based) - Best for large datasets, infinite scroll\r\n * - Aggregate pagination - Best for complex queries requiring aggregation\r\n * \r\n * @example\r\n * ```typescript\r\n * const engine = new PaginationEngine(UserModel, {\r\n * defaultLimit: 20,\r\n * maxLimit: 100,\r\n * useEstimatedCount: true\r\n * });\r\n *\r\n * // Offset pagination\r\n * const page1 = await engine.paginate({ page: 1, limit: 20 });\r\n *\r\n * // Keyset pagination (better for large datasets)\r\n * const stream1 = await engine.stream({ sort: { createdAt: -1 }, limit: 20 });\r\n * const stream2 = await engine.stream({ sort: { createdAt: -1 }, after: stream1.next });\r\n * ```\r\n */\r\n\r\nimport type { Model } from 'mongoose';\r\nimport { encodeCursor, decodeCursor, validateCursorSort, validateCursorVersion } from './utils/cursor.js';\r\nimport { validateKeysetSort, getPrimaryField } from './utils/sort.js';\r\nimport { buildKeysetFilter } from './utils/filter.js';\r\nimport {\r\n validateLimit,\r\n validatePage,\r\n shouldWarnDeepPagination,\r\n calculateSkip,\r\n calculateTotalPages,\r\n} from './utils/limits.js';\r\nimport { createError } from '../utils/error.js';\r\nimport type {\r\n PaginationConfig,\r\n OffsetPaginationOptions,\r\n KeysetPaginationOptions,\r\n AggregatePaginationOptions,\r\n OffsetPaginationResult,\r\n KeysetPaginationResult,\r\n AggregatePaginationResult,\r\n AnyDocument,\r\n} from '../types.js';\r\n\r\n/**\r\n * Internal pagination config with required values\r\n */\r\ninterface ResolvedPaginationConfig {\r\n defaultLimit: number;\r\n maxLimit: number;\r\n maxPage: number;\r\n deepPageThreshold: number;\r\n cursorVersion: number;\r\n useEstimatedCount: boolean;\r\n}\r\n\r\n/**\r\n * Production-grade pagination engine for MongoDB\r\n * Supports offset, keyset (cursor), and aggregate pagination\r\n */\r\nexport class PaginationEngine<TDoc = AnyDocument> {\r\n public readonly Model: Model<TDoc>;\r\n public readonly config: ResolvedPaginationConfig;\r\n\r\n /**\r\n * Create a new pagination engine\r\n *\r\n * @param Model - Mongoose model to paginate\r\n * @param config - Pagination configuration\r\n */\r\n constructor(Model: Model<TDoc>, config: PaginationConfig = {}) {\r\n this.Model = Model;\r\n this.config = {\r\n defaultLimit: config.defaultLimit || 10,\r\n maxLimit: config.maxLimit || 100,\r\n maxPage: config.maxPage || 10000,\r\n deepPageThreshold: config.deepPageThreshold || 100,\r\n cursorVersion: config.cursorVersion || 1,\r\n useEstimatedCount: config.useEstimatedCount || false,\r\n };\r\n }\r\n\r\n /**\r\n * Offset-based pagination using skip/limit\r\n * Best for small datasets and when users need random page access\r\n * O(n) performance - slower for deep pages\r\n *\r\n * @param options - Pagination options\r\n * @returns Pagination result with total count\r\n *\r\n * @example\r\n * const result = await engine.paginate({\r\n * filters: { status: 'active' },\r\n * sort: { createdAt: -1 },\r\n * page: 1,\r\n * limit: 20\r\n * });\r\n * console.log(result.docs, result.total, result.hasNext);\r\n */\r\n async paginate(options: OffsetPaginationOptions = {}): Promise<OffsetPaginationResult<TDoc>> {\r\n const {\r\n filters = {},\r\n sort = { _id: -1 },\r\n page = 1,\r\n limit = this.config.defaultLimit,\r\n select,\r\n populate = [],\r\n lean = true,\r\n session,\r\n } = options;\r\n\r\n const sanitizedPage = validatePage(page, this.config);\r\n const sanitizedLimit = validateLimit(limit, this.config);\r\n const skip = calculateSkip(sanitizedPage, sanitizedLimit);\r\n\r\n let query = this.Model.find(filters as Record<string, unknown>);\r\n if (select) query = query.select(select);\r\n if (populate && (Array.isArray(populate) ? populate.length : populate)) {\r\n query = query.populate(populate as string | string[]);\r\n }\r\n query = query.sort(sort).skip(skip).limit(sanitizedLimit).lean(lean);\r\n if (session) query = query.session(session);\r\n\r\n const hasFilters = Object.keys(filters).length > 0;\r\n const useEstimated = this.config.useEstimatedCount && !hasFilters;\r\n\r\n // Note: estimatedDocumentCount() doesn't support sessions or filters\r\n // It reads collection metadata (O(1) instant), not actual documents\r\n // Falls back to countDocuments() when filters are present\r\n const [docs, total] = await Promise.all([\r\n query.exec(),\r\n useEstimated\r\n ? this.Model.estimatedDocumentCount()\r\n : this.Model.countDocuments(filters as Record<string, unknown>).session(session ?? null),\r\n ]);\r\n\r\n const totalPages = calculateTotalPages(total, sanitizedLimit);\r\n const warning = shouldWarnDeepPagination(sanitizedPage, this.config.deepPageThreshold)\r\n ? `Deep pagination (page ${sanitizedPage}). Consider getAll({ after, sort, limit }) for better performance.`\r\n : undefined;\r\n\r\n return {\r\n method: 'offset',\r\n docs: docs as TDoc[],\r\n page: sanitizedPage,\r\n limit: sanitizedLimit,\r\n total,\r\n pages: totalPages,\r\n hasNext: sanitizedPage < totalPages,\r\n hasPrev: sanitizedPage > 1,\r\n ...(warning && { warning }),\r\n };\r\n }\r\n\r\n /**\r\n * Keyset (cursor-based) pagination for high-performance streaming\r\n * Best for large datasets, infinite scroll, real-time feeds\r\n * O(1) performance - consistent speed regardless of position\r\n *\r\n * @param options - Pagination options (sort is required)\r\n * @returns Pagination result with next cursor\r\n *\r\n * @example\r\n * // First page\r\n * const page1 = await engine.stream({\r\n * sort: { createdAt: -1 },\r\n * limit: 20\r\n * });\r\n *\r\n * // Next page using cursor\r\n * const page2 = await engine.stream({\r\n * sort: { createdAt: -1 },\r\n * after: page1.next,\r\n * limit: 20\r\n * });\r\n */\r\n async stream(options: KeysetPaginationOptions): Promise<KeysetPaginationResult<TDoc>> {\r\n const {\r\n filters = {},\r\n sort,\r\n after,\r\n limit = this.config.defaultLimit,\r\n select,\r\n populate = [],\r\n lean = true,\r\n session,\r\n } = options;\r\n\r\n if (!sort) {\r\n throw createError(400, 'sort is required for keyset pagination');\r\n }\r\n\r\n const sanitizedLimit = validateLimit(limit, this.config);\r\n const normalizedSort = validateKeysetSort(sort);\r\n\r\n let query: Record<string, unknown> = { ...filters };\r\n\r\n if (after) {\r\n const cursor = decodeCursor(after);\r\n validateCursorVersion(cursor.version, this.config.cursorVersion);\r\n validateCursorSort(cursor.sort, normalizedSort);\r\n query = buildKeysetFilter(query, normalizedSort, cursor.value, cursor.id);\r\n }\r\n\r\n let mongoQuery = this.Model.find(query);\r\n if (select) mongoQuery = mongoQuery.select(select);\r\n if (populate && (Array.isArray(populate) ? populate.length : populate)) {\r\n mongoQuery = mongoQuery.populate(populate as string | string[]);\r\n }\r\n mongoQuery = mongoQuery.sort(normalizedSort).limit(sanitizedLimit + 1).lean(lean);\r\n if (session) mongoQuery = mongoQuery.session(session);\r\n\r\n const docs = await mongoQuery.exec() as (TDoc & Record<string, unknown>)[];\r\n\r\n const hasMore = docs.length > sanitizedLimit;\r\n if (hasMore) docs.pop();\r\n\r\n const primaryField = getPrimaryField(normalizedSort);\r\n const nextCursor = hasMore && docs.length > 0\r\n ? encodeCursor(docs[docs.length - 1], primaryField, normalizedSort, this.config.cursorVersion)\r\n : null;\r\n\r\n return {\r\n method: 'keyset',\r\n docs,\r\n limit: sanitizedLimit,\r\n hasMore,\r\n next: nextCursor,\r\n };\r\n }\r\n\r\n /**\r\n * Aggregate pipeline with pagination\r\n * Best for complex queries requiring aggregation stages\r\n * Uses $facet to combine results and count in single query\r\n *\r\n * @param options - Aggregation options\r\n * @returns Pagination result with total count\r\n *\r\n * @example\r\n * const result = await engine.aggregatePaginate({\r\n * pipeline: [\r\n * { $match: { status: 'active' } },\r\n * { $group: { _id: '$category', count: { $sum: 1 } } },\r\n * { $sort: { count: -1 } }\r\n * ],\r\n * page: 1,\r\n * limit: 20\r\n * });\r\n */\r\n async aggregatePaginate(options: AggregatePaginationOptions = {}): Promise<AggregatePaginationResult<TDoc>> {\r\n const {\r\n pipeline = [],\r\n page = 1,\r\n limit = this.config.defaultLimit,\r\n session,\r\n } = options;\r\n\r\n const sanitizedPage = validatePage(page, this.config);\r\n const sanitizedLimit = validateLimit(limit, this.config);\r\n const skip = calculateSkip(sanitizedPage, sanitizedLimit);\r\n\r\n const facetPipeline = [\r\n ...pipeline,\r\n {\r\n $facet: {\r\n docs: [{ $skip: skip }, { $limit: sanitizedLimit }],\r\n total: [{ $count: 'count' }],\r\n },\r\n },\r\n ];\r\n\r\n const aggregation = this.Model.aggregate(facetPipeline);\r\n if (session) aggregation.session(session);\r\n\r\n const [result] = await aggregation.exec() as [{ docs: TDoc[]; total: { count: number }[] }];\r\n const docs = result.docs;\r\n const total = result.total[0]?.count || 0;\r\n const totalPages = calculateTotalPages(total, sanitizedLimit);\r\n\r\n const warning = shouldWarnDeepPagination(sanitizedPage, this.config.deepPageThreshold)\r\n ? `Deep pagination in aggregate (page ${sanitizedPage}). Uses $skip internally.`\r\n : undefined;\r\n\r\n return {\r\n method: 'aggregate',\r\n docs,\r\n page: sanitizedPage,\r\n limit: sanitizedLimit,\r\n total,\r\n pages: totalPages,\r\n hasNext: sanitizedPage < totalPages,\r\n hasPrev: sanitizedPage > 1,\r\n ...(warning && { warning }),\r\n };\r\n }\r\n}\r\n","/**\r\n * Repository Pattern - Data Access Layer\r\n * \r\n * Event-driven, plugin-based abstraction for MongoDB operations\r\n * Inspired by Meta & Stripe's repository patterns\r\n * \r\n * @example\r\n * ```typescript\r\n * const userRepo = new Repository(UserModel, [\r\n * timestampPlugin(),\r\n * softDeletePlugin(),\r\n * ]);\r\n * \r\n * // Create\r\n * const user = await userRepo.create({ name: 'John', email: 'john@example.com' });\r\n * \r\n * // Read with pagination\r\n * const users = await userRepo.getAll({ page: 1, limit: 20, filters: { status: 'active' } });\r\n * \r\n * // Update\r\n * const updated = await userRepo.update(user._id, { name: 'John Doe' });\r\n * \r\n * // Delete\r\n * await userRepo.delete(user._id);\r\n * ```\r\n */\r\n\r\nimport mongoose from 'mongoose';\r\nimport type { Model, ClientSession, PipelineStage, PopulateOptions } from 'mongoose';\r\nimport { createError } from './utils/error.js';\r\nimport * as createActions from './actions/create.js';\r\nimport * as readActions from './actions/read.js';\r\nimport * as updateActions from './actions/update.js';\r\nimport * as deleteActions from './actions/delete.js';\r\nimport * as aggregateActions from './actions/aggregate.js';\r\nimport { PaginationEngine } from './pagination/PaginationEngine.js';\r\nimport type {\r\n PaginationConfig,\r\n PluginType,\r\n Plugin,\r\n RepositoryContext,\r\n OffsetPaginationResult,\r\n KeysetPaginationResult,\r\n AggregatePaginationResult,\r\n SortSpec,\r\n PopulateSpec,\r\n SelectSpec,\r\n AnyDocument,\r\n HttpError,\r\n} from './types.js';\r\n\r\ntype HookListener = (data: any) => void | Promise<void>;\r\n\r\n/**\r\n * Production-grade repository for MongoDB\r\n * Event-driven, plugin-based, with smart pagination\r\n */\r\nexport class Repository<TDoc = AnyDocument> {\r\n public readonly Model: Model<TDoc>;\r\n public readonly model: string;\r\n public readonly _hooks: Map<string, HookListener[]>;\r\n public readonly _pagination: PaginationEngine<TDoc>;\r\n [key: string]: unknown;\r\n\r\n constructor(Model: Model<TDoc>, plugins: PluginType[] = [], paginationConfig: PaginationConfig = {}) {\r\n this.Model = Model;\r\n this.model = Model.modelName;\r\n this._hooks = new Map();\r\n this._pagination = new PaginationEngine(Model, paginationConfig);\r\n plugins.forEach(plugin => this.use(plugin));\r\n }\r\n\r\n /**\r\n * Register a plugin\r\n */\r\n use(plugin: PluginType): this {\r\n if (typeof plugin === 'function') {\r\n plugin(this);\r\n } else if (plugin && typeof (plugin as Plugin).apply === 'function') {\r\n (plugin as Plugin).apply(this);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Register event listener\r\n */\r\n on(event: string, listener: HookListener): this {\r\n if (!this._hooks.has(event)) {\r\n this._hooks.set(event, []);\r\n }\r\n this._hooks.get(event)!.push(listener);\r\n return this;\r\n }\r\n\r\n /**\r\n * Emit event\r\n */\r\n emit(event: string, data: unknown): void {\r\n const listeners = this._hooks.get(event) || [];\r\n listeners.forEach(listener => listener(data));\r\n }\r\n\r\n /**\r\n * Create single document\r\n */\r\n async create(data: Record<string, unknown>, options: { session?: ClientSession } = {}): Promise<TDoc> {\r\n const context = await this._buildContext('create', { data, ...options });\r\n\r\n try {\r\n const result = await createActions.create(this.Model, context.data || data, options);\r\n this.emit('after:create', { context, result });\r\n return result;\r\n } catch (error) {\r\n this.emit('error:create', { context, error });\r\n throw this._handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Create multiple documents\r\n */\r\n async createMany(\r\n dataArray: Record<string, unknown>[],\r\n options: { session?: ClientSession; ordered?: boolean } = {}\r\n ): Promise<TDoc[]> {\r\n const context = await this._buildContext('createMany', { dataArray, ...options });\r\n\r\n try {\r\n const result = await createActions.createMany(this.Model, context.dataArray || dataArray, options);\r\n this.emit('after:createMany', { context, result });\r\n return result;\r\n } catch (error) {\r\n this.emit('error:createMany', { context, error });\r\n throw this._handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Get document by ID\r\n */\r\n async getById(\r\n id: string,\r\n options: { select?: SelectSpec; populate?: PopulateSpec; lean?: boolean; session?: ClientSession; throwOnNotFound?: boolean; skipCache?: boolean; cacheTtl?: number } = {}\r\n ): Promise<TDoc | null> {\r\n const context = await this._buildContext('getById', { id, ...options });\r\n \r\n // Check if cache plugin returned a cached result\r\n if ((context as Record<string, unknown>)._cacheHit) {\r\n return (context as Record<string, unknown>)._cachedResult as TDoc | null;\r\n }\r\n \r\n const result = await readActions.getById(this.Model, id, context);\r\n this.emit('after:getById', { context, result });\r\n return result;\r\n }\r\n\r\n /**\r\n * Get single document by query\r\n */\r\n async getByQuery(\r\n query: Record<string, unknown>,\r\n options: { select?: SelectSpec; populate?: PopulateSpec; lean?: boolean; session?: ClientSession; throwOnNotFound?: boolean; skipCache?: boolean; cacheTtl?: number } = {}\r\n ): Promise<TDoc | null> {\r\n const context = await this._buildContext('getByQuery', { query, ...options });\r\n \r\n // Check if cache plugin returned a cached result\r\n if ((context as Record<string, unknown>)._cacheHit) {\r\n return (context as Record<string, unknown>)._cachedResult as TDoc | null;\r\n }\r\n \r\n const result = await readActions.getByQuery(this.Model, query, context);\r\n this.emit('after:getByQuery', { context, result });\r\n return result;\r\n }\r\n\r\n /**\r\n * Unified pagination - auto-detects offset vs keyset based on params\r\n *\r\n * Auto-detection logic:\r\n * - If params has 'cursor' or 'after' → uses keyset pagination (stream)\r\n * - If params has 'pagination' or 'page' → uses offset pagination (paginate)\r\n * - Else → defaults to offset pagination with page=1\r\n *\r\n * @example\r\n * // Offset pagination (page-based)\r\n * await repo.getAll({ page: 1, limit: 50, filters: { status: 'active' } });\r\n * await repo.getAll({ pagination: { page: 2, limit: 20 } });\r\n *\r\n * // Keyset pagination (cursor-based)\r\n * await repo.getAll({ cursor: 'eyJ2Ij...', limit: 50 });\r\n * await repo.getAll({ after: 'eyJ2Ij...', sort: { createdAt: -1 } });\r\n *\r\n * // Simple query (defaults to page 1)\r\n * await repo.getAll({ filters: { status: 'active' } });\r\n * \r\n * // Skip cache for fresh data\r\n * await repo.getAll({ filters: { status: 'active' } }, { skipCache: true });\r\n */\r\n async getAll(\r\n params: {\r\n filters?: Record<string, unknown>;\r\n sort?: SortSpec | string;\r\n cursor?: string;\r\n after?: string;\r\n page?: number;\r\n pagination?: { page?: number; limit?: number };\r\n limit?: number;\r\n search?: string;\r\n } = {},\r\n options: { select?: SelectSpec; populate?: PopulateSpec; lean?: boolean; session?: ClientSession; skipCache?: boolean; cacheTtl?: number } = {}\r\n ): Promise<OffsetPaginationResult<TDoc> | KeysetPaginationResult<TDoc>> {\r\n const context = await this._buildContext('getAll', { ...params, ...options });\r\n\r\n // Check if cache plugin returned a cached result\r\n if ((context as Record<string, unknown>)._cacheHit) {\r\n return (context as Record<string, unknown>)._cachedResult as OffsetPaginationResult<TDoc> | KeysetPaginationResult<TDoc>;\r\n }\r\n\r\n // Auto-detect pagination mode\r\n const hasPageParam = params.page !== undefined || params.pagination;\r\n const hasCursorParam = 'cursor' in params || 'after' in params;\r\n const hasExplicitSort = params.sort !== undefined;\r\n\r\n const useKeyset = !hasPageParam && (hasCursorParam || hasExplicitSort);\r\n\r\n // Extract common params\r\n const filters = params.filters || {};\r\n const search = params.search;\r\n const sort = params.sort || '-createdAt';\r\n const limit = params.limit || params.pagination?.limit || this._pagination.config.defaultLimit;\r\n\r\n // Build query with search support\r\n let query: Record<string, unknown> = { ...filters };\r\n if (search) query.$text = { $search: search };\r\n\r\n // Common options\r\n const paginationOptions = {\r\n filters: query,\r\n sort: this._parseSort(sort),\r\n limit,\r\n populate: this._parsePopulate(context.populate || options.populate),\r\n select: context.select || options.select,\r\n lean: context.lean ?? options.lean ?? true,\r\n session: options.session,\r\n };\r\n\r\n let result: OffsetPaginationResult<TDoc> | KeysetPaginationResult<TDoc>;\r\n \r\n if (useKeyset) {\r\n // Keyset pagination (cursor-based)\r\n result = await this._pagination.stream({\r\n ...paginationOptions,\r\n sort: paginationOptions.sort, // Required for keyset\r\n after: params.cursor || params.after,\r\n });\r\n } else {\r\n // Offset pagination (page-based) - default\r\n const page = params.pagination?.page || params.page || 1;\r\n result = await this._pagination.paginate({\r\n ...paginationOptions,\r\n page,\r\n });\r\n }\r\n \r\n this.emit('after:getAll', { context, result });\r\n return result;\r\n }\r\n\r\n /**\r\n * Get or create document\r\n */\r\n async getOrCreate(\r\n query: Record<string, unknown>,\r\n createData: Record<string, unknown>,\r\n options: { session?: ClientSession } = {}\r\n ): Promise<TDoc | null> {\r\n return readActions.getOrCreate(this.Model, query, createData, options);\r\n }\r\n\r\n /**\r\n * Count documents\r\n */\r\n async count(query: Record<string, unknown> = {}, options: { session?: ClientSession } = {}): Promise<number> {\r\n return readActions.count(this.Model, query, options);\r\n }\r\n\r\n /**\r\n * Check if document exists\r\n */\r\n async exists(query: Record<string, unknown>, options: { session?: ClientSession } = {}): Promise<{ _id: unknown } | null> {\r\n return readActions.exists(this.Model, query, options);\r\n }\r\n\r\n /**\r\n * Update document by ID\r\n */\r\n async update(\r\n id: string,\r\n data: Record<string, unknown>,\r\n options: { select?: SelectSpec; populate?: PopulateSpec; lean?: boolean; session?: ClientSession } = {}\r\n ): Promise<TDoc> {\r\n const context = await this._buildContext('update', { id, data, ...options });\r\n\r\n try {\r\n const result = await updateActions.update(this.Model, id, context.data || data, context);\r\n this.emit('after:update', { context, result });\r\n return result;\r\n } catch (error) {\r\n this.emit('error:update', { context, error });\r\n throw this._handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Delete document by ID\r\n */\r\n async delete(id: string, options: { session?: ClientSession } = {}): Promise<{ success: boolean; message: string }> {\r\n const context = await this._buildContext('delete', { id, ...options });\r\n\r\n try {\r\n // Check if soft delete was performed by plugin\r\n if ((context as any).softDeleted) {\r\n const result = { success: true, message: 'Soft deleted successfully' };\r\n this.emit('after:delete', { context, result });\r\n return result;\r\n }\r\n\r\n const result = await deleteActions.deleteById(this.Model, id, options);\r\n this.emit('after:delete', { context, result });\r\n return result;\r\n } catch (error) {\r\n this.emit('error:delete', { context, error });\r\n throw this._handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Execute aggregation pipeline\r\n */\r\n async aggregate<TResult = unknown>(\r\n pipeline: PipelineStage[],\r\n options: { session?: ClientSession } = {}\r\n ): Promise<TResult[]> {\r\n return aggregateActions.aggregate(this.Model, pipeline, options);\r\n }\r\n\r\n /**\r\n * Aggregate pipeline with pagination\r\n * Best for: Complex queries, grouping, joins\r\n */\r\n async aggregatePaginate(\r\n options: { pipeline?: PipelineStage[]; page?: number; limit?: number; session?: ClientSession } = {}\r\n ): Promise<AggregatePaginationResult<TDoc>> {\r\n const context = await this._buildContext('aggregatePaginate', options);\r\n return this._pagination.aggregatePaginate(context);\r\n }\r\n\r\n /**\r\n * Get distinct values\r\n */\r\n async distinct<T = unknown>(\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n ): Promise<T[]> {\r\n return aggregateActions.distinct(this.Model, field, query, options);\r\n }\r\n\r\n /**\r\n * Execute callback within a transaction\r\n */\r\n async withTransaction<T>(callback: (session: ClientSession) => Promise<T>): Promise<T> {\r\n const session = await mongoose.startSession();\r\n session.startTransaction();\r\n try {\r\n const result = await callback(session);\r\n await session.commitTransaction();\r\n return result;\r\n } catch (error) {\r\n await session.abortTransaction();\r\n throw error;\r\n } finally {\r\n session.endSession();\r\n }\r\n }\r\n\r\n /**\r\n * Execute custom query with event emission\r\n */\r\n async _executeQuery<T>(buildQuery: (Model: Model<TDoc>) => Promise<T>): Promise<T> {\r\n const operation = buildQuery.name || 'custom';\r\n const context = await this._buildContext(operation, {});\r\n\r\n try {\r\n const result = await buildQuery(this.Model);\r\n this.emit(`after:${operation}`, { context, result });\r\n return result;\r\n } catch (error) {\r\n this.emit(`error:${operation}`, { context, error });\r\n throw this._handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Build operation context and run before hooks\r\n */\r\n async _buildContext(operation: string, options: Record<string, unknown>): Promise<RepositoryContext> {\r\n const context: RepositoryContext = { operation, model: this.model, ...options };\r\n const event = `before:${operation}`;\r\n const hooks = this._hooks.get(event) || [];\r\n\r\n for (const hook of hooks) {\r\n await hook(context);\r\n }\r\n\r\n return context;\r\n }\r\n\r\n /**\r\n * Parse sort string or object\r\n */\r\n _parseSort(sort: SortSpec | string | undefined): SortSpec {\r\n if (!sort) return { createdAt: -1 };\r\n if (typeof sort === 'object') return sort;\r\n\r\n const sortOrder = sort.startsWith('-') ? -1 : 1;\r\n const sortField = sort.startsWith('-') ? sort.substring(1) : sort;\r\n return { [sortField]: sortOrder };\r\n }\r\n\r\n /**\r\n * Parse populate specification\r\n */\r\n _parsePopulate(populate: PopulateSpec | undefined): string[] | PopulateOptions[] {\r\n if (!populate) return [];\r\n if (typeof populate === 'string') return populate.split(',').map(p => p.trim());\r\n if (Array.isArray(populate)) return populate.map(p => (typeof p === 'string' ? p.trim() : p)) as string[] | PopulateOptions[];\r\n return [populate];\r\n }\r\n\r\n /**\r\n * Handle errors with proper HTTP status codes\r\n */\r\n _handleError(error: Error): HttpError {\r\n if (error instanceof mongoose.Error.ValidationError) {\r\n const messages = Object.values(error.errors).map(err => (err as Error).message);\r\n return createError(400, `Validation Error: ${messages.join(', ')}`);\r\n }\r\n if (error instanceof mongoose.Error.CastError) {\r\n return createError(400, `Invalid ${error.path}: ${error.value}`);\r\n }\r\n if ((error as HttpError).status && error.message) return error as HttpError;\r\n return createError(500, error.message || 'Internal Server Error');\r\n }\r\n}\r\n\r\nexport default Repository;\r\n","/**\r\n * Field Selection Utilities\r\n *\r\n * Provides explicit, performant field filtering using Mongoose projections.\r\n *\r\n * Philosophy:\r\n * - Explicit is better than implicit\r\n * - Filter at DB level (10x faster than in-memory)\r\n * - Progressive disclosure (show more fields as trust increases)\r\n *\r\n * @example\r\n * ```typescript\r\n * // For Mongoose queries (PREFERRED - 90% of cases)\r\n * const projection = getMongooseProjection(request.user, fieldPresets.gymPlans);\r\n * const plans = await GymPlan.find().select(projection).lean();\r\n *\r\n * // For complex data (10% of cases - aggregations, multiple sources)\r\n * const filtered = filterResponseData(complexData, fieldPresets.gymPlans, request.user);\r\n * ```\r\n */\r\n\r\nimport type { FieldPreset, UserContext } from '../types.js';\r\n\r\n/**\r\n * Get allowed fields for a user based on their context\r\n *\r\n * @param user - User object from request.user (or null for public)\r\n * @param preset - Field preset configuration\r\n * @returns Array of allowed field names\r\n * \r\n * @example\r\n * const fields = getFieldsForUser(request.user, {\r\n * public: ['id', 'name', 'price'],\r\n * authenticated: ['description', 'features'],\r\n * admin: ['createdAt', 'internalNotes']\r\n * });\r\n */\r\nexport function getFieldsForUser(user: UserContext | null | undefined, preset: FieldPreset): string[] {\r\n if (!preset) {\r\n throw new Error('Field preset is required');\r\n }\r\n\r\n // Start with public fields\r\n const fields: string[] = [...(preset.public || [])];\r\n\r\n // Add authenticated fields if user is logged in\r\n if (user) {\r\n fields.push(...(preset.authenticated || []));\r\n\r\n // Add admin fields if user is admin/superadmin\r\n const roles = Array.isArray(user.roles) ? user.roles : (user.roles ? [user.roles] : []);\r\n if (roles.includes('admin') || roles.includes('superadmin')) {\r\n fields.push(...(preset.admin || []));\r\n }\r\n }\r\n\r\n // Remove duplicates\r\n return [...new Set(fields)];\r\n}\r\n\r\n/**\r\n * Get Mongoose projection string for query .select()\r\n *\r\n * @param user - User object from request.user\r\n * @param preset - Field preset configuration\r\n * @returns Space-separated field names for Mongoose .select()\r\n *\r\n * @example\r\n * const projection = getMongooseProjection(request.user, fieldPresets.gymPlans);\r\n * const plans = await GymPlan.find({ organizationId }).select(projection).lean();\r\n */\r\nexport function getMongooseProjection(user: UserContext | null | undefined, preset: FieldPreset): string {\r\n const fields = getFieldsForUser(user, preset);\r\n return fields.join(' ');\r\n}\r\n\r\n/**\r\n * Filter a single object to include only allowed fields\r\n */\r\nfunction filterObject<T extends Record<string, unknown>>(\r\n obj: T,\r\n allowedFields: string[]\r\n): Partial<T> {\r\n if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {\r\n return obj;\r\n }\r\n\r\n const filtered: Partial<T> = {};\r\n\r\n for (const field of allowedFields) {\r\n if (field in obj) {\r\n (filtered as Record<string, unknown>)[field] = obj[field];\r\n }\r\n }\r\n\r\n return filtered;\r\n}\r\n\r\n/**\r\n * Filter response data to include only allowed fields\r\n *\r\n * Use this for complex responses where Mongoose projections aren't applicable:\r\n * - Aggregation pipeline results\r\n * - Data from multiple sources\r\n * - Custom computed fields\r\n *\r\n * For simple DB queries, prefer getMongooseProjection() (10x faster)\r\n *\r\n * @param data - Data to filter\r\n * @param preset - Field preset configuration\r\n * @param user - User object from request.user\r\n * @returns Filtered data\r\n *\r\n * @example\r\n * const stats = await calculateComplexStats();\r\n * const filtered = filterResponseData(stats, fieldPresets.dashboard, request.user);\r\n * return reply.send(filtered);\r\n */\r\nexport function filterResponseData<T extends Record<string, unknown>>(\r\n data: T | T[],\r\n preset: FieldPreset,\r\n user: UserContext | null = null\r\n): Partial<T> | Partial<T>[] {\r\n const allowedFields = getFieldsForUser(user, preset);\r\n\r\n // Handle arrays\r\n if (Array.isArray(data)) {\r\n return data.map(item => filterObject(item, allowedFields));\r\n }\r\n\r\n // Handle single object\r\n return filterObject(data, allowedFields);\r\n}\r\n\r\n/**\r\n * Helper to create field presets (module-level)\r\n *\r\n * Each module should define its own field preset in its own directory.\r\n * This keeps modules independent and self-contained.\r\n *\r\n * @param config - Field configuration\r\n * @returns Field preset\r\n *\r\n * @example\r\n * // In modules/gym-plan/gym-plan.fields.ts\r\n * export const gymPlanFieldPreset = createFieldPreset({\r\n * public: ['id', 'name', 'price'],\r\n * authenticated: ['features', 'description'],\r\n * admin: ['createdAt', 'updatedAt', 'internalNotes']\r\n * });\r\n */\r\nexport function createFieldPreset(config: Partial<FieldPreset>): FieldPreset {\r\n return {\r\n public: config.public || [],\r\n authenticated: config.authenticated || [],\r\n admin: config.admin || [],\r\n };\r\n}\r\n","/**\r\n * Field Filter Plugin\r\n * Automatically filters response fields based on user roles\r\n */\r\n\r\nimport { getFieldsForUser } from '../utils/field-selection.js';\r\nimport type { Plugin, RepositoryContext, RepositoryInstance, FieldPreset } from '../types.js';\r\n\r\n/**\r\n * Field filter plugin that restricts fields based on user context\r\n * \r\n * @example\r\n * const fieldPreset = {\r\n * public: ['id', 'name'],\r\n * authenticated: ['email'],\r\n * admin: ['createdAt', 'internalNotes']\r\n * };\r\n * \r\n * const repo = new Repository(Model, [fieldFilterPlugin(fieldPreset)]);\r\n */\r\nexport function fieldFilterPlugin(fieldPreset: FieldPreset): Plugin {\r\n return {\r\n name: 'fieldFilter',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n const applyFieldFiltering = (context: RepositoryContext): void => {\r\n if (!fieldPreset) return;\r\n\r\n const user = (context as any).context?.user || (context as any).user;\r\n const fields = getFieldsForUser(user, fieldPreset);\r\n const presetSelect = fields.join(' ');\r\n\r\n if (context.select) {\r\n context.select = `${presetSelect} ${context.select}`;\r\n } else {\r\n context.select = presetSelect;\r\n }\r\n };\r\n\r\n repo.on('before:getAll', applyFieldFiltering);\r\n repo.on('before:getById', applyFieldFiltering);\r\n repo.on('before:getByQuery', applyFieldFiltering);\r\n },\r\n };\r\n}\r\n\r\nexport default fieldFilterPlugin;\r\n","/**\r\n * Timestamp Plugin\r\n * Auto-injects createdAt/updatedAt timestamps on create/update\r\n */\r\n\r\nimport type { Plugin, RepositoryContext, RepositoryInstance } from '../types.js';\r\n\r\n/**\r\n * Timestamp plugin that auto-injects timestamps\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [timestampPlugin()]);\r\n */\r\nexport function timestampPlugin(): Plugin {\r\n return {\r\n name: 'timestamp',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n repo.on('before:create', (context: RepositoryContext) => {\r\n if (!context.data) return;\r\n const now = new Date();\r\n if (!context.data.createdAt) context.data.createdAt = now;\r\n if (!context.data.updatedAt) context.data.updatedAt = now;\r\n });\r\n\r\n repo.on('before:update', (context: RepositoryContext) => {\r\n if (!context.data) return;\r\n context.data.updatedAt = new Date();\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default timestampPlugin;\r\n","/**\r\n * Audit Log Plugin\r\n * Logs repository operations for auditing purposes\r\n */\r\n\r\nimport type { Plugin, RepositoryContext, RepositoryInstance, Logger } from '../types.js';\r\n\r\n/**\r\n * Audit log plugin that logs all repository operations\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [auditLogPlugin(console)]);\r\n */\r\nexport function auditLogPlugin(logger: Logger): Plugin {\r\n return {\r\n name: 'auditLog',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n repo.on('after:create', ({ context, result }: { context: RepositoryContext; result: unknown }) => {\r\n logger?.info?.('Document created', {\r\n model: context.model || repo.model,\r\n id: (result as Record<string, unknown>)?._id,\r\n userId: context.user?._id || context.user?.id,\r\n organizationId: context.organizationId,\r\n });\r\n });\r\n\r\n repo.on('after:update', ({ context, result }: { context: RepositoryContext; result: unknown }) => {\r\n logger?.info?.('Document updated', {\r\n model: context.model || repo.model,\r\n id: context.id || (result as Record<string, unknown>)?._id,\r\n userId: context.user?._id || context.user?.id,\r\n organizationId: context.organizationId,\r\n });\r\n });\r\n\r\n repo.on('after:delete', ({ context }: { context: RepositoryContext }) => {\r\n logger?.info?.('Document deleted', {\r\n model: context.model || repo.model,\r\n id: context.id,\r\n userId: context.user?._id || context.user?.id,\r\n organizationId: context.organizationId,\r\n });\r\n });\r\n\r\n repo.on('error:create', ({ context, error }: { context: RepositoryContext; error: Error }) => {\r\n logger?.error?.('Create failed', {\r\n model: context.model || repo.model,\r\n error: error.message,\r\n userId: context.user?._id || context.user?.id,\r\n });\r\n });\r\n\r\n repo.on('error:update', ({ context, error }: { context: RepositoryContext; error: Error }) => {\r\n logger?.error?.('Update failed', {\r\n model: context.model || repo.model,\r\n id: context.id,\r\n error: error.message,\r\n userId: context.user?._id || context.user?.id,\r\n });\r\n });\r\n\r\n repo.on('error:delete', ({ context, error }: { context: RepositoryContext; error: Error }) => {\r\n logger?.error?.('Delete failed', {\r\n model: context.model || repo.model,\r\n id: context.id,\r\n error: error.message,\r\n userId: context.user?._id || context.user?.id,\r\n });\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default auditLogPlugin;\r\n","/**\r\n * Soft Delete Plugin\r\n * Implements soft delete pattern - marks documents as deleted instead of removing\r\n */\r\n\r\nimport type { Plugin, RepositoryContext, RepositoryInstance, SoftDeleteOptions } from '../types.js';\r\n\r\n/**\r\n * Soft delete plugin\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [\r\n * softDeletePlugin({ deletedField: 'deletedAt' })\r\n * ]);\r\n */\r\nexport function softDeletePlugin(options: SoftDeleteOptions = {}): Plugin {\r\n const deletedField = options.deletedField || 'deletedAt';\r\n const deletedByField = options.deletedByField || 'deletedBy';\r\n\r\n return {\r\n name: 'softDelete',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n repo.on('before:delete', async (context: RepositoryContext) => {\r\n if (options.soft !== false) {\r\n const updateData: Record<string, unknown> = {\r\n [deletedField]: new Date(),\r\n };\r\n\r\n if (context.user) {\r\n updateData[deletedByField] = context.user._id || context.user.id;\r\n }\r\n\r\n await repo.Model.findByIdAndUpdate(context.id, updateData, { session: context.session });\r\n\r\n (context as Record<string, unknown>).softDeleted = true;\r\n }\r\n });\r\n\r\n repo.on('before:getAll', (context: RepositoryContext) => {\r\n if (!context.includeDeleted && options.soft !== false) {\r\n const queryParams = (context as Record<string, unknown>).queryParams as Record<string, unknown> || {};\r\n queryParams.filters = {\r\n ...((queryParams.filters as Record<string, unknown>) || {}),\r\n [deletedField]: { $exists: false },\r\n };\r\n (context as Record<string, unknown>).queryParams = queryParams;\r\n }\r\n });\r\n\r\n repo.on('before:getById', (context: RepositoryContext) => {\r\n if (!context.includeDeleted && options.soft !== false) {\r\n context.query = {\r\n ...(context.query || {}),\r\n [deletedField]: { $exists: false },\r\n };\r\n }\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default softDeletePlugin;\r\n","/**\r\n * Method Registry Plugin\r\n *\r\n * Enables plugins to dynamically add methods to repository instances.\r\n * Foundation for extensibility - allows other plugins to extend repositories\r\n * with custom methods while maintaining type safety and proper binding.\r\n *\r\n * @example\r\n * ```typescript\r\n * const repo = new Repository(User, [methodRegistryPlugin()]);\r\n *\r\n * // Now you can register custom methods\r\n * repo.registerMethod('findActive', async function() {\r\n * return this.getAll({ filters: { status: 'active' } });\r\n * });\r\n * ```\r\n */\r\n\r\nimport type { Plugin, RepositoryInstance } from '../types.js';\r\n\r\n/**\r\n * Extended repository interface with method registry\r\n */\r\nexport interface MethodRegistryRepository extends RepositoryInstance {\r\n registerMethod(name: string, fn: Function): void;\r\n hasMethod(name: string): boolean;\r\n getRegisteredMethods(): string[];\r\n}\r\n\r\n/**\r\n * Method registry plugin that enables dynamic method registration\r\n */\r\nexport function methodRegistryPlugin(): Plugin {\r\n return {\r\n name: 'method-registry',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n const registeredMethods: string[] = [];\r\n\r\n /**\r\n * Register a new method on the repository instance\r\n */\r\n repo.registerMethod = function (name: string, fn: Function): void {\r\n // Check for naming conflicts\r\n if ((repo as Record<string, unknown>)[name]) {\r\n throw new Error(\r\n `Cannot register method '${name}': Method already exists on repository. ` +\r\n `Choose a different name or use a plugin that doesn't conflict.`\r\n );\r\n }\r\n\r\n // Validate method name\r\n if (!name || typeof name !== 'string') {\r\n throw new Error('Method name must be a non-empty string');\r\n }\r\n\r\n // Validate function\r\n if (typeof fn !== 'function') {\r\n throw new Error(`Method '${name}' must be a function`);\r\n }\r\n\r\n // Bind function to repository instance\r\n (repo as Record<string, unknown>)[name] = fn.bind(repo);\r\n registeredMethods.push(name);\r\n\r\n // Emit event for plugin system awareness\r\n repo.emit('method:registered', { name, fn });\r\n };\r\n\r\n /**\r\n * Check if a method is registered\r\n */\r\n repo.hasMethod = function (name: string): boolean {\r\n return typeof (repo as Record<string, unknown>)[name] === 'function';\r\n };\r\n\r\n /**\r\n * Get list of all dynamically registered methods\r\n */\r\n (repo as MethodRegistryRepository).getRegisteredMethods = function (): string[] {\r\n return [...registeredMethods];\r\n };\r\n },\r\n };\r\n}\r\n\r\nexport default methodRegistryPlugin;\r\n","/**\r\n * Validation Chain Plugin\r\n * \r\n * Composable validation for repository operations with customizable rules.\r\n */\r\n\r\nimport { createError } from '../utils/error.js';\r\nimport type {\r\n Plugin,\r\n RepositoryInstance,\r\n RepositoryContext,\r\n ValidatorDefinition,\r\n ValidationChainOptions,\r\n HttpError,\r\n} from '../types.js';\r\n\r\ntype OperationType = 'create' | 'createMany' | 'update' | 'delete';\r\n\r\n/**\r\n * Validation chain plugin\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [\r\n * validationChainPlugin([\r\n * requireField('email'),\r\n * uniqueField('email', 'Email already exists'),\r\n * blockIf('no-delete-admin', ['delete'], ctx => ctx.data?.role === 'admin', 'Cannot delete admin'),\r\n * ])\r\n * ]);\r\n */\r\nexport function validationChainPlugin(\r\n validators: ValidatorDefinition[] = [],\r\n options: ValidationChainOptions = {}\r\n): Plugin {\r\n const { stopOnFirstError = true } = options;\r\n\r\n // Validate all validators have required properties\r\n validators.forEach((v, idx) => {\r\n if (!v.name || typeof v.name !== 'string') {\r\n throw new Error(`Validator at index ${idx} missing 'name' (string)`);\r\n }\r\n if (typeof v.validate !== 'function') {\r\n throw new Error(`Validator '${v.name}' missing 'validate' function`);\r\n }\r\n });\r\n\r\n // Group validators by operation\r\n const validatorsByOperation: Record<OperationType, ValidatorDefinition[]> = {\r\n create: [],\r\n update: [],\r\n delete: [],\r\n createMany: [],\r\n };\r\n const allOperationsValidators: ValidatorDefinition[] = [];\r\n\r\n validators.forEach(v => {\r\n if (!v.operations || v.operations.length === 0) {\r\n allOperationsValidators.push(v);\r\n } else {\r\n v.operations.forEach(op => {\r\n if (validatorsByOperation[op]) {\r\n validatorsByOperation[op].push(v);\r\n }\r\n });\r\n }\r\n });\r\n\r\n return {\r\n name: 'validation-chain',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n const getValidatorsForOperation = (operation: OperationType): ValidatorDefinition[] => {\r\n const specific = validatorsByOperation[operation] || [];\r\n return [...allOperationsValidators, ...specific];\r\n };\r\n\r\n const runValidators = async (operation: OperationType, context: RepositoryContext): Promise<void> => {\r\n const operationValidators = getValidatorsForOperation(operation);\r\n const errors: Array<{ validator: string; error: string }> = [];\r\n\r\n for (const validator of operationValidators) {\r\n try {\r\n await validator.validate(context, repo);\r\n } catch (error) {\r\n if (stopOnFirstError) {\r\n throw error;\r\n }\r\n errors.push({\r\n validator: validator.name,\r\n error: (error as Error).message || String(error),\r\n });\r\n }\r\n }\r\n\r\n if (errors.length > 0) {\r\n const err = createError(\r\n 400,\r\n `Validation failed: ${errors.map(e => `[${e.validator}] ${e.error}`).join('; ')}`\r\n ) as HttpError;\r\n err.validationErrors = errors;\r\n throw err;\r\n }\r\n };\r\n\r\n repo.on('before:create', async (context: RepositoryContext) => runValidators('create', context));\r\n repo.on('before:createMany', async (context: RepositoryContext) => runValidators('createMany', context));\r\n repo.on('before:update', async (context: RepositoryContext) => runValidators('update', context));\r\n repo.on('before:delete', async (context: RepositoryContext) => runValidators('delete', context));\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Block operation if condition is true\r\n * \r\n * @example\r\n * blockIf('block-library', ['delete'], ctx => ctx.data?.managed, 'Cannot delete managed records')\r\n */\r\nexport function blockIf(\r\n name: string,\r\n operations: OperationType[],\r\n condition: (context: RepositoryContext) => boolean,\r\n errorMessage: string\r\n): ValidatorDefinition {\r\n return {\r\n name,\r\n operations,\r\n validate: (context: RepositoryContext) => {\r\n if (condition(context)) {\r\n throw createError(403, errorMessage);\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Require a field to be present\r\n */\r\nexport function requireField(\r\n field: string,\r\n operations: OperationType[] = ['create']\r\n): ValidatorDefinition {\r\n return {\r\n name: `require-${field}`,\r\n operations,\r\n validate: (context: RepositoryContext) => {\r\n if (!context.data || context.data[field] === undefined || context.data[field] === null) {\r\n throw createError(400, `Field '${field}' is required`);\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Auto-inject a value if not present\r\n */\r\nexport function autoInject(\r\n field: string,\r\n getter: (context: RepositoryContext) => unknown,\r\n operations: OperationType[] = ['create']\r\n): ValidatorDefinition {\r\n return {\r\n name: `auto-inject-${field}`,\r\n operations,\r\n validate: (context: RepositoryContext) => {\r\n if (context.data && !(field in context.data)) {\r\n const value = getter(context);\r\n if (value !== null && value !== undefined) {\r\n context.data[field] = value;\r\n }\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Make a field immutable (cannot be updated)\r\n */\r\nexport function immutableField(field: string): ValidatorDefinition {\r\n return {\r\n name: `immutable-${field}`,\r\n operations: ['update'],\r\n validate: (context: RepositoryContext) => {\r\n if (context.data && field in context.data) {\r\n throw createError(400, `Field '${field}' cannot be modified`);\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Ensure field value is unique\r\n */\r\nexport function uniqueField(field: string, errorMessage?: string): ValidatorDefinition {\r\n return {\r\n name: `unique-${field}`,\r\n operations: ['create', 'update'],\r\n validate: async (context: RepositoryContext, repo?: RepositoryInstance) => {\r\n if (!context.data || !context.data[field] || !repo) return;\r\n\r\n const query = { [field]: context.data[field] };\r\n \r\n // Use repo's getByQuery method\r\n const getByQuery = (repo as Record<string, Function>).getByQuery;\r\n if (typeof getByQuery !== 'function') return;\r\n\r\n const existing = await getByQuery.call(repo, query, {\r\n select: '_id',\r\n lean: true,\r\n throwOnNotFound: false,\r\n }) as Record<string, unknown> | null;\r\n\r\n if (existing && String(existing._id) !== String(context.id)) {\r\n throw createError(409, errorMessage || `${field} already exists`);\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport default validationChainPlugin;\r\n","/**\r\n * MongoDB Operations Plugin\r\n *\r\n * Adds MongoDB-specific operations to repositories.\r\n * Requires method-registry.plugin.js to be loaded first.\r\n */\r\n\r\nimport { createError } from '../utils/error.js';\r\nimport * as createActions from '../actions/create.js';\r\nimport type { Plugin, RepositoryInstance, ObjectId } from '../types.js';\r\n\r\n/**\r\n * MongoDB operations plugin\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [\r\n * methodRegistryPlugin(),\r\n * mongoOperationsPlugin(),\r\n * ]);\r\n * \r\n * await repo.increment(productId, 'views', 1);\r\n * await repo.pushToArray(productId, 'tags', 'featured');\r\n */\r\nexport function mongoOperationsPlugin(): Plugin {\r\n return {\r\n name: 'mongo-operations',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n // Check if method-registry is available\r\n if (!repo.registerMethod) {\r\n throw new Error(\r\n 'mongoOperationsPlugin requires methodRegistryPlugin. ' +\r\n 'Add methodRegistryPlugin() before mongoOperationsPlugin() in plugins array.'\r\n );\r\n }\r\n\r\n /**\r\n * Update existing document or insert new one\r\n */\r\n repo.registerMethod('upsert', async function (\r\n this: RepositoryInstance,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return createActions.upsert(this.Model, query, data, options);\r\n });\r\n\r\n // Helper: Validate and perform numeric operation\r\n const validateAndUpdateNumeric = async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: number,\r\n operator: string,\r\n operationName: string,\r\n options: Record<string, unknown>\r\n ) {\r\n if (typeof value !== 'number') {\r\n throw createError(400, `${operationName} value must be a number`);\r\n }\r\n return (this as Record<string, Function>).update(id, { [operator]: { [field]: value } }, options);\r\n };\r\n\r\n /**\r\n * Atomically increment numeric field\r\n */\r\n repo.registerMethod('increment', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: number = 1,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return validateAndUpdateNumeric.call(this, id, field, value, '$inc', 'Increment', options);\r\n });\r\n\r\n /**\r\n * Atomically decrement numeric field\r\n */\r\n repo.registerMethod('decrement', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: number = 1,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return validateAndUpdateNumeric.call(this, id, field, -value, '$inc', 'Decrement', options);\r\n });\r\n\r\n // Helper: Generic MongoDB operator update\r\n const applyOperator = function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: unknown,\r\n operator: string,\r\n options: Record<string, unknown>\r\n ) {\r\n return (this as Record<string, Function>).update(id, { [operator]: { [field]: value } }, options);\r\n };\r\n\r\n /**\r\n * Push value to array field\r\n */\r\n repo.registerMethod('pushToArray', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: unknown,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return applyOperator.call(this, id, field, value, '$push', options);\r\n });\r\n\r\n /**\r\n * Remove value from array field\r\n */\r\n repo.registerMethod('pullFromArray', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: unknown,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return applyOperator.call(this, id, field, value, '$pull', options);\r\n });\r\n\r\n /**\r\n * Add value to array only if not already present (unique)\r\n */\r\n repo.registerMethod('addToSet', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: unknown,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return applyOperator.call(this, id, field, value, '$addToSet', options);\r\n });\r\n\r\n /**\r\n * Set field value (alias for update with $set)\r\n */\r\n repo.registerMethod('setField', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: unknown,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return applyOperator.call(this, id, field, value, '$set', options);\r\n });\r\n\r\n /**\r\n * Unset (remove) field from document\r\n */\r\n repo.registerMethod('unsetField', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n fields: string | string[],\r\n options: Record<string, unknown> = {}\r\n ) {\r\n const fieldArray = Array.isArray(fields) ? fields : [fields];\r\n const unsetObj = fieldArray.reduce((acc, field) => {\r\n acc[field] = '';\r\n return acc;\r\n }, {} as Record<string, string>);\r\n\r\n return (this as Record<string, Function>).update(id, { $unset: unsetObj }, options);\r\n });\r\n\r\n /**\r\n * Rename field in document\r\n */\r\n repo.registerMethod('renameField', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n oldName: string,\r\n newName: string,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return (this as Record<string, Function>).update(id, { $rename: { [oldName]: newName } }, options);\r\n });\r\n\r\n /**\r\n * Multiply numeric field by value\r\n */\r\n repo.registerMethod('multiplyField', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n multiplier: number,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return validateAndUpdateNumeric.call(this, id, field, multiplier, '$mul', 'Multiplier', options);\r\n });\r\n\r\n /**\r\n * Set field to minimum value (only if current value is greater)\r\n */\r\n repo.registerMethod('setMin', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: unknown,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return applyOperator.call(this, id, field, value, '$min', options);\r\n });\r\n\r\n /**\r\n * Set field to maximum value (only if current value is less)\r\n */\r\n repo.registerMethod('setMax', async function (\r\n this: RepositoryInstance,\r\n id: string | ObjectId,\r\n field: string,\r\n value: unknown,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return applyOperator.call(this, id, field, value, '$max', options);\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default mongoOperationsPlugin;\r\n","/**\r\n * Batch Operations Plugin\r\n * Adds bulk update/delete operations with proper event emission\r\n */\r\n\r\nimport type { ClientSession } from 'mongoose';\r\nimport type { Plugin, RepositoryInstance, RepositoryContext, HttpError } from '../types.js';\r\n\r\n/**\r\n * Batch operations plugin\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [\r\n * methodRegistryPlugin(),\r\n * batchOperationsPlugin(),\r\n * ]);\r\n * \r\n * await repo.updateMany({ status: 'pending' }, { status: 'active' });\r\n * await repo.deleteMany({ status: 'deleted' });\r\n */\r\nexport function batchOperationsPlugin(): Plugin {\r\n return {\r\n name: 'batch-operations',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n if (!repo.registerMethod) {\r\n throw new Error('batchOperationsPlugin requires methodRegistryPlugin');\r\n }\r\n\r\n /**\r\n * Update multiple documents\r\n */\r\n repo.registerMethod('updateMany', async function (\r\n this: RepositoryInstance,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n const _buildContext = (this as Record<string, Function>)._buildContext;\r\n const context = await _buildContext.call(this, 'updateMany', { query, data, options }) as RepositoryContext;\r\n\r\n try {\r\n this.emit('before:updateMany', context);\r\n\r\n const result = await this.Model.updateMany(query, data, {\r\n runValidators: true,\r\n session: options.session as ClientSession | undefined,\r\n }).exec();\r\n\r\n this.emit('after:updateMany', { context, result });\r\n return result;\r\n } catch (error) {\r\n this.emit('error:updateMany', { context, error });\r\n const _handleError = (this as Record<string, Function>)._handleError;\r\n throw _handleError.call(this, error as Error) as HttpError;\r\n }\r\n });\r\n\r\n /**\r\n * Delete multiple documents\r\n */\r\n repo.registerMethod('deleteMany', async function (\r\n this: RepositoryInstance,\r\n query: Record<string, unknown>,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n const _buildContext = (this as Record<string, Function>)._buildContext;\r\n const context = await _buildContext.call(this, 'deleteMany', { query, options }) as RepositoryContext;\r\n\r\n try {\r\n this.emit('before:deleteMany', context);\r\n\r\n const result = await this.Model.deleteMany(query, {\r\n session: options.session as ClientSession | undefined,\r\n }).exec();\r\n\r\n this.emit('after:deleteMany', { context, result });\r\n return result;\r\n } catch (error) {\r\n this.emit('error:deleteMany', { context, error });\r\n const _handleError = (this as Record<string, Function>)._handleError;\r\n throw _handleError.call(this, error as Error) as HttpError;\r\n }\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default batchOperationsPlugin;\r\n","/**\r\n * Aggregate Helpers Plugin\r\n * Adds common aggregation helper methods\r\n */\r\n\r\nimport type { PipelineStage } from 'mongoose';\r\nimport type { Plugin, RepositoryInstance } from '../types.js';\r\n\r\n/**\r\n * Aggregate helpers plugin\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [\r\n * methodRegistryPlugin(),\r\n * aggregateHelpersPlugin(),\r\n * ]);\r\n * \r\n * const groups = await repo.groupBy('category');\r\n * const total = await repo.sum('amount', { status: 'completed' });\r\n */\r\nexport function aggregateHelpersPlugin(): Plugin {\r\n return {\r\n name: 'aggregate-helpers',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n if (!repo.registerMethod) {\r\n throw new Error('aggregateHelpersPlugin requires methodRegistryPlugin');\r\n }\r\n\r\n /**\r\n * Group by field\r\n */\r\n repo.registerMethod('groupBy', async function (\r\n this: RepositoryInstance,\r\n field: string,\r\n options: { limit?: number; session?: unknown } = {}\r\n ) {\r\n const pipeline: PipelineStage[] = [\r\n { $group: { _id: `$${field}`, count: { $sum: 1 } } },\r\n { $sort: { count: -1 } },\r\n ];\r\n\r\n if (options.limit) {\r\n pipeline.push({ $limit: options.limit });\r\n }\r\n\r\n const aggregate = (this as Record<string, Function>).aggregate;\r\n return aggregate.call(this, pipeline, options);\r\n });\r\n\r\n // Helper: Generic aggregation operation\r\n const aggregateOperation = async function (\r\n this: RepositoryInstance,\r\n field: string,\r\n operator: string,\r\n resultKey: string,\r\n query: Record<string, unknown> = {},\r\n options: Record<string, unknown> = {}\r\n ): Promise<number> {\r\n const pipeline: PipelineStage[] = [\r\n { $match: query },\r\n { $group: { _id: null, [resultKey]: { [operator]: `$${field}` } } },\r\n ];\r\n\r\n const aggregate = (this as Record<string, Function>).aggregate;\r\n const result = await aggregate.call(this, pipeline, options) as Array<Record<string, number>>;\r\n return result[0]?.[resultKey] || 0;\r\n };\r\n\r\n /**\r\n * Sum field values\r\n */\r\n repo.registerMethod('sum', async function (\r\n this: RepositoryInstance,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return aggregateOperation.call(this, field, '$sum', 'total', query, options);\r\n });\r\n\r\n /**\r\n * Average field values\r\n */\r\n repo.registerMethod('average', async function (\r\n this: RepositoryInstance,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return aggregateOperation.call(this, field, '$avg', 'avg', query, options);\r\n });\r\n\r\n /**\r\n * Get minimum value\r\n */\r\n repo.registerMethod('min', async function (\r\n this: RepositoryInstance,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return aggregateOperation.call(this, field, '$min', 'min', query, options);\r\n });\r\n\r\n /**\r\n * Get maximum value\r\n */\r\n repo.registerMethod('max', async function (\r\n this: RepositoryInstance,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: Record<string, unknown> = {}\r\n ) {\r\n return aggregateOperation.call(this, field, '$max', 'max', query, options);\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default aggregateHelpersPlugin;\r\n","/**\r\n * Subdocument Plugin\r\n * Adds subdocument array operations\r\n */\r\n\r\nimport type { ClientSession } from 'mongoose';\r\nimport { createError } from '../utils/error.js';\r\nimport type { Plugin, RepositoryInstance, ObjectId } from '../types.js';\r\n\r\n/**\r\n * Subdocument plugin for managing nested arrays\r\n * \r\n * @example\r\n * const repo = new Repository(Model, [\r\n * methodRegistryPlugin(),\r\n * subdocumentPlugin(),\r\n * ]);\r\n * \r\n * await repo.addSubdocument(parentId, 'items', { name: 'Item 1' });\r\n * await repo.updateSubdocument(parentId, 'items', itemId, { name: 'Updated Item' });\r\n */\r\nexport function subdocumentPlugin(): Plugin {\r\n return {\r\n name: 'subdocument',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n if (!repo.registerMethod) {\r\n throw new Error('subdocumentPlugin requires methodRegistryPlugin');\r\n }\r\n\r\n /**\r\n * Add subdocument to array\r\n */\r\n repo.registerMethod('addSubdocument', async function (\r\n this: RepositoryInstance,\r\n parentId: string | ObjectId,\r\n arrayPath: string,\r\n subData: Record<string, unknown>,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n const update = (this as Record<string, Function>).update;\r\n return update.call(this, parentId, { $push: { [arrayPath]: subData } }, options);\r\n });\r\n\r\n /**\r\n * Get subdocument from array\r\n */\r\n repo.registerMethod('getSubdocument', async function (\r\n this: RepositoryInstance,\r\n parentId: string | ObjectId,\r\n arrayPath: string,\r\n subId: string | ObjectId,\r\n options: { lean?: boolean; session?: unknown } = {}\r\n ) {\r\n const _executeQuery = (this as Record<string, Function>)._executeQuery;\r\n return _executeQuery.call(this, async (Model: typeof this.Model) => {\r\n const parent = await Model.findById(parentId).session(options.session as never).exec();\r\n if (!parent) throw createError(404, 'Parent not found');\r\n\r\n const parentObj = parent as Record<string, unknown>;\r\n const arrayField = parentObj[arrayPath] as { id: (id: string | ObjectId) => Record<string, unknown> | null } | undefined;\r\n \r\n if (!arrayField || typeof arrayField.id !== 'function') {\r\n throw createError(404, 'Array field not found');\r\n }\r\n\r\n const sub = arrayField.id(subId);\r\n if (!sub) throw createError(404, 'Subdocument not found');\r\n\r\n return options.lean && typeof (sub as Record<string, unknown>).toObject === 'function'\r\n ? (sub as { toObject: () => Record<string, unknown> }).toObject()\r\n : sub;\r\n });\r\n });\r\n\r\n /**\r\n * Update subdocument in array\r\n */\r\n repo.registerMethod('updateSubdocument', async function (\r\n this: RepositoryInstance,\r\n parentId: string | ObjectId,\r\n arrayPath: string,\r\n subId: string | ObjectId,\r\n updateData: Record<string, unknown>,\r\n options: { session?: unknown } = {}\r\n ) {\r\n const _executeQuery = (this as Record<string, Function>)._executeQuery;\r\n return _executeQuery.call(this, async (Model: typeof this.Model) => {\r\n const query = { _id: parentId, [`${arrayPath}._id`]: subId };\r\n const update = { $set: { [`${arrayPath}.$`]: { ...updateData, _id: subId } } };\r\n\r\n const result = await Model.findOneAndUpdate(query, update, {\r\n new: true,\r\n runValidators: true,\r\n session: options.session as ClientSession | undefined,\r\n }).exec();\r\n\r\n if (!result) throw createError(404, 'Parent or subdocument not found');\r\n return result;\r\n });\r\n });\r\n\r\n /**\r\n * Delete subdocument from array\r\n */\r\n repo.registerMethod('deleteSubdocument', async function (\r\n this: RepositoryInstance,\r\n parentId: string | ObjectId,\r\n arrayPath: string,\r\n subId: string | ObjectId,\r\n options: Record<string, unknown> = {}\r\n ) {\r\n const update = (this as Record<string, Function>).update;\r\n return update.call(this, parentId, { $pull: { [arrayPath]: { _id: subId } } }, options);\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default subdocumentPlugin;\r\n","/**\r\n * Cache Key Utilities\r\n * \r\n * Generates deterministic, collision-free cache keys for MongoDB queries.\r\n * Key design inspired by Next.js cache tags and best practices from Stripe/Meta.\r\n */\r\n\r\nimport type { SortSpec, SelectSpec, PopulateSpec } from '../types.js';\r\n\r\n/**\r\n * Simple hash function for query parameters\r\n * Using djb2 algorithm - fast and good distribution\r\n */\r\nfunction hashString(str: string): string {\r\n let hash = 5381;\r\n for (let i = 0; i < str.length; i++) {\r\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i);\r\n }\r\n // Convert to positive hex string\r\n return (hash >>> 0).toString(16);\r\n}\r\n\r\n/**\r\n * Normalize and stringify an object for hashing\r\n * Ensures deterministic key generation regardless of property order\r\n */\r\nfunction stableStringify(obj: unknown): string {\r\n if (obj === null || obj === undefined) return '';\r\n if (typeof obj !== 'object') return String(obj);\r\n if (Array.isArray(obj)) {\r\n return '[' + obj.map(stableStringify).join(',') + ']';\r\n }\r\n \r\n const sorted = Object.keys(obj as Record<string, unknown>)\r\n .sort()\r\n .map(key => `${key}:${stableStringify((obj as Record<string, unknown>)[key])}`);\r\n return '{' + sorted.join(',') + '}';\r\n}\r\n\r\n/**\r\n * Generate cache key for getById operations\r\n * \r\n * Format: {prefix}:id:{model}:{documentId}\r\n * \r\n * @example\r\n * byIdKey('mk', 'User', '507f1f77bcf86cd799439011')\r\n * // => 'mk:id:User:507f1f77bcf86cd799439011'\r\n */\r\nexport function byIdKey(prefix: string, model: string, id: string): string {\r\n return `${prefix}:id:${model}:${id}`;\r\n}\r\n\r\n/**\r\n * Generate cache key for single-document queries\r\n * \r\n * Format: {prefix}:one:{model}:{queryHash}\r\n * \r\n * @example\r\n * byQueryKey('mk', 'User', { email: 'john@example.com' })\r\n * // => 'mk:one:User:a1b2c3d4'\r\n */\r\nexport function byQueryKey(\r\n prefix: string,\r\n model: string,\r\n query: Record<string, unknown>,\r\n options?: { select?: SelectSpec; populate?: PopulateSpec }\r\n): string {\r\n const hashInput = stableStringify({ q: query, s: options?.select, p: options?.populate });\r\n return `${prefix}:one:${model}:${hashString(hashInput)}`;\r\n}\r\n\r\n/**\r\n * Generate cache key for paginated list queries\r\n * \r\n * Format: {prefix}:list:{model}:{version}:{queryHash}\r\n * \r\n * The version component enables efficient bulk invalidation:\r\n * - On any mutation, bump the version\r\n * - All list cache keys become invalid without scanning/deleting each\r\n * \r\n * @example\r\n * listQueryKey('mk', 'User', 1, { filters: { status: 'active' }, page: 1, limit: 20 })\r\n * // => 'mk:list:User:1:e5f6g7h8'\r\n */\r\nexport function listQueryKey(\r\n prefix: string,\r\n model: string,\r\n version: number,\r\n params: {\r\n filters?: Record<string, unknown>;\r\n sort?: SortSpec;\r\n page?: number;\r\n limit?: number;\r\n after?: string;\r\n select?: SelectSpec;\r\n populate?: PopulateSpec;\r\n }\r\n): string {\r\n const hashInput = stableStringify({\r\n f: params.filters,\r\n s: params.sort,\r\n pg: params.page,\r\n lm: params.limit,\r\n af: params.after,\r\n sl: params.select,\r\n pp: params.populate,\r\n });\r\n return `${prefix}:list:${model}:${version}:${hashString(hashInput)}`;\r\n}\r\n\r\n/**\r\n * Generate cache key for collection version tag\r\n * \r\n * Format: {prefix}:ver:{model}\r\n * \r\n * Used to track mutation version for list invalidation\r\n */\r\nexport function versionKey(prefix: string, model: string): string {\r\n return `${prefix}:ver:${model}`;\r\n}\r\n\r\n/**\r\n * Generate pattern for clearing all cache keys for a model\r\n * \r\n * Format: {prefix}:*:{model}:*\r\n * \r\n * @example\r\n * modelPattern('mk', 'User')\r\n * // => 'mk:*:User:*'\r\n */\r\nexport function modelPattern(prefix: string, model: string): string {\r\n return `${prefix}:*:${model}:*`;\r\n}\r\n\r\n/**\r\n * Generate pattern for clearing all list cache keys for a model\r\n * \r\n * Format: {prefix}:list:{model}:*\r\n */\r\nexport function listPattern(prefix: string, model: string): string {\r\n return `${prefix}:list:${model}:*`;\r\n}\r\n\r\n","/**\r\n * Cache Plugin\r\n * \r\n * Optional caching layer for MongoKit with automatic invalidation.\r\n * Bring-your-own cache adapter (Redis, Memcached, in-memory, etc.)\r\n * \r\n * Features:\r\n * - Cache-aside (read-through) pattern with configurable TTLs\r\n * - Automatic invalidation on create/update/delete\r\n * - Collection version tags for efficient list cache invalidation\r\n * - Manual invalidation methods for microservice scenarios\r\n * - Skip cache per-operation with `skipCache: true`\r\n * \r\n * @example\r\n * ```typescript\r\n * import { Repository, cachePlugin } from '@classytic/mongokit';\r\n * import Redis from 'ioredis';\r\n * \r\n * const redis = new Redis();\r\n * \r\n * const userRepo = new Repository(UserModel, [\r\n * cachePlugin({\r\n * adapter: {\r\n * async get(key) { return JSON.parse(await redis.get(key) || 'null'); },\r\n * async set(key, value, ttl) { await redis.setex(key, ttl, JSON.stringify(value)); },\r\n * async del(key) { await redis.del(key); },\r\n * async clear(pattern) {\r\n * const keys = await redis.keys(pattern || '*');\r\n * if (keys.length) await redis.del(...keys);\r\n * }\r\n * },\r\n * ttl: 60, // 1 minute default\r\n * })\r\n * ]);\r\n * \r\n * // Reads check cache first\r\n * const user = await userRepo.getById(id); // cached\r\n * \r\n * // Skip cache for fresh data\r\n * const fresh = await userRepo.getById(id, { skipCache: true });\r\n * \r\n * // Mutations auto-invalidate\r\n * await userRepo.update(id, { name: 'New Name' }); // invalidates cache\r\n * \r\n * // Manual invalidation for microservice sync\r\n * await userRepo.invalidateCache(id); // invalidate single doc\r\n * await userRepo.invalidateAllCache(); // invalidate all for this model\r\n * ```\r\n */\r\n\r\nimport type {\r\n Plugin,\r\n RepositoryContext,\r\n RepositoryInstance,\r\n CacheAdapter,\r\n CacheOptions,\r\n CacheStats,\r\n SortSpec,\r\n} from '../types.js';\r\nimport {\r\n byIdKey,\r\n byQueryKey,\r\n listQueryKey,\r\n versionKey,\r\n modelPattern,\r\n} from '../utils/cache-keys.js';\r\n\r\n/** Internal resolved options */\r\ninterface ResolvedCacheOptions {\r\n adapter: CacheAdapter;\r\n ttl: number;\r\n byIdTtl: number;\r\n queryTtl: number;\r\n prefix: string;\r\n debug: boolean;\r\n skipIfLargeLimit: number;\r\n}\r\n\r\n/**\r\n * Cache plugin factory\r\n * \r\n * @param options - Cache configuration\r\n * @returns Plugin instance\r\n */\r\nexport function cachePlugin(options: CacheOptions): Plugin {\r\n const config: ResolvedCacheOptions = {\r\n adapter: options.adapter,\r\n ttl: options.ttl ?? 60,\r\n byIdTtl: options.byIdTtl ?? options.ttl ?? 60,\r\n queryTtl: options.queryTtl ?? options.ttl ?? 60,\r\n prefix: options.prefix ?? 'mk',\r\n debug: options.debug ?? false,\r\n skipIfLargeLimit: options.skipIf?.largeLimit ?? 100,\r\n };\r\n\r\n // Stats for monitoring\r\n const stats: CacheStats = {\r\n hits: 0,\r\n misses: 0,\r\n sets: 0,\r\n invalidations: 0,\r\n };\r\n\r\n // Collection version for list invalidation (in-memory, synced to cache)\r\n let collectionVersion = 0;\r\n\r\n const log = (msg: string, data?: unknown) => {\r\n if (config.debug) {\r\n console.log(`[mongokit:cache] ${msg}`, data ?? '');\r\n }\r\n };\r\n\r\n return {\r\n name: 'cache',\r\n\r\n apply(repo: RepositoryInstance): void {\r\n const model = repo.model;\r\n\r\n // Initialize version from cache on startup\r\n (async () => {\r\n try {\r\n const cached = await config.adapter.get<number>(versionKey(config.prefix, model));\r\n if (cached !== null) {\r\n collectionVersion = cached;\r\n log(`Initialized version for ${model}:`, collectionVersion);\r\n }\r\n } catch (e) {\r\n log(`Failed to initialize version for ${model}:`, e);\r\n }\r\n })();\r\n\r\n /**\r\n * Helper to bump collection version (invalidates all list caches)\r\n */\r\n async function bumpVersion(): Promise<void> {\r\n collectionVersion++;\r\n try {\r\n await config.adapter.set(versionKey(config.prefix, model), collectionVersion, config.ttl * 10);\r\n stats.invalidations++;\r\n log(`Bumped version for ${model} to:`, collectionVersion);\r\n } catch (e) {\r\n log(`Failed to bump version for ${model}:`, e);\r\n }\r\n }\r\n\r\n /**\r\n * Helper to invalidate a specific document by ID\r\n */\r\n async function invalidateById(id: string): Promise<void> {\r\n const key = byIdKey(config.prefix, model, id);\r\n try {\r\n await config.adapter.del(key);\r\n stats.invalidations++;\r\n log(`Invalidated byId cache:`, key);\r\n } catch (e) {\r\n log(`Failed to invalidate byId cache:`, e);\r\n }\r\n }\r\n\r\n // ============================================================\r\n // READ HOOKS - Check cache before DB query\r\n // ============================================================\r\n\r\n /**\r\n * before:getById - Check cache for document\r\n */\r\n repo.on('before:getById', async (context: RepositoryContext) => {\r\n if ((context as Record<string, unknown>).skipCache) {\r\n log(`Skipping cache for getById: ${context.id}`);\r\n return;\r\n }\r\n\r\n const id = String(context.id);\r\n const key = byIdKey(config.prefix, model, id);\r\n\r\n try {\r\n const cached = await config.adapter.get(key);\r\n if (cached !== null) {\r\n stats.hits++;\r\n log(`Cache HIT for getById:`, key);\r\n // Store in context for Repository to use\r\n (context as Record<string, unknown>)._cacheHit = true;\r\n (context as Record<string, unknown>)._cachedResult = cached;\r\n } else {\r\n stats.misses++;\r\n log(`Cache MISS for getById:`, key);\r\n }\r\n } catch (e) {\r\n log(`Cache error for getById:`, e);\r\n stats.misses++;\r\n }\r\n });\r\n\r\n /**\r\n * before:getByQuery - Check cache for single-doc query\r\n */\r\n repo.on('before:getByQuery', async (context: RepositoryContext) => {\r\n if ((context as Record<string, unknown>).skipCache) {\r\n log(`Skipping cache for getByQuery`);\r\n return;\r\n }\r\n\r\n const query = (context.query || {}) as Record<string, unknown>;\r\n const key = byQueryKey(config.prefix, model, query, {\r\n select: context.select,\r\n populate: context.populate,\r\n });\r\n\r\n try {\r\n const cached = await config.adapter.get(key);\r\n if (cached !== null) {\r\n stats.hits++;\r\n log(`Cache HIT for getByQuery:`, key);\r\n (context as Record<string, unknown>)._cacheHit = true;\r\n (context as Record<string, unknown>)._cachedResult = cached;\r\n } else {\r\n stats.misses++;\r\n log(`Cache MISS for getByQuery:`, key);\r\n }\r\n } catch (e) {\r\n log(`Cache error for getByQuery:`, e);\r\n stats.misses++;\r\n }\r\n });\r\n\r\n /**\r\n * before:getAll - Check cache for list query\r\n */\r\n repo.on('before:getAll', async (context: RepositoryContext) => {\r\n if ((context as Record<string, unknown>).skipCache) {\r\n log(`Skipping cache for getAll`);\r\n return;\r\n }\r\n\r\n // Skip caching large result sets\r\n const limit = (context as Record<string, unknown>).limit as number | undefined;\r\n if (limit && limit > config.skipIfLargeLimit) {\r\n log(`Skipping cache for large query (limit: ${limit})`);\r\n return;\r\n }\r\n\r\n const params = {\r\n filters: (context as Record<string, unknown>).filters as Record<string, unknown> | undefined,\r\n sort: (context as Record<string, unknown>).sort as SortSpec | undefined,\r\n page: (context as Record<string, unknown>).page as number | undefined,\r\n limit,\r\n after: (context as Record<string, unknown>).after as string | undefined,\r\n select: context.select,\r\n populate: context.populate,\r\n };\r\n\r\n const key = listQueryKey(config.prefix, model, collectionVersion, params);\r\n\r\n try {\r\n const cached = await config.adapter.get(key);\r\n if (cached !== null) {\r\n stats.hits++;\r\n log(`Cache HIT for getAll:`, key);\r\n (context as Record<string, unknown>)._cacheHit = true;\r\n (context as Record<string, unknown>)._cachedResult = cached;\r\n } else {\r\n stats.misses++;\r\n log(`Cache MISS for getAll:`, key);\r\n }\r\n } catch (e) {\r\n log(`Cache error for getAll:`, e);\r\n stats.misses++;\r\n }\r\n });\r\n\r\n // ============================================================\r\n // AFTER HOOKS - Store results in cache\r\n // ============================================================\r\n\r\n /**\r\n * after:getById - Cache the result\r\n */\r\n repo.on('after:getById', async (payload: { context: RepositoryContext; result: unknown }) => {\r\n const { context, result } = payload;\r\n \r\n // Don't cache if we got a cache hit (result came from cache)\r\n if ((context as Record<string, unknown>)._cacheHit) return;\r\n if ((context as Record<string, unknown>).skipCache) return;\r\n if (result === null) return; // Don't cache not-found\r\n\r\n const id = String(context.id);\r\n const key = byIdKey(config.prefix, model, id);\r\n const ttl = ((context as Record<string, unknown>).cacheTtl as number) ?? config.byIdTtl;\r\n\r\n try {\r\n await config.adapter.set(key, result, ttl);\r\n stats.sets++;\r\n log(`Cached getById result:`, key);\r\n } catch (e) {\r\n log(`Failed to cache getById:`, e);\r\n }\r\n });\r\n\r\n /**\r\n * after:getByQuery - Cache the result\r\n */\r\n repo.on('after:getByQuery', async (payload: { context: RepositoryContext; result: unknown }) => {\r\n const { context, result } = payload;\r\n \r\n if ((context as Record<string, unknown>)._cacheHit) return;\r\n if ((context as Record<string, unknown>).skipCache) return;\r\n if (result === null) return;\r\n\r\n const query = (context.query || {}) as Record<string, unknown>;\r\n const key = byQueryKey(config.prefix, model, query, {\r\n select: context.select,\r\n populate: context.populate,\r\n });\r\n const ttl = ((context as Record<string, unknown>).cacheTtl as number) ?? config.queryTtl;\r\n\r\n try {\r\n await config.adapter.set(key, result, ttl);\r\n stats.sets++;\r\n log(`Cached getByQuery result:`, key);\r\n } catch (e) {\r\n log(`Failed to cache getByQuery:`, e);\r\n }\r\n });\r\n\r\n /**\r\n * after:getAll - Cache the result\r\n */\r\n repo.on('after:getAll', async (payload: { context: RepositoryContext; result: unknown }) => {\r\n const { context, result } = payload;\r\n \r\n if ((context as Record<string, unknown>)._cacheHit) return;\r\n if ((context as Record<string, unknown>).skipCache) return;\r\n\r\n const limit = (context as Record<string, unknown>).limit as number | undefined;\r\n if (limit && limit > config.skipIfLargeLimit) return;\r\n\r\n const params = {\r\n filters: (context as Record<string, unknown>).filters as Record<string, unknown> | undefined,\r\n sort: (context as Record<string, unknown>).sort as SortSpec | undefined,\r\n page: (context as Record<string, unknown>).page as number | undefined,\r\n limit,\r\n after: (context as Record<string, unknown>).after as string | undefined,\r\n select: context.select,\r\n populate: context.populate,\r\n };\r\n\r\n const key = listQueryKey(config.prefix, model, collectionVersion, params);\r\n const ttl = ((context as Record<string, unknown>).cacheTtl as number) ?? config.queryTtl;\r\n\r\n try {\r\n await config.adapter.set(key, result, ttl);\r\n stats.sets++;\r\n log(`Cached getAll result:`, key);\r\n } catch (e) {\r\n log(`Failed to cache getAll:`, e);\r\n }\r\n });\r\n\r\n // ============================================================\r\n // WRITE HOOKS - Invalidate cache on mutations\r\n // ============================================================\r\n\r\n /**\r\n * after:create - Bump version to invalidate list caches\r\n */\r\n repo.on('after:create', async () => {\r\n await bumpVersion();\r\n });\r\n\r\n /**\r\n * after:createMany - Bump version to invalidate list caches\r\n */\r\n repo.on('after:createMany', async () => {\r\n await bumpVersion();\r\n });\r\n\r\n /**\r\n * after:update - Invalidate by ID and bump version\r\n */\r\n repo.on('after:update', async (payload: { context: RepositoryContext; result: unknown }) => {\r\n const { context } = payload;\r\n const id = String(context.id);\r\n \r\n await Promise.all([\r\n invalidateById(id),\r\n bumpVersion(),\r\n ]);\r\n });\r\n\r\n /**\r\n * after:updateMany - Bump version (can't track individual IDs efficiently)\r\n */\r\n repo.on('after:updateMany', async () => {\r\n await bumpVersion();\r\n });\r\n\r\n /**\r\n * after:delete - Invalidate by ID and bump version\r\n */\r\n repo.on('after:delete', async (payload: { context: RepositoryContext }) => {\r\n const { context } = payload;\r\n const id = String(context.id);\r\n \r\n await Promise.all([\r\n invalidateById(id),\r\n bumpVersion(),\r\n ]);\r\n });\r\n\r\n /**\r\n * after:deleteMany - Bump version\r\n */\r\n repo.on('after:deleteMany', async () => {\r\n await bumpVersion();\r\n });\r\n\r\n // ============================================================\r\n // PUBLIC METHODS - Manual invalidation for microservices\r\n // ============================================================\r\n\r\n /**\r\n * Invalidate cache for a specific document\r\n * Use when document was updated outside this service\r\n * \r\n * @example\r\n * await userRepo.invalidateCache('507f1f77bcf86cd799439011');\r\n */\r\n repo.invalidateCache = async (id: string): Promise<void> => {\r\n await invalidateById(id);\r\n log(`Manual invalidation for ID:`, id);\r\n };\r\n\r\n /**\r\n * Invalidate all list caches for this model\r\n * Use when bulk changes happened outside this service\r\n * \r\n * @example\r\n * await userRepo.invalidateListCache();\r\n */\r\n repo.invalidateListCache = async (): Promise<void> => {\r\n await bumpVersion();\r\n log(`Manual list cache invalidation for ${model}`);\r\n };\r\n\r\n /**\r\n * Invalidate ALL cache entries for this model\r\n * Nuclear option - use sparingly\r\n * \r\n * @example\r\n * await userRepo.invalidateAllCache();\r\n */\r\n repo.invalidateAllCache = async (): Promise<void> => {\r\n if (config.adapter.clear) {\r\n try {\r\n await config.adapter.clear(modelPattern(config.prefix, model));\r\n stats.invalidations++;\r\n log(`Full cache invalidation for ${model}`);\r\n } catch (e) {\r\n log(`Failed full cache invalidation for ${model}:`, e);\r\n }\r\n } else {\r\n // Fallback: just bump version (invalidates lists) \r\n await bumpVersion();\r\n log(`Partial cache invalidation for ${model} (adapter.clear not available)`);\r\n }\r\n };\r\n\r\n /**\r\n * Get cache statistics for monitoring\r\n * \r\n * @example\r\n * const stats = userRepo.getCacheStats();\r\n * console.log(`Hit rate: ${stats.hits / (stats.hits + stats.misses) * 100}%`);\r\n */\r\n repo.getCacheStats = (): CacheStats => ({ ...stats });\r\n\r\n /**\r\n * Reset cache statistics\r\n */\r\n repo.resetCacheStats = (): void => {\r\n stats.hits = 0;\r\n stats.misses = 0;\r\n stats.sets = 0;\r\n stats.invalidations = 0;\r\n };\r\n },\r\n };\r\n}\r\n\r\nexport default cachePlugin;\r\n\r\n","/**\r\n * In-Memory Cache Adapter\r\n * \r\n * Simple cache adapter for development and testing.\r\n * NOT recommended for production - use Redis or similar.\r\n * \r\n * @example\r\n * ```typescript\r\n * import { cachePlugin, createMemoryCache } from '@classytic/mongokit';\r\n * \r\n * const repo = new Repository(UserModel, [\r\n * cachePlugin({\r\n * adapter: createMemoryCache(),\r\n * ttl: 60,\r\n * })\r\n * ]);\r\n * ```\r\n */\r\n\r\nimport type { CacheAdapter } from '../types.js';\r\n\r\ninterface CacheEntry {\r\n value: unknown;\r\n expiresAt: number;\r\n}\r\n\r\n/**\r\n * Creates an in-memory cache adapter\r\n * \r\n * Features:\r\n * - Automatic TTL expiration\r\n * - Pattern-based clearing (simple glob with *)\r\n * - Max entries limit to prevent memory leaks\r\n * \r\n * @param maxEntries - Maximum cache entries before oldest are evicted (default: 1000)\r\n */\r\nexport function createMemoryCache(maxEntries: number = 1000): CacheAdapter {\r\n const cache = new Map<string, CacheEntry>();\r\n\r\n function cleanup(): void {\r\n const now = Date.now();\r\n for (const [key, entry] of cache) {\r\n if (entry.expiresAt < now) {\r\n cache.delete(key);\r\n }\r\n }\r\n }\r\n\r\n function evictOldest(): void {\r\n if (cache.size >= maxEntries) {\r\n // Delete the oldest entry (first key in Map maintains insertion order)\r\n const firstKey = cache.keys().next().value;\r\n if (firstKey) cache.delete(firstKey);\r\n }\r\n }\r\n\r\n return {\r\n async get<T>(key: string): Promise<T | null> {\r\n cleanup();\r\n const entry = cache.get(key);\r\n if (!entry) return null;\r\n if (entry.expiresAt < Date.now()) {\r\n cache.delete(key);\r\n return null;\r\n }\r\n return entry.value as T;\r\n },\r\n\r\n async set<T>(key: string, value: T, ttl: number): Promise<void> {\r\n cleanup();\r\n evictOldest();\r\n cache.set(key, {\r\n value,\r\n expiresAt: Date.now() + ttl * 1000,\r\n });\r\n },\r\n\r\n async del(key: string): Promise<void> {\r\n cache.delete(key);\r\n },\r\n\r\n async clear(pattern?: string): Promise<void> {\r\n if (!pattern) {\r\n cache.clear();\r\n return;\r\n }\r\n\r\n // Simple glob pattern matching (supports * wildcards)\r\n const regex = new RegExp(\r\n '^' + pattern.replace(/\\*/g, '.*').replace(/\\?/g, '.') + '$'\r\n );\r\n\r\n for (const key of cache.keys()) {\r\n if (regex.test(key)) {\r\n cache.delete(key);\r\n }\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport default createMemoryCache;\r\n\r\n","/**\r\n * Repository Actions\r\n * Modular, composable data access operations\r\n */\r\n\r\nexport * as create from './create.js';\r\nexport * as read from './read.js';\r\nexport * as update from './update.js';\r\nexport * as deleteActions from './delete.js';\r\nexport * as aggregate from './aggregate.js';\r\n","/**\r\n * MongoKit - Event-driven repository pattern for MongoDB\r\n * \r\n * Production-grade MongoDB repositories with zero dependencies -\r\n * smart pagination, events, and plugins.\r\n * \r\n * @module @classytic/mongokit\r\n * @author Sadman Chowdhury (Github: @siam923)\r\n * @license MIT\r\n * \r\n * @example\r\n * ```typescript\r\n * import { Repository, createRepository } from '@classytic/mongokit';\r\n * import { timestampPlugin, softDeletePlugin } from '@classytic/mongokit';\r\n * \r\n * // Create repository with plugins\r\n * const userRepo = createRepository(UserModel, [\r\n * timestampPlugin(),\r\n * softDeletePlugin(),\r\n * ]);\r\n * \r\n * // Create\r\n * const user = await userRepo.create({ name: 'John', email: 'john@example.com' });\r\n * \r\n * // Read with pagination (auto-detects offset vs keyset)\r\n * const users = await userRepo.getAll({ page: 1, limit: 20 });\r\n * \r\n * // Keyset pagination for infinite scroll\r\n * const stream = await userRepo.getAll({ sort: { createdAt: -1 }, limit: 50 });\r\n * const nextStream = await userRepo.getAll({ after: stream.next, sort: { createdAt: -1 } });\r\n * \r\n * // Update\r\n * await userRepo.update(user._id, { name: 'John Doe' });\r\n * \r\n * // Delete\r\n * await userRepo.delete(user._id);\r\n * ```\r\n */\r\n\r\n// Core exports\r\nexport { Repository } from './Repository.js';\r\nexport { PaginationEngine } from './pagination/PaginationEngine.js';\r\n\r\n// Plugins\r\nexport { fieldFilterPlugin } from './plugins/field-filter.plugin.js';\r\nexport { timestampPlugin } from './plugins/timestamp.plugin.js';\r\nexport { auditLogPlugin } from './plugins/audit-log.plugin.js';\r\nexport { softDeletePlugin } from './plugins/soft-delete.plugin.js';\r\nexport { methodRegistryPlugin } from './plugins/method-registry.plugin.js';\r\nexport {\r\n validationChainPlugin,\r\n blockIf,\r\n requireField,\r\n autoInject,\r\n immutableField,\r\n uniqueField,\r\n} from './plugins/validation-chain.plugin.js';\r\nexport { mongoOperationsPlugin } from './plugins/mongo-operations.plugin.js';\r\nexport { batchOperationsPlugin } from './plugins/batch-operations.plugin.js';\r\nexport { aggregateHelpersPlugin } from './plugins/aggregate-helpers.plugin.js';\r\nexport { subdocumentPlugin } from './plugins/subdocument.plugin.js';\r\nexport { cachePlugin } from './plugins/cache.plugin.js';\r\n\r\n// Utilities\r\nexport {\r\n getFieldsForUser,\r\n getMongooseProjection,\r\n filterResponseData,\r\n createFieldPreset,\r\n} from './utils/field-selection.js';\r\n\r\nexport { createError } from './utils/error.js';\r\n\r\nexport { createMemoryCache } from './utils/memory-cache.js';\r\n\r\n// Actions (for advanced use cases)\r\nexport * as actions from './actions/index.js';\r\n\r\n// Types\r\nexport type {\r\n // Core types\r\n ObjectId,\r\n AnyDocument,\r\n AnyModel,\r\n SortDirection,\r\n SortSpec,\r\n PopulateSpec,\r\n SelectSpec,\r\n \r\n // Pagination\r\n PaginationConfig,\r\n OffsetPaginationOptions,\r\n KeysetPaginationOptions,\r\n AggregatePaginationOptions,\r\n OffsetPaginationResult,\r\n KeysetPaginationResult,\r\n AggregatePaginationResult,\r\n PaginationResult,\r\n \r\n // Repository\r\n OperationOptions,\r\n CreateOptions,\r\n UpdateOptions,\r\n DeleteResult,\r\n UpdateManyResult,\r\n ValidationResult,\r\n UpdateWithValidationResult,\r\n \r\n // Context\r\n UserContext,\r\n RepositoryContext,\r\n \r\n // Plugins\r\n Plugin,\r\n PluginFunction,\r\n PluginType,\r\n RepositoryInstance,\r\n \r\n // Events\r\n RepositoryEvent,\r\n EventPayload,\r\n \r\n // Field Selection\r\n FieldPreset,\r\n \r\n // Query Parser\r\n ParsedQuery,\r\n \r\n // Schema Builder\r\n FieldRules,\r\n SchemaBuilderOptions,\r\n JsonSchema,\r\n CrudSchemas,\r\n \r\n // Cursor\r\n DecodedCursor,\r\n \r\n // Validators\r\n ValidatorDefinition,\r\n ValidationChainOptions,\r\n \r\n // Logger\r\n Logger,\r\n \r\n // Soft Delete\r\n SoftDeleteOptions,\r\n \r\n // Aggregates\r\n LookupOptions,\r\n GroupResult,\r\n MinMaxResult,\r\n \r\n // Cache\r\n CacheAdapter,\r\n CacheOptions,\r\n CacheOperationOptions,\r\n CacheStats,\r\n \r\n // Error\r\n HttpError,\r\n} from './types.js';\r\n\r\n// Re-export Repository as default\r\nimport { Repository } from './Repository.js';\r\n\r\n/**\r\n * Factory function to create a repository instance\r\n * \r\n * @param Model - Mongoose model\r\n * @param plugins - Array of plugins to apply\r\n * @returns Repository instance\r\n * \r\n * @example\r\n * const userRepo = createRepository(UserModel, [timestampPlugin()]);\r\n */\r\nexport function createRepository<TDoc>(\r\n Model: import('mongoose').Model<TDoc>,\r\n plugins: import('./types.js').PluginType[] = []\r\n): Repository<TDoc> {\r\n return new Repository(Model, plugins);\r\n}\r\n\r\nexport default Repository;\r\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pagination/utils/cursor.ts","../../src/pagination/utils/sort.ts","../../src/pagination/utils/filter.ts","../../src/pagination/utils/limits.ts","../../src/utils/error.ts","../../src/pagination/PaginationEngine.ts"],"names":[],"mappings":"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","file":"PaginationEngine.js","sourcesContent":["/**\r\n * Cursor Utilities\r\n * \r\n * Encoding and decoding of cursor tokens for keyset pagination.\r\n * Cursors are base64-encoded JSON containing position data and metadata.\r\n */\r\n\r\nimport mongoose from 'mongoose';\r\nimport type { SortSpec, DecodedCursor, ObjectId, CursorPayload, ValueType } from '../../types.js';\r\n\r\n/**\r\n * Encodes document values and sort metadata into a base64 cursor token\r\n *\r\n * @param doc - Document to extract cursor values from\r\n * @param primaryField - Primary sort field name\r\n * @param sort - Normalized sort specification\r\n * @param version - Cursor version for forward compatibility\r\n * @returns Base64-encoded cursor token\r\n */\r\nexport function encodeCursor(\r\n doc: Record<string, unknown>,\r\n primaryField: string,\r\n sort: SortSpec,\r\n version: number = 1\r\n): string {\r\n const primaryValue = doc[primaryField];\r\n const idValue = doc._id;\r\n\r\n const payload: CursorPayload = {\r\n v: serializeValue(primaryValue),\r\n t: getValueType(primaryValue),\r\n id: serializeValue(idValue) as string,\r\n idType: getValueType(idValue),\r\n sort,\r\n ver: version,\r\n };\r\n\r\n return Buffer.from(JSON.stringify(payload)).toString('base64');\r\n}\r\n\r\n/**\r\n * Decodes a cursor token back into document values and sort metadata\r\n *\r\n * @param token - Base64-encoded cursor token\r\n * @returns Decoded cursor data\r\n * @throws Error if token is invalid or malformed\r\n */\r\nexport function decodeCursor(token: string): DecodedCursor {\r\n try {\r\n const json = Buffer.from(token, 'base64').toString('utf-8');\r\n const payload = JSON.parse(json) as CursorPayload;\r\n\r\n return {\r\n value: rehydrateValue(payload.v, payload.t),\r\n id: rehydrateValue(payload.id, payload.idType) as ObjectId | string,\r\n sort: payload.sort,\r\n version: payload.ver,\r\n };\r\n } catch {\r\n throw new Error('Invalid cursor token');\r\n }\r\n}\r\n\r\n/**\r\n * Validates that cursor sort matches current query sort\r\n *\r\n * @param cursorSort - Sort specification from cursor\r\n * @param currentSort - Sort specification from query\r\n * @throws Error if sorts don't match\r\n */\r\nexport function validateCursorSort(cursorSort: SortSpec, currentSort: SortSpec): void {\r\n const cursorSortStr = JSON.stringify(cursorSort);\r\n const currentSortStr = JSON.stringify(currentSort);\r\n\r\n if (cursorSortStr !== currentSortStr) {\r\n throw new Error('Cursor sort does not match current query sort');\r\n }\r\n}\r\n\r\n/**\r\n * Validates cursor version matches expected version\r\n *\r\n * @param cursorVersion - Version from cursor\r\n * @param expectedVersion - Expected version from config\r\n * @throws Error if versions don't match\r\n */\r\nexport function validateCursorVersion(cursorVersion: number, expectedVersion: number): void {\r\n if (cursorVersion !== expectedVersion) {\r\n throw new Error(`Cursor version ${cursorVersion} does not match expected version ${expectedVersion}`);\r\n }\r\n}\r\n\r\n/**\r\n * Serializes a value for cursor storage\r\n */\r\nfunction serializeValue(value: unknown): string | number | boolean {\r\n if (value instanceof Date) return value.toISOString();\r\n if (value instanceof mongoose.Types.ObjectId) return value.toString();\r\n return value as string | number | boolean;\r\n}\r\n\r\n/**\r\n * Gets the type identifier for a value\r\n */\r\nfunction getValueType(value: unknown): ValueType {\r\n if (value instanceof Date) return 'date';\r\n if (value instanceof mongoose.Types.ObjectId) return 'objectid';\r\n if (typeof value === 'boolean') return 'boolean';\r\n if (typeof value === 'number') return 'number';\r\n if (typeof value === 'string') return 'string';\r\n return 'unknown';\r\n}\r\n\r\n/**\r\n * Rehydrates a serialized value back to its original type\r\n */\r\nfunction rehydrateValue(serialized: unknown, type: ValueType): unknown {\r\n switch (type) {\r\n case 'date':\r\n return new Date(serialized as string);\r\n case 'objectid':\r\n return new mongoose.Types.ObjectId(serialized as string);\r\n case 'boolean':\r\n return Boolean(serialized);\r\n case 'number':\r\n return Number(serialized);\r\n default:\r\n return serialized;\r\n }\r\n}\r\n","/**\r\n * Sort Utilities\r\n * \r\n * Normalization and validation of sort specifications for pagination.\r\n */\r\n\r\nimport type { SortSpec, SortDirection } from '../../types.js';\r\n\r\n/**\r\n * Normalizes sort object to ensure stable key order\r\n * Primary fields first, _id last (not alphabetical)\r\n *\r\n * @param sort - Sort specification\r\n * @returns Normalized sort with stable key order\r\n */\r\nexport function normalizeSort(sort: SortSpec): SortSpec {\r\n const normalized: SortSpec = {};\r\n\r\n Object.keys(sort).forEach(key => {\r\n if (key !== '_id') normalized[key] = sort[key];\r\n });\r\n\r\n if (sort._id !== undefined) {\r\n normalized._id = sort._id;\r\n }\r\n\r\n return normalized;\r\n}\r\n\r\n/**\r\n * Validates and normalizes sort for keyset pagination\r\n * Auto-adds _id tie-breaker if needed\r\n * Ensures _id direction matches primary field\r\n *\r\n * @param sort - Sort specification\r\n * @returns Validated and normalized sort\r\n * @throws Error if sort is invalid for keyset pagination\r\n */\r\nexport function validateKeysetSort(sort: SortSpec): SortSpec {\r\n const keys = Object.keys(sort);\r\n\r\n if (keys.length === 1 && keys[0] !== '_id') {\r\n const field = keys[0];\r\n const direction = sort[field];\r\n return normalizeSort({ [field]: direction, _id: direction });\r\n }\r\n\r\n if (keys.length === 1 && keys[0] === '_id') {\r\n return normalizeSort(sort);\r\n }\r\n\r\n if (keys.length === 2) {\r\n if (!keys.includes('_id')) {\r\n throw new Error('Keyset pagination requires _id as tie-breaker');\r\n }\r\n\r\n const primaryField = keys.find(k => k !== '_id')!;\r\n const primaryDirection = sort[primaryField];\r\n const idDirection = sort._id;\r\n\r\n if (primaryDirection !== idDirection) {\r\n throw new Error('_id direction must match primary field direction');\r\n }\r\n\r\n return normalizeSort(sort);\r\n }\r\n\r\n throw new Error('Keyset pagination only supports single field + _id');\r\n}\r\n\r\n/**\r\n * Inverts sort directions (1 becomes -1, -1 becomes 1)\r\n *\r\n * @param sort - Sort specification\r\n * @returns Inverted sort\r\n */\r\nexport function invertSort(sort: SortSpec): SortSpec {\r\n const inverted: SortSpec = {};\r\n\r\n Object.keys(sort).forEach(key => {\r\n inverted[key] = (sort[key] === 1 ? -1 : 1) as SortDirection;\r\n });\r\n\r\n return inverted;\r\n}\r\n\r\n/**\r\n * Extracts primary sort field (first non-_id field)\r\n *\r\n * @param sort - Sort specification\r\n * @returns Primary field name\r\n */\r\nexport function getPrimaryField(sort: SortSpec): string {\r\n const keys = Object.keys(sort);\r\n return keys.find(k => k !== '_id') || '_id';\r\n}\r\n\r\n/**\r\n * Gets sort direction for a specific field\r\n *\r\n * @param sort - Sort specification\r\n * @param field - Field name\r\n * @returns Sort direction\r\n */\r\nexport function getDirection(sort: SortSpec, field: string): SortDirection | undefined {\r\n return sort[field];\r\n}\r\n","/**\r\n * Filter Utilities\r\n * \r\n * Build MongoDB filters for keyset pagination with proper cursor positioning.\r\n */\r\n\r\nimport type { SortSpec, FilterQuery, AnyDocument, ObjectId } from '../../types.js';\r\n\r\n/**\r\n * Builds MongoDB filter for keyset pagination\r\n * Creates compound $or condition for proper cursor-based filtering\r\n *\r\n * @param baseFilters - Existing query filters\r\n * @param sort - Normalized sort specification\r\n * @param cursorValue - Primary field value from cursor\r\n * @param cursorId - _id value from cursor\r\n * @returns MongoDB filter with keyset condition\r\n *\r\n * @example\r\n * buildKeysetFilter(\r\n * { status: 'active' },\r\n * { createdAt: -1, _id: -1 },\r\n * new Date('2024-01-01'),\r\n * new ObjectId('...')\r\n * )\r\n * // Returns:\r\n * // {\r\n * // status: 'active',\r\n * // $or: [\r\n * // { createdAt: { $lt: Date('2024-01-01') } },\r\n * // { createdAt: Date('2024-01-01'), _id: { $lt: ObjectId('...') } }\r\n * // ]\r\n * // }\r\n */\r\nexport function buildKeysetFilter(\r\n baseFilters: FilterQuery<AnyDocument>,\r\n sort: SortSpec,\r\n cursorValue: unknown,\r\n cursorId: ObjectId | string\r\n): FilterQuery<AnyDocument> {\r\n const primaryField = Object.keys(sort).find(k => k !== '_id') || '_id';\r\n const direction = sort[primaryField];\r\n const operator = direction === 1 ? '$gt' : '$lt';\r\n\r\n return {\r\n ...baseFilters,\r\n $or: [\r\n { [primaryField]: { [operator]: cursorValue } },\r\n {\r\n [primaryField]: cursorValue,\r\n _id: { [operator]: cursorId },\r\n },\r\n ],\r\n } as FilterQuery<AnyDocument>;\r\n}\r\n","/**\r\n * Limit Utilities\r\n * \r\n * Validation and calculation helpers for pagination limits and pages.\r\n */\r\n\r\nimport type { PaginationConfig } from '../../types.js';\r\n\r\n/**\r\n * Validates and sanitizes limit value\r\n * Parses strings to numbers and prevents NaN bugs\r\n *\r\n * @param limit - Requested limit\r\n * @param config - Pagination configuration\r\n * @returns Sanitized limit between 1 and maxLimit\r\n */\r\nexport function validateLimit(limit: number | string, config: PaginationConfig): number {\r\n const parsed = Number(limit);\r\n\r\n if (!Number.isFinite(parsed) || parsed < 1) {\r\n return config.defaultLimit || 10;\r\n }\r\n\r\n return Math.min(Math.floor(parsed), config.maxLimit || 100);\r\n}\r\n\r\n/**\r\n * Validates and sanitizes page number\r\n * Parses strings to numbers and prevents NaN bugs\r\n *\r\n * @param page - Requested page (1-indexed)\r\n * @param config - Pagination configuration\r\n * @returns Sanitized page number >= 1\r\n * @throws Error if page exceeds maxPage\r\n */\r\nexport function validatePage(page: number | string, config: PaginationConfig): number {\r\n const parsed = Number(page);\r\n\r\n if (!Number.isFinite(parsed) || parsed < 1) {\r\n return 1;\r\n }\r\n\r\n const sanitized = Math.floor(parsed);\r\n\r\n if (sanitized > (config.maxPage || 10000)) {\r\n throw new Error(`Page ${sanitized} exceeds maximum ${config.maxPage || 10000}`);\r\n }\r\n\r\n return sanitized;\r\n}\r\n\r\n/**\r\n * Checks if page number should trigger deep pagination warning\r\n *\r\n * @param page - Current page number\r\n * @param threshold - Warning threshold\r\n * @returns True if warning should be shown\r\n */\r\nexport function shouldWarnDeepPagination(page: number, threshold: number): boolean {\r\n return page > threshold;\r\n}\r\n\r\n/**\r\n * Calculates number of documents to skip for offset pagination\r\n *\r\n * @param page - Page number (1-indexed)\r\n * @param limit - Documents per page\r\n * @returns Number of documents to skip\r\n */\r\nexport function calculateSkip(page: number, limit: number): number {\r\n return (page - 1) * limit;\r\n}\r\n\r\n/**\r\n * Calculates total number of pages\r\n *\r\n * @param total - Total document count\r\n * @param limit - Documents per page\r\n * @returns Total number of pages\r\n */\r\nexport function calculateTotalPages(total: number, limit: number): number {\r\n return Math.ceil(total / limit);\r\n}\r\n","/**\r\n * Error Utilities\r\n * \r\n * HTTP-compatible error creation for repository operations\r\n */\r\n\r\nimport type { HttpError } from '../types.js';\r\n\r\n/**\r\n * Creates an error with HTTP status code\r\n *\r\n * @param status - HTTP status code\r\n * @param message - Error message\r\n * @returns Error with status property\r\n * \r\n * @example\r\n * throw createError(404, 'Document not found');\r\n * throw createError(400, 'Invalid input');\r\n * throw createError(403, 'Access denied');\r\n */\r\nexport function createError(status: number, message: string): HttpError {\r\n const error = new Error(message) as HttpError;\r\n error.status = status;\r\n return error;\r\n}\r\n","/**\r\n * Pagination Engine\r\n * \r\n * Production-grade pagination for MongoDB with support for:\r\n * - Offset pagination (page-based) - Best for small datasets, random page access\r\n * - Keyset pagination (cursor-based) - Best for large datasets, infinite scroll\r\n * - Aggregate pagination - Best for complex queries requiring aggregation\r\n * \r\n * @example\r\n * ```typescript\r\n * const engine = new PaginationEngine(UserModel, {\r\n * defaultLimit: 20,\r\n * maxLimit: 100,\r\n * useEstimatedCount: true\r\n * });\r\n *\r\n * // Offset pagination\r\n * const page1 = await engine.paginate({ page: 1, limit: 20 });\r\n *\r\n * // Keyset pagination (better for large datasets)\r\n * const stream1 = await engine.stream({ sort: { createdAt: -1 }, limit: 20 });\r\n * const stream2 = await engine.stream({ sort: { createdAt: -1 }, after: stream1.next });\r\n * ```\r\n */\r\n\r\nimport type { Model } from 'mongoose';\r\nimport { encodeCursor, decodeCursor, validateCursorSort, validateCursorVersion } from './utils/cursor.js';\r\nimport { validateKeysetSort, getPrimaryField } from './utils/sort.js';\r\nimport { buildKeysetFilter } from './utils/filter.js';\r\nimport {\r\n validateLimit,\r\n validatePage,\r\n shouldWarnDeepPagination,\r\n calculateSkip,\r\n calculateTotalPages,\r\n} from './utils/limits.js';\r\nimport { createError } from '../utils/error.js';\r\nimport type {\r\n PaginationConfig,\r\n OffsetPaginationOptions,\r\n KeysetPaginationOptions,\r\n AggregatePaginationOptions,\r\n OffsetPaginationResult,\r\n KeysetPaginationResult,\r\n AggregatePaginationResult,\r\n AnyDocument,\r\n} from '../types.js';\r\n\r\n/**\r\n * Internal pagination config with required values\r\n */\r\ninterface ResolvedPaginationConfig {\r\n defaultLimit: number;\r\n maxLimit: number;\r\n maxPage: number;\r\n deepPageThreshold: number;\r\n cursorVersion: number;\r\n useEstimatedCount: boolean;\r\n}\r\n\r\n/**\r\n * Production-grade pagination engine for MongoDB\r\n * Supports offset, keyset (cursor), and aggregate pagination\r\n */\r\nexport class PaginationEngine<TDoc = AnyDocument> {\r\n public readonly Model: Model<TDoc>;\r\n public readonly config: ResolvedPaginationConfig;\r\n\r\n /**\r\n * Create a new pagination engine\r\n *\r\n * @param Model - Mongoose model to paginate\r\n * @param config - Pagination configuration\r\n */\r\n constructor(Model: Model<TDoc>, config: PaginationConfig = {}) {\r\n this.Model = Model;\r\n this.config = {\r\n defaultLimit: config.defaultLimit || 10,\r\n maxLimit: config.maxLimit || 100,\r\n maxPage: config.maxPage || 10000,\r\n deepPageThreshold: config.deepPageThreshold || 100,\r\n cursorVersion: config.cursorVersion || 1,\r\n useEstimatedCount: config.useEstimatedCount || false,\r\n };\r\n }\r\n\r\n /**\r\n * Offset-based pagination using skip/limit\r\n * Best for small datasets and when users need random page access\r\n * O(n) performance - slower for deep pages\r\n *\r\n * @param options - Pagination options\r\n * @returns Pagination result with total count\r\n *\r\n * @example\r\n * const result = await engine.paginate({\r\n * filters: { status: 'active' },\r\n * sort: { createdAt: -1 },\r\n * page: 1,\r\n * limit: 20\r\n * });\r\n * console.log(result.docs, result.total, result.hasNext);\r\n */\r\n async paginate(options: OffsetPaginationOptions = {}): Promise<OffsetPaginationResult<TDoc>> {\r\n const {\r\n filters = {},\r\n sort = { _id: -1 },\r\n page = 1,\r\n limit = this.config.defaultLimit,\r\n select,\r\n populate = [],\r\n lean = true,\r\n session,\r\n } = options;\r\n\r\n const sanitizedPage = validatePage(page, this.config);\r\n const sanitizedLimit = validateLimit(limit, this.config);\r\n const skip = calculateSkip(sanitizedPage, sanitizedLimit);\r\n\r\n let query = this.Model.find(filters as Record<string, unknown>);\r\n if (select) query = query.select(select);\r\n if (populate && (Array.isArray(populate) ? populate.length : populate)) {\r\n query = query.populate(populate as string | string[]);\r\n }\r\n query = query.sort(sort).skip(skip).limit(sanitizedLimit).lean(lean);\r\n if (session) query = query.session(session);\r\n\r\n const hasFilters = Object.keys(filters).length > 0;\r\n const useEstimated = this.config.useEstimatedCount && !hasFilters;\r\n\r\n // Note: estimatedDocumentCount() doesn't support sessions or filters\r\n // It reads collection metadata (O(1) instant), not actual documents\r\n // Falls back to countDocuments() when filters are present\r\n const [docs, total] = await Promise.all([\r\n query.exec(),\r\n useEstimated\r\n ? this.Model.estimatedDocumentCount()\r\n : this.Model.countDocuments(filters as Record<string, unknown>).session(session ?? null),\r\n ]);\r\n\r\n const totalPages = calculateTotalPages(total, sanitizedLimit);\r\n const warning = shouldWarnDeepPagination(sanitizedPage, this.config.deepPageThreshold)\r\n ? `Deep pagination (page ${sanitizedPage}). Consider getAll({ after, sort, limit }) for better performance.`\r\n : undefined;\r\n\r\n return {\r\n method: 'offset',\r\n docs: docs as TDoc[],\r\n page: sanitizedPage,\r\n limit: sanitizedLimit,\r\n total,\r\n pages: totalPages,\r\n hasNext: sanitizedPage < totalPages,\r\n hasPrev: sanitizedPage > 1,\r\n ...(warning && { warning }),\r\n };\r\n }\r\n\r\n /**\r\n * Keyset (cursor-based) pagination for high-performance streaming\r\n * Best for large datasets, infinite scroll, real-time feeds\r\n * O(1) performance - consistent speed regardless of position\r\n *\r\n * @param options - Pagination options (sort is required)\r\n * @returns Pagination result with next cursor\r\n *\r\n * @example\r\n * // First page\r\n * const page1 = await engine.stream({\r\n * sort: { createdAt: -1 },\r\n * limit: 20\r\n * });\r\n *\r\n * // Next page using cursor\r\n * const page2 = await engine.stream({\r\n * sort: { createdAt: -1 },\r\n * after: page1.next,\r\n * limit: 20\r\n * });\r\n */\r\n async stream(options: KeysetPaginationOptions): Promise<KeysetPaginationResult<TDoc>> {\r\n const {\r\n filters = {},\r\n sort,\r\n after,\r\n limit = this.config.defaultLimit,\r\n select,\r\n populate = [],\r\n lean = true,\r\n session,\r\n } = options;\r\n\r\n if (!sort) {\r\n throw createError(400, 'sort is required for keyset pagination');\r\n }\r\n\r\n const sanitizedLimit = validateLimit(limit, this.config);\r\n const normalizedSort = validateKeysetSort(sort);\r\n\r\n let query: Record<string, unknown> = { ...filters };\r\n\r\n if (after) {\r\n const cursor = decodeCursor(after);\r\n validateCursorVersion(cursor.version, this.config.cursorVersion);\r\n validateCursorSort(cursor.sort, normalizedSort);\r\n query = buildKeysetFilter(query, normalizedSort, cursor.value, cursor.id);\r\n }\r\n\r\n let mongoQuery = this.Model.find(query);\r\n if (select) mongoQuery = mongoQuery.select(select);\r\n if (populate && (Array.isArray(populate) ? populate.length : populate)) {\r\n mongoQuery = mongoQuery.populate(populate as string | string[]);\r\n }\r\n mongoQuery = mongoQuery.sort(normalizedSort).limit(sanitizedLimit + 1).lean(lean);\r\n if (session) mongoQuery = mongoQuery.session(session);\r\n\r\n const docs = await mongoQuery.exec() as (TDoc & Record<string, unknown>)[];\r\n\r\n const hasMore = docs.length > sanitizedLimit;\r\n if (hasMore) docs.pop();\r\n\r\n const primaryField = getPrimaryField(normalizedSort);\r\n const nextCursor = hasMore && docs.length > 0\r\n ? encodeCursor(docs[docs.length - 1], primaryField, normalizedSort, this.config.cursorVersion)\r\n : null;\r\n\r\n return {\r\n method: 'keyset',\r\n docs,\r\n limit: sanitizedLimit,\r\n hasMore,\r\n next: nextCursor,\r\n };\r\n }\r\n\r\n /**\r\n * Aggregate pipeline with pagination\r\n * Best for complex queries requiring aggregation stages\r\n * Uses $facet to combine results and count in single query\r\n *\r\n * @param options - Aggregation options\r\n * @returns Pagination result with total count\r\n *\r\n * @example\r\n * const result = await engine.aggregatePaginate({\r\n * pipeline: [\r\n * { $match: { status: 'active' } },\r\n * { $group: { _id: '$category', count: { $sum: 1 } } },\r\n * { $sort: { count: -1 } }\r\n * ],\r\n * page: 1,\r\n * limit: 20\r\n * });\r\n */\r\n async aggregatePaginate(options: AggregatePaginationOptions = {}): Promise<AggregatePaginationResult<TDoc>> {\r\n const {\r\n pipeline = [],\r\n page = 1,\r\n limit = this.config.defaultLimit,\r\n session,\r\n } = options;\r\n\r\n const sanitizedPage = validatePage(page, this.config);\r\n const sanitizedLimit = validateLimit(limit, this.config);\r\n const skip = calculateSkip(sanitizedPage, sanitizedLimit);\r\n\r\n const facetPipeline = [\r\n ...pipeline,\r\n {\r\n $facet: {\r\n docs: [{ $skip: skip }, { $limit: sanitizedLimit }],\r\n total: [{ $count: 'count' }],\r\n },\r\n },\r\n ];\r\n\r\n const aggregation = this.Model.aggregate(facetPipeline);\r\n if (session) aggregation.session(session);\r\n\r\n const [result] = await aggregation.exec() as [{ docs: TDoc[]; total: { count: number }[] }];\r\n const docs = result.docs;\r\n const total = result.total[0]?.count || 0;\r\n const totalPages = calculateTotalPages(total, sanitizedLimit);\r\n\r\n const warning = shouldWarnDeepPagination(sanitizedPage, this.config.deepPageThreshold)\r\n ? `Deep pagination in aggregate (page ${sanitizedPage}). Uses $skip internally.`\r\n : undefined;\r\n\r\n return {\r\n method: 'aggregate',\r\n docs,\r\n page: sanitizedPage,\r\n limit: sanitizedLimit,\r\n total,\r\n pages: totalPages,\r\n hasNext: sanitizedPage < totalPages,\r\n hasPrev: sanitizedPage > 1,\r\n ...(warning && { warning }),\r\n };\r\n }\r\n}\r\n"]}
|