@classytic/mongokit 1.0.2 → 2.1.0
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 +772 -151
- package/dist/actions/index.cjs +479 -0
- package/dist/actions/index.cjs.map +1 -0
- package/dist/actions/index.d.cts +3 -0
- package/dist/actions/index.d.ts +3 -0
- package/dist/actions/index.js +473 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/index-BfVJZF-3.d.cts +337 -0
- package/dist/index-CgOJ2pqz.d.ts +337 -0
- package/dist/index.cjs +2142 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +239 -0
- package/dist/index.d.ts +239 -0
- package/dist/index.js +2108 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-cache-DG2oSSbx.d.ts +142 -0
- package/dist/memory-cache-DqfFfKes.d.cts +142 -0
- package/dist/pagination/PaginationEngine.cjs +375 -0
- package/dist/pagination/PaginationEngine.cjs.map +1 -0
- package/dist/pagination/PaginationEngine.d.cts +117 -0
- package/dist/pagination/PaginationEngine.d.ts +117 -0
- package/dist/pagination/PaginationEngine.js +369 -0
- package/dist/pagination/PaginationEngine.js.map +1 -0
- package/dist/plugins/index.cjs +874 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.cts +275 -0
- package/dist/plugins/index.d.ts +275 -0
- package/dist/plugins/index.js +857 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/types-Nxhmi1aI.d.cts +510 -0
- package/dist/types-Nxhmi1aI.d.ts +510 -0
- package/dist/utils/index.cjs +667 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +189 -0
- package/dist/utils/index.d.ts +189 -0
- package/dist/utils/index.js +643 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +54 -24
- package/src/Repository.js +0 -225
- package/src/actions/aggregate.js +0 -191
- package/src/actions/create.js +0 -59
- package/src/actions/delete.js +0 -88
- package/src/actions/index.js +0 -11
- package/src/actions/read.js +0 -156
- package/src/actions/update.js +0 -176
- package/src/hooks/lifecycle.js +0 -146
- package/src/index.js +0 -60
- package/src/plugins/aggregate-helpers.plugin.js +0 -71
- package/src/plugins/audit-log.plugin.js +0 -60
- package/src/plugins/batch-operations.plugin.js +0 -66
- package/src/plugins/field-filter.plugin.js +0 -27
- package/src/plugins/index.js +0 -19
- package/src/plugins/method-registry.plugin.js +0 -140
- package/src/plugins/mongo-operations.plugin.js +0 -313
- package/src/plugins/soft-delete.plugin.js +0 -46
- package/src/plugins/subdocument.plugin.js +0 -66
- package/src/plugins/timestamp.plugin.js +0 -19
- package/src/plugins/validation-chain.plugin.js +0 -145
- package/src/utils/field-selection.js +0 -156
- package/src/utils/index.js +0 -12
- package/types/actions/index.d.ts +0 -121
- package/types/index.d.ts +0 -104
- package/types/plugins/index.d.ts +0 -88
- package/types/utils/index.d.ts +0 -24
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/field-selection.ts","../../src/utils/queryParser.ts","../../src/utils/mongooseToJsonSchema.ts","../../src/utils/error.ts","../../src/utils/memory-cache.ts","../../src/utils/cache-keys.ts"],"names":["mongoose"],"mappings":"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","file":"index.js","sourcesContent":["/**\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 * Query Parser\r\n * \r\n * Parses HTTP query parameters into MongoDB-compatible query objects.\r\n * Supports operators, pagination, sorting, and filtering.\r\n */\r\n\r\nimport mongoose from 'mongoose';\r\nimport type { ParsedQuery, SortSpec, FilterQuery, AnyDocument } from '../types.js';\r\n\r\ntype OperatorMap = Record<string, string>;\r\ntype FilterValue = string | number | boolean | null | undefined | Record<string, unknown> | unknown[];\r\n\r\nclass QueryParser {\r\n private operators: OperatorMap = {\r\n eq: '$eq',\r\n ne: '$ne',\r\n gt: '$gt',\r\n gte: '$gte',\r\n lt: '$lt',\r\n lte: '$lte',\r\n in: '$in',\r\n nin: '$nin',\r\n like: '$regex',\r\n contains: '$regex',\r\n regex: '$regex',\r\n exists: '$exists',\r\n size: '$size',\r\n type: '$type',\r\n };\r\n\r\n /**\r\n * Dangerous MongoDB operators that should never be accepted from user input\r\n * Security: Prevent NoSQL injection attacks\r\n */\r\n private dangerousOperators = ['$where', '$function', '$accumulator', '$expr'];\r\n\r\n /**\r\n * Parse query parameters into MongoDB query format\r\n */\r\n parseQuery(query: Record<string, unknown> | null | undefined): ParsedQuery {\r\n const {\r\n page,\r\n limit = 20,\r\n sort = '-createdAt',\r\n populate,\r\n search,\r\n after,\r\n cursor,\r\n ...filters\r\n } = query || {};\r\n\r\n // Build base parsed object\r\n const parsed: ParsedQuery = {\r\n filters: this._parseFilters(filters as Record<string, FilterValue>),\r\n limit: parseInt(String(limit), 10),\r\n sort: this._parseSort(sort as string | SortSpec | undefined),\r\n populate: populate as string | undefined,\r\n search: search as string | undefined,\r\n };\r\n\r\n // MongoKit pagination mode detection:\r\n // 1. If 'page' is provided → offset mode\r\n // 2. If 'after' or 'cursor' is provided → keyset mode\r\n // 3. If neither, default to offset mode (page 1)\r\n\r\n if (after || cursor) {\r\n // Keyset (cursor-based) pagination\r\n parsed.after = (after || cursor) as string;\r\n } else if (page !== undefined) {\r\n // Offset (page-based) pagination\r\n parsed.page = parseInt(String(page), 10);\r\n } else {\r\n // Default to offset mode, page 1\r\n parsed.page = 1;\r\n }\r\n\r\n const orGroup = this._parseOr(query);\r\n if (orGroup) {\r\n parsed.filters = { ...parsed.filters, $or: orGroup } as FilterQuery<AnyDocument>;\r\n }\r\n\r\n parsed.filters = this._enhanceWithBetween(parsed.filters);\r\n\r\n return parsed;\r\n }\r\n\r\n /**\r\n * Parse sort parameter\r\n * Converts string like '-createdAt' to { createdAt: -1 }\r\n * Handles multiple sorts: '-createdAt,name' → { createdAt: -1, name: 1 }\r\n */\r\n private _parseSort(sort: string | SortSpec | undefined): SortSpec | undefined {\r\n if (!sort) return undefined;\r\n if (typeof sort === 'object') return sort;\r\n\r\n const sortObj: SortSpec = {};\r\n const fields = sort.split(',').map(s => s.trim());\r\n\r\n for (const field of fields) {\r\n if (field.startsWith('-')) {\r\n sortObj[field.substring(1)] = -1;\r\n } else {\r\n sortObj[field] = 1;\r\n }\r\n }\r\n\r\n return sortObj;\r\n }\r\n\r\n /**\r\n * Parse standard filter parameter (filter[field]=value)\r\n */\r\n private _parseFilters(filters: Record<string, FilterValue>): FilterQuery<AnyDocument> {\r\n const parsedFilters: Record<string, unknown> = {};\r\n\r\n for (const [key, value] of Object.entries(filters)) {\r\n // SECURITY: Block dangerous MongoDB operators\r\n if (this.dangerousOperators.includes(key) || (key.startsWith('$') && !['$or', '$and'].includes(key))) {\r\n console.warn(`[mongokit] Blocked dangerous operator: ${key}`);\r\n continue;\r\n }\r\n\r\n // Skip non-filter parameters that are handled separately\r\n if (['page', 'limit', 'sort', 'populate', 'search', 'select', 'lean', 'includeDeleted'].includes(key)) {\r\n continue;\r\n }\r\n\r\n // Handle bracket syntax both shapes:\r\n // 1) field[operator]=value (Express default keeps key as string)\r\n const operatorMatch = key.match(/^(.+)\\[(.+)\\]$/);\r\n if (operatorMatch) {\r\n const [, , operator] = operatorMatch;\r\n // Block dangerous operators in bracket syntax\r\n if (this.dangerousOperators.includes('$' + operator)) {\r\n console.warn(`[mongokit] Blocked dangerous operator: ${operator}`);\r\n continue;\r\n }\r\n this._handleOperatorSyntax(parsedFilters, {}, operatorMatch, value);\r\n continue;\r\n }\r\n\r\n // 2) field[operator]=value parsed as object (qs or similar)\r\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\r\n this._handleBracketSyntax(key, value as Record<string, unknown>, parsedFilters);\r\n } else {\r\n // Handle direct field assignment (e.g., upc=123)\r\n parsedFilters[key] = this._convertValue(value);\r\n }\r\n }\r\n\r\n return parsedFilters as FilterQuery<AnyDocument>;\r\n }\r\n\r\n /**\r\n * Handle operator syntax: field[operator]=value\r\n */\r\n private _handleOperatorSyntax(\r\n filters: Record<string, unknown>,\r\n regexFields: Record<string, boolean>,\r\n operatorMatch: RegExpMatchArray,\r\n value: FilterValue\r\n ): void {\r\n const [, field, operator] = operatorMatch;\r\n\r\n // Handle regex options separately\r\n if (operator.toLowerCase() === 'options' && regexFields[field]) {\r\n const fieldValue = filters[field];\r\n if (typeof fieldValue === 'object' && fieldValue !== null && '$regex' in (fieldValue as Record<string, unknown>)) {\r\n (fieldValue as Record<string, unknown>).$options = value;\r\n }\r\n return;\r\n }\r\n\r\n // Handle like/contains - convert to $regex for MongoDB\r\n if (operator.toLowerCase() === 'contains' || operator.toLowerCase() === 'like') {\r\n filters[field] = { $regex: new RegExp(String(value), 'i') };\r\n regexFields[field] = true;\r\n return;\r\n }\r\n\r\n // Convert to MongoDB operator for standard operators\r\n const mongoOperator = this._toMongoOperator(operator);\r\n\r\n // SECURITY: Block dangerous MongoDB operators\r\n if (this.dangerousOperators.includes(mongoOperator)) {\r\n console.warn(`[mongokit] Blocked dangerous operator in field[${operator}]: ${mongoOperator}`);\r\n return;\r\n }\r\n\r\n if (mongoOperator === '$eq') {\r\n filters[field] = value; // Direct value for equality\r\n } else if (mongoOperator === '$regex') {\r\n filters[field] = { $regex: value };\r\n regexFields[field] = true;\r\n } else {\r\n // Handle other operators\r\n if (typeof filters[field] !== 'object' || filters[field] === null || Array.isArray(filters[field])) {\r\n filters[field] = {};\r\n }\r\n\r\n // Process value based on operator type\r\n let processedValue: unknown;\r\n const op = operator.toLowerCase();\r\n\r\n if (['gt', 'gte', 'lt', 'lte', 'size'].includes(op)) {\r\n // These operators require a numeric value\r\n processedValue = parseFloat(String(value));\r\n if (isNaN(processedValue as number)) return;\r\n } else if (op === 'in' || op === 'nin') {\r\n // These operators require an array\r\n processedValue = Array.isArray(value) ? value : String(value).split(',').map(v => v.trim());\r\n } else {\r\n // Default processing for other operators\r\n processedValue = this._convertValue(value);\r\n }\r\n\r\n (filters[field] as Record<string, unknown>)[mongoOperator] = processedValue;\r\n }\r\n }\r\n\r\n /**\r\n * Handle bracket syntax with object value\r\n */\r\n private _handleBracketSyntax(\r\n field: string,\r\n operators: Record<string, unknown>,\r\n parsedFilters: Record<string, unknown>\r\n ): void {\r\n if (!parsedFilters[field]) {\r\n parsedFilters[field] = {};\r\n }\r\n\r\n for (const [operator, value] of Object.entries(operators)) {\r\n // Special handling for 'between' operator (processed later in _enhanceWithBetween)\r\n if (operator === 'between') {\r\n (parsedFilters[field] as Record<string, unknown>).between = value;\r\n continue;\r\n }\r\n\r\n if (this.operators[operator]) {\r\n const mongoOperator = this.operators[operator];\r\n let processedValue: unknown;\r\n\r\n // Operator-specific value processing is crucial for correctness.\r\n if (['gt', 'gte', 'lt', 'lte', 'size'].includes(operator)) {\r\n // These operators require a numeric value.\r\n processedValue = parseFloat(String(value));\r\n if (isNaN(processedValue as number)) continue;\r\n } else if (operator === 'in' || operator === 'nin') {\r\n // These operators require an array.\r\n processedValue = Array.isArray(value) ? value : String(value).split(',').map(v => v.trim());\r\n } else if (operator === 'like' || operator === 'contains') {\r\n // These operators require a RegExp.\r\n processedValue = (value !== undefined && value !== null) ? new RegExp(String(value), 'i') : /.*/;\r\n } else {\r\n // Default processing for other operators like 'eq', 'ne'.\r\n processedValue = this._convertValue(value);\r\n }\r\n\r\n (parsedFilters[field] as Record<string, unknown>)[mongoOperator] = processedValue;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Convert operator to MongoDB format\r\n */\r\n private _toMongoOperator(operator: string): string {\r\n const op = operator.toLowerCase();\r\n return op.startsWith('$') ? op : '$' + op;\r\n }\r\n\r\n /**\r\n * Convert values based on operator type\r\n */\r\n private _convertValue(value: unknown): unknown {\r\n if (value === null || value === undefined) return value;\r\n if (Array.isArray(value)) return value.map(v => this._convertValue(v));\r\n if (typeof value === 'object') return value;\r\n\r\n const stringValue = String(value);\r\n\r\n // Only convert specific known values\r\n if (stringValue === 'true') return true;\r\n if (stringValue === 'false') return false;\r\n\r\n // Convert ObjectIds only if they are valid 24-character hex strings\r\n // Use string representation instead of ObjectId object to avoid serialization issues\r\n if (mongoose.Types.ObjectId.isValid(stringValue) && stringValue.length === 24) {\r\n return stringValue; // Return as string, let Mongoose handle the conversion\r\n }\r\n\r\n // Return as string - this preserves UPCs, styleIds, and other string fields\r\n return stringValue;\r\n }\r\n\r\n /**\r\n * Parse $or conditions\r\n */\r\n private _parseOr(query: Record<string, unknown> | null | undefined): Record<string, unknown>[] | undefined {\r\n const orArray: Record<string, unknown>[] = [];\r\n const raw = query?.or || query?.OR || query?.$or;\r\n if (!raw) return undefined;\r\n\r\n const items = Array.isArray(raw) ? raw : typeof raw === 'object' ? Object.values(raw as Record<string, unknown>) : [];\r\n for (const item of items) {\r\n if (typeof item === 'object' && item) {\r\n orArray.push(this._parseFilters(item as Record<string, FilterValue>));\r\n }\r\n }\r\n return orArray.length ? orArray : undefined;\r\n }\r\n\r\n /**\r\n * Enhance filters with between operator\r\n */\r\n private _enhanceWithBetween(filters: FilterQuery<AnyDocument>): FilterQuery<AnyDocument> {\r\n const output = { ...filters } as Record<string, unknown>;\r\n for (const [key, value] of Object.entries(filters || {})) {\r\n if (value && typeof value === 'object' && 'between' in (value as Record<string, unknown>)) {\r\n const between = (value as Record<string, unknown>).between as string;\r\n const [from, to] = String(between).split(',').map(s => s.trim());\r\n const fromDate = from ? new Date(from) : undefined;\r\n const toDate = to ? new Date(to) : undefined;\r\n const range: Record<string, Date> = {};\r\n if (fromDate && !isNaN(fromDate.getTime())) range.$gte = fromDate;\r\n if (toDate && !isNaN(toDate.getTime())) range.$lte = toDate;\r\n output[key] = range;\r\n }\r\n }\r\n return output as FilterQuery<AnyDocument>;\r\n }\r\n}\r\n\r\nexport default new QueryParser();\r\n","/**\r\n * Mongoose to JSON Schema Converter with Field Rules\r\n * \r\n * Generates Fastify JSON schemas from Mongoose models with declarative field rules.\r\n * \r\n * Field Rules (options.fieldRules):\r\n * - immutable: Field cannot be updated (omitted from update schema)\r\n * - immutableAfterCreate: Alias for immutable\r\n * - systemManaged: System-only field (omitted from create/update)\r\n * - optional: Remove from required array\r\n * \r\n * Additional Options:\r\n * - strictAdditionalProperties: Set to true to add \"additionalProperties: false\" to schemas\r\n * This makes Fastify reject unknown fields at validation level (default: false for backward compatibility)\r\n * \r\n * @example\r\n * buildCrudSchemasFromModel(Model, {\r\n * strictAdditionalProperties: true, // Reject unknown fields\r\n * fieldRules: {\r\n * organizationId: { immutable: true },\r\n * status: { systemManaged: true },\r\n * },\r\n * create: { omitFields: ['verifiedAt'] },\r\n * update: { omitFields: ['customerId'] }\r\n * })\r\n */\r\n\r\nimport mongoose, { Schema } from 'mongoose';\r\nimport type { SchemaBuilderOptions, JsonSchema, CrudSchemas, ValidationResult } from '../types.js';\r\n\r\nfunction isMongooseSchema(value: unknown): value is Schema {\r\n return value instanceof mongoose.Schema;\r\n}\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n return Object.prototype.toString.call(value) === '[object Object]';\r\n}\r\n\r\nfunction isObjectIdType(t: unknown): boolean {\r\n return t === mongoose.Schema.Types.ObjectId || t === mongoose.Types.ObjectId;\r\n}\r\n\r\n/**\r\n * Build CRUD schemas from Mongoose schema\r\n */\r\nexport function buildCrudSchemasFromMongooseSchema(\r\n mongooseSchema: Schema,\r\n options: SchemaBuilderOptions = {}\r\n): CrudSchemas {\r\n const tree = (mongooseSchema as Schema & { obj?: Record<string, unknown> })?.obj || {};\r\n\r\n // Always generate JSON schemas\r\n const jsonCreate = buildJsonSchemaForCreate(tree, options);\r\n const jsonUpdate = buildJsonSchemaForUpdate(jsonCreate, options);\r\n const jsonParams: JsonSchema = {\r\n type: 'object',\r\n properties: { id: { type: 'string', pattern: '^[0-9a-fA-F]{24}$' } },\r\n required: ['id'],\r\n };\r\n const jsonQuery = buildJsonSchemaForQuery(tree, options);\r\n\r\n const crudSchemas = {\r\n create: { body: jsonCreate },\r\n update: { body: jsonUpdate, params: jsonParams },\r\n get: { params: jsonParams },\r\n list: { query: jsonQuery },\r\n remove: { params: jsonParams },\r\n };\r\n\r\n return { createBody: jsonCreate, updateBody: jsonUpdate, params: jsonParams, listQuery: jsonQuery, crudSchemas };\r\n}\r\n\r\n/**\r\n * Build CRUD schemas from Mongoose model\r\n */\r\nexport function buildCrudSchemasFromModel(\r\n mongooseModel: mongoose.Model<unknown>,\r\n options: SchemaBuilderOptions = {}\r\n): CrudSchemas {\r\n if (!mongooseModel || !mongooseModel.schema) {\r\n throw new Error('Invalid mongoose model');\r\n }\r\n return buildCrudSchemasFromMongooseSchema(mongooseModel.schema, options);\r\n}\r\n\r\n/**\r\n * Get fields that are immutable (cannot be updated)\r\n */\r\nexport function getImmutableFields(options: SchemaBuilderOptions = {}): string[] {\r\n const immutable: string[] = [];\r\n const fieldRules = options?.fieldRules || {};\r\n\r\n Object.entries(fieldRules).forEach(([field, rules]) => {\r\n if (rules.immutable || rules.immutableAfterCreate) {\r\n immutable.push(field);\r\n }\r\n });\r\n\r\n // Add explicit update.omitFields\r\n (options?.update?.omitFields || []).forEach(f => {\r\n if (!immutable.includes(f)) immutable.push(f);\r\n });\r\n\r\n return immutable;\r\n}\r\n\r\n/**\r\n * Get fields that are system-managed (cannot be set by users)\r\n */\r\nexport function getSystemManagedFields(options: SchemaBuilderOptions = {}): string[] {\r\n const systemManaged: string[] = [];\r\n const fieldRules = options?.fieldRules || {};\r\n\r\n Object.entries(fieldRules).forEach(([field, rules]) => {\r\n if (rules.systemManaged) {\r\n systemManaged.push(field);\r\n }\r\n });\r\n\r\n return systemManaged;\r\n}\r\n\r\n/**\r\n * Check if field is allowed in update\r\n */\r\nexport function isFieldUpdateAllowed(fieldName: string, options: SchemaBuilderOptions = {}): boolean {\r\n const immutableFields = getImmutableFields(options);\r\n const systemManagedFields = getSystemManagedFields(options);\r\n\r\n return !immutableFields.includes(fieldName) && !systemManagedFields.includes(fieldName);\r\n}\r\n\r\n/**\r\n * Validate update body against field rules\r\n */\r\nexport function validateUpdateBody(\r\n body: Record<string, unknown> = {},\r\n options: SchemaBuilderOptions = {}\r\n): ValidationResult {\r\n const violations: ValidationResult['violations'] = [];\r\n const immutableFields = getImmutableFields(options);\r\n const systemManagedFields = getSystemManagedFields(options);\r\n\r\n Object.keys(body).forEach(field => {\r\n if (immutableFields.includes(field)) {\r\n violations.push({ field, reason: 'Field is immutable' });\r\n } else if (systemManagedFields.includes(field)) {\r\n violations.push({ field, reason: 'Field is system-managed' });\r\n }\r\n });\r\n\r\n return {\r\n valid: violations.length === 0,\r\n violations,\r\n };\r\n}\r\n\r\n// ==== JSON Schema helpers ====\r\n\r\nfunction jsonTypeFor(\r\n def: unknown,\r\n options: SchemaBuilderOptions,\r\n seen: WeakSet<object>\r\n): Record<string, unknown> {\r\n if (Array.isArray(def)) {\r\n // Check if it's an array of Mixed\r\n if (def[0] === mongoose.Schema.Types.Mixed) {\r\n return { type: 'array', items: { type: 'object', additionalProperties: true } };\r\n }\r\n return { type: 'array', items: jsonTypeFor(def[0] ?? String, options, seen) };\r\n }\r\n\r\n if (isPlainObject(def) && 'type' in def) {\r\n const typedDef = def as Record<string, unknown>;\r\n \r\n if (typedDef.enum && Array.isArray(typedDef.enum) && typedDef.enum.length) {\r\n return { type: 'string', enum: (typedDef.enum as unknown[]).map(String) };\r\n }\r\n \r\n // Array typed via { type: [X] }\r\n if (Array.isArray(typedDef.type)) {\r\n const inner = typedDef.type[0] !== undefined ? typedDef.type[0] : String;\r\n // Check if it's an array of Mixed\r\n if (inner === mongoose.Schema.Types.Mixed) {\r\n return { type: 'array', items: { type: 'object', additionalProperties: true } };\r\n }\r\n return { type: 'array', items: jsonTypeFor(inner, options, seen) };\r\n }\r\n \r\n if (typedDef.type === String) return { type: 'string' };\r\n if (typedDef.type === Number) return { type: 'number' };\r\n if (typedDef.type === Boolean) return { type: 'boolean' };\r\n if (typedDef.type === Date) {\r\n const mode = options?.dateAs || 'datetime';\r\n return mode === 'date' ? { type: 'string', format: 'date' } : { type: 'string', format: 'date-time' };\r\n }\r\n if (typedDef.type === Map || typedDef.type === mongoose.Schema.Types.Map) {\r\n const ofSchema = jsonTypeFor(typedDef.of || String, options, seen);\r\n return { type: 'object', additionalProperties: ofSchema };\r\n }\r\n if (typedDef.type === mongoose.Schema.Types.Mixed) {\r\n // Mixed type - accepts any valid JSON value\r\n return { type: 'object', additionalProperties: true };\r\n }\r\n if (isObjectIdType(typedDef.type)) {\r\n return { type: 'string', pattern: '^[0-9a-fA-F]{24}$' };\r\n }\r\n if (isMongooseSchema(typedDef.type)) {\r\n const obj = (typedDef.type as Schema & { obj?: Record<string, unknown> }).obj;\r\n if (obj && typeof obj === 'object') {\r\n if (seen.has(obj)) return { type: 'object', additionalProperties: true };\r\n seen.add(obj);\r\n return convertTreeToJsonSchema(obj, options, seen) as unknown as Record<string, unknown>;\r\n }\r\n }\r\n }\r\n\r\n if (def === String) return { type: 'string' };\r\n if (def === Number) return { type: 'number' };\r\n if (def === Boolean) return { type: 'boolean' };\r\n if (def === Date) {\r\n const mode = options?.dateAs || 'datetime';\r\n return mode === 'date' ? { type: 'string', format: 'date' } : { type: 'string', format: 'date-time' };\r\n }\r\n if (isObjectIdType(def)) return { type: 'string', pattern: '^[0-9a-fA-F]{24}$' };\r\n if (isPlainObject(def)) {\r\n if (seen.has(def)) return { type: 'object', additionalProperties: true };\r\n seen.add(def);\r\n return convertTreeToJsonSchema(def, options, seen) as unknown as Record<string, unknown>;\r\n }\r\n return {};\r\n}\r\n\r\nfunction convertTreeToJsonSchema(\r\n tree: Record<string, unknown>,\r\n options: SchemaBuilderOptions,\r\n seen: WeakSet<object> = new WeakSet()\r\n): JsonSchema {\r\n if (!tree || typeof tree !== 'object') {\r\n return { type: 'object', properties: {} };\r\n }\r\n if (seen.has(tree)) {\r\n return { type: 'object', additionalProperties: true };\r\n }\r\n seen.add(tree);\r\n\r\n const properties: Record<string, unknown> = {};\r\n const required: string[] = [];\r\n\r\n for (const [key, val] of Object.entries(tree || {})) {\r\n if (key === '__v' || key === '_id' || key === 'id') continue;\r\n const cfg = isPlainObject(val) && 'type' in val ? val : { type: val };\r\n properties[key] = jsonTypeFor(val, options, seen);\r\n if ((cfg as Record<string, unknown>).required === true) required.push(key);\r\n }\r\n\r\n const schema: JsonSchema = { type: 'object', properties };\r\n if (required.length) schema.required = required;\r\n return schema;\r\n}\r\n\r\nfunction buildJsonSchemaForCreate(\r\n tree: Record<string, unknown>,\r\n options: SchemaBuilderOptions\r\n): JsonSchema {\r\n const base = convertTreeToJsonSchema(tree, options, new WeakSet());\r\n\r\n // Collect fields to omit\r\n const fieldsToOmit = new Set(['createdAt', 'updatedAt', '__v']);\r\n\r\n // Add explicit omitFields\r\n (options?.create?.omitFields || []).forEach(f => fieldsToOmit.add(f));\r\n\r\n // Auto-detect systemManaged fields from fieldRules\r\n const fieldRules = options?.fieldRules || {};\r\n Object.entries(fieldRules).forEach(([field, rules]) => {\r\n if (rules.systemManaged) {\r\n fieldsToOmit.add(field);\r\n }\r\n });\r\n\r\n // Apply omissions\r\n fieldsToOmit.forEach(field => {\r\n if (base.properties?.[field]) {\r\n delete (base.properties as Record<string, unknown>)[field];\r\n }\r\n if (base.required) {\r\n base.required = base.required.filter(k => k !== field);\r\n }\r\n });\r\n\r\n // Apply overrides\r\n const reqOv = options?.create?.requiredOverrides || {};\r\n const optOv = options?.create?.optionalOverrides || {};\r\n base.required = base.required || [];\r\n\r\n for (const [k, v] of Object.entries(reqOv)) {\r\n if (v && !base.required.includes(k)) base.required.push(k);\r\n }\r\n\r\n for (const [k, v] of Object.entries(optOv)) {\r\n if (v && base.required) base.required = base.required.filter(x => x !== k);\r\n }\r\n\r\n // Auto-apply optional from fieldRules\r\n Object.entries(fieldRules).forEach(([field, rules]) => {\r\n if (rules.optional && base.required) {\r\n base.required = base.required.filter(x => x !== field);\r\n }\r\n });\r\n\r\n // schemaOverrides\r\n const schemaOverrides = options?.create?.schemaOverrides || {};\r\n for (const [k, override] of Object.entries(schemaOverrides)) {\r\n if (base.properties?.[k]) {\r\n (base.properties as Record<string, unknown>)[k] = override;\r\n }\r\n }\r\n\r\n // Strict additional properties (opt-in for better security)\r\n if (options?.strictAdditionalProperties === true) {\r\n base.additionalProperties = false;\r\n }\r\n\r\n return base;\r\n}\r\n\r\nfunction buildJsonSchemaForUpdate(\r\n createJson: JsonSchema,\r\n options: SchemaBuilderOptions\r\n): JsonSchema {\r\n const clone = JSON.parse(JSON.stringify(createJson)) as JsonSchema;\r\n delete clone.required;\r\n\r\n // Collect fields to omit\r\n const fieldsToOmit = new Set<string>();\r\n\r\n // 1. Explicit omitFields\r\n (options?.update?.omitFields || []).forEach(f => fieldsToOmit.add(f));\r\n\r\n // 2. Auto-detect immutable fields from fieldRules\r\n const fieldRules = options?.fieldRules || {};\r\n Object.entries(fieldRules).forEach(([field, rules]) => {\r\n if (rules.immutable || rules.immutableAfterCreate) {\r\n fieldsToOmit.add(field);\r\n }\r\n });\r\n\r\n // Apply omissions\r\n fieldsToOmit.forEach(field => {\r\n if (clone.properties?.[field]) {\r\n delete (clone.properties as Record<string, unknown>)[field];\r\n }\r\n });\r\n\r\n // Strict additional properties (opt-in for better security)\r\n if (options?.strictAdditionalProperties === true) {\r\n clone.additionalProperties = false;\r\n }\r\n\r\n return clone;\r\n}\r\n\r\nfunction buildJsonSchemaForQuery(\r\n _tree: Record<string, unknown>,\r\n options: SchemaBuilderOptions\r\n): JsonSchema {\r\n const basePagination: JsonSchema = {\r\n type: 'object',\r\n properties: {\r\n page: { type: 'string' },\r\n limit: { type: 'string' },\r\n sort: { type: 'string' },\r\n populate: { type: 'string' },\r\n search: { type: 'string' },\r\n select: { type: 'string' },\r\n lean: { type: 'string' },\r\n includeDeleted: { type: 'string' },\r\n },\r\n additionalProperties: true,\r\n };\r\n\r\n const filterable = options?.query?.filterableFields || {};\r\n for (const [k, v] of Object.entries(filterable)) {\r\n if (basePagination.properties) {\r\n (basePagination.properties as Record<string, unknown>)[k] = v && typeof v === 'object' && 'type' in v ? v : { type: 'string' };\r\n }\r\n }\r\n\r\n return basePagination;\r\n}\r\n\r\nexport default {\r\n buildCrudSchemasFromMongooseSchema,\r\n buildCrudSchemasFromModel,\r\n getImmutableFields,\r\n getSystemManagedFields,\r\n isFieldUpdateAllowed,\r\n validateUpdateBody,\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 * 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 * 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"]}
|
package/package.json
CHANGED
|
@@ -1,27 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/mongokit",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Production-grade MongoDB repositories with zero dependencies - smart pagination, events, and plugins",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./
|
|
7
|
-
"
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
|
-
"types": "./
|
|
11
|
-
"import": "./
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./pagination": {
|
|
16
|
+
"types": "./dist/pagination/PaginationEngine.d.ts",
|
|
17
|
+
"import": "./dist/pagination/PaginationEngine.mjs",
|
|
18
|
+
"require": "./dist/pagination/PaginationEngine.js"
|
|
12
19
|
},
|
|
13
20
|
"./plugins": {
|
|
14
|
-
"types": "./
|
|
15
|
-
"import": "./
|
|
21
|
+
"types": "./dist/plugins/index.d.ts",
|
|
22
|
+
"import": "./dist/plugins/index.mjs",
|
|
23
|
+
"require": "./dist/plugins/index.js"
|
|
16
24
|
},
|
|
17
25
|
"./utils": {
|
|
18
|
-
"types": "./
|
|
19
|
-
"import": "./
|
|
26
|
+
"types": "./dist/utils/index.d.ts",
|
|
27
|
+
"import": "./dist/utils/index.mjs",
|
|
28
|
+
"require": "./dist/utils/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./actions": {
|
|
31
|
+
"types": "./dist/actions/index.d.ts",
|
|
32
|
+
"import": "./dist/actions/index.mjs",
|
|
33
|
+
"require": "./dist/actions/index.js"
|
|
20
34
|
}
|
|
21
35
|
},
|
|
22
36
|
"files": [
|
|
23
|
-
"
|
|
24
|
-
"types",
|
|
37
|
+
"dist",
|
|
25
38
|
"README.md",
|
|
26
39
|
"LICENSE"
|
|
27
40
|
],
|
|
@@ -31,10 +44,19 @@
|
|
|
31
44
|
"repository",
|
|
32
45
|
"repository-pattern",
|
|
33
46
|
"data-access",
|
|
47
|
+
"pagination",
|
|
48
|
+
"cursor-pagination",
|
|
49
|
+
"infinite-scroll",
|
|
50
|
+
"offset-pagination",
|
|
51
|
+
"keyset-pagination",
|
|
52
|
+
"caching",
|
|
53
|
+
"redis",
|
|
54
|
+
"cache",
|
|
34
55
|
"multi-tenant",
|
|
35
56
|
"multi-tenancy",
|
|
36
57
|
"event-driven",
|
|
37
58
|
"plugin-based",
|
|
59
|
+
"zero-dependencies",
|
|
38
60
|
"express",
|
|
39
61
|
"fastify",
|
|
40
62
|
"nestjs",
|
|
@@ -52,24 +74,32 @@
|
|
|
52
74
|
},
|
|
53
75
|
"homepage": "https://github.com/classytic/mongokit#readme",
|
|
54
76
|
"peerDependencies": {
|
|
55
|
-
"mongoose": "^8.0.0 || ^9.0.0"
|
|
56
|
-
"mongoose-paginate-v2": "^1.9.0",
|
|
57
|
-
"mongoose-aggregate-paginate-v2": "^1.1.0"
|
|
58
|
-
},
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"http-errors": "^2.0.0"
|
|
77
|
+
"mongoose": "^8.0.0 || ^9.0.0"
|
|
61
78
|
},
|
|
62
79
|
"engines": {
|
|
63
80
|
"node": ">=18"
|
|
64
81
|
},
|
|
65
82
|
"scripts": {
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
83
|
+
"build": "tsup",
|
|
84
|
+
"dev": "tsup --watch",
|
|
85
|
+
"test": "vitest run",
|
|
86
|
+
"test:watch": "vitest",
|
|
87
|
+
"test:coverage": "vitest run --coverage",
|
|
88
|
+
"typecheck": "tsc --noEmit",
|
|
89
|
+
"prepublishOnly": "npm run build && npm run typecheck",
|
|
90
|
+
"publish:dry": "npm publish --dry-run --access public",
|
|
91
|
+
"publish:npm": "npm publish --access public",
|
|
92
|
+
"release": "npm run build && npm run typecheck && npm publish --access public",
|
|
93
|
+
"release:patch": "npm version patch && npm run release",
|
|
94
|
+
"release:minor": "npm version minor && npm run release",
|
|
95
|
+
"release:major": "npm version major && npm run release"
|
|
69
96
|
},
|
|
70
97
|
"devDependencies": {
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"mongoose
|
|
98
|
+
"@types/node": "^22.0.0",
|
|
99
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
100
|
+
"mongoose": "^9.0.0",
|
|
101
|
+
"tsup": "^8.0.0",
|
|
102
|
+
"typescript": "^5.7.0",
|
|
103
|
+
"vitest": "^3.0.0"
|
|
74
104
|
}
|
|
75
105
|
}
|
package/src/Repository.js
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import mongoose from 'mongoose';
|
|
2
|
-
import createError from 'http-errors';
|
|
3
|
-
import * as createActions from './actions/create.js';
|
|
4
|
-
import * as readActions from './actions/read.js';
|
|
5
|
-
import * as updateActions from './actions/update.js';
|
|
6
|
-
import * as deleteActions from './actions/delete.js';
|
|
7
|
-
import * as aggregateActions from './actions/aggregate.js';
|
|
8
|
-
|
|
9
|
-
export class Repository {
|
|
10
|
-
constructor(Model, plugins = []) {
|
|
11
|
-
this.Model = Model;
|
|
12
|
-
this.model = Model.modelName;
|
|
13
|
-
this._hooks = new Map();
|
|
14
|
-
plugins.forEach(plugin => this.use(plugin));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
use(plugin) {
|
|
18
|
-
if (typeof plugin === 'function') {
|
|
19
|
-
plugin(this);
|
|
20
|
-
} else if (plugin && typeof plugin.apply === 'function') {
|
|
21
|
-
plugin.apply(this);
|
|
22
|
-
}
|
|
23
|
-
return this;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
on(event, listener) {
|
|
27
|
-
if (!this._hooks.has(event)) {
|
|
28
|
-
this._hooks.set(event, []);
|
|
29
|
-
}
|
|
30
|
-
this._hooks.get(event).push(listener);
|
|
31
|
-
return this;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
emit(event, data) {
|
|
35
|
-
const listeners = this._hooks.get(event) || [];
|
|
36
|
-
listeners.forEach(listener => listener(data));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async create(data, options = {}) {
|
|
40
|
-
const context = await this._buildContext('create', { data, ...options });
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const result = await createActions.create(this.Model, context.data, options);
|
|
44
|
-
this.emit('after:create', { context, result });
|
|
45
|
-
return result;
|
|
46
|
-
} catch (error) {
|
|
47
|
-
this.emit('error:create', { context, error });
|
|
48
|
-
throw this._handleError(error);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async createMany(dataArray, options = {}) {
|
|
53
|
-
const context = await this._buildContext('createMany', { dataArray, ...options });
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const result = await createActions.createMany(this.Model, context.dataArray || dataArray, options);
|
|
57
|
-
this.emit('after:createMany', { context, result });
|
|
58
|
-
return result;
|
|
59
|
-
} catch (error) {
|
|
60
|
-
this.emit('error:createMany', { context, error });
|
|
61
|
-
throw this._handleError(error);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async getById(id, options = {}) {
|
|
66
|
-
const context = await this._buildContext('getById', { id, ...options });
|
|
67
|
-
return readActions.getById(this.Model, id, context);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async getByQuery(query, options = {}) {
|
|
71
|
-
const context = await this._buildContext('getByQuery', { query, ...options });
|
|
72
|
-
return readActions.getByQuery(this.Model, query, context);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async getAll(queryParams = {}, options = {}) {
|
|
76
|
-
const context = await this._buildContext('getAll', { queryParams, ...options });
|
|
77
|
-
|
|
78
|
-
const {
|
|
79
|
-
pagination = { page: 1, limit: 10 },
|
|
80
|
-
search,
|
|
81
|
-
sort = '-createdAt',
|
|
82
|
-
filters = {},
|
|
83
|
-
} = context.queryParams || queryParams;
|
|
84
|
-
|
|
85
|
-
let query = { ...filters };
|
|
86
|
-
if (search) query.$text = { $search: search };
|
|
87
|
-
|
|
88
|
-
const paginateOptions = {
|
|
89
|
-
page: parseInt(pagination.page, 10),
|
|
90
|
-
limit: parseInt(pagination.limit, 10),
|
|
91
|
-
sort: this._parseSort(sort),
|
|
92
|
-
populate: this._parsePopulate(context.populate || options.populate),
|
|
93
|
-
select: context.select || options.select,
|
|
94
|
-
lean: context.lean ?? options.lean ?? true,
|
|
95
|
-
session: options.session,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
if (!this.Model.paginate) {
|
|
99
|
-
throw createError(500, `Model ${this.model} missing paginate plugin`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return this.Model.paginate(query, paginateOptions);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async getOrCreate(query, createData, options = {}) {
|
|
106
|
-
return readActions.getOrCreate(this.Model, query, createData, options);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async count(query = {}, options = {}) {
|
|
110
|
-
return readActions.count(this.Model, query, options);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async exists(query, options = {}) {
|
|
114
|
-
return readActions.exists(this.Model, query, options);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async update(id, data, options = {}) {
|
|
118
|
-
const context = await this._buildContext('update', { id, data, ...options });
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
const result = await updateActions.update(this.Model, id, context.data, context);
|
|
122
|
-
this.emit('after:update', { context, result });
|
|
123
|
-
return result;
|
|
124
|
-
} catch (error) {
|
|
125
|
-
this.emit('error:update', { context, error });
|
|
126
|
-
throw this._handleError(error);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async delete(id, options = {}) {
|
|
131
|
-
const context = await this._buildContext('delete', { id, ...options });
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
const result = await deleteActions.deleteById(this.Model, id, options);
|
|
135
|
-
this.emit('after:delete', { context, result });
|
|
136
|
-
return result;
|
|
137
|
-
} catch (error) {
|
|
138
|
-
this.emit('error:delete', { context, error });
|
|
139
|
-
throw this._handleError(error);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async aggregate(pipeline, options = {}) {
|
|
144
|
-
return aggregateActions.aggregate(this.Model, pipeline, options);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async aggregatePaginate(pipeline, options = {}) {
|
|
148
|
-
return aggregateActions.aggregatePaginate(this.Model, pipeline, options);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async distinct(field, query = {}, options = {}) {
|
|
152
|
-
return aggregateActions.distinct(this.Model, field, query, options);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async withTransaction(callback) {
|
|
156
|
-
const session = await mongoose.startSession();
|
|
157
|
-
session.startTransaction();
|
|
158
|
-
try {
|
|
159
|
-
const result = await callback(session);
|
|
160
|
-
await session.commitTransaction();
|
|
161
|
-
return result;
|
|
162
|
-
} catch (error) {
|
|
163
|
-
await session.abortTransaction();
|
|
164
|
-
throw error;
|
|
165
|
-
} finally {
|
|
166
|
-
session.endSession();
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async _executeQuery(buildQuery) {
|
|
171
|
-
const operation = buildQuery.name || 'custom';
|
|
172
|
-
const context = await this._buildContext(operation, {});
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
const result = await buildQuery(this.Model);
|
|
176
|
-
this.emit(`after:${operation}`, { context, result });
|
|
177
|
-
return result;
|
|
178
|
-
} catch (error) {
|
|
179
|
-
this.emit(`error:${operation}`, { context, error });
|
|
180
|
-
throw this._handleError(error);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async _buildContext(operation, options) {
|
|
185
|
-
const context = { operation, model: this.model, ...options };
|
|
186
|
-
const event = `before:${operation}`;
|
|
187
|
-
const hooks = this._hooks.get(event) || [];
|
|
188
|
-
|
|
189
|
-
for (const hook of hooks) {
|
|
190
|
-
await hook(context);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return context;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
_parseSort(sort) {
|
|
197
|
-
if (!sort) return { createdAt: -1 };
|
|
198
|
-
if (typeof sort === 'object') return sort;
|
|
199
|
-
|
|
200
|
-
const sortOrder = sort.startsWith('-') ? -1 : 1;
|
|
201
|
-
const sortField = sort.startsWith('-') ? sort.substring(1) : sort;
|
|
202
|
-
return { [sortField]: sortOrder };
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
_parsePopulate(populate) {
|
|
206
|
-
if (!populate) return [];
|
|
207
|
-
if (typeof populate === 'string') return populate.split(',').map(p => p.trim());
|
|
208
|
-
if (Array.isArray(populate)) return populate.map(p => (typeof p === 'string' ? p.trim() : p));
|
|
209
|
-
return [populate];
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
_handleError(error) {
|
|
213
|
-
if (error instanceof mongoose.Error.ValidationError) {
|
|
214
|
-
const messages = Object.values(error.errors).map(err => err.message);
|
|
215
|
-
return createError(400, `Validation Error: ${messages.join(', ')}`);
|
|
216
|
-
}
|
|
217
|
-
if (error instanceof mongoose.Error.CastError) {
|
|
218
|
-
return createError(400, `Invalid ${error.path}: ${error.value}`);
|
|
219
|
-
}
|
|
220
|
-
if (error.status && error.message) return error;
|
|
221
|
-
return createError(500, error.message || 'Internal Server Error');
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export default Repository;
|