@nxgt/shared-mongo 1.0.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.
Files changed (169) hide show
  1. package/README.md +15 -0
  2. package/dist/audit/audit.model.d.ts +209 -0
  3. package/dist/audit/audit.model.d.ts.map +1 -0
  4. package/dist/audit/audit.service.d.ts +17 -0
  5. package/dist/audit/audit.service.d.ts.map +1 -0
  6. package/dist/audit/audit.types.d.ts +29 -0
  7. package/dist/audit/audit.types.d.ts.map +1 -0
  8. package/dist/audit/audit.utils.d.ts +50 -0
  9. package/dist/audit/audit.utils.d.ts.map +1 -0
  10. package/dist/audit/index.d.ts +5 -0
  11. package/dist/audit/index.d.ts.map +1 -0
  12. package/dist/filters/filter.utils.d.ts +112 -0
  13. package/dist/filters/filter.utils.d.ts.map +1 -0
  14. package/dist/filters/index.d.ts +16 -0
  15. package/dist/filters/index.d.ts.map +1 -0
  16. package/dist/filters/index.js +199 -0
  17. package/dist/filters/index.js.map +10 -0
  18. package/dist/index.d.ts +14 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +1847 -0
  21. package/dist/index.js.map +70 -0
  22. package/dist/integrity/index.d.ts +3 -0
  23. package/dist/integrity/index.d.ts.map +1 -0
  24. package/dist/integrity/integrity.registry.d.ts +38 -0
  25. package/dist/integrity/integrity.registry.d.ts.map +1 -0
  26. package/dist/integrity/integrity.types.d.ts +26 -0
  27. package/dist/integrity/integrity.types.d.ts.map +1 -0
  28. package/dist/migrations/cli.d.ts +28 -0
  29. package/dist/migrations/cli.d.ts.map +1 -0
  30. package/dist/migrations/disconnect.d.ts +8 -0
  31. package/dist/migrations/disconnect.d.ts.map +1 -0
  32. package/dist/migrations/index.d.ts +6 -0
  33. package/dist/migrations/index.d.ts.map +1 -0
  34. package/dist/migrations/migrate.d.ts +47 -0
  35. package/dist/migrations/migrate.d.ts.map +1 -0
  36. package/dist/migrations/migration.model.d.ts +7 -0
  37. package/dist/migrations/migration.model.d.ts.map +1 -0
  38. package/dist/migrations/migration.runner.d.ts +47 -0
  39. package/dist/migrations/migration.runner.d.ts.map +1 -0
  40. package/dist/migrations/migration.types.d.ts +48 -0
  41. package/dist/migrations/migration.types.d.ts.map +1 -0
  42. package/dist/migrations/migration.utils.d.ts +40 -0
  43. package/dist/migrations/migration.utils.d.ts.map +1 -0
  44. package/dist/models/index.d.ts +3 -0
  45. package/dist/models/index.d.ts.map +1 -0
  46. package/dist/models/pagination.d.ts +34 -0
  47. package/dist/models/pagination.d.ts.map +1 -0
  48. package/dist/models/postal-address.model.d.ts +64 -0
  49. package/dist/models/postal-address.model.d.ts.map +1 -0
  50. package/dist/mongoose.d.ts +3 -0
  51. package/dist/mongoose.d.ts.map +1 -0
  52. package/dist/plugins/consts.d.ts +6 -0
  53. package/dist/plugins/consts.d.ts.map +1 -0
  54. package/dist/plugins/errors.d.ts +3 -0
  55. package/dist/plugins/errors.d.ts.map +1 -0
  56. package/dist/plugins/index.d.ts +15 -0
  57. package/dist/plugins/index.d.ts.map +1 -0
  58. package/dist/plugins/pagination/index.d.ts +4 -0
  59. package/dist/plugins/pagination/index.d.ts.map +1 -0
  60. package/dist/plugins/pagination/types.d.ts +61 -0
  61. package/dist/plugins/pagination/types.d.ts.map +1 -0
  62. package/dist/plugins/pagination/utils.d.ts +24 -0
  63. package/dist/plugins/pagination/utils.d.ts.map +1 -0
  64. package/dist/plugins/shared/index.d.ts +3 -0
  65. package/dist/plugins/shared/index.d.ts.map +1 -0
  66. package/dist/plugins/shared/shared.d.ts +3 -0
  67. package/dist/plugins/shared/shared.d.ts.map +1 -0
  68. package/dist/plugins/soft-delete/index.d.ts +3 -0
  69. package/dist/plugins/soft-delete/index.d.ts.map +1 -0
  70. package/dist/plugins/soft-delete/soft-delete.d.ts +3 -0
  71. package/dist/plugins/soft-delete/soft-delete.d.ts.map +1 -0
  72. package/dist/services/crud.service.d.ts +88 -0
  73. package/dist/services/crud.service.d.ts.map +1 -0
  74. package/dist/services/index.d.ts +2 -0
  75. package/dist/services/index.d.ts.map +1 -0
  76. package/dist/types/index.d.ts +4 -0
  77. package/dist/types/index.d.ts.map +1 -0
  78. package/dist/types/pagination.d.ts +72 -0
  79. package/dist/types/shared.d.ts +49 -0
  80. package/dist/types/soft-delete.d.ts +627 -0
  81. package/dist/utils/clear-database.d.ts +24 -0
  82. package/dist/utils/clear-database.d.ts.map +1 -0
  83. package/dist/utils/error.utils.d.ts +4 -0
  84. package/dist/utils/error.utils.d.ts.map +1 -0
  85. package/dist/utils/filter.utils.d.ts +40 -0
  86. package/dist/utils/filter.utils.d.ts.map +1 -0
  87. package/dist/utils/helpers.d.ts +72 -0
  88. package/dist/utils/helpers.d.ts.map +1 -0
  89. package/dist/utils/index.d.ts +12 -0
  90. package/dist/utils/index.d.ts.map +1 -0
  91. package/dist/utils/mappers.d.ts +4 -0
  92. package/dist/utils/mappers.d.ts.map +1 -0
  93. package/dist/utils/models.d.ts +3 -0
  94. package/dist/utils/models.d.ts.map +1 -0
  95. package/dist/utils/mongo-utils.d.ts +45 -0
  96. package/dist/utils/mongo-utils.d.ts.map +1 -0
  97. package/dist/utils/object-id.utils.d.ts +16 -0
  98. package/dist/utils/object-id.utils.d.ts.map +1 -0
  99. package/dist/utils/pagination.utils.d.ts +6 -0
  100. package/dist/utils/pagination.utils.d.ts.map +1 -0
  101. package/dist/utils/schema.d.ts +2 -0
  102. package/dist/utils/schema.d.ts.map +1 -0
  103. package/dist/utils/sort.utils.d.ts +12 -0
  104. package/dist/utils/sort.utils.d.ts.map +1 -0
  105. package/dist/validation/index.d.ts +2 -0
  106. package/dist/validation/index.d.ts.map +1 -0
  107. package/dist/validation/validation.types.d.ts +36 -0
  108. package/dist/validation/validation.types.d.ts.map +1 -0
  109. package/dist/validation/validation.utils.d.ts +6 -0
  110. package/dist/validation/validation.utils.d.ts.map +1 -0
  111. package/dist/validation/validators/email.validator.d.ts +8 -0
  112. package/dist/validation/validators/email.validator.d.ts.map +1 -0
  113. package/dist/validation/validators/future.validator.d.ts +8 -0
  114. package/dist/validation/validators/future.validator.d.ts.map +1 -0
  115. package/dist/validation/validators/guid.validator.d.ts +6 -0
  116. package/dist/validation/validators/guid.validator.d.ts.map +1 -0
  117. package/dist/validation/validators/index.d.ts +30 -0
  118. package/dist/validation/validators/index.d.ts.map +1 -0
  119. package/dist/validation/validators/ip.validator.d.ts +6 -0
  120. package/dist/validation/validators/ip.validator.d.ts.map +1 -0
  121. package/dist/validation/validators/ipv4.validator.d.ts +6 -0
  122. package/dist/validation/validators/ipv4.validator.d.ts.map +1 -0
  123. package/dist/validation/validators/ipv6.validator.d.ts +6 -0
  124. package/dist/validation/validators/ipv6.validator.d.ts.map +1 -0
  125. package/dist/validation/validators/mac.validator.d.ts +6 -0
  126. package/dist/validation/validators/mac.validator.d.ts.map +1 -0
  127. package/dist/validation/validators/max-length.validator.d.ts +6 -0
  128. package/dist/validation/validators/max-length.validator.d.ts.map +1 -0
  129. package/dist/validation/validators/max.validator.d.ts +6 -0
  130. package/dist/validation/validators/max.validator.d.ts.map +1 -0
  131. package/dist/validation/validators/min-length.validator.d.ts +6 -0
  132. package/dist/validation/validators/min-length.validator.d.ts.map +1 -0
  133. package/dist/validation/validators/min.validator.d.ts +6 -0
  134. package/dist/validation/validators/min.validator.d.ts.map +1 -0
  135. package/dist/validation/validators/negative.validator.d.ts +6 -0
  136. package/dist/validation/validators/negative.validator.d.ts.map +1 -0
  137. package/dist/validation/validators/not-blank.validator.d.ts +6 -0
  138. package/dist/validation/validators/not-blank.validator.d.ts.map +1 -0
  139. package/dist/validation/validators/not-empty.validator.d.ts +6 -0
  140. package/dist/validation/validators/not-empty.validator.d.ts.map +1 -0
  141. package/dist/validation/validators/object-id.validator.d.ts +6 -0
  142. package/dist/validation/validators/object-id.validator.d.ts.map +1 -0
  143. package/dist/validation/validators/past.validator.d.ts +8 -0
  144. package/dist/validation/validators/past.validator.d.ts.map +1 -0
  145. package/dist/validation/validators/pattern.validator.d.ts +6 -0
  146. package/dist/validation/validators/pattern.validator.d.ts.map +1 -0
  147. package/dist/validation/validators/phone.validator.d.ts +6 -0
  148. package/dist/validation/validators/phone.validator.d.ts.map +1 -0
  149. package/dist/validation/validators/positive.validator.d.ts +6 -0
  150. package/dist/validation/validators/positive.validator.d.ts.map +1 -0
  151. package/dist/validation/validators/range.validator.d.ts +6 -0
  152. package/dist/validation/validators/range.validator.d.ts.map +1 -0
  153. package/dist/validation/validators/required.validator.d.ts +6 -0
  154. package/dist/validation/validators/required.validator.d.ts.map +1 -0
  155. package/dist/validation/validators/size.validator.d.ts +6 -0
  156. package/dist/validation/validators/size.validator.d.ts.map +1 -0
  157. package/dist/validation/validators/ssn.validator.d.ts +6 -0
  158. package/dist/validation/validators/ssn.validator.d.ts.map +1 -0
  159. package/dist/validation/validators/street.validator.d.ts +6 -0
  160. package/dist/validation/validators/street.validator.d.ts.map +1 -0
  161. package/dist/validation/validators/time.validator.d.ts +6 -0
  162. package/dist/validation/validators/time.validator.d.ts.map +1 -0
  163. package/dist/validation/validators/url.validator.d.ts +8 -0
  164. package/dist/validation/validators/url.validator.d.ts.map +1 -0
  165. package/dist/validation/validators/uuid.validator.d.ts +6 -0
  166. package/dist/validation/validators/uuid.validator.d.ts.map +1 -0
  167. package/dist/validation/validators/zip-code.validator.d.ts +6 -0
  168. package/dist/validation/validators/zip-code.validator.d.ts.map +1 -0
  169. package/package.json +68 -0
@@ -0,0 +1,70 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/types/pagination.d.ts", "../src/index.ts", "../src/audit/audit.model.ts", "../src/plugins/pagination/utils.ts", "../src/plugins/pagination/types.ts", "../src/plugins/pagination/index.ts", "../src/audit/audit.types.ts", "../src/audit/audit.utils.ts", "../src/mongoose.ts", "../src/utils/clear-database.ts", "../src/utils/error.utils.ts", "../src/utils/filter.utils.ts", "../src/utils/helpers.ts", "../src/utils/object-id.utils.ts", "../src/utils/mappers.ts", "../src/plugins/index.ts", "../src/plugins/errors.ts", "../src/plugins/shared/shared.ts", "../src/plugins/shared/index.ts", "../src/plugins/consts.ts", "../src/utils/mongo-utils.ts", "../src/utils/pagination.utils.ts", "../src/utils/sort.utils.ts", "../src/audit/audit.service.ts", "../src/integrity/integrity.registry.ts", "../src/migrations/disconnect.ts", "../src/migrations/migration.runner.ts", "../src/migrations/migration.model.ts", "../src/migrations/migration.utils.ts", "../src/migrations/migrate.ts", "../src/models/postal-address.model.ts", "../src/validation/validators/email.validator.ts", "../src/validation/validation.utils.ts", "../src/validation/validators/future.validator.ts", "../src/validation/validators/guid.validator.ts", "../src/validation/validators/ip.validator.ts", "../src/validation/validators/ipv4.validator.ts", "../src/validation/validators/ipv6.validator.ts", "../src/validation/validators/mac.validator.ts", "../src/validation/validators/max.validator.ts", "../src/validation/validators/max-length.validator.ts", "../src/validation/validators/min.validator.ts", "../src/validation/validators/min-length.validator.ts", "../src/validation/validators/negative.validator.ts", "../src/validation/validators/not-blank.validator.ts", "../src/validation/validators/not-empty.validator.ts", "../src/validation/validators/object-id.validator.ts", "../src/validation/validators/past.validator.ts", "../src/validation/validators/pattern.validator.ts", "../src/validation/validators/phone.validator.ts", "../src/validation/validators/positive.validator.ts", "../src/validation/validators/range.validator.ts", "../src/validation/validators/required.validator.ts", "../src/validation/validators/size.validator.ts", "../src/validation/validators/ssn.validator.ts", "../src/validation/validators/street.validator.ts", "../src/validation/validators/time.validator.ts", "../src/validation/validators/url.validator.ts", "../src/validation/validators/uuid.validator.ts", "../src/validation/validators/zip-code.validator.ts", "../src/services/crud.service.ts"],
4
+ "sourcesContent": [
5
+ "import 'mongoose';\nimport type {\n\tIConnection,\n\tNestedPaginationOptions,\n\tPaginationOptions,\n} from '../models/pagination';\nimport type {\n\tCursorPaginateOptions,\n\tICursorPaginatedType,\n\tIPaginatedType,\n\tNestedOffsetPaginationOptions,\n\tPaginateOffsetOptions,\n} from '../plugins/pagination/types';\n\n/**\n * Five statics, because the two repositories put different meanings on\n * `paginate` and neither was tested. See `plugins/pagination/utils.ts`.\n *\n * This file is hand-written, so `tsc` passes it through rather than emitting\n * it — `build.ts` copies it into `dist/` instead. Without that copy every one\n * of these declarations disappears for a consumer.\n */\ndeclare module 'mongoose' {\n\texport interface Model<\n\t\tTRawDocType,\n\t\tTQueryHelpers = object,\n\t\tTInstanceMethods = object,\n\t\tTVirtuals = object,\n\t\tTHydratedDocumentType = HydratedDocument<\n\t\t\tTRawDocType,\n\t\t\tTVirtuals & TInstanceMethods,\n\t\t\tTQueryHelpers,\n\t\t\tTVirtuals\n\t\t>,\n\t\tTSchema = any,\n\t\tTLeanResultType = TRawDocType,\n\t> extends NodeJS.EventEmitter,\n\t\t\tIndexManager,\n\t\t\tSessionStarter {\n\t\tpaginate<_ResultDoc = THydratedDocumentType>(\n\t\t\tfilter: PaginationOptions & {\n\t\t\t\tdeleted?: 'Deleted' | 'WidthDeleted';\n\t\t\t} & {\n\t\t\t\tpopulate?: string | PopulateOptions | (string | PopulateOptions)[];\n\t\t\t},\n\t\t\tprojection?: ProjectionType<TRawDocType> | null | undefined,\n\t\t\toptions?: (QueryOptions<TRawDocType> & { lean: true }) | undefined,\n\t\t): Promise<IConnection<TRawDocType>>;\n\n\t\tpaginateList(\n\t\t\tdocs: THydratedDocumentType[],\n\t\t\toptions: NestedPaginationOptions,\n\t\t): IConnection<TRawDocType>;\n\n\t\tpaginateOffset<_ResultDoc = THydratedDocumentType>(\n\t\t\tfilter: PaginateOffsetOptions,\n\t\t\tprojection?: ProjectionType<TRawDocType> | null | undefined,\n\t\t\toptions?: (QueryOptions<TRawDocType> & { lean: true }) | undefined,\n\t\t): Promise<IPaginatedType<TRawDocType>>;\n\n\t\tpaginateListOffset(\n\t\t\tdocs: THydratedDocumentType[],\n\t\t\toptions: NestedOffsetPaginationOptions,\n\t\t): Promise<IPaginatedType<TRawDocType>>;\n\n\t\tcursorPaginate<_ResultDoc = THydratedDocumentType>(\n\t\t\tfilter: CursorPaginateOptions,\n\t\t\tprojection?: ProjectionType<TRawDocType> | null | undefined,\n\t\t\toptions?: (QueryOptions<TRawDocType> & { lean: true }) | undefined,\n\t\t): Promise<ICursorPaginatedType<TRawDocType>>;\n\t}\n}\n",
6
+ "import './types';\n\nexport * from 'async-mutex';\nexport * from 'mongoose';\nexport * from './audit';\nexport * from './integrity';\nexport * from './migrations';\nexport * from './models';\nexport { mongoose } from './mongoose';\nexport * from './plugins';\nexport * from './services';\nexport * from './utils';\nexport * from './utils/schema';\nexport * from './validation';\n",
7
+ "import { logger } from '@nxgt/shared-logging';\nimport { redis } from 'bun';\nimport type { HydratedDocument, Model } from 'mongoose';\nimport { model, Schema } from 'mongoose';\nimport { pagination } from '../plugins/pagination';\nimport { CommitType } from './audit.types';\nimport { AUDIT_EVENT } from './audit.utils';\n\nexport interface Audit {\n\tid: string;\n\ttype: string;\n\tglobalId: string;\n\tauthor: string;\n\tstate: any;\n\tproperties: string[];\n\tchanges: any[];\n\tversion: number;\n}\n\nexport type AuditDocument = HydratedDocument<Audit>;\n\ntype AuditModel = Model<AuditDocument, object, object, object>;\n\nconst schema = new Schema<AuditDocument, AuditModel, object, object, object>(\n\t{\n\t\ttype: {\n\t\t\ttype: String,\n\t\t\tenum: [CommitType.INITIAL, CommitType.UPDATE, CommitType.TERMINAL],\n\t\t},\n\t\tauthor: String,\n\t\tglobalId: { type: String, required: true },\n\t\tstate: { type: Schema.Types.Mixed, required: true },\n\t\tproperties: [{ type: String, required: true }],\n\t\tchanges: [{ type: Schema.Types.Mixed, required: true }],\n\t\tversion: { type: Number, required: true, default: 0 },\n\t},\n\t{\n\t\ttimestamps: { createdAt: 'date', updatedAt: false },\n\t\tversionKey: false,\n\t},\n);\n\n(() => {\n\tpagination(schema);\n})();\n\nexport const AuditModel = model('Audit', schema);\n\nexport const AUDIT_CHANGE_STREAM = AuditModel.watch([\n\t{\n\t\t$match: {\n\t\t\toperationType: 'insert',\n\t\t},\n\t},\n]);\n\n(() => {\n\tAUDIT_CHANGE_STREAM.on('change', async (data) => {\n\t\ttry {\n\t\t\tawait redis.publish(\n\t\t\t\tAUDIT_EVENT,\n\t\t\t\tJSON.stringify(await AuditModel.findById(data.documentKey._id)),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlogger.error(error);\n\t\t}\n\t});\n})();\n",
8
+ "import { CustomException } from '@nxgt/shared-exceptions';\nimport type { Document, HydratedDocument, QueryFilter, Schema } from 'mongoose';\nimport type {\n\tIConnection,\n\tIPageInfo,\n\tNestedPaginationOptions,\n\tPaginationOptions,\n} from '../../models/pagination';\nimport type {\n\tCursorPaginateOptions,\n\tNestedOffsetPaginationOptions,\n\tPaginateOffsetOptions,\n} from './types';\n\nconst MAX_SIZE = 100;\n\n/**\n * Both repositories put a `paginate` static on every schema, and they meant\n * different things by it: sellix-monorepo answered `{data, metadata}` from a\n * page and a size, nxgt-federation answered a Relay `{edges, pageInfo,\n * totalCount}` from a cursor.\n *\n * `paginate` keeps federation's meaning because federation calls it from\n * dozens of services and sellix-monorepo called it from none — its offset\n * variants were dead code there. They survive under explicit names rather than\n * being deleted, since a cursor connection cannot express \"page 7 of 12\".\n *\n * paginate cursor, Relay connection\n * paginateList cursor, over a list already in memory\n * paginateOffset page/size, {data, metadata}\n * paginateListOffset page/size, over a list already in memory\n * cursorPaginate cursor, {data, metadata} — sellix's third shape\n */\nexport function applyPagination(schema: Schema) {\n\tschema.static('paginate', async function () {\n\t\tconst options =\n\t\t\t<PaginationOptions & { deleted?: 'Deleted' | 'WithDeleted' }>(\n\t\t\t\targuments?.[0]\n\t\t\t) ?? {};\n\n\t\tconst { first, last, before, after, extraFilter } = options;\n\n\t\tlet filter = options.filter ?? {};\n\t\tconst deleted = options.deleted ?? '';\n\n\t\tconst countDocuments = (f: any) =>\n\t\t\tthis[`countDocuments${deleted}`]?.(f) ?? this.countDocuments(f);\n\n\t\tif (extraFilter) {\n\t\t\tfilter = filter ? { $and: [filter, extraFilter] } : extraFilter;\n\t\t}\n\n\t\tif (first && last) {\n\t\t\tthrow CustomException.badRequest({\n\t\t\t\tmessage: 'errors.could-not-use-first-and-last-together',\n\t\t\t});\n\t\t}\n\n\t\tif (after) {\n\t\t\tfilter = filter\n\t\t\t\t? { $and: [filter, { _id: { $gt: after } }] }\n\t\t\t\t: { _id: { $gt: after } };\n\t\t}\n\n\t\tif (before) {\n\t\t\tfilter = filter\n\t\t\t\t? { $and: [filter, { _id: { $lt: before } }] }\n\t\t\t\t: { _id: { $lt: before } };\n\t\t}\n\n\t\tconst limit = Math.min(first ?? last ?? MAX_SIZE, MAX_SIZE);\n\t\t// Backward pagination reads in reverse.\n\t\tconst sort = { _id: last || before ? -1 : 1 };\n\n\t\tlet query = (\n\t\t\t(this[`find${deleted}`] as any)?.(\n\t\t\t\tfilter,\n\t\t\t\targuments?.[1],\n\t\t\t\targuments?.[2],\n\t\t\t) ?? this.find(filter, arguments?.[1], arguments?.[2])\n\t\t).sort(sort);\n\n\t\t// One more than asked for, to know whether another page exists.\n\t\tquery = query.limit(limit + 1);\n\n\t\tconst result = await query.exec();\n\t\tconst hasExtraDoc = result.length > limit;\n\t\tconst actualResults = hasExtraDoc ? result.slice(0, limit) : result;\n\n\t\tconst total = await countDocuments(filter);\n\n\t\tconst edges = actualResults.map((item: any) => ({\n\t\t\tnode: item,\n\t\t\tcursor: item.id,\n\t\t}));\n\n\t\tconst pageInfo: IPageInfo = {\n\t\t\thasNextPage: hasExtraDoc,\n\t\t\tstartCursor: edges?.[0]?.cursor,\n\t\t\tendCursor: edges?.[edges.length - 1]?.cursor,\n\t\t};\n\n\t\treturn { edges, pageInfo, totalCount: total };\n\t});\n\n\tschema.static('paginateList', function () {\n\t\tconst docs = (arguments?.[0] ?? []) as HydratedDocument<any>[];\n\t\tconst options = <NestedPaginationOptions>arguments?.[1] ?? {};\n\t\treturn paginateListData(docs, options);\n\t});\n\n\tschema.static('paginateOffset', async function () {\n\t\tconst options = <PaginateOffsetOptions>arguments?.[0] ?? {};\n\t\tconst filter = options.filter ?? {};\n\t\tconst sort = options.sort ?? {};\n\t\tconst populate = options.populate ?? [];\n\t\tconst deleted = options.deleted ?? '';\n\n\t\tconst count = await ((this as any)[`countDocuments${deleted}`]?.(filter) ??\n\t\t\tthis.countDocuments(filter));\n\n\t\tconst { size, page, totalPages, skip } = offsetWindow(options, count);\n\n\t\tconst docs = await (\n\t\t\t(this as any)[`find${deleted}`]?.(\n\t\t\t\tfilter,\n\t\t\t\targuments?.[1],\n\t\t\t\targuments?.[2],\n\t\t\t) ?? this.find(filter, arguments?.[1], arguments?.[2])\n\t\t)\n\t\t\t.populate(populate)\n\t\t\t.sort(sort)\n\t\t\t.skip(skip)\n\t\t\t.limit(size)\n\t\t\t.exec();\n\n\t\treturn {\n\t\t\tdata: docs,\n\t\t\tmetadata: {\n\t\t\t\tpage,\n\t\t\t\tsize,\n\t\t\t\ttotalElements: count,\n\t\t\t\ttotalPages,\n\t\t\t\tnbOfElements: docs.length,\n\t\t\t\thasPreviousPage: page > 1,\n\t\t\t\thasNextPage: page < totalPages,\n\t\t\t},\n\t\t};\n\t});\n\n\tschema.static('paginateListOffset', async function () {\n\t\tconst docs = arguments?.[0] ?? [];\n\t\tconst options = <NestedOffsetPaginationOptions>arguments?.[1] ?? {};\n\t\tconst count = docs.length;\n\n\t\tconst { size, page, totalPages, skip } = offsetWindow(options, count);\n\n\t\treturn {\n\t\t\tdata: docs.slice(skip, skip + size),\n\t\t\tmetadata: {\n\t\t\t\tpage,\n\t\t\t\tsize,\n\t\t\t\ttotalElements: count,\n\t\t\t\ttotalPages,\n\t\t\t\tnbOfElements: docs.length,\n\t\t\t\thasPreviousPage: page > 1,\n\t\t\t\thasNextPage: page < totalPages,\n\t\t\t},\n\t\t};\n\t});\n\n\tschema.static('cursorPaginate', async function () {\n\t\tconst options = <CursorPaginateOptions>arguments?.[0] ?? {};\n\t\tconst filter = options.filter ?? {};\n\t\tconst populate = options.populate ?? [];\n\t\tconst deleted = options.deleted ?? '';\n\n\t\tconst { after, before } = options;\n\t\tconst first =\n\t\t\toptions.first && options.first > 0 ? options.first : undefined;\n\t\tconst last = options.last && options.last > 0 ? options.last : undefined;\n\n\t\tif (first && last) {\n\t\t\tthrow CustomException.badRequest({\n\t\t\t\tmessage: 'errors.could-not-use-first-and-last-together',\n\t\t\t});\n\t\t}\n\n\t\tconst cursorFilter: QueryFilter<any> = filter;\n\t\tif (after) cursorFilter._id = { $gt: after };\n\t\tif (before) cursorFilter._id = { $lt: before };\n\n\t\tconst limit = Math.min(first ?? last ?? MAX_SIZE, MAX_SIZE);\n\t\tconst querySort = { _id: last || before ? -1 : 1 };\n\n\t\tconst query = (\n\t\t\t(this as any)[`find${deleted}`]?.(\n\t\t\t\tcursorFilter,\n\t\t\t\targuments?.[1],\n\t\t\t\targuments?.[2],\n\t\t\t) ?? this.find(cursorFilter, arguments?.[1], arguments?.[2])\n\t\t)\n\t\t\t.populate(populate)\n\t\t\t.sort(querySort);\n\n\t\tquery.limit(Math.max(limit ?? 0, 1) + 1);\n\n\t\tconst docs = await query.exec();\n\n\t\tconst hasExtraDoc = docs.length > limit;\n\t\tconst resultDocs = hasExtraDoc ? docs.slice(0, limit) : docs;\n\t\tif (last) {\n\t\t\tresultDocs.reverse();\n\t\t}\n\n\t\tconst totalElements = await ((this as any)[`countDocuments${deleted}`]?.(\n\t\t\tfilter,\n\t\t) ?? this.countDocuments(filter));\n\n\t\treturn {\n\t\t\tdata: resultDocs,\n\t\t\tmetadata: {\n\t\t\t\tstartCursor:\n\t\t\t\t\tresultDocs.length > 0 ? resultDocs[0]._id.toString() : null,\n\t\t\t\tendCursor:\n\t\t\t\t\tresultDocs.length > 0\n\t\t\t\t\t\t? resultDocs[resultDocs.length - 1]._id.toString()\n\t\t\t\t\t\t: null,\n\t\t\t\thasNextPage: hasExtraDoc,\n\t\t\t\ttotalElements,\n\t\t\t},\n\t\t};\n\t});\n}\n\n/**\n * The page window, shared by both offset statics.\n *\n * sellix-monorepo computed the size as `Math.min(Math.min(1, size ?? 20), 100)`,\n * whose inner `Math.min(1, …)` pins every page to a single document whatever\n * the caller asks for. Nothing called these statics, so nothing ever saw it.\n */\nfunction offsetWindow(\n\toptions: { page?: number; size?: number },\n\tcount: number,\n) {\n\tconst size = Math.min(Math.max(options.size ?? 20, 1), MAX_SIZE);\n\tconst page = Math.max(options.page ?? 1, 1);\n\treturn {\n\t\tsize,\n\t\tpage,\n\t\ttotalPages: Math.floor((count - 1) / size) + 1,\n\t\tskip: (page - 1) * size,\n\t};\n}\n\nexport function paginateListData<T extends HydratedDocument<{ id: string }>>(\n\tlist: T[],\n\toptions: PaginationOptions,\n): IConnection<T> {\n\tconst { first, last, before, after } = options;\n\n\tif (first && last) {\n\t\tthrow CustomException.badRequest({\n\t\t\tmessage: 'errors.could-not-use-first-and-last-together',\n\t\t});\n\t}\n\n\tconst isBackward = last || before;\n\n\tconst sortedData = (list as Document[]).sort((a, b) => {\n\t\tif (a._id.toString() < b._id.toString()) return isBackward ? 1 : -1;\n\t\tif (a._id.toString() > b._id.toString()) return isBackward ? -1 : 1;\n\t\treturn 0;\n\t});\n\n\tconst total = sortedData.length;\n\n\tlet filteredData = sortedData;\n\tif (after || before) {\n\t\tconst index = sortedData.findIndex(\n\t\t\t(item) => (item as any).id === (after ?? before),\n\t\t);\n\t\tfilteredData = index !== -1 ? sortedData.slice(index + 1) : sortedData;\n\t}\n\n\tconst limit = Math.min(first ?? last ?? MAX_SIZE, MAX_SIZE);\n\n\tconst hasExtraDoc = filteredData.length > limit;\n\tconst resultData = filteredData.slice(0, limit);\n\n\tconst edges = resultData.map((item) => ({\n\t\tnode: item,\n\t\tcursor: (item as any).id,\n\t}));\n\n\tconst pageInfo: IPageInfo = {\n\t\thasNextPage: hasExtraDoc,\n\t\tstartCursor: edges?.[0]?.cursor,\n\t\tendCursor: edges?.[edges.length - 1]?.cursor,\n\t};\n\n\treturn { edges, pageInfo, totalCount: total } as IConnection<T>;\n}\n",
9
+ "import type { PopulateOptions } from 'mongoose';\n\n/**\n * Offset pagination — page and size.\n *\n * The cursor/Relay shapes live in `../../models/pagination.ts` and own the\n * plain names (`PaginationOptions`, `NestedPaginationOptions`), because that is\n * what `Model.paginate` answers and what every consumer of it passes. These\n * carry the `Offset` prefix so both can be exported from one package; they had\n * the plain names in sellix-monorepo, where nothing called them.\n */\nexport class OffsetPaginationOptions {\n\tfilter?: object;\n\tsort?: object;\n\tpage?: number;\n\tsize?: number;\n}\n\nexport class NestedOffsetPaginationOptions {\n\tpage?: number;\n\tsize?: number;\n}\n\nexport interface OffsetPageInfo {\n\tpage: number;\n\tsize: number;\n\ttotalPages: number;\n\tnbOfElements: number;\n\ttotalElements: number;\n\thasNextPage: boolean;\n\thasPreviousPage: boolean;\n}\n\nexport interface IPaginatedType<T> {\n\tdata: T[];\n\tmetadata: OffsetPageInfo;\n}\n\nexport type PaginateOffsetOptions = OffsetPaginationOptions & {\n\tdeleted?: 'Deleted' | 'WidthDeleted';\n} & {\n\tpopulate?: string | PopulateOptions | (string | PopulateOptions)[];\n};\n\nexport class CursorPaginationOptions {\n\tfilter?: object;\n\tfirst?: number;\n\tlast?: number;\n\tafter?: string;\n\tbefore?: string;\n}\n\nexport interface CursorPageInfo {\n\tstartCursor: string | null;\n\tendCursor: string | null;\n\thasNextPage: boolean;\n\ttotalElements: number;\n}\n\nexport interface ICursorPaginatedType<T> {\n\tdata: T[];\n\tmetadata: CursorPageInfo;\n}\n\nexport type CursorPaginateOptions = CursorPaginationOptions & {\n\tdeleted?: 'Deleted' | 'WidthDeleted';\n} & {\n\tpopulate?: string | PopulateOptions | (string | PopulateOptions)[];\n};\n",
10
+ "import type { Schema } from 'mongoose';\nimport { applyPagination } from './utils';\n\nexport const pagination = (schema: Schema) => {\n\tapplyPagination(schema);\n};\nexport * from './types';\n",
11
+ "import type { Mutex } from 'async-mutex';\nimport type mongoose from 'mongoose';\nimport type { Audit } from './audit.model';\n\nexport enum ChangeOperationType {\n\tADD = 'add',\n\tREPLACE = 'replace',\n\tREMOVE = 'remove',\n}\n\nexport enum CommitType {\n\tINITIAL = 'INITIAL',\n\tUPDATE = 'UPDATE',\n\tTERMINAL = 'TERMINAL',\n}\n\nexport interface Change<T>\n\textends Omit<Audit, 'state' | 'changes' | 'properties'> {\n\tstate: T;\n\tproperties: (keyof T)[];\n\tchanges: { op: ChangeOperationType; path: [keyof T]; value: any }[];\n}\n\nexport type ChangeListeningOptions = {\n\tauthor?: string;\n\tomitFields?: string[];\n\tmodels: mongoose.Model<any>[];\n\tmutex?: Mutex;\n};\n",
12
+ "import { delay } from '@nxgt/shared/helpers';\nimport { createLogger } from '@nxgt/shared-logging';\nimport { Mutex } from 'async-mutex';\nimport { diff } from 'just-diff';\nimport { omit } from 'lodash';\nimport { mongoose } from '../mongoose';\nimport { MONGO_UTILS } from '../utils';\nimport { type Audit, AuditModel } from './audit.model';\nimport type { ChangeListeningOptions } from './audit.types';\n\nconst mutex = new Mutex();\n\nconst logger = createLogger({ name: 'audit' });\n\n/**\n * Processes MongoDB change streams and creates audit logs based on changes.\n * @param {mongoose.mongo.ChangeStream<any, any>} changeStream - The MongoDB change stream.\n * @param {Object} options - Configuration options for the audit process.\n * @param {string[]} [options.omitFields] - Fields to omit when comparing states.\n * @param {UserPrincipal} [options.user] - The user making the changes.\n */\nexport function auditChanges(\n\tchangeStream: mongoose.mongo.ChangeStream<any, any>,\n\toptions: { omitFields?: string[]; author?: string },\n) {\n\toptions.omitFields = options.omitFields ?? [\n\t\t'_id',\n\t\t'id',\n\t\t'version',\n\t\t'createdDate',\n\t\t'lastModifiedDate',\n\t\t'createdBy',\n\t\t'lastModifiedBy',\n\t\t'__v',\n\t];\n\tchangeStream.on('change', async (data) => {\n\t\tconst globalId = `${data.ns.coll}/${data.documentKey._id.toHexString()}`;\n\n\t\tconst previousSnapshot = await AuditModel.findOne({\n\t\t\tglobalId,\n\t\t})\n\t\t\t.sort({ version: -1 })\n\t\t\t.exec();\n\n\t\tconst stateBeforeChange = previousSnapshot?.state;\n\n\t\tif (['delete', 'update', 'replace'].includes(data.operationType)) {\n\t\t\tconst doc = await mongoose.connection.db\n\t\t\t\t?.collection(data.ns.coll)\n\t\t\t\t.findOne({ _id: { $eq: data.documentKey._id } });\n\t\t\tconst state = doc ? { ...doc, id: doc._id.toHexString() } : undefined;\n\t\t\tconst changes =\n\t\t\t\tdata.operationType === 'delete'\n\t\t\t\t\t? []\n\t\t\t\t\t: diff(\n\t\t\t\t\t\t\tomit(stateBeforeChange, options.omitFields ?? []),\n\t\t\t\t\t\t\tomit(state, options.omitFields ?? []),\n\t\t\t\t\t\t);\n\t\t\tawait AuditModel.create({\n\t\t\t\ttype: data.operationType === 'delete' ? 'TERMINAL' : 'UPDATE',\n\t\t\t\tauthor: options.author,\n\t\t\t\tchanges,\n\t\t\t\tproperties: changes.flatMap((change) => change.path.toString()),\n\t\t\t\tstate: state ??\n\t\t\t\t\tpreviousSnapshot?.state ?? {\n\t\t\t\t\t\t_id: data.documentKey._id,\n\t\t\t\t\t\tid: data.documentKey._id.toHexString(),\n\t\t\t\t\t},\n\t\t\t\tversion: (previousSnapshot?.version ?? 0) + 1,\n\t\t\t\tglobalId,\n\t\t\t});\n\t\t} else {\n\t\t\tconst state = data.fullDocument\n\t\t\t\t? {\n\t\t\t\t\t\t...data.fullDocument,\n\t\t\t\t\t\tid: data.fullDocument._id.toHexString(),\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\n\t\t\tconst changes = diff({}, omit(state, options.omitFields ?? []));\n\t\t\tawait AuditModel.create({\n\t\t\t\ttype: 'INITIAL',\n\t\t\t\tauthor: options.author,\n\t\t\t\tchanges,\n\t\t\t\tversion: 0,\n\t\t\t\tproperties: changes.flatMap((change) => change.path.toString()),\n\t\t\t\tstate,\n\t\t\t\tglobalId,\n\t\t\t});\n\t\t}\n\t});\n}\n\n/**\n * Executes a given asynchronous block of code while listening for changes in specified MongoDB models.\n * Automatically closes all change streams after execution.\n *\n * @template T\n * @param {() => Promise<T>} bloc - An asynchronous function to execute while monitoring changes.\n * @param {Object} options - Configuration options for the change listener.\n * @param {string} [options.author] - The author initiating the change listener (used for auditing purposes).\n * @param {string[]} [options.omitFields] - Fields to omit from the auditing process.\n * @param {mongoose.Model<any>[]} options.models - The Mongoose models to watch for changes.\n * @param {Mutex} [options.mutex] - An optional mutex to ensure exclusive access during execution.\n *\n * @returns {Promise<T>} - Resolves with the result of the executed block of code.\n *\n * @throws {Error} - Propagates any errors from the `bloc` function or other internal operations.\n */\nexport function runWithChangesListening<T>(\n\tbloc: () => Promise<T>,\n\toptions: ChangeListeningOptions,\n): Promise<T> {\n\treturn (options.mutex ?? mutex).runExclusive(async () => {\n\t\tconst changeStreams = options.models.map((model) =>\n\t\t\tmodel.watch(MONGO_UTILS.auditPipeline),\n\t\t);\n\t\tchangeStreams.forEach((changeStream) => {\n\t\t\tauditChanges(changeStream, omit(options, 'models'));\n\t\t});\n\t\ttry {\n\t\t\treturn await mongoose.connection.transaction(\n\t\t\t\tasync () => {\n\t\t\t\t\treturn await bloc();\n\t\t\t\t},\n\t\t\t\t{ readPreference: 'primary' },\n\t\t\t);\n\t\t} finally {\n\t\t\tawait delay(1);\n\t\t\tfor (const changeStream of changeStreams) {\n\t\t\t\tawait changeStream.close();\n\t\t\t}\n\t\t}\n\t});\n}\n\nexport const AUDIT_EVENT = 'event:audit';\n\ntype RegisterAuditSubscriptionOptions<\n\tT extends {\n\t\tpublish<D>(topic: string, data: D): void;\n\t},\n> = {\n\tpubsub: T;\n};\n\n/**\n * Registers a subscription to MongoDB audit events, allowing real-time notifications of changes in the database.\n * @param {Object} options - Configuration options for the subscription.\n * @param {Object} options.pubsub - An object with a `publish` method to send notifications (e.g., a PubSub instance).\n */\nexport function registerAuditSubscription<\n\tT extends { publish(topic: string, ...data: any): void },\n>({ pubsub }: RegisterAuditSubscriptionOptions<T>) {\n\tconst AUDIT_CHANGE_STREAM = AuditModel.watch([\n\t\t{\n\t\t\t$match: {\n\t\t\t\toperationType: 'insert',\n\t\t\t},\n\t\t},\n\t]);\n\n\tAUDIT_CHANGE_STREAM.on('change', async (data) => {\n\t\ttry {\n\t\t\tpubsub.publish(\n\t\t\t\tAUDIT_EVENT,\n\t\t\t\tawait AuditModel.findById(data.documentKey._id),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlogger.error(error);\n\t\t}\n\t});\n}\n\nexport type AuditPayload = {\n\t[AUDIT_EVENT]: [payload: Audit];\n};\n",
13
+ "import mongoose from 'mongoose';\n\nexport { mongoose };\n",
14
+ "import type { Connection } from 'mongoose';\nimport { mongoose } from '../mongoose';\n\n/**\n * Empties every non-view, non-system collection on `connection`.\n *\n * Test-suite helper, deliberately living here rather than in each app: it used\n * to exist as five identical unguarded copies here and five more in\n * `sellix-monorepo`, and one shell export was enough to point a whole suite at a\n * real database and empty it — which is how `sellix` was lost once. Bun gives\n * the process environment precedence over `--env-file`, so `MONGODB_URI` set in\n * a shell silently beats `.env.test` — and the centralized env layout makes a\n * forgotten `--env-file=.env.test` resolve to the production URI just as\n * quietly.\n *\n * Hence the guard, and hence both halves of it: `NODE_ENV` and the database\n * name are each individually defeatable by exactly the kind of stray export\n * that caused the incident, so both must hold. An unconnected connection\n * reports an empty name and is refused, so this fails closed.\n *\n * `Bun.env` rather than an app's parsed env: this package has no schema of its\n * own to load, and reading the raw value is the point — the guard must see what\n * the process actually got, not what a `.default()` filled in.\n */\nexport async function clearDatabase(\n\tconnection: Connection = mongoose.connection,\n): Promise<void> {\n\tconst database = connection.name;\n\n\tif (Bun.env.NODE_ENV !== 'test' || !database.endsWith('-test')) {\n\t\tthrow new Error(\n\t\t\t`clearDatabase refused to run: NODE_ENV=\"${Bun.env.NODE_ENV}\", database=\"${database}\". ` +\n\t\t\t\t'It only runs with NODE_ENV=test against a database whose name ends in \"-test\". ' +\n\t\t\t\t'A test run reaching a non-test database usually means MONGODB_URI is set in the ' +\n\t\t\t\t'shell, or the test env file was not passed.',\n\t\t);\n\t}\n\n\tconst collections = await connection.listCollections();\n\n\tawait Promise.all(\n\t\tcollections\n\t\t\t.filter(\n\t\t\t\t(collection) =>\n\t\t\t\t\tcollection.type !== 'view' && !collection.name.includes('system'),\n\t\t\t)\n\t\t\t.map((collection) =>\n\t\t\t\tconnection.collection(collection.name).deleteMany({}),\n\t\t\t),\n\t);\n}\n",
15
+ "import type { LocaleKey } from '@nxgt/i18n';\nimport { CustomException } from '@nxgt/shared-exceptions';\nimport mongoose from 'mongoose';\n\nexport function castError(error: mongoose.MongooseError) {\n\tlet props: { message?: LocaleKey; options?: object; debugMessage?: string } =\n\t\t{};\n\tif (error instanceof CustomException) {\n\t\treturn error;\n\t}\n\tswitch (true) {\n\t\tcase error instanceof mongoose.Error.CastError:\n\t\t\tprops = {\n\t\t\t\tmessage: 'errors.cast-failed',\n\t\t\t\toptions: { field: error.path },\n\t\t\t};\n\t\t\tbreak;\n\t\tcase error instanceof mongoose.Error.VersionError:\n\t\t\tprops = {\n\t\t\t\tmessage: 'errors.optimistic-lock-failed',\n\t\t\t\tdebugMessage: error.message,\n\t\t\t};\n\t\t\tbreak;\n\t\tcase error instanceof mongoose.Error.DocumentNotFoundError:\n\t\t\tprops = {\n\t\t\t\tmessage: 'errors.not-found',\n\t\t\t};\n\t\t\tbreak;\n\t\tcase error instanceof mongoose.Error.MongooseServerSelectionError:\n\t\t\tprops = {\n\t\t\t\tmessage: 'errors.server-connection-failed',\n\t\t\t};\n\t\t\tbreak;\n\t\tcase error instanceof mongoose.Error.ValidationError:\n\t\t\tprops = {\n\t\t\t\tmessage: Object.values(error.errors)\n\t\t\t\t\t.map((e) => e.message)\n\t\t\t\t\t.join(' ') as LocaleKey,\n\t\t\t};\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprops = {\n\t\t\t\tmessage: 'errors.something-went-wrong',\n\t\t\t};\n\t}\n\n\treturn CustomException.badRequest({\n\t\tmessage: props.message || '',\n\t\toptions: props.options,\n\t\tdebugMessage: error.message,\n\t});\n}\n",
16
+ "import type { DateRangeFilter, StringArrayFilter } from '@nxgt/shared/models';\nimport type { QueryFilter } from 'mongoose';\n\n/**\n * Helper to build MongoDB date range filter from DateRangeFilter\n * @param dateRange - The date range filter with from and to dates\n * @returns MongoDB date range filter ($gte and/or $lte)\n */\nexport function buildDateRangeFilter(dateRange: DateRangeFilter | undefined) {\n\tif (!dateRange) {\n\t\treturn undefined;\n\t}\n\n\tconst filter: any = {};\n\n\tif (dateRange.from) {\n\t\tfilter.$gte = new Date(dateRange.from);\n\t}\n\n\tif (dateRange.to) {\n\t\tfilter.$lte = new Date(dateRange.to);\n\t}\n\n\treturn Object.keys(filter).length > 0 ? filter : undefined;\n}\n\n/**\n * Helper to build MongoDB filter from ArrayFilter\n * @param arrayFilter - The array filter with values and operator\n * @returns MongoDB filter query ($in or $all)\n */\nexport function buildArrayFilter(arrayFilter?: StringArrayFilter | null) {\n\tif (!arrayFilter?.values) {\n\t\treturn undefined;\n\t}\n\n\treturn arrayFilter.operator === 'and'\n\t\t? { $all: arrayFilter.values }\n\t\t: arrayFilter.values;\n}\n\n/**\n * Helper to add a filter condition to a query object\n */\nexport function addFilterCondition(\n\tquery: QueryFilter<any>,\n\tfield: string,\n\tcondition: any,\n): void {\n\tif (condition) {\n\t\tquery[field] = condition;\n\t}\n}\n\n/**\n * Escape the characters that would otherwise be read as regex syntax\n */\nfunction escapeRegex(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Helper to build a case-insensitive substring match from a search term\n *\n * Returns the bare condition, like every other builder here — it is\n * `addFilterCondition` that keys it by field. Returning `{ [field]: … }` had it\n * keyed twice, so Mongoose saw `{ username: { username: { $regex } } }` and\n * threw a CastError on every user search.\n *\n * The term reaches this from a request body, so it is escaped rather than\n * compiled as written: unescaped, a caller can hand the database a\n * catastrophically backtracking pattern.\n *\n * @param value - The search term, as the caller typed it\n * @returns MongoDB regex condition ($regex and $options), or undefined\n */\nexport function buildRegexFilter(value: string | undefined) {\n\tif (value) {\n\t\treturn { $regex: escapeRegex(value), $options: 'i' };\n\t}\n\treturn undefined;\n}\n",
17
+ "import type { ListStringPatch } from '@nxgt/shared/models';\nimport { CustomException } from '@nxgt/shared-exceptions';\nimport { logger } from '@nxgt/shared-logging';\nimport { isNil } from 'lodash';\nimport type { Model, PipelineStage, QueryFilter, UpdateQuery } from 'mongoose';\nimport mongoose from 'mongoose';\nimport type { Populated } from './models';\nimport { isValidObjectID } from './object-id.utils';\n\n/** Whether `name` currently exists as a *view* rather than as a collection. */\nasync function isView(name: string): Promise<boolean> {\n\tconst db = mongoose.connection.db;\n\tif (!db) return false;\n\n\tconst [existing] = await db.listCollections({ name }).toArray();\n\treturn existing?.type === 'view';\n}\n\n/**\n * (Re)creates `viewModel`'s namespace as a MongoDB view over `model`.\n *\n * The drop-then-create is retried because it races the view model's own\n * `autoCreate`/`autoIndex`: Mongoose materialises the namespace as an ordinary\n * collection when it initialises the model, and if that lands between the drop\n * and the create, the create fails with `NamespaceExists` and the app is left\n * querying an empty collection that will never return a row. It only shows up\n * on a *fresh* database — an existing one already has the view — which is\n * exactly when nobody is watching, so the result is verified rather than\n * assumed, and a definitive failure is logged loudly instead of silently.\n */\nexport async function safeCreateView<T, R>(\n\tmodel: Model<T, any, any, any, any, any, any>,\n\tviewModel: Model<R, any, any, any, any, any, any>,\n\tpipeline: PipelineStage[] = [],\n\tattempts = 3,\n) {\n\ttry {\n\t\tawait model.createCollection();\n\t} catch (error) {\n\t\tlogger.error(\n\t\t\t`Error creating collection for model ${model.modelName}:`,\n\t\t\terror,\n\t\t);\n\t}\n\tconst viewName = viewModel.collection.name;\n\n\tfor (let attempt = 1; attempt <= attempts; attempt++) {\n\t\ttry {\n\t\t\tawait mongoose.connection.dropCollection(viewName);\n\t\t\tlogger.info(`Dropped existing view for model ${viewModel.modelName}`);\n\t\t} catch (error) {\n\t\t\t// Nothing to drop on a fresh database — expected, not a failure.\n\t\t\tlogger.debug(\n\t\t\t\t`No existing namespace to drop for model ${viewModel.modelName}: ${error}`,\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tawait viewModel.createCollection({\n\t\t\t\tviewOn: model.collection.name,\n\t\t\t\tpipeline,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`Error creating view for model ${viewModel.modelName}:`,\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\n\t\tif (await isView(viewName)) return;\n\n\t\tlogger.warn(\n\t\t\t`${viewName} is not a view after attempt ${attempt}/${attempts} — retrying`,\n\t\t);\n\n\t\t// Back off before trying again: the competing `autoCreate` is a single\n\t\t// round trip, and retrying inside it would just lose the same race at\n\t\t// the same point. 50ms, 100ms — short enough not to delay boot.\n\t\tif (attempt < attempts) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, attempt * 50));\n\t\t}\n\t}\n\n\tlogger.error(\n\t\t`Failed to create view ${viewName} for model ${viewModel.modelName}: it exists as a plain collection, so every query through it will come back empty.`,\n\t);\n}\n\n/**\n * Resolves a list patch against the values a document already holds and\n * returns the whole resulting list.\n *\n * Use this from `buildUpdateData`. Its sibling `buildListStringPatch` returns\n * MongoDB update operators, which only mean anything to `findOneAndUpdate` —\n * `MongoCrudService.update()` assigns onto a document and calls `save()`, where\n * a key named `$addToSet` is an unknown property Mongoose drops without a\n * word. An `add` then looked applied and changed nothing.\n *\n * Ids are validated against `model` exactly like the operator builder does, so\n * an unknown id is dropped rather than stored.\n *\n * @param current - The list the document holds today; populated docs, raw ids or ObjectIds all work.\n * @param model - The Mongoose model of the items in the list.\n * @param value - The add / remove / replace patch, if the caller sent one.\n * @param filter - Extra conditions the referenced items must satisfy.\n * @returns The resulting list of ids, or undefined when there is nothing to change.\n */\n/**\n * Applies a list patch to a plain list of strings.\n *\n * Synchronous, and therefore purely syntactic: unlike\n * {@link resolveListStringPatch} it does not ask the database whether the ids\n * exist, so an unknown id survives here where the async one drops it. Use this\n * when the caller has already established what the ids are.\n */\nexport function patchListString(\n\tlist: string[] = [],\n\tpatch?: ListStringPatch | null,\n) {\n\tif (!patch) {\n\t\treturn list;\n\t}\n\tconst add = patch.add ?? [];\n\tconst remove = patch.remove ?? [];\n\tconst replace = patch.replace ?? [];\n\tlet result = [...list, ...add];\n\tresult = result.filter((item) => !remove.includes(item));\n\tif (replace.length) {\n\t\tresult = replace;\n\t}\n\treturn Array.from(new Set(result));\n}\n\n/** {@link patchListString} over a path holding ObjectIds or populated docs. */\nexport function patchListObjectId(\n\tlist: mongoose.Types.ObjectId[] | Populated<any>[] = [],\n\tpatch?: ListStringPatch | null,\n) {\n\tconst values = list.map((item) =>\n\t\titem instanceof mongoose.Types.ObjectId\n\t\t\t? item.toHexString()\n\t\t\t: item._id.toHexString(),\n\t);\n\treturn patchListString(values, patch)\n\t\t.filter(isValidObjectID)\n\t\t.map((id) => new mongoose.Types.ObjectId(id));\n}\n\nexport async function resolveListStringPatch<T>(\n\tcurrent: unknown,\n\tmodel: Model<T, any, any, any, any, any, any>,\n\tvalue?: ListStringPatch,\n\tfilter: QueryFilter<T> = {},\n): Promise<string[] | undefined> {\n\tif (\n\t\t!value?.replace?.length &&\n\t\t!value?.add?.length &&\n\t\t!value?.remove?.length\n\t) {\n\t\treturn undefined;\n\t}\n\n\t// ListStringPatch's fields are nullable, so null reaches here as well as\n\t// undefined; the length guard below answers for both.\n\tconst idsOf = async (ids?: string[] | null) =>\n\t\tids?.length\n\t\t\t? (await model.find({ _id: ids, ...filter }).exec()).map(\n\t\t\t\t\t(item: { _id: unknown }) => String(item._id),\n\t\t\t\t)\n\t\t\t: [];\n\n\tif (value.replace?.length) {\n\t\treturn idsOf(value.replace);\n\t}\n\n\t// An autopopulated path holds documents rather than ids, so read through\n\t// whatever shape is there instead of assuming one.\n\tconst held = (Array.isArray(current) ? current : []).map((item) =>\n\t\tString((item as { _id?: unknown })?._id ?? item),\n\t);\n\tconst removed = new Set(value.remove ?? []);\n\n\treturn [\n\t\t...new Set([\n\t\t\t...held.filter((id) => !removed.has(id)),\n\t\t\t...(await idsOf(value.add)),\n\t\t]),\n\t];\n}\n\n/**\n * Builds a MongoDB update query for adding, removing, or replacing items in a list of strings.\n *\n * Only usable through `findOneAndUpdate` and friends — see\n * `resolveListStringPatch` for the document-assignment path.\n *\n * @param _source - The Mongoose model of the source document.\n * @param path - The path of the list field to be updated.\n * @param model - The Mongoose model of the items in the list.\n * @param value - An object containing arrays of strings to add, remove, or replace.\n * @param filter - An optional filter to apply when validating the existence of items to be added, removed, or replaced.\n * @returns An update query object for MongoDB.\n */\nexport async function buildListStringPatch<T, S>(\n\t_source: Model<S, any, any, any, any, any, any>,\n\tpath: keyof S,\n\tmodel: Model<T, any, any, any, any, any, any>,\n\tvalue?: ListStringPatch,\n\tfilter: QueryFilter<T> = {},\n): Promise<UpdateQuery<S>> {\n\tconst add = value?.add?.length\n\t\t? (\n\t\t\t\tawait model\n\t\t\t\t\t.find({\n\t\t\t\t\t\t_id: value.add,\n\t\t\t\t\t\t...filter,\n\t\t\t\t\t})\n\t\t\t\t\t.exec()\n\t\t\t).map((item: { _id: unknown }) => item._id)\n\t\t: [];\n\tconst remove = value?.remove?.length\n\t\t? (\n\t\t\t\tawait model\n\t\t\t\t\t.find({\n\t\t\t\t\t\t_id: value.remove,\n\t\t\t\t\t\t...filter,\n\t\t\t\t\t})\n\t\t\t\t\t.exec()\n\t\t\t).map((item: { _id: unknown }) => item._id)\n\t\t: [];\n\tconst replace = value?.replace?.length\n\t\t? (\n\t\t\t\tawait model\n\t\t\t\t\t.find({\n\t\t\t\t\t\t_id: value.replace,\n\t\t\t\t\t\t...filter,\n\t\t\t\t\t})\n\t\t\t\t\t.exec()\n\t\t\t).map((item: { _id: unknown }) => item._id)\n\t\t: [];\n\treturn {\n\t\t...(value?.add?.length && {\n\t\t\t$addToSet: {\n\t\t\t\t[path]: {\n\t\t\t\t\t$each: add,\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\t...(value?.remove?.length && {\n\t\t\t$pullAll: {\n\t\t\t\t[path]: remove,\n\t\t\t},\n\t\t}),\n\t\t...(value?.replace?.length && {\n\t\t\t[path]: replace,\n\t\t}),\n\t} as UpdateQuery<S>;\n}\n\n/**\n * Builds a MongoDB update query for adding, removing, or replacing items in a list of strings.\n *\n * @param path - The path of the list field to be updated.\n * @param value - An object containing arrays of strings to add, remove, or replace.\n * @returns An update query object for MongoDB.\n */\nexport async function buildListStringPatchUpdate<T>(\n\tpath: keyof T,\n\tvalue?: ListStringPatch,\n): Promise<UpdateQuery<T>> {\n\tconst add = value?.add ?? [];\n\tconst remove = value?.remove ?? [];\n\tconst replace = value?.replace ?? [];\n\treturn {\n\t\t...(add.length && {\n\t\t\t$addToSet: {\n\t\t\t\t[path]: {\n\t\t\t\t\t$each: add,\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\t...(remove.length && {\n\t\t\t$pullAll: {\n\t\t\t\t[path]: remove,\n\t\t\t},\n\t\t}),\n\t\t...(replace.length && {\n\t\t\t[path]: replace,\n\t\t}),\n\t} as UpdateQuery<T>;\n}\n\nexport function checkVersion(modelVersion: number, version?: number) {\n\tif (isNil(version)) {\n\t\treturn;\n\t}\n\tif (modelVersion !== version) {\n\t\tthrow CustomException.badRequest({\n\t\t\tmessage: 'errors.optimistic-lock-failed',\n\t\t});\n\t}\n}\n",
18
+ "import mongoose, { Types } from 'mongoose';\n\nexport function objectIdString() {\n\treturn new mongoose.mongo.ObjectId().toHexString();\n}\n\nexport function toObjectId(id: string) {\n\treturn new Types.ObjectId(id);\n}\n\nexport function toObjectIds(ids: string[]) {\n\treturn ids.map(toObjectId);\n}\n\nexport function isValidObjectID(id: string | Types.ObjectId) {\n\treturn Types.ObjectId.isValid(id);\n}\n\nexport function validObjectIds(ids?: string[] | null) {\n\treturn ids?.filter(isValidObjectID);\n}\n\n/**\n * sellix-monorepo's name for {@link toObjectId}.\n *\n * It answered a `mongoose.mongo.ObjectId` (the BSON driver's class) where\n * `toObjectId` answers a `Types.ObjectId` (Mongoose's own). The two are\n * interchangeable everywhere either was used, so this is an alias rather than\n * a second implementation.\n */\nexport function objectIdFromString(id: string) {\n\treturn toObjectId(id);\n}\n",
19
+ "import { omit } from 'lodash';\nimport type { Document } from 'mongoose';\n\nexport const toObject = <T>(\n\tdoc: Document<T> | null,\n\t...omitFields: string[]\n) => {\n\tif (!doc) return null;\n\treturn {\n\t\t...omit(doc.toObject({ getters: true, virtuals: true, versionKey: true }), [\n\t\t\t'_id',\n\t\t\t...omitFields,\n\t\t]),\n\t} as any;\n};\n\nexport const toObjects = <T>(docs: Document<T>[], ...omitFields: string[]) =>\n\tdocs.map((doc) => toObject(doc, ...omitFields));\n",
20
+ "import type { Schema } from 'mongoose';\nimport autopopulate from 'mongoose-autopopulate';\nimport leanVirtuals from 'mongoose-lean-virtuals';\nimport { errors } from './errors';\nimport { pagination } from './pagination';\nimport { shared } from './shared';\n\nexport const MONGOOSE_PLUGINS = {\n\tshared,\n\terrors,\n\tpagination,\n\tleanVirtuals,\n\tautopopulate,\n};\n\nexport function applyPlugins(schema: Schema, plugins: any[]) {\n\tplugins.forEach((plugin) => {\n\t\tschema.plugin(plugin);\n\t});\n}\n\nexport * from './consts';\nexport * from './pagination/types';\n",
21
+ "import { CustomException } from '@nxgt/shared-exceptions';\nimport type { Schema } from 'mongoose';\nimport { castError } from '../utils/error.utils';\n\nexport const errors = (schema: Schema) => {\n\tschema.post(\n\t\t[\n\t\t\t'save',\n\t\t\t'deleteOne',\n\t\t\t'findOneAndDelete',\n\t\t\t'updateOne',\n\t\t\t'findOneAndUpdate',\n\t\t\t'replaceOne',\n\t\t\t'findOneAndReplace',\n\t\t\t'findOne',\n\t\t\t'countDocuments',\n\t\t],\n\t\t(error: any, _: any, next: any) => {\n\t\t\tif (error) {\n\t\t\t\tif (error.name === 'MongoServerError' && error.code === 11000) {\n\t\t\t\t\tnext(\n\t\t\t\t\t\tCustomException.badRequest({\n\t\t\t\t\t\t\tmessage: 'errors.duplicate-key',\n\t\t\t\t\t\t\tdebugMessage: error.message,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tnext(castError(error));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnext();\n\t\t\t}\n\t\t},\n\t);\n};\n",
22
+ "import { type LocaleKey, translate } from '@nxgt/i18n';\nimport { CustomException, ErrorCode } from '@nxgt/shared-exceptions';\nimport { has } from 'lodash';\nimport type { Schema } from 'mongoose';\nimport mongoose from 'mongoose';\n\nexport function applySharedOperations(schema: Schema) {\n\tschema.static('ensureExists', async function () {\n\t\tconst result = await mongoose.Model.exists\n\t\t\t.apply(this, [arguments?.[0] ?? {}])\n\t\t\t.exec();\n\n\t\tif (!result) {\n\t\t\tconst localeKey = `${this.collection.collectionName}.errors.not-found`;\n\t\t\tthrow CustomException.notFound({\n\t\t\t\tmessage:\n\t\t\t\t\targuments?.[1]?.message ??\n\t\t\t\t\t(translate(localeKey as LocaleKey) === localeKey\n\t\t\t\t\t\t? 'errors.not-found'\n\t\t\t\t\t\t: localeKey),\n\t\t\t\toptions: arguments?.[1]?.options,\n\t\t\t});\n\t\t}\n\t});\n\n\tschema.static('requireById', async function () {\n\t\ttry {\n\t\t\tconst doc = await mongoose.Model.findById\n\t\t\t\t.apply(this, [arguments?.[0] ?? {}])\n\t\t\t\t.exec();\n\t\t\tif (!doc) {\n\t\t\t\tconst localeKey = `${this.collection.collectionName}.errors.not-found`;\n\t\t\t\tthrow CustomException.notFound({\n\t\t\t\t\tmessage:\n\t\t\t\t\t\targuments?.[1]?.message ??\n\t\t\t\t\t\t(translate(localeKey as LocaleKey) === localeKey\n\t\t\t\t\t\t\t? 'errors.not-found'\n\t\t\t\t\t\t\t: localeKey),\n\t\t\t\t\toptions: arguments?.[1]?.options,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn doc;\n\t\t} catch (error: any) {\n\t\t\t// Without this the CustomException.notFound thrown just above is\n\t\t\t// caught here and re-wrapped as a 400 — nxgt-federation dropped the\n\t\t\t// guard in the same change that added the throw.\n\t\t\tif (error instanceof CustomException) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow CustomException.from({\n\t\t\t\tmessage: arguments?.[1]?.message ?? error?.message,\n\t\t\t\tcode: arguments?.[1]?.code ?? ErrorCode.BadRequest,\n\t\t\t\tdebugMessage: translate((error as Error).message as LocaleKey),\n\t\t\t});\n\t\t}\n\t});\n\n\tif (schema.options.versionKey) {\n\t\tschema.pre(['findOneAndUpdate'], async function () {\n\t\t\tconst update = this.getUpdate() as any;\n\t\t\tif (!update) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (has(update, 'version')) {\n\t\t\t\tdelete update.version;\n\t\t\t}\n\t\t\tconst keys = ['$set', '$setOnInsert'];\n\t\t\tfor (const key of keys) {\n\t\t\t\tif (update[key] != null && update[key].version != null) {\n\t\t\t\t\tdelete update[key].version;\n\t\t\t\t\tif (Object.keys(update[key]).length === 0) {\n\t\t\t\t\t\tdelete update[key];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tupdate.$inc = update.$inc || {};\n\t\t\tupdate.$inc.version = 1;\n\t\t});\n\t}\n}\n",
23
+ "import type { Schema } from 'mongoose';\nimport { applySharedOperations } from './shared';\n\nexport function shared(schema: Schema) {\n\tapplySharedOperations(schema);\n}\n",
24
+ "export const PLUGIN_OPTIONS = {\n\tautopopulate: { maxDepth: 1 },\n};\n",
25
+ "import { auditChanges } from '../audit';\nimport { applyPlugins } from '../plugins';\nimport { castError } from './error.utils';\n\nimport * as helpers from './helpers';\nimport * as mappers from './mappers';\n\nexport const MONGO_UTILS = {\n\tapplyPlugins,\n\tcastError,\n\tauditChanges,\n\t...mappers,\n\t...helpers,\n\ttimestamps: { createdAt: 'createdDate', updatedAt: 'lastModifiedDate' },\n\tcoreOptions: {\n\t\ttoObject: { virtuals: true, versionKey: true },\n\t\ttoJSON: { virtuals: true, versionKey: true },\n\t\ttimestamps: { createdAt: 'createdDate', updatedAt: 'lastModifiedDate' },\n\t\tversionKey: 'version',\n\t\toptimisticConcurrency: true,\n\t},\n\tauditPipeline: [\n\t\t{\n\t\t\t$match: {\n\t\t\t\toperationType: { $in: ['insert', 'update', 'replace', 'delete'] },\n\t\t\t},\n\t\t},\n\t],\n};\n",
26
+ "import type { HydratedDocument } from 'mongoose';\nimport type { IConnection, NestedPaginationOptions } from '../models';\nimport { paginateListData } from '../plugins/pagination/utils';\n\nexport function paginateList<T extends HydratedDocument<{ id: string }>>(\n\tdocs: T[],\n\toptions: NestedPaginationOptions,\n): IConnection<T> {\n\treturn paginateListData(docs, options);\n}\n",
27
+ "/**\n * Sort building lives in `@nxgt/shared`, one layer down, because it is plain\n * object work with no Mongoose in it. Re-exported here because that is where\n * sellix-monorepo imported it from.\n *\n * `SortOrder` is deliberately not re-exported: Mongoose exports a type of that\n * name and this package re-exports Mongoose wholesale, so forwarding ours too\n * makes the root ambiguous and `tsc` drops both. Import `SortOrder` from\n * `@nxgt/shared`; `SortDirection` here is the same enum.\n */\nexport { buildSort, SortDirection, type SortField } from '@nxgt/shared/helpers';\n",
28
+ "import { castAsync } from '@nxgt/shared/helpers';\nimport type { QueryFilter } from 'mongoose';\nimport type { IConnection, PaginationOptions } from '../models';\nimport { type Audit, type AuditDocument, AuditModel } from './audit.model';\nimport type { Change } from './audit.types';\n\nexport class AuditService {\n\tprivate model = AuditModel;\n\n\tasync findChangesPaginated<T>(options: PaginationOptions) {\n\t\treturn castAsync<IConnection<Change<T>>>(this.model.paginate(options));\n\t}\n\n\tfindChangesPaginatedByCollectionAndOid<T>(\n\t\toid: string,\n\t\tcollection: string,\n\t\toptions: PaginationOptions,\n\t) {\n\t\tconst collectionFilter: QueryFilter<AuditDocument> = {\n\t\t\tglobalId: { $regex: `^${collection}/${oid}$` },\n\t\t};\n\t\tconst filter: QueryFilter<AuditDocument> = options.filter\n\t\t\t? {\n\t\t\t\t\t$and: [collectionFilter, options.filter],\n\t\t\t\t}\n\t\t\t: collectionFilter;\n\t\treturn this.findChangesPaginated<T>({ ...options, filter });\n\t}\n\n\tfindChangesPaginatedByCollection<T>(\n\t\tcollection: string,\n\t\toptions: PaginationOptions,\n\t) {\n\t\tconst collectionFilter: QueryFilter<AuditDocument> = {\n\t\t\tglobalId: { $regex: `^${collection}/` },\n\t\t};\n\t\tconst filter: QueryFilter<AuditDocument> = options.filter\n\t\t\t? {\n\t\t\t\t\t$and: [collectionFilter, options.filter],\n\t\t\t\t}\n\t\t\t: collectionFilter;\n\t\treturn this.findChangesPaginated<T>({ ...options, filter });\n\t}\n\n\tasync findChanges<T>(filter: QueryFilter<AuditDocument> = {}) {\n\t\treturn this.model.find<Change<T>>(filter ?? {});\n\t}\n\n\tmatches(audit: Audit, filter: { collection: string; type?: string }) {\n\t\treturn (\n\t\t\taudit.globalId.startsWith(`${filter.collection}/`) &&\n\t\t\t(filter.type ? filter.type === audit.type : true)\n\t\t);\n\t}\n\n\textractId(audit: Audit) {\n\t\treturn audit.globalId.split('/')[1];\n\t}\n}\n",
29
+ "import type { LocaleKey } from '@nxgt/i18n';\nimport { CustomException } from '@nxgt/shared-exceptions';\nimport type {\n\tBlockerOption,\n\tCascadeOption,\n\tRegisterBlockerOptions,\n\tRegisterCascadeOptions,\n} from './integrity.types';\n\nexport class IntegrityRegistry {\n\tprivate blockers = new Map<string, BlockerOption[]>();\n\tprivate cascades = new Map<string, CascadeOption[]>();\n\n\t/**\n\t * Register a check that blocks deletion of a target model.\n\t * Safe to call multiple times — deduplicated by `id`.\n\t *\n\t * @param options.id - Unique identifier for this blocker\n\t * @param options.model - Mongoose model name to guard (e.g. `RoleModel.name`)\n\t * @param options.errorCode - i18n key thrown when the blocker is triggered\n\t * @param options.blocker - Function returning the count of referencing documents\n\t */\n\tregisterBlocker(options: RegisterBlockerOptions) {\n\t\tconst { id, model, errorCode, blocker } = options;\n\t\tconst current = this.blockers.get(model) ?? [];\n\t\tif (current.some((it) => it.id === id)) return;\n\t\tcurrent.push({ id, fn: blocker, errorCode });\n\t\tthis.blockers.set(model, current);\n\t}\n\n\t/**\n\t * Register a cascade cleanup executed **inside** the deletion transaction.\n\t * Safe to call multiple times — deduplicated by `id`.\n\t *\n\t * @param options.id - Unique identifier for this cascade\n\t * @param options.model - Mongoose model name of the parent being deleted\n\t * @param options.cascade - Cleanup function (runs inside MongoDB transaction)\n\t */\n\tregisterCascade(options: RegisterCascadeOptions) {\n\t\tconst { id, model, cascade } = options;\n\t\tconst current = this.cascades.get(model) ?? [];\n\t\tif (current.some((it) => it.id === id)) return;\n\t\tcurrent.push({ id, fn: cascade });\n\t\tthis.cascades.set(model, current);\n\t}\n\n\t/**\n\t * Run all registered blockers for a model in parallel and throw if any\n\t * referencing documents are found. All failing constraints are collected\n\t * before throwing so the caller sees the full picture at once.\n\t */\n\tasync validateDeletion(model: string, ids: string[]): Promise<void> {\n\t\tconst collectionBlockers = this.blockers.get(model) ?? [];\n\n\t\tconst results = await Promise.all(\n\t\t\tcollectionBlockers.map(async ({ fn, errorCode }) => {\n\t\t\t\tconst count = await fn(ids);\n\t\t\t\treturn count > 0 ? errorCode : null;\n\t\t\t}),\n\t\t);\n\n\t\tconst failures = results.filter(Boolean) as string[];\n\t\tif (failures.length > 0) {\n\t\t\tthrow CustomException.conflict({\n\t\t\t\tmessage: failures[0] as LocaleKey,\n\t\t\t\toptions: { ids, blockedBy: failures },\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Execute all registered cascade handlers for a model in parallel.\n\t * Called inside `runWithChangesListening` so everything runs within\n\t * the same MongoDB transaction.\n\t */\n\tasync runCascades(model: string, ids: string[]): Promise<void> {\n\t\tconst handlers = this.cascades.get(model) ?? [];\n\t\tawait Promise.all(handlers.map(({ fn }) => fn(ids)));\n\t}\n}\n\nexport const integrityRegistry = new IntegrityRegistry();\n",
30
+ "import { mongoose } from '../mongoose';\n\n/**\n * Errors mongodb 7 raises while interrupting still-checked-out sockets during\n * `MongoClient.close()` — typically an in-flight replica-set heartbeat.\n * They are not a failed command; they escape `disconnect()` as an\n * `uncaughtException` / `unhandledRejection` that Bun otherwise prints.\n */\nfunction isTeardownError(err: unknown): boolean {\n\tconst name =\n\t\ttypeof err === 'object' && err !== null && 'name' in err\n\t\t\t? String(err.name)\n\t\t\t: '';\n\tconst message = err instanceof Error ? err.message : String(err);\n\treturn (\n\t\tname === 'MongoClientClosedError' ||\n\t\tname === 'MongoPoolClosedError' ||\n\t\tmessage.includes('client was closed') ||\n\t\tmessage.includes('closed connection pool')\n\t);\n}\n\nfunction ignoreTeardownError(err: unknown): void {\n\tif (!isTeardownError(err)) {\n\t\tthrow err;\n\t}\n}\n\n/**\n * Close the default mongoose connection without surfacing mongodb 7's\n * teardown noise. Used by the programmatic `migrate()` / `withMigrationRunner`\n * helpers, which must actually drop the connection (a CLI can just\n * `process.exit`).\n */\nexport async function disconnectQuietly(): Promise<void> {\n\tprocess.on('uncaughtException', ignoreTeardownError);\n\tprocess.on('unhandledRejection', ignoreTeardownError);\n\ttry {\n\t\tawait mongoose.disconnect().catch(ignoreTeardownError);\n\t\t// PoolClosedError can land on the next turn, after close() has resolved.\n\t\tawait new Promise<void>((resolve) => setImmediate(resolve));\n\t} finally {\n\t\tprocess.off('uncaughtException', ignoreTeardownError);\n\t\tprocess.off('unhandledRejection', ignoreTeardownError);\n\t}\n}\n",
31
+ "import { Mutex } from 'async-mutex';\nimport { MigrationModel } from './migration.model';\nimport type {\n\tMigrationDefinition,\n\tMigrationListEntry,\n\tMigrationRunnerOptions,\n\tRunDownOptions,\n\tRunUpOptions,\n} from './migration.types';\nimport {\n\tcreateMigrationFile,\n\tloadMigrationFiles,\n\tlogger,\n\tsortMigrationsAsc,\n\tsortMigrationsDesc,\n} from './migration.utils';\n\nconst mutex = new Mutex();\n\n// ─── Runner ───────────────────────────────────────────────────────────────────\n\n/**\n * `MigrationRunner` manages the full lifecycle of database migrations:\n *\n * - `up()` — run all pending migrations, or a specific one by name\n * - `down()` — rollback the last batch, or a specific migration by name\n * - `list()` — return every known migration with its current status\n * - `create()` — generate a new migration file\n *\n * A `Mutex` ensures that concurrent invocations within the same process are\n * serialised; for multi-process safety you should use an external lock\n * (e.g. a MongoDB distributed lock) in front of the runner.\n */\nexport class MigrationRunner {\n\tprivate readonly migrationsDir: string;\n\tprivate readonly connection: MigrationRunnerOptions['connection'];\n\n\tconstructor(options: MigrationRunnerOptions) {\n\t\tthis.migrationsDir = options.migrationsDir;\n\t\tthis.connection = options.connection;\n\t}\n\n\t// ─── Public API ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Run all pending migrations in ascending timestamp order.\n\t */\n\tasync up(options?: RunUpOptions): Promise<void> {\n\t\tawait mutex.runExclusive(async () => {\n\t\t\tconst allMigrations = await loadMigrationFiles(this.migrationsDir);\n\n\t\t\tif (options?.name) {\n\t\t\t\tawait this.runSpecificUp(allMigrations, options.name, options.dryRun);\n\t\t\t} else {\n\t\t\t\tawait this.runPendingUp(allMigrations, options?.dryRun);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Rollback the last batch of migrations in descending timestamp order.\n\t */\n\tasync down(options?: RunDownOptions): Promise<void> {\n\t\tawait mutex.runExclusive(async () => {\n\t\t\tconst allMigrations = await loadMigrationFiles(this.migrationsDir);\n\n\t\t\tif (options?.name) {\n\t\t\t\tawait this.runSpecificDown(allMigrations, options.name, options.dryRun);\n\t\t\t} else {\n\t\t\t\tawait this.runLastBatchDown(allMigrations, options?.dryRun);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new migration file.\n\t */\n\tasync create(options: { name: string }): Promise<string> {\n\t\tconst filePath = await createMigrationFile(\n\t\t\tthis.migrationsDir,\n\t\t\toptions.name,\n\t\t);\n\t\tlogger.info(`created migration: ${filePath}`);\n\t\treturn filePath;\n\t}\n\n\t/**\n\t * Returns every migration file found in `migrationsDir` combined with its\n\t * persisted status from the database.\n\t */\n\tasync list(): Promise<MigrationListEntry[]> {\n\t\tconst [allMigrations, records] = await Promise.all([\n\t\t\tloadMigrationFiles(this.migrationsDir),\n\t\t\tMigrationModel.find({}).sort({ name: 1 }).lean().exec(),\n\t\t]);\n\n\t\tconst recordByName = new Map(records.map((r) => [r.name, r]));\n\n\t\treturn sortMigrationsAsc(allMigrations).map((migration) => {\n\t\t\tconst record = recordByName.get(migration.name);\n\t\t\tif (!record) {\n\t\t\t\treturn {\n\t\t\t\t\tname: migration.name,\n\t\t\t\t\tstatus: 'pending',\n\t\t\t\t} satisfies MigrationListEntry;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tname: record.name,\n\t\t\t\tstatus: record.status,\n\t\t\t\tbatch: record.batch,\n\t\t\t\texecutedAt: record.executedAt,\n\t\t\t} satisfies MigrationListEntry;\n\t\t});\n\t}\n\n\t// ─── Up helpers ───────────────────────────────────────────────────────────\n\n\tprivate async runPendingUp(\n\t\tallMigrations: MigrationDefinition[],\n\t\tdryRun?: boolean,\n\t): Promise<void> {\n\t\tconst executedNames = await this.fetchExecutedNames();\n\t\tconst pending = sortMigrationsAsc(allMigrations).filter(\n\t\t\t(m) => !executedNames.has(m.name),\n\t\t);\n\n\t\tif (pending.length === 0) {\n\t\t\tlogger.info('no pending migrations');\n\t\t\treturn;\n\t\t}\n\n\t\tif (dryRun) {\n\t\t\tlogger.info(`[DRY RUN] pending migrations to run: ${pending.length}`);\n\t\t\tfor (const m of pending) logger.info(`[DRY RUN] → ${m.name}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst batch = await this.nextBatchNumber();\n\n\t\tfor (const migration of pending) {\n\t\t\tawait this.executeMigrationUp(migration, batch);\n\t\t}\n\t}\n\n\tprivate async runSpecificUp(\n\t\tallMigrations: MigrationDefinition[],\n\t\tname: string,\n\t\tdryRun?: boolean,\n\t): Promise<void> {\n\t\tconst migration = allMigrations.find((m) => m.name === name);\n\t\tif (!migration) {\n\t\t\tthrow new Error(`migrations.errors.not-found: ${name}`);\n\t\t}\n\n\t\tif (dryRun) {\n\t\t\tlogger.info(`[DRY RUN] specific migration to run: ${migration.name}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst batch = await this.nextBatchNumber();\n\t\tawait this.executeMigrationUp(migration, batch);\n\t}\n\n\tprivate async executeMigrationUp(\n\t\tmigration: MigrationDefinition,\n\t\tbatch: number,\n\t): Promise<void> {\n\t\tlogger.info(`running up → ${migration.name}`);\n\t\tconst start = Date.now();\n\n\t\tconst session = await this.connection.startSession();\n\n\t\ttry {\n\t\t\tawait session.withTransaction(async () => {\n\t\t\t\tawait migration.up(this.connection, session);\n\n\t\t\t\tconst duration = Date.now() - start;\n\n\t\t\t\tawait MigrationModel.findOneAndUpdate(\n\t\t\t\t\t{ name: migration.name },\n\t\t\t\t\t{\n\t\t\t\t\t\tname: migration.name,\n\t\t\t\t\t\tbatch,\n\t\t\t\t\t\tstatus: 'up',\n\t\t\t\t\t\texecutedAt: new Date(),\n\t\t\t\t\t\tduration,\n\t\t\t\t\t\terror: undefined,\n\t\t\t\t\t},\n\t\t\t\t\t{ upsert: true, returnDocument: 'after', session },\n\t\t\t\t).exec();\n\t\t\t});\n\n\t\t\tconst duration = Date.now() - start;\n\t\t\tlogger.info(`✓ ${migration.name} (${duration}ms)`);\n\t\t} catch (err) {\n\t\t\tconst duration = Date.now() - start;\n\t\t\tconst errorMessage = err instanceof Error ? err.message : String(err);\n\n\t\t\tawait MigrationModel.findOneAndUpdate(\n\t\t\t\t{ name: migration.name },\n\t\t\t\t{\n\t\t\t\t\tname: migration.name,\n\t\t\t\t\tbatch,\n\t\t\t\t\tstatus: 'failed',\n\t\t\t\t\texecutedAt: new Date(),\n\t\t\t\t\tduration,\n\t\t\t\t\terror: errorMessage,\n\t\t\t\t},\n\t\t\t\t{ upsert: true, returnDocument: 'after' },\n\t\t\t).exec();\n\n\t\t\tlogger.error(`✗ ${migration.name} — ${errorMessage}`);\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tawait session.endSession();\n\t\t}\n\t}\n\n\t// ─── Down helpers ─────────────────────────────────────────────────────────\n\n\tprivate async runLastBatchDown(\n\t\tallMigrations: MigrationDefinition[],\n\t\tdryRun?: boolean,\n\t): Promise<void> {\n\t\tconst lastBatch = await this.fetchLastBatch();\n\t\tif (lastBatch === null) {\n\t\t\tlogger.info('nothing to roll back');\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastBatchRecords = await MigrationModel.find({ batch: lastBatch })\n\t\t\t.sort({ name: -1 })\n\t\t\t.lean()\n\t\t\t.exec();\n\n\t\tconst migrationByName = new Map(allMigrations.map((m) => [m.name, m]));\n\t\tconst toRollback = lastBatchRecords\n\t\t\t.map((r) => migrationByName.get(r.name))\n\t\t\t.filter((m): m is MigrationDefinition => m !== undefined);\n\n\t\tif (dryRun) {\n\t\t\tlogger.info(`[DRY RUN] migrations to roll back (batch ${lastBatch}):`);\n\t\t\tfor (const m of sortMigrationsDesc(toRollback))\n\t\t\t\tlogger.info(`[DRY RUN] → ${m.name}`);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const record of sortMigrationsDesc(toRollback)) {\n\t\t\tawait this.executeMigrationDown(record);\n\t\t}\n\t}\n\n\tprivate async runSpecificDown(\n\t\tallMigrations: MigrationDefinition[],\n\t\tname: string,\n\t\tdryRun?: boolean,\n\t): Promise<void> {\n\t\tconst migration = allMigrations.find((m) => m.name === name);\n\t\tif (!migration) {\n\t\t\tthrow new Error(`migrations.errors.not-found: ${name}`);\n\t\t}\n\n\t\tif (dryRun) {\n\t\t\tlogger.info(\n\t\t\t\t`[DRY RUN] specific migration to roll back: ${migration.name}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.executeMigrationDown(migration);\n\t}\n\n\tprivate async executeMigrationDown(\n\t\tmigration: MigrationDefinition,\n\t): Promise<void> {\n\t\tif (!migration.down) {\n\t\t\tthrow new Error(\n\t\t\t\t`migrations.errors.missing-down-export: ${migration.name}`,\n\t\t\t);\n\t\t}\n\n\t\tlogger.info(`running down → ${migration.name}`);\n\t\tconst start = Date.now();\n\n\t\tconst session = await this.connection.startSession();\n\n\t\ttry {\n\t\t\tawait session.withTransaction(async () => {\n\t\t\t\tawait migration.down?.(this.connection, session);\n\n\t\t\t\tawait MigrationModel.deleteOne({ name: migration.name })\n\t\t\t\t\t.session(session)\n\t\t\t\t\t.exec();\n\t\t\t});\n\n\t\t\tconst duration = Date.now() - start;\n\t\t\tlogger.info(`✓ rolled back ${migration.name} (${duration}ms)`);\n\t\t} catch (err) {\n\t\t\tconst errorMessage = err instanceof Error ? err.message : String(err);\n\t\t\tlogger.error(`✗ rollback failed ${migration.name} — ${errorMessage}`);\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tawait session.endSession();\n\t\t}\n\t}\n\n\t// ─── DB helpers ───────────────────────────────────────────────────────────\n\n\tprivate async fetchExecutedNames(): Promise<Set<string>> {\n\t\tconst records = await MigrationModel.find({ status: 'up' }, { name: 1 })\n\t\t\t.lean()\n\t\t\t.exec();\n\t\treturn new Set(records.map((r) => r.name));\n\t}\n\n\tprivate async fetchLastBatch(): Promise<number | null> {\n\t\tconst record = await MigrationModel.findOne({ status: 'up' })\n\t\t\t.sort({ batch: -1 })\n\t\t\t.select('batch')\n\t\t\t.lean()\n\t\t\t.exec();\n\t\treturn record?.batch ?? null;\n\t}\n\n\tprivate async nextBatchNumber(): Promise<number> {\n\t\tconst last = await this.fetchLastBatch();\n\t\treturn (last ?? 0) + 1;\n\t}\n}\n",
32
+ "import type { HydratedDocument, Model } from 'mongoose';\nimport { model, Schema } from 'mongoose';\nimport type { MigrationRecord, MigrationStatus } from './migration.types';\n\nexport type MigrationDocument = HydratedDocument<MigrationRecord>;\n\ntype MigrationModel = Model<MigrationDocument>;\n\nconst migrationSchema = new Schema<MigrationDocument, MigrationModel>(\n\t{\n\t\tname: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t\tunique: true,\n\t\t\tindex: true,\n\t\t},\n\t\tbatch: {\n\t\t\ttype: Number,\n\t\t\trequired: true,\n\t\t},\n\t\tstatus: {\n\t\t\ttype: String,\n\t\t\tenum: ['up', 'failed'] satisfies MigrationStatus[],\n\t\t\trequired: true,\n\t\t},\n\t\texecutedAt: {\n\t\t\ttype: Date,\n\t\t\trequired: true,\n\t\t},\n\t\tduration: {\n\t\t\ttype: Number,\n\t\t\trequired: true,\n\t\t},\n\t\terror: {\n\t\t\ttype: String,\n\t\t},\n\t},\n\t{\n\t\tcollection: 'migrations',\n\t\tversionKey: false,\n\t},\n);\n\nexport const MigrationModel = model<MigrationDocument, MigrationModel>(\n\t'Migration',\n\tmigrationSchema,\n);\n",
33
+ "import { readdir, writeFile } from 'node:fs/promises';\nimport { extname, join, resolve } from 'node:path';\nimport { createLogger, type Logger } from '@nxgt/shared-logging';\nimport type { MigrationDefinition } from './migration.types';\n\nexport const logger: Logger = createLogger({ name: 'migrations' });\n\n// ─── Filename validation ──────────────────────────────────────────────────────\n\n/**\n * Valid migration filename pattern:\n * `<1-16-digit-timestamp>-<description>.ts`\n *\n * Description can contain alphanumeric characters, hyphens, and underscores.\n *\n * Examples:\n * - `20260421120000-add-user-indexes.ts`\n * - `1-initial_setup.ts`\n */\nconst MIGRATION_FILE_PATTERN = /^\\d{1,16}-[a-zA-Z0-9_-]+\\.ts$/;\n\nexport function isMigrationFile(filename: string): boolean {\n\treturn MIGRATION_FILE_PATTERN.test(filename);\n}\n\n/**\n * Extracts the migration name (filename without extension).\n * e.g. `20260421120000-add-user-indexes.ts` → `20260421120000-add-user-indexes`\n */\nexport function migrationName(filename: string): string {\n\treturn filename.slice(0, -extname(filename).length);\n}\n\n/**\n * Extracts the timestamp prefix from a migration name.\n * e.g. `20260421120000-add-user-indexes` → `20260421120000`\n * e.g. `123-abc` → `123`\n */\nexport function migrationTimestamp(name: string): string {\n\treturn name.split('-')[0] || '';\n}\n\n// ─── Sorting ──────────────────────────────────────────────────────────────────\n\n/**\n * Sorts migration definitions in ascending timestamp order (oldest first).\n * Numerical comparison of the prefix.\n */\nexport function sortMigrationsAsc(\n\tmigrations: MigrationDefinition[],\n): MigrationDefinition[] {\n\treturn [...migrations].sort((a, b) => {\n\t\tconst tsA = BigInt(migrationTimestamp(a.name));\n\t\tconst tsB = BigInt(migrationTimestamp(b.name));\n\t\tif (tsA < tsB) return -1;\n\t\tif (tsA > tsB) return 1;\n\t\treturn 0;\n\t});\n}\n\n/**\n * Sorts migration definitions in descending timestamp order (newest first).\n */\nexport function sortMigrationsDesc(\n\tmigrations: MigrationDefinition[],\n): MigrationDefinition[] {\n\treturn [...migrations].sort((a, b) => {\n\t\tconst tsA = BigInt(migrationTimestamp(a.name));\n\t\tconst tsB = BigInt(migrationTimestamp(b.name));\n\t\tif (tsA < tsB) return 1;\n\t\tif (tsA > tsB) return -1;\n\t\treturn 0;\n\t});\n}\n\n// ─── Generator ────────────────────────────────────────────────────────────────\n\n/**\n * Creates a new migration file with a 14-digit timestamp prefix and a boilerplate template.\n */\nexport async function createMigrationFile(\n\tmigrationsDir: string,\n\tdescription: string,\n): Promise<string> {\n\tconst timestamp = new Date()\n\t\t.toISOString()\n\t\t.replace(/[-T:Z]/g, '')\n\t\t.slice(0, 14);\n\n\t// Sanitize description: replace spaces with hyphens, keep only alphanumeric, underscores, and hyphens\n\tconst sanitized = description\n\t\t.toLowerCase()\n\t\t.replace(/\\s+/g, '-')\n\t\t.replace(/[^a-z0-9_-]/g, '');\n\n\tconst filename = `${timestamp}-${sanitized}.ts`;\n\tconst filePath = join(resolve(migrationsDir), filename);\n\n\tconst content = `import type { ClientSession, Connection } from 'mongoose';\n\nexport async function up(db: Connection, session?: ClientSession): Promise<void> {\n\t// TODO: Implement migration\n}\n\nexport async function down(db: Connection, session?: ClientSession): Promise<void> {\n\t// TODO: Implement rollback\n}\n`;\n\n\tawait writeFile(filePath, content, 'utf8');\n\n\t// Attempt to format with Biome if available\n\ttry {\n\t\tconst { spawnSync } = require('node:child_process');\n\t\tspawnSync('bunx', ['@biomejs/biome', 'format', '--write', filePath]);\n\t} catch {\n\t\t// Ignore if biome is not found or fails\n\t}\n\n\treturn filePath;\n}\n\n// ─── File loader ──────────────────────────────────────────────────────────────\n\n/**\n * Reads all valid migration files from `migrationsDir`, dynamically imports\n * each one, and returns an array of `MigrationDefinition` objects sorted in\n * ascending timestamp order (ready for `up()`).\n *\n * Only files matching the `<14-digit-timestamp>-<kebab-description>.ts` pattern\n * are considered. All other files (helpers, fixtures, etc.) are silently skipped.\n *\n * @throws {Error} If a migration file does not export an `up` function.\n */\nexport async function loadMigrationFiles(\n\tmigrationsDir: string,\n): Promise<MigrationDefinition[]> {\n\tconst absoluteDir = resolve(migrationsDir);\n\n\tlet filenames: string[];\n\ttry {\n\t\tfilenames = await readdir(absoluteDir);\n\t} catch {\n\t\tthrow new Error(`migrations.errors.directory-not-found: ${absoluteDir}`);\n\t}\n\n\tconst migrationFiles = filenames.filter(isMigrationFile);\n\n\tconst definitions = await Promise.all(\n\t\tmigrationFiles.map(async (filename) => {\n\t\t\tconst filePath = join(absoluteDir, filename);\n\t\t\tconst name = migrationName(filename);\n\n\t\t\tconst module = await import(filePath);\n\n\t\t\tif (typeof module.up !== 'function') {\n\t\t\t\tthrow new Error(`migrations.errors.missing-up-export: ${filename}`);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tname,\n\t\t\t\tfilePath,\n\t\t\t\tup: module.up,\n\t\t\t\tdown: typeof module.down === 'function' ? module.down : undefined,\n\t\t\t} satisfies MigrationDefinition;\n\t\t}),\n\t);\n\n\treturn sortMigrationsAsc(definitions);\n}\n",
34
+ "import { mongoose } from '../mongoose';\nimport { disconnectQuietly } from './disconnect';\nimport { MigrationRunner } from './migration.runner';\nimport type { RunDownOptions, RunUpOptions } from './migration.types';\n\n// ─── Programmatic options ─────────────────────────────────────────────────────\n\nexport interface MigrateOptions {\n\t/** Absolute or relative path to the directory containing migration files */\n\tmigrationsDir: string;\n\t/**\n\t * MongoDB connection URI.\n\t * Defaults to `process.env.MONGODB_URI` when omitted.\n\t * Not required for 'create' operation.\n\t */\n\turi?: string;\n\t/** Options passed to `MigrationRunner.up()` when `operation` is `'up'` */\n\tup?: RunUpOptions;\n\t/** Options passed to `MigrationRunner.down()` when `operation` is `'down'` */\n\tdown?: RunDownOptions;\n\t/** Options passed to `MigrationRunner.create()` when `operation` is `'create'` */\n\tcreate?: { name: string };\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction resolveUri(options: MigrateOptions): string {\n\tconst uri = options.uri ?? Bun.env.MONGODB_URI;\n\tif (!uri) {\n\t\tthrow new Error(\n\t\t\t'migrations.errors.missing-uri: provide `uri` in options or set MONGODB_URI',\n\t\t);\n\t}\n\treturn uri;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Run a specific migration operation.\n *\n * Connects to MongoDB, executes, then disconnects — fully self-contained.\n * For 'create', it does not connect to the database.\n */\nexport async function migrate(\n\toperation: 'up' | 'down' | 'list' | 'create' = 'list',\n\toptions: MigrateOptions,\n): Promise<void> {\n\tif (operation === 'create') {\n\t\tconst runner = new MigrationRunner({\n\t\t\tmigrationsDir: options.migrationsDir,\n\t\t\tconnection: null as any,\n\t\t});\n\t\tawait runner.create(options.create ?? { name: 'unnamed-migration' });\n\t\treturn;\n\t}\n\n\tconst uri = resolveUri(options);\n\tawait mongoose.connect(uri);\n\tconst runner = new MigrationRunner({\n\t\tmigrationsDir: options.migrationsDir,\n\t\tconnection: mongoose.connection,\n\t});\n\ttry {\n\t\tif (operation === 'list') {\n\t\t\tawait runner.list();\n\t\t} else {\n\t\t\tawait runner[operation](options[operation]);\n\t\t}\n\t} finally {\n\t\tawait disconnectQuietly();\n\t}\n}\n\n/**\n * Lower-level helper: run a callback with an already-configured `MigrationRunner`,\n * managing the connection lifecycle automatically.\n *\n * Use this when you need full control (e.g. embedding migrations inside a\n * larger startup script that also does other work on the connection).\n *\n * @example\n * ```ts\n * import { withMigrationRunner } from '@nxgt/shared-mongo';\n *\n * await withMigrationRunner({ migrationsDir: './src/migrations' }, async (runner) => {\n * const list = await runner.list();\n * console.table(list);\n * await runner.up();\n * });\n * ```\n */\nexport async function withMigrationRunner<T>(\n\toptions: MigrateOptions,\n\tfn: (runner: MigrationRunner) => Promise<T>,\n): Promise<T> {\n\tconst uri = resolveUri(options);\n\tawait mongoose.connect(uri);\n\tconst runner = new MigrationRunner({\n\t\tmigrationsDir: options.migrationsDir,\n\t\tconnection: mongoose.connection,\n\t});\n\ttry {\n\t\treturn await fn(runner);\n\t} finally {\n\t\tawait disconnectQuietly();\n\t}\n}\n",
35
+ "import { Schema } from 'mongoose';\nimport { VALIDATORS } from '../validation';\n\nexport type PostalAddress = {\n\tstreet?: string;\n\tlocality?: string;\n\tregion?: string;\n\tpostalCode?: string;\n\tcountry?: string; // ISO 3166-1 alpha-2, validated at the GraphQL layer via CountryCode\n};\n\nexport const PostalAddressSchema = new Schema<PostalAddress>(\n\t{\n\t\tstreet: { type: String, validate: VALIDATORS.maxLength(200) },\n\t\tlocality: { type: String, validate: VALIDATORS.maxLength(100) },\n\t\tregion: { type: String, validate: VALIDATORS.maxLength(100) },\n\t\tpostalCode: { type: String, validate: VALIDATORS.maxLength(20) },\n\t\tcountry: { type: String, validate: VALIDATORS.size([2, 2]) },\n\t},\n\t{ _id: false },\n);\n",
36
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function email(args: ValidatorOptions<{ domains?: string[] }>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{\n\t\t\t\tdomains: options.value.domains?.join(', '),\n\t\t\t\tnumberOfDomains: options.value.domains?.length ?? 0,\n\t\t\t},\n\t\t\t'validation.errors.email',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(typeof value === 'string' &&\n\t\t\t\t\tREGEX.email.test(value) &&\n\t\t\t\t\t(options.value.domains?.length\n\t\t\t\t\t\t? options.value.domains.filter((domain) => value.includes(domain))\n\t\t\t\t\t\t\t\t.length === options.value.domains.length\n\t\t\t\t\t\t: true))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
37
+ "import { type LocaleKey, translate } from '@nxgt/i18n';\nimport { cast } from '@nxgt/shared/helpers';\nimport { isArray, isNil } from 'lodash';\nimport type { MessageType, ValidatorOptions } from './validation.types';\n\nexport function parseValidatorOptions<T>(args: ValidatorOptions<T>): {\n\tvalue: T;\n\tmessage?: (\n\t\toptions?: object,\n\t\tdefaultMessage?: MessageType,\n\t) => (props: any) => string;\n} {\n\tfunction parseField<F>(field: F | [F, MessageType]) {\n\t\treturn isArray(field) && field.length === 2 && typeof field[1] === 'string'\n\t\t\t? { value: field[0], message: field[1] }\n\t\t\t: ({ value: cast(field) } satisfies { value: F; message?: MessageType });\n\t}\n\n\tconst field = parseField(args);\n\treturn {\n\t\t...field,\n\t\tmessage: (options?: object, defaultMessage?: MessageType) => (props) => {\n\t\t\treturn translate(\n\t\t\t\t(isNil(props.value)\n\t\t\t\t\t? 'validation.errors.required'\n\t\t\t\t\t: (field.message ?? defaultMessage ?? '')) as LocaleKey,\n\t\t\t\t{\n\t\t\t\t\t...props,\n\t\t\t\t\t...options,\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t};\n}\n",
38
+ "import i18next from 'i18next';\nimport { isNil, omit } from 'lodash';\nimport { DateTime } from 'luxon';\nimport type { ValidateOpts } from 'mongoose';\nimport type { DateFields, ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function future(\n\targs: ValidatorOptions<\n\t\tPartial<Record<DateFields, number>> & { datetime?: boolean }\n\t>,\n) {\n\tconst options = parseValidatorOptions(args);\n\n\tconst limit = DateTime.now().minus(omit(options.value, 'datetime'));\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{\n\t\t\t\tlimit: limit\n\t\t\t\t\t.setLocale(i18next.language)\n\t\t\t\t\t.toLocaleString(\n\t\t\t\t\t\t(options.value.datetime ?? true)\n\t\t\t\t\t\t\t? DateTime.DATETIME_FULL\n\t\t\t\t\t\t\t: DateTime.DATE_FULL,\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t'validation.errors.future',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(value instanceof Date &&\n\t\t\t\t\tDateTime.fromJSDate(value).isValid &&\n\t\t\t\t\tDateTime.fromJSDate(value) >= limit)\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
39
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function guid(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.guid'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.guid.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
40
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function ip(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.ip'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.ip.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
41
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function ipv4(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.ipv4'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.ipv4.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
42
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function ipv6(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.ipv6'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.ipv6.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
43
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function mac(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.mac'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.mac.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
44
+ "import { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function max(args: ValidatorOptions<number>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({ max: options.value }, 'validation.errors.max'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'number' && value <= options.value)\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
45
+ "import { isArray, isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function maxLength(args: ValidatorOptions<number>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{ maxLength: options.value },\n\t\t\t'validation.errors.max-length',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(typeof value === 'string' && value.length <= options.value) ||\n\t\t\t\t(isArray(value) && value.length <= options.value)\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
46
+ "import { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function min(args: ValidatorOptions<number>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({ min: options.value }, 'validation.errors.min'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'number' && value >= options.value)\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
47
+ "import { isArray, isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function minLength(args: ValidatorOptions<number>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{ minLength: options.value },\n\t\t\t'validation.errors.min-length',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(typeof value === 'string' && value.length >= options.value) ||\n\t\t\t\t(isArray(value) && value.length >= options.value)\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
48
+ "import { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function negative(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.negative'),\n\t\tvalidator(value) {\n\t\t\treturn isNil(value) || (typeof value === 'number' && value <= 0);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
49
+ "import { isEmpty, isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function notBlank(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.not-blank'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && !isEmpty(value.trim()))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
50
+ "import { isArray, isEmpty, isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function notEmpty(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.not-empty'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t((typeof value === 'string' || isArray(value)) && !isEmpty(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
51
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function objectId(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.object-id'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(typeof value === 'string' && REGEX.objectId.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
52
+ "import i18next from 'i18next';\nimport { isNil, omit } from 'lodash';\nimport { DateTime } from 'luxon';\nimport type { ValidateOpts } from 'mongoose';\nimport type { DateFields, ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function past(\n\targs: ValidatorOptions<\n\t\tPartial<Record<DateFields, number>> & { datetime?: boolean }\n\t>,\n) {\n\tconst options = parseValidatorOptions(args);\n\n\tconst limit = DateTime.now().minus(omit(options.value, 'datetime'));\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{\n\t\t\t\tlimit: limit\n\t\t\t\t\t.setLocale(i18next.language)\n\t\t\t\t\t.toLocaleString(\n\t\t\t\t\t\t(options.value.datetime ?? true)\n\t\t\t\t\t\t\t? DateTime.DATETIME_FULL\n\t\t\t\t\t\t\t: DateTime.DATE_FULL,\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t'validation.errors.past',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(value instanceof Date &&\n\t\t\t\t\tDateTime.fromJSDate(value).isValid &&\n\t\t\t\t\tDateTime.fromJSDate(value) <= limit)\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
53
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function pattern(args: ValidatorOptions<string>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{ pattern: options.value },\n\t\t\t'validation.errors.pattern',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn isNil(value) || REGEX.regex(options.value).test(value.toString());\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
54
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function phone(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.phone'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.phone.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
55
+ "import { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function positive(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.positive'),\n\t\tvalidator(value) {\n\t\t\treturn isNil(value) || (typeof value === 'number' && value >= 0);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
56
+ "import { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function range(args: ValidatorOptions<[number, number]>) {\n\tconst options = parseValidatorOptions(args);\n\n\tif (options.value[0] > options.value[1]) {\n\t\tthrow new Error(\n\t\t\t'First argument must ne less than or equal to the second argument',\n\t\t);\n\t}\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{ min: options.value[0], max: options.value[1] },\n\t\t\t'validation.errors.range',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(typeof value === 'number' &&\n\t\t\t\t\tvalue >= options.value[0] &&\n\t\t\t\t\tvalue <= options.value[1])\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
57
+ "import { isEmpty, isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function required(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.required'),\n\t\tvalidator(value) {\n\t\t\treturn typeof value === 'number'\n\t\t\t\t? !isNil(value)\n\t\t\t\t: !isNil(value) && !isEmpty(value);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
58
+ "import { isArray, isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function size(args: ValidatorOptions<[number, number]>) {\n\tconst options = parseValidatorOptions(args);\n\n\tif (options.value[0] > options.value[1]) {\n\t\tthrow new Error(\n\t\t\t'First argument must ne less than or equal to the second argument',\n\t\t);\n\t}\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{ min: options.value[0], max: options.value[1] },\n\t\t\t'validation.errors.size',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t((typeof value === 'string' || isArray(value)) &&\n\t\t\t\t\tvalue.length >= options.value[0] &&\n\t\t\t\t\tvalue.length <= options.value[1])\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
59
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function ssn(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.ssn'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.ssn.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
60
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function street(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.street'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.street.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
61
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function time(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.time'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.time.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
62
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function url(args: ValidatorOptions<{ domains?: string[] }>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.(\n\t\t\t{\n\t\t\t\tdomains: options.value.domains?.join(', '),\n\t\t\t\tnumberOfDomains: options.value.domains?.length ?? 0,\n\t\t\t},\n\t\t\t'validation.errors.url',\n\t\t),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) ||\n\t\t\t\t(typeof value === 'string' &&\n\t\t\t\t\tREGEX.url.test(value) &&\n\t\t\t\t\t(options.value.domains?.length\n\t\t\t\t\t\t? options.value.domains.filter((domain) => value.includes(domain))\n\t\t\t\t\t\t\t\t.length === options.value.domains.length\n\t\t\t\t\t\t: true))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
63
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function uuid(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.uuid'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.uuid.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
64
+ "import { REGEX } from '@nxgt/shared/helpers';\nimport { isNil } from 'lodash';\nimport type { ValidateOpts } from 'mongoose';\nimport type { ValidatorOptions } from '../validation.types';\nimport { parseValidatorOptions } from '../validation.utils';\n\nexport function zipCode(args: ValidatorOptions<true>) {\n\tconst options = parseValidatorOptions(args);\n\n\treturn {\n\t\tmessage: options.message?.({}, 'validation.errors.zip-code'),\n\t\tvalidator(value) {\n\t\t\treturn (\n\t\t\t\tisNil(value) || (typeof value === 'string' && REGEX.zipCode.test(value))\n\t\t\t);\n\t\t},\n\t} satisfies ValidateOpts<object, object>;\n}\n",
65
+ "import type { LocaleKey } from '@nxgt/i18n';\nimport type { Principal } from '@nxgt/shared';\nimport { cleanObject } from '@nxgt/shared/helpers';\nimport { CustomException } from '@nxgt/shared-exceptions';\nimport type { Mutex } from 'async-mutex';\nimport type { HydratedDocument, Model, QueryFilter } from 'mongoose';\nimport { runWithChangesListening } from '../audit';\nimport { integrityRegistry } from '../integrity';\n\ntype InferDocType<D extends HydratedDocument<any>> =\n\tD extends HydratedDocument<infer T> ? T : D;\n\nexport abstract class MongoCrudService<\n\tD extends HydratedDocument<any>,\n\tCInput = any,\n\tUInput = any,\n> {\n\tprotected abstract model: Model<D>;\n\n\t/**\n\t * Additional models to watch in the change stream (e.g. child models\n\t * that are cascade-deleted alongside the parent).\n\t */\n\tprotected extraModels: Model<any>[] = [];\n\n\tprotected abstract mutex: Mutex;\n\n\tconstructor(readonly principal?: Principal | null) {}\n\n\tprotected get changesOptions() {\n\t\treturn {\n\t\t\tmodels: [this.model, ...this.extraModels],\n\t\t\tauthor: this.principal?.name || 'system',\n\t\t\tmutex: this.mutex,\n\t\t};\n\t}\n\n\t// ─── Query ────────────────────────────────────────────────────────────────\n\n\tasync find(filter: QueryFilter<D> = {}): Promise<D[]> {\n\t\treturn this.model.find(filter).exec() as Promise<D[]>;\n\t}\n\n\t/**\n\t * Fetches one document by id.\n\t *\n\t * Overriding this to point at another model is fine — that is what the\n\t * hierarchical services do, and `update()` reads through\n\t * `findWritableById()` precisely so a read-only view can be used here.\n\t * Overriding it to reshape the result is not: `create()` returns what\n\t * this hands back, so anything but a hydrated document breaks writes on\n\t * that service. Strip or map fields at the serialization boundary\n\t * instead.\n\t */\n\tasync findById(id: string): Promise<D> {\n\t\tconst entity = await this.model.findById(id).exec();\n\t\tif (!entity) {\n\t\t\tthrow CustomException.notFound({\n\t\t\t\tmessage: `${this.model.collection.name}.errors.not-found`,\n\t\t\t});\n\t\t}\n\t\treturn entity as D;\n\t}\n\n\t// ─── Writes ───────────────────────────────────────────────────────────────\n\n\tasync create(input: CInput): Promise<D> {\n\t\tconst entity = await runWithChangesListening(async () => {\n\t\t\tawait this.beforeCreate(input);\n\n\t\t\tconst data = await this.buildCreateData(input);\n\n\t\t\treturn this.model.create({\n\t\t\t\t...data,\n\t\t\t\tcreatedBy: this.principal?.name,\n\t\t\t\tlastModifiedBy: this.principal?.name,\n\t\t\t} as any);\n\t\t}, this.changesOptions);\n\n\t\treturn this.findById((entity as any).id);\n\t}\n\n\t/**\n\t * The document `update()` mutates and saves.\n\t *\n\t * Deliberately not `findById()`: a service is free to point that at a\n\t * *view* (`HierarchicalDirectoryModel`, `HierarchicalTypologyModel`) to\n\t * get materialised `ancestors`, and Mongo refuses to save a document\n\t * loaded from one — \"Namespace x.y is a view, not a collection\". Writes\n\t * therefore go through `this.model`, which is the collection by\n\t * definition. For a service whose `findById` override only changes the\n\t * not-found message, this loads exactly the same document.\n\t */\n\tprotected async findWritableById(id: string): Promise<D> {\n\t\tconst entity = await this.model.findById(id).exec();\n\t\tif (!entity) {\n\t\t\tthrow CustomException.notFound({\n\t\t\t\tmessage: `${this.model.collection.name}.errors.not-found`,\n\t\t\t});\n\t\t}\n\t\treturn entity as D;\n\t}\n\n\tasync update(id: string, input: UInput): Promise<D> {\n\t\treturn runWithChangesListening(async () => {\n\t\t\tconst doc = await this.findWritableById(id);\n\t\t\tawait this.beforeUpdate(doc, input);\n\t\t\tconst data = await this.buildUpdateData(doc, input);\n\n\t\t\tObject.assign(\n\t\t\t\tdoc as any,\n\t\t\t\tcleanObject({\n\t\t\t\t\t...data,\n\t\t\t\t\tlastModifiedBy: this.principal?.name,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait (doc as any).save();\n\n\t\t\t// Read back through `findById()`, exactly as `create()` does: the\n\t\t\t// document just saved came from the collection, so on a service\n\t\t\t// backed by a view it would answer without the fields the view\n\t\t\t// materialises.\n\t\t\treturn this.findById(id);\n\t\t}, this.changesOptions);\n\t}\n\n\t// ─── Deletion ─────────────────────────────────────────────────────────────\n\n\t/**\n\t * Deletion flow:\n\t * 1. `beforeDeleteMany` hook — custom pre-checks (outside transaction)\n\t * 2. `validateDeletion` — all integrity blockers in parallel (outside transaction)\n\t * 3. `runWithChangesListening`:\n\t * a. `runCascades` — registered cascade handlers (inside transaction)\n\t * b. `model.deleteMany` — parent documents deleted (inside transaction)\n\t */\n\tasync deleteMany(ids: string[]): Promise<void> {\n\t\tawait runWithChangesListening(async () => {\n\t\t\tawait this.beforeDeleteMany(ids);\n\t\t\tawait integrityRegistry.validateDeletion(this.model.modelName, ids);\n\n\t\t\tawait integrityRegistry.runCascades(this.model.modelName, ids);\n\t\t\treturn this.model.deleteMany({ _id: { $in: ids } }).exec();\n\t\t}, this.changesOptions);\n\t}\n\n\tasync delete(id: string): Promise<void> {\n\t\tawait this.model.ensureExists(\n\t\t\t{ _id: id },\n\t\t\t{\n\t\t\t\tmessage: `${this.model.collection.name}.errors.not-found` as LocaleKey,\n\t\t\t},\n\t\t);\n\t\tawait this.deleteMany([id]);\n\t}\n\n\t// ─── Hooks ────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Override to customize the data passed to `model.create()`.\n\t * Default: spread input as-is.\n\t */\n\tprotected buildCreateData(\n\t\tinput: CInput,\n\t): Promise<Partial<InferDocType<D>>> | Partial<InferDocType<D>> {\n\t\treturn input as unknown as Partial<InferDocType<D>>;\n\t}\n\n\t/**\n\t * Override to customize the fields applied to the document during update.\n\t * Default: spread input as-is.\n\t */\n\tprotected buildUpdateData(\n\t\t_doc: D,\n\t\tinput: UInput,\n\t): Promise<Partial<InferDocType<D>>> | Partial<InferDocType<D>> {\n\t\treturn input as unknown as Partial<InferDocType<D>>;\n\t}\n\n\t/**\n\t * Called before integrity validation and the deletion transaction.\n\t * Override to add pre-delete checks (e.g. status guards).\n\t */\n\tprotected async beforeDeleteMany(_ids: string[]): Promise<void> {}\n\n\t/**\n\t * Called inside the create transaction, before `model.create()`.\n\t * Override to add pre-create guards (e.g. uniqueness or status checks).\n\t * The raw input is passed in case the check depends on it.\n\t */\n\tprotected async beforeCreate(_input: CInput): Promise<void> {}\n\n\t/**\n\t * Called inside the update transaction, after `findById`, before\n\t * `buildUpdateData`. Override to add pre-update guards (e.g. status locks).\n\t * Receives the already-fetched document — no extra DB round-trip needed.\n\t */\n\tprotected async beforeUpdate(_doc: D, _input: UInput): Promise<void> {}\n}\n"
66
+ ],
67
+ "mappings": "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",
68
+ "debugId": "91BF3312614B3B9464756E2164756E21",
69
+ "names": []
70
+ }
@@ -0,0 +1,3 @@
1
+ export * from './integrity.registry';
2
+ export * from './integrity.types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/integrity/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { RegisterBlockerOptions, RegisterCascadeOptions } from './integrity.types';
2
+ export declare class IntegrityRegistry {
3
+ private blockers;
4
+ private cascades;
5
+ /**
6
+ * Register a check that blocks deletion of a target model.
7
+ * Safe to call multiple times — deduplicated by `id`.
8
+ *
9
+ * @param options.id - Unique identifier for this blocker
10
+ * @param options.model - Mongoose model name to guard (e.g. `RoleModel.name`)
11
+ * @param options.errorCode - i18n key thrown when the blocker is triggered
12
+ * @param options.blocker - Function returning the count of referencing documents
13
+ */
14
+ registerBlocker(options: RegisterBlockerOptions): void;
15
+ /**
16
+ * Register a cascade cleanup executed **inside** the deletion transaction.
17
+ * Safe to call multiple times — deduplicated by `id`.
18
+ *
19
+ * @param options.id - Unique identifier for this cascade
20
+ * @param options.model - Mongoose model name of the parent being deleted
21
+ * @param options.cascade - Cleanup function (runs inside MongoDB transaction)
22
+ */
23
+ registerCascade(options: RegisterCascadeOptions): void;
24
+ /**
25
+ * Run all registered blockers for a model in parallel and throw if any
26
+ * referencing documents are found. All failing constraints are collected
27
+ * before throwing so the caller sees the full picture at once.
28
+ */
29
+ validateDeletion(model: string, ids: string[]): Promise<void>;
30
+ /**
31
+ * Execute all registered cascade handlers for a model in parallel.
32
+ * Called inside `runWithChangesListening` so everything runs within
33
+ * the same MongoDB transaction.
34
+ */
35
+ runCascades(model: string, ids: string[]): Promise<void>;
36
+ }
37
+ export declare const integrityRegistry: IntegrityRegistry;
38
+ //# sourceMappingURL=integrity.registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.registry.d.ts","sourceRoot":"","sources":["../../src/integrity/integrity.registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGX,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,mBAAmB,CAAC;AAE3B,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;;;;;;;OAQG;IACH,eAAe,CAAC,OAAO,EAAE,sBAAsB;IAQ/C;;;;;;;OAOG;IACH,eAAe,CAAC,OAAO,EAAE,sBAAsB;IAQ/C;;;;OAIG;IACG,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnE;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAI9D;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
@@ -0,0 +1,26 @@
1
+ export type DeletionBlocker = (ids: string[]) => Promise<number>;
2
+ export type BlockerOption = {
3
+ id: string;
4
+ fn: DeletionBlocker;
5
+ errorCode: string;
6
+ };
7
+ export type RegisterBlockerOptions = {
8
+ id: string;
9
+ model: string;
10
+ errorCode: string;
11
+ blocker: DeletionBlocker;
12
+ };
13
+ export type CascadeHandler = (ids: string[]) => Promise<void>;
14
+ export type CascadeOption = {
15
+ id: string;
16
+ fn: CascadeHandler;
17
+ };
18
+ export type RegisterCascadeOptions = {
19
+ /** Unique identifier for this cascade — used for deduplication. */
20
+ id: string;
21
+ /** Mongoose model name (e.g. `OrderModel.name`) of the parent being deleted. */
22
+ model: string;
23
+ /** Cleanup function executed inside the deletion transaction. */
24
+ cascade: CascadeHandler;
25
+ };
26
+ //# sourceMappingURL=integrity.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.types.d.ts","sourceRoot":"","sources":["../../src/integrity/integrity.types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,eAAe,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,eAAe,CAAC;CACzB,CAAC;AAIF,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,MAAM,aAAa,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,cAAc,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACpC,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,EAAE,cAAc,CAAC;CACxB,CAAC"}
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Migration CLI
4
+ *
5
+ * Usage:
6
+ * bun src/migrations/cli.ts <command> [options]
7
+ *
8
+ * Commands:
9
+ * up Run all pending migrations (or a specific one with --name)
10
+ * down Rollback the last batch (or a specific one with --name)
11
+ * list Print all migrations with their current status
12
+ * create Generate a new migration file with boilerplate
13
+ *
14
+ * Options:
15
+ * --dir <path> Directory containing migration files (default: ./migrations)
16
+ * --name <name> Name for new migration (create) or target specific (up/down)
17
+ * --uri <uri> MongoDB connection URI (overrides MONGODB_URI env var)
18
+ * --dry-run Show what would happen without executing (up/down)
19
+ *
20
+ * Examples:
21
+ * bun src/migrations/cli.ts create --name add-user-indexes
22
+ * bun src/migrations/cli.ts up --dir ./migrations
23
+ * bun src/migrations/cli.ts up --name 20260421120000-add-user-indexes --dry-run
24
+ * bun src/migrations/cli.ts down --dir ./migrations
25
+ * bun src/migrations/cli.ts list --dir ./migrations
26
+ */
27
+ export {};
28
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/migrations/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Close the default mongoose connection without surfacing mongodb 7's
3
+ * teardown noise. Used by the programmatic `migrate()` / `withMigrationRunner`
4
+ * helpers, which must actually drop the connection (a CLI can just
5
+ * `process.exit`).
6
+ */
7
+ export declare function disconnectQuietly(): Promise<void>;
8
+ //# sourceMappingURL=disconnect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disconnect.d.ts","sourceRoot":"","sources":["../../src/migrations/disconnect.ts"],"names":[],"mappings":"AA4BA;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAWvD"}
@@ -0,0 +1,6 @@
1
+ export * from './migrate';
2
+ export * from './migration.model';
3
+ export * from './migration.runner';
4
+ export * from './migration.types';
5
+ export * from './migration.utils';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { MigrationRunner } from './migration.runner';
2
+ import type { RunDownOptions, RunUpOptions } from './migration.types';
3
+ export interface MigrateOptions {
4
+ /** Absolute or relative path to the directory containing migration files */
5
+ migrationsDir: string;
6
+ /**
7
+ * MongoDB connection URI.
8
+ * Defaults to `process.env.MONGODB_URI` when omitted.
9
+ * Not required for 'create' operation.
10
+ */
11
+ uri?: string;
12
+ /** Options passed to `MigrationRunner.up()` when `operation` is `'up'` */
13
+ up?: RunUpOptions;
14
+ /** Options passed to `MigrationRunner.down()` when `operation` is `'down'` */
15
+ down?: RunDownOptions;
16
+ /** Options passed to `MigrationRunner.create()` when `operation` is `'create'` */
17
+ create?: {
18
+ name: string;
19
+ };
20
+ }
21
+ /**
22
+ * Run a specific migration operation.
23
+ *
24
+ * Connects to MongoDB, executes, then disconnects — fully self-contained.
25
+ * For 'create', it does not connect to the database.
26
+ */
27
+ export declare function migrate(operation: "up" | "down" | "list" | "create" | undefined, options: MigrateOptions): Promise<void>;
28
+ /**
29
+ * Lower-level helper: run a callback with an already-configured `MigrationRunner`,
30
+ * managing the connection lifecycle automatically.
31
+ *
32
+ * Use this when you need full control (e.g. embedding migrations inside a
33
+ * larger startup script that also does other work on the connection).
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { withMigrationRunner } from '@nxgt/shared-mongo';
38
+ *
39
+ * await withMigrationRunner({ migrationsDir: './src/migrations' }, async (runner) => {
40
+ * const list = await runner.list();
41
+ * console.table(list);
42
+ * await runner.up();
43
+ * });
44
+ * ```
45
+ */
46
+ export declare function withMigrationRunner<T>(options: MigrateOptions, fn: (runner: MigrationRunner) => Promise<T>): Promise<T>;
47
+ //# sourceMappingURL=migrate.d.ts.map