@cyberskill/shared 3.13.0 → 3.14.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 (97) hide show
  1. package/dist/config/env/env.util.d.ts +5 -0
  2. package/dist/config/env/env.util.js +20 -16
  3. package/dist/config/env/env.util.js.map +1 -1
  4. package/dist/config/env/index.js +2 -2
  5. package/dist/config/vitest/vitest.e2e.js +4 -4
  6. package/dist/config/vitest/vitest.e2e.js.map +1 -1
  7. package/dist/config/vitest/vitest.unit.js +5 -5
  8. package/dist/config/vitest/vitest.unit.js.map +1 -1
  9. package/dist/config/vitest/vitest.unit.setup.js +10 -0
  10. package/dist/config/vitest/vitest.unit.setup.js.map +1 -0
  11. package/dist/node/apollo-server/apollo-server.type.d.ts +13 -1
  12. package/dist/node/apollo-server/apollo-server.util.d.ts +1 -0
  13. package/dist/node/apollo-server/apollo-server.util.js +40 -16
  14. package/dist/node/apollo-server/apollo-server.util.js.map +1 -1
  15. package/dist/node/cli/index.js +26 -28
  16. package/dist/node/cli/index.js.map +1 -1
  17. package/dist/node/command/command.util.d.ts +5 -0
  18. package/dist/node/command/command.util.js +49 -48
  19. package/dist/node/command/command.util.js.map +1 -1
  20. package/dist/node/command/index.js +2 -2
  21. package/dist/node/express/express.type.d.ts +11 -0
  22. package/dist/node/express/express.util.d.ts +34 -6
  23. package/dist/node/express/express.util.js +81 -56
  24. package/dist/node/express/express.util.js.map +1 -1
  25. package/dist/node/express/index.js +2 -2
  26. package/dist/node/log/log.type.d.ts +17 -0
  27. package/dist/node/log/log.type.js.map +1 -1
  28. package/dist/node/log/log.util.js +25 -11
  29. package/dist/node/log/log.util.js.map +1 -1
  30. package/dist/node/mongo/index.d.ts +2 -1
  31. package/dist/node/mongo/index.js +7 -8
  32. package/dist/node/mongo/mongo.constant.d.ts +5 -0
  33. package/dist/node/mongo/mongo.constant.js +2 -2
  34. package/dist/node/mongo/mongo.constant.js.map +1 -1
  35. package/dist/node/mongo/mongo.controller.mongoose.d.ts +3 -0
  36. package/dist/node/mongo/mongo.controller.mongoose.js +41 -55
  37. package/dist/node/mongo/mongo.controller.mongoose.js.map +1 -1
  38. package/dist/node/mongo/mongo.controller.native.d.ts +29 -2
  39. package/dist/node/mongo/mongo.controller.native.js +31 -14
  40. package/dist/node/mongo/mongo.controller.native.js.map +1 -1
  41. package/dist/node/mongo/mongo.type.d.ts +3 -1
  42. package/dist/node/mongo/mongo.util.d.ts +1 -0
  43. package/dist/node/mongo/mongo.util.js +38 -17
  44. package/dist/node/mongo/mongo.util.js.map +1 -1
  45. package/dist/node/package/package.util.js +47 -47
  46. package/dist/node/path/index.js +2 -2
  47. package/dist/node/path/path.constant.d.ts +4 -0
  48. package/dist/node/path/path.constant.js +75 -72
  49. package/dist/node/path/path.constant.js.map +1 -1
  50. package/dist/node/storage/storage.util.d.ts +50 -1
  51. package/dist/node/storage/storage.util.js +79 -54
  52. package/dist/node/storage/storage.util.js.map +1 -1
  53. package/dist/node/upload/upload.type.d.ts +2 -0
  54. package/dist/node/upload/upload.type.js.map +1 -1
  55. package/dist/node/upload/upload.util.d.ts +1 -0
  56. package/dist/node/upload/upload.util.js +62 -52
  57. package/dist/node/upload/upload.util.js.map +1 -1
  58. package/dist/node/ws/ws.util.d.ts +7 -0
  59. package/dist/node/ws/ws.util.js +20 -19
  60. package/dist/node/ws/ws.util.js.map +1 -1
  61. package/dist/react/apollo-client/apollo-client.component.js.map +1 -1
  62. package/dist/react/apollo-client/apollo-client.type.d.ts +2 -0
  63. package/dist/react/apollo-client/apollo-client.util.js +6 -6
  64. package/dist/react/apollo-client/apollo-client.util.js.map +1 -1
  65. package/dist/react/apollo-error/apollo-error.component.js +1 -1
  66. package/dist/react/apollo-error/apollo-error.component.js.map +1 -1
  67. package/dist/react/apollo-error/apollo-error.util.js.map +1 -1
  68. package/dist/react/i18next/i18next.server.d.ts +17 -0
  69. package/dist/react/i18next/i18next.server.js +9 -0
  70. package/dist/react/i18next/i18next.server.js.map +1 -0
  71. package/dist/react/next-intl/next-intl.hoc.d.ts +4 -8
  72. package/dist/react/next-intl/next-intl.hoc.js +14 -10
  73. package/dist/react/next-intl/next-intl.hoc.js.map +1 -1
  74. package/dist/react/next-intl/next-intl.server.d.ts +10 -0
  75. package/dist/react/next-intl/next-intl.server.js +7 -0
  76. package/dist/react/next-intl/next-intl.server.js.map +1 -0
  77. package/dist/react/storage/storage.util.d.ts +34 -1
  78. package/dist/react/storage/storage.util.js +30 -5
  79. package/dist/react/storage/storage.util.js.map +1 -1
  80. package/dist/react/userback/userback.component.js.map +1 -1
  81. package/dist/typescript/common.type.d.ts +4 -0
  82. package/dist/typescript/common.type.js +2 -2
  83. package/dist/typescript/common.type.js.map +1 -1
  84. package/dist/typescript/index.js +2 -2
  85. package/dist/util/object/object.util.js +29 -18
  86. package/dist/util/object/object.util.js.map +1 -1
  87. package/dist/util/serializer/serializer.util.d.ts +8 -0
  88. package/dist/util/serializer/serializer.util.js +51 -64
  89. package/dist/util/serializer/serializer.util.js.map +1 -1
  90. package/dist/util/storage/storage-envelope.d.ts +25 -0
  91. package/dist/util/storage/storage-envelope.js +18 -0
  92. package/dist/util/storage/storage-envelope.js.map +1 -0
  93. package/package.json +33 -12
  94. package/dist/node/mongo/mongo.type.js +0 -8
  95. package/dist/node/mongo/mongo.type.js.map +0 -1
  96. package/dist/node_modules/.pnpm/vitest@4.1.2_@types_node@25.5.0_jsdom@29.0.1_@noble_hashes@1.8.0__vite@8.0.3_@types_nod_0827261ede788764a5d99ac6bdf44bde/node_modules/vitest/dist/config.js +0 -8
  97. package/dist/node_modules/.pnpm/vitest@4.1.2_@types_node@25.5.0_jsdom@29.0.1_@noble_hashes@1.8.0__vite@8.0.3_@types_nod_0827261ede788764a5d99ac6bdf44bde/node_modules/vitest/dist/config.js.map +0 -1
@@ -26,4 +26,21 @@ export interface I_ThrowError {
26
26
  }
27
27
  export interface I_Log extends I_LogCommon {
28
28
  printBoxedLog: (title: string, issues: I_IssueEntry[], color?: string) => void;
29
+ /**
30
+ * Creates a context-aware logger that prefixes all messages with a correlation ID.
31
+ * Useful for distributed tracing across CyberSkill services.
32
+ *
33
+ * @param correlationId - A UUID correlation ID. If not provided, a new UUID is generated.
34
+ * @returns A logger with standard methods that prefix output with the correlation ID.
35
+ */
36
+ withContext: (correlationId?: string) => {
37
+ correlationId: string;
38
+ fatal: (...args: unknown[]) => void;
39
+ error: (...args: unknown[]) => void;
40
+ warn: (...args: unknown[]) => void;
41
+ log: (...args: unknown[]) => void;
42
+ info: (...args: unknown[]) => void;
43
+ success: (...args: unknown[]) => void;
44
+ debug: (...args: unknown[]) => void;
45
+ };
29
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"log.type.js","names":[],"sources":["../../../src/node/log/log.type.ts"],"sourcesContent":["import type { I_Log as I_LogCommon } from '#typescript/index.js';\n\nexport type { I_CatchErrorOptions } from '#util/log/index.js';\n\n/**\n * Enum representing the type of issues for logging and error handling.\n * - Error: Represents an error issue.\n * - Warning: Represents a warning issue.\n */\nexport enum E_IssueType {\n Error = 'error',\n Warning = 'warning',\n}\n\nexport interface I_IssueEntry {\n type: E_IssueType;\n file: string;\n message: string;\n position?: string;\n rule?: string;\n}\n\nexport interface I_ThrowError {\n message?: string;\n status?: {\n CODE: string | number;\n MESSAGE: string;\n };\n type?: 'graphql' | 'rest';\n}\n\nexport interface I_Log extends I_LogCommon {\n printBoxedLog: (\n title: string,\n issues: I_IssueEntry[],\n color?: string,\n ) => void;\n}\n"],"mappings":";AASA,IAAY,IAAL,yBAAA,GAAA;QACH,EAAA,QAAA,SACA,EAAA,UAAA;KACH"}
1
+ {"version":3,"file":"log.type.js","names":[],"sources":["../../../src/node/log/log.type.ts"],"sourcesContent":["import type { I_Log as I_LogCommon } from '#typescript/index.js';\n\nexport type { I_CatchErrorOptions } from '#util/log/index.js';\n\n/**\n * Enum representing the type of issues for logging and error handling.\n * - Error: Represents an error issue.\n * - Warning: Represents a warning issue.\n */\nexport enum E_IssueType {\n Error = 'error',\n Warning = 'warning',\n}\n\nexport interface I_IssueEntry {\n type: E_IssueType;\n file: string;\n message: string;\n position?: string;\n rule?: string;\n}\n\nexport interface I_ThrowError {\n message?: string;\n status?: {\n CODE: string | number;\n MESSAGE: string;\n };\n type?: 'graphql' | 'rest';\n}\n\nexport interface I_Log extends I_LogCommon {\n printBoxedLog: (\n title: string,\n issues: I_IssueEntry[],\n color?: string,\n ) => void;\n /**\n * Creates a context-aware logger that prefixes all messages with a correlation ID.\n * Useful for distributed tracing across CyberSkill services.\n *\n * @param correlationId - A UUID correlation ID. If not provided, a new UUID is generated.\n * @returns A logger with standard methods that prefix output with the correlation ID.\n */\n withContext: (correlationId?: string) => {\n correlationId: string;\n fatal: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n log: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n success: (...args: unknown[]) => void;\n debug: (...args: unknown[]) => void;\n };\n}\n"],"mappings":";AASA,IAAY,IAAL,yBAAA,GAAA;QACH,EAAA,QAAA,SACA,EAAA,UAAA;KACH"}
@@ -4,20 +4,21 @@ import { getEnv as n } from "../../config/env/env.util.js";
4
4
  import { GraphQLError as r } from "graphql";
5
5
  import i from "chalk";
6
6
  import a from "consola";
7
+ import { randomUUID as o } from "node:crypto";
7
8
  //#region src/node/log/log.util.ts
8
- var o = !1;
9
- function s() {
10
- o || (o = !0, n().DEBUG || (a.level = 4));
9
+ var s = !1;
10
+ function c() {
11
+ s || (s = !0, n().DEBUG || (a.level = 4));
11
12
  }
12
- function c({ message: t, status: n = e.INTERNAL_SERVER_ERROR, type: i = "graphql" }) {
13
+ function l({ message: t, status: n = e.INTERNAL_SERVER_ERROR, type: i = "graphql" }) {
13
14
  let a = t ?? n.MESSAGE ?? "Internal server error";
14
15
  throw i === "graphql" ? new r(a, { extensions: { code: n.CODE } }) : Error(a);
15
16
  }
16
- function l(e) {
17
+ function u(e) {
17
18
  let t = i[e];
18
19
  return typeof t == "function" ? t : i.green;
19
20
  }
20
- var u = {
21
+ var d = {
21
22
  silent: a.silent,
22
23
  level: a.level,
23
24
  fatal: a.fatal,
@@ -39,16 +40,29 @@ var u = {
39
40
  }
40
41
  t.forEach(({ file: e, position: t, rule: r, message: o }) => {
41
42
  let s = `${e}${t ? `:${t}` : ""}`;
42
- a.log(`${i.gray("File:")} ${i.blue(s)}`), r && a.log(` ${l(n)("Rule:")} ${r}`), a.log(` ${l(n)("Message:")} ${o}`);
43
- }), a.box(l(n)(`${e} : ${t.length}`)), a.log(i.gray("─".repeat(40)));
43
+ a.log(`${i.gray("File:")} ${i.blue(s)}`), r && a.log(` ${u(n)("Rule:")} ${r}`), a.log(` ${u(n)("Message:")} ${o}`);
44
+ }), a.box(u(n)(`${e} : ${t.length}`)), a.log(i.gray("─".repeat(40)));
45
+ },
46
+ withContext(e) {
47
+ let t = e ?? o(), n = i.gray(`[${t}]`), r = (e) => (...t) => e(n, ...t);
48
+ return {
49
+ correlationId: t,
50
+ fatal: r(a.fatal),
51
+ error: r(a.error),
52
+ warn: r(a.warn),
53
+ log: r(a.log),
54
+ info: r(a.info),
55
+ success: r(a.success),
56
+ debug: r(a.debug)
57
+ };
44
58
  }
45
59
  };
46
- function d(e, n) {
60
+ function f(e, n) {
47
61
  return t(e, n, (e) => {
48
- s(), u.error(e);
62
+ c(), d.error(e);
49
63
  });
50
64
  }
51
65
  //#endregion
52
- export { d as catchError, u as log, c as throwError };
66
+ export { f as catchError, d as log, l as throwError };
53
67
 
54
68
  //# sourceMappingURL=log.util.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"log.util.js","names":[],"sources":["../../../src/node/log/log.util.ts"],"sourcesContent":["import type { ChalkInstance } from 'chalk';\n\nimport chalk from 'chalk';\nimport consola from 'consola';\nimport { GraphQLError } from 'graphql';\n\nimport type { I_Return } from '#typescript/index.js';\n\nimport { getEnv } from '#config/env/index.js';\nimport { RESPONSE_STATUS } from '#constant/index.js';\nimport { baseCatchError } from '#util/log/index.js';\n\nimport type { I_CatchErrorOptions, I_IssueEntry, I_Log, I_ThrowError } from './log.type.js';\n\nlet _logLevelConfigured = false;\n\n/**\n * Lazily configures the consola log level based on the DEBUG environment variable.\n * Only runs once on first invocation to avoid repeated env loading.\n */\nfunction ensureLogLevel() {\n if (!_logLevelConfigured) {\n _logLevelConfigured = true;\n const env = getEnv();\n\n if (!env.DEBUG) {\n consola.level = 4;\n }\n }\n}\n\n/**\n * Throws a standardized error with optional status information and type specification.\n * This function creates and throws errors that can be either GraphQL errors (with extensions)\n * or standard JavaScript errors, depending on the specified type.\n *\n * @param options - Error configuration including message, status information, and error type.\n * @param options.message - The error message to display.\n * @param options.status - The response status information (defaults to INTERNAL_SERVER_ERROR).\n * @param options.type - The type of error to throw ('graphql' or 'rest', defaults to 'graphql').\n * @throws {GraphQLError} When type is 'graphql', throws a GraphQL error with extensions.\n * @throws {Error} When type is 'rest' or unspecified, throws a standard JavaScript error.\n */\nexport function throwError({\n message,\n status = RESPONSE_STATUS.INTERNAL_SERVER_ERROR,\n type = 'graphql',\n}: I_ThrowError): never {\n const responseMessage\n = message ?? status.MESSAGE ?? 'Internal server error';\n\n if (type === 'graphql') {\n throw new GraphQLError(responseMessage, {\n extensions: { code: status.CODE },\n });\n }\n\n throw new Error(responseMessage);\n}\n\n/**\n * Gets a chalk color instance by keyword name.\n * This function safely retrieves a chalk color function by name, falling back to green\n * if the specified color is not available or invalid.\n *\n * @param color - The color keyword to get the chalk instance for.\n * @returns A chalk instance for the specified color, or green as fallback.\n */\nfunction chalkKeyword(color: string): ChalkInstance {\n const chalkColor = chalk[color as keyof typeof chalk];\n\n return typeof chalkColor === 'function' ? (chalkColor as ChalkInstance) : chalk.green;\n}\n\n/**\n * Enhanced logging interface that extends consola with custom functionality.\n * This object provides all standard consola logging methods plus additional features\n * like boxed log printing for structured error/warning display.\n */\nexport const log: I_Log = {\n silent: consola.silent,\n level: consola.level,\n fatal: consola.fatal,\n error: consola.error,\n warn: consola.warn,\n log: consola.log,\n info: consola.info,\n success: consola.success,\n ready: consola.ready,\n start: consola.start,\n box: consola.box,\n debug: consola.debug,\n trace: consola.trace,\n verbose: consola.verbose,\n /**\n * Prints a boxed log with structured issue information.\n * This method displays issues (errors or warnings) in a formatted box with:\n * - File paths and line/column positions\n * - Rule violations (if applicable)\n * - Error/warning messages\n * - Color-coded output based on issue type\n *\n * @param title - The title to display in the box header.\n * @param issues - An array of issue entries to display.\n * @param color - The color to use for highlighting (defaults to 'red').\n */\n printBoxedLog(title: string, issues: I_IssueEntry[], color = 'red') {\n if (!issues?.length) {\n consola.box(chalk.green(title));\n return;\n }\n\n issues.forEach(({ file, position, rule, message }) => {\n const positionSuffix = position ? `:${position}` : '';\n const filePath = `${file}${positionSuffix}`;\n consola.log(`${chalk.gray('File:')} ${chalk.blue(filePath)}`);\n\n if (rule) {\n consola.log(` ${chalkKeyword(color)('Rule:')} ${rule}`);\n }\n\n consola.log(` ${chalkKeyword(color)('Message:')} ${message}`);\n });\n\n consola.box(chalkKeyword(color)(`${title} : ${issues.length}`));\n\n consola.log(chalk.gray('─'.repeat(40)));\n },\n};\n\n/**\n * Catches and handles errors with configurable behavior.\n * Delegates to the shared `baseCatchError` implementation, adding Node-specific\n * log-level configuration via `ensureLogLevel()` before logging.\n *\n * @param errorInput - The error to catch and handle.\n * @param options - Configuration options for error handling behavior.\n * @returns Either the specified return value or a standardized error response object.\n */\nexport function catchError<T = unknown>(errorInput: unknown, options: I_CatchErrorOptions & { returnValue: T }): T;\nexport function catchError<T = unknown>(errorInput: unknown, options?: I_CatchErrorOptions): I_Return<T>;\nexport function catchError<T = unknown>(errorInput: unknown, options?: I_CatchErrorOptions): I_Return<T> | T {\n return baseCatchError<T>(errorInput, options, (message) => {\n ensureLogLevel();\n log.error(message);\n });\n}\n"],"mappings":";;;;;;;AAcA,IAAI,IAAsB;AAM1B,SAAS,IAAiB;AACtB,CAAK,MACD,IAAsB,IACV,GAAQ,CAEX,UACL,EAAQ,QAAQ;;AAiB5B,SAAgB,EAAW,EACvB,YACA,YAAS,EAAgB,uBACzB,UAAO,aACa;CACpB,IAAM,IACA,KAAW,EAAO,WAAW;AAQnC,OANI,MAAS,YACH,IAAI,EAAa,GAAiB,EACpC,YAAY,EAAE,MAAM,EAAO,MAAM,EACpC,CAAC,GAGI,MAAM,EAAgB;;AAWpC,SAAS,EAAa,GAA8B;CAChD,IAAM,IAAa,EAAM;AAEzB,QAAO,OAAO,KAAe,aAAc,IAA+B,EAAM;;AAQpF,IAAa,IAAa;CACtB,QAAQ,EAAQ;CAChB,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,MAAM,EAAQ;CACd,KAAK,EAAQ;CACb,MAAM,EAAQ;CACd,SAAS,EAAQ;CACjB,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,KAAK,EAAQ;CACb,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,SAAS,EAAQ;CAajB,cAAc,GAAe,GAAwB,IAAQ,OAAO;AAChE,MAAI,CAAC,GAAQ,QAAQ;AACjB,KAAQ,IAAI,EAAM,MAAM,EAAM,CAAC;AAC/B;;AAiBJ,EAdA,EAAO,SAAS,EAAE,SAAM,aAAU,SAAM,iBAAc;GAElD,IAAM,IAAW,GAAG,IADG,IAAW,IAAI,MAAa;AAQnD,GANA,EAAQ,IAAI,GAAG,EAAM,KAAK,QAAQ,CAAC,GAAG,EAAM,KAAK,EAAS,GAAG,EAEzD,KACA,EAAQ,IAAI,MAAM,EAAa,EAAM,CAAC,QAAQ,CAAC,GAAG,IAAO,EAG7D,EAAQ,IAAI,MAAM,EAAa,EAAM,CAAC,WAAW,CAAC,GAAG,IAAU;IACjE,EAEF,EAAQ,IAAI,EAAa,EAAM,CAAC,GAAG,EAAM,KAAK,EAAO,SAAS,CAAC,EAE/D,EAAQ,IAAI,EAAM,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;;CAE9C;AAaD,SAAgB,EAAwB,GAAqB,GAAgD;AACzG,QAAO,EAAkB,GAAY,IAAU,MAAY;AAEvD,EADA,GAAgB,EAChB,EAAI,MAAM,EAAQ;GACpB"}
1
+ {"version":3,"file":"log.util.js","names":[],"sources":["../../../src/node/log/log.util.ts"],"sourcesContent":["import type { ChalkInstance } from 'chalk';\n\nimport chalk from 'chalk';\nimport consola from 'consola';\nimport { GraphQLError } from 'graphql';\nimport { randomUUID } from 'node:crypto';\n\nimport type { I_Return } from '#typescript/index.js';\n\nimport { getEnv } from '#config/env/index.js';\nimport { RESPONSE_STATUS } from '#constant/index.js';\nimport { baseCatchError } from '#util/log/index.js';\n\nimport type { I_CatchErrorOptions, I_IssueEntry, I_Log, I_ThrowError } from './log.type.js';\n\nlet _logLevelConfigured = false;\n\n/**\n * Lazily configures the consola log level based on the DEBUG environment variable.\n * Only runs once on first invocation to avoid repeated env loading.\n */\nfunction ensureLogLevel() {\n if (!_logLevelConfigured) {\n _logLevelConfigured = true;\n const env = getEnv();\n\n if (!env.DEBUG) {\n consola.level = 4;\n }\n }\n}\n\n/**\n * Throws a standardized error with optional status information and type specification.\n * This function creates and throws errors that can be either GraphQL errors (with extensions)\n * or standard JavaScript errors, depending on the specified type.\n *\n * @param options - Error configuration including message, status information, and error type.\n * @param options.message - The error message to display.\n * @param options.status - The response status information (defaults to INTERNAL_SERVER_ERROR).\n * @param options.type - The type of error to throw ('graphql' or 'rest', defaults to 'graphql').\n * @throws {GraphQLError} When type is 'graphql', throws a GraphQL error with extensions.\n * @throws {Error} When type is 'rest' or unspecified, throws a standard JavaScript error.\n */\nexport function throwError({\n message,\n status = RESPONSE_STATUS.INTERNAL_SERVER_ERROR,\n type = 'graphql',\n}: I_ThrowError): never {\n const responseMessage\n = message ?? status.MESSAGE ?? 'Internal server error';\n\n if (type === 'graphql') {\n throw new GraphQLError(responseMessage, {\n extensions: { code: status.CODE },\n });\n }\n\n throw new Error(responseMessage);\n}\n\n/**\n * Gets a chalk color instance by keyword name.\n * This function safely retrieves a chalk color function by name, falling back to green\n * if the specified color is not available or invalid.\n *\n * @param color - The color keyword to get the chalk instance for.\n * @returns A chalk instance for the specified color, or green as fallback.\n */\nfunction chalkKeyword(color: string): ChalkInstance {\n const chalkColor = chalk[color as keyof typeof chalk];\n\n return typeof chalkColor === 'function' ? (chalkColor as ChalkInstance) : chalk.green;\n}\n\n/**\n * Enhanced logging interface that extends consola with custom functionality.\n * This object provides all standard consola logging methods plus additional features\n * like boxed log printing for structured error/warning display.\n */\nexport const log: I_Log = {\n silent: consola.silent,\n level: consola.level,\n fatal: consola.fatal,\n error: consola.error,\n warn: consola.warn,\n log: consola.log,\n info: consola.info,\n success: consola.success,\n ready: consola.ready,\n start: consola.start,\n box: consola.box,\n debug: consola.debug,\n trace: consola.trace,\n verbose: consola.verbose,\n /**\n * Prints a boxed log with structured issue information.\n * This method displays issues (errors or warnings) in a formatted box with:\n * - File paths and line/column positions\n * - Rule violations (if applicable)\n * - Error/warning messages\n * - Color-coded output based on issue type\n *\n * @param title - The title to display in the box header.\n * @param issues - An array of issue entries to display.\n * @param color - The color to use for highlighting (defaults to 'red').\n */\n printBoxedLog(title: string, issues: I_IssueEntry[], color = 'red') {\n if (!issues?.length) {\n consola.box(chalk.green(title));\n return;\n }\n\n issues.forEach(({ file, position, rule, message }) => {\n const positionSuffix = position ? `:${position}` : '';\n const filePath = `${file}${positionSuffix}`;\n consola.log(`${chalk.gray('File:')} ${chalk.blue(filePath)}`);\n\n if (rule) {\n consola.log(` ${chalkKeyword(color)('Rule:')} ${rule}`);\n }\n\n consola.log(` ${chalkKeyword(color)('Message:')} ${message}`);\n });\n\n consola.box(chalkKeyword(color)(`${title} : ${issues.length}`));\n\n consola.log(chalk.gray('─'.repeat(40)));\n },\n /**\n * Creates a context-aware logger that prefixes all messages with a correlation ID.\n * Useful for distributed tracing across CyberSkill services.\n *\n * @param correlationId - A UUID correlation ID. If not provided, a new UUID is generated.\n * @returns A logger object with all standard methods that prefix output with the correlation ID.\n */\n withContext(correlationId?: string) {\n const id = correlationId ?? randomUUID();\n const prefix = chalk.gray(`[${id}]`);\n\n const withPrefix = (fn: (...args: unknown[]) => void) => {\n return (...args: unknown[]) => fn(prefix, ...args);\n };\n\n return {\n correlationId: id,\n fatal: withPrefix(consola.fatal),\n error: withPrefix(consola.error),\n warn: withPrefix(consola.warn),\n log: withPrefix(consola.log),\n info: withPrefix(consola.info),\n success: withPrefix(consola.success),\n debug: withPrefix(consola.debug),\n };\n },\n};\n\n/**\n * Catches and handles errors with configurable behavior.\n * Delegates to the shared `baseCatchError` implementation, adding Node-specific\n * log-level configuration via `ensureLogLevel()` before logging.\n *\n * @param errorInput - The error to catch and handle.\n * @param options - Configuration options for error handling behavior.\n * @returns Either the specified return value or a standardized error response object.\n */\nexport function catchError<T = unknown>(errorInput: unknown, options: I_CatchErrorOptions & { returnValue: T }): T;\nexport function catchError<T = unknown>(errorInput: unknown, options?: I_CatchErrorOptions): I_Return<T>;\nexport function catchError<T = unknown>(errorInput: unknown, options?: I_CatchErrorOptions): I_Return<T> | T {\n return baseCatchError<T>(errorInput, options, (message) => {\n ensureLogLevel();\n log.error(message);\n });\n}\n"],"mappings":";;;;;;;;AAeA,IAAI,IAAsB;AAM1B,SAAS,IAAiB;AACtB,CAAK,MACD,IAAsB,IACV,GAAQ,CAEX,UACL,EAAQ,QAAQ;;AAiB5B,SAAgB,EAAW,EACvB,YACA,YAAS,EAAgB,uBACzB,UAAO,aACa;CACpB,IAAM,IACA,KAAW,EAAO,WAAW;AAQnC,OANI,MAAS,YACH,IAAI,EAAa,GAAiB,EACpC,YAAY,EAAE,MAAM,EAAO,MAAM,EACpC,CAAC,GAGI,MAAM,EAAgB;;AAWpC,SAAS,EAAa,GAA8B;CAChD,IAAM,IAAa,EAAM;AAEzB,QAAO,OAAO,KAAe,aAAc,IAA+B,EAAM;;AAQpF,IAAa,IAAa;CACtB,QAAQ,EAAQ;CAChB,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,MAAM,EAAQ;CACd,KAAK,EAAQ;CACb,MAAM,EAAQ;CACd,SAAS,EAAQ;CACjB,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,KAAK,EAAQ;CACb,OAAO,EAAQ;CACf,OAAO,EAAQ;CACf,SAAS,EAAQ;CAajB,cAAc,GAAe,GAAwB,IAAQ,OAAO;AAChE,MAAI,CAAC,GAAQ,QAAQ;AACjB,KAAQ,IAAI,EAAM,MAAM,EAAM,CAAC;AAC/B;;AAiBJ,EAdA,EAAO,SAAS,EAAE,SAAM,aAAU,SAAM,iBAAc;GAElD,IAAM,IAAW,GAAG,IADG,IAAW,IAAI,MAAa;AAQnD,GANA,EAAQ,IAAI,GAAG,EAAM,KAAK,QAAQ,CAAC,GAAG,EAAM,KAAK,EAAS,GAAG,EAEzD,KACA,EAAQ,IAAI,MAAM,EAAa,EAAM,CAAC,QAAQ,CAAC,GAAG,IAAO,EAG7D,EAAQ,IAAI,MAAM,EAAa,EAAM,CAAC,WAAW,CAAC,GAAG,IAAU;IACjE,EAEF,EAAQ,IAAI,EAAa,EAAM,CAAC,GAAG,EAAM,KAAK,EAAO,SAAS,CAAC,EAE/D,EAAQ,IAAI,EAAM,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;;CAS3C,YAAY,GAAwB;EAChC,IAAM,IAAK,KAAiB,GAAY,EAClC,IAAS,EAAM,KAAK,IAAI,EAAG,GAAG,EAE9B,KAAc,OACR,GAAG,MAAoB,EAAG,GAAQ,GAAG,EAAK;AAGtD,SAAO;GACH,eAAe;GACf,OAAO,EAAW,EAAQ,MAAM;GAChC,OAAO,EAAW,EAAQ,MAAM;GAChC,MAAM,EAAW,EAAQ,KAAK;GAC9B,KAAK,EAAW,EAAQ,IAAI;GAC5B,MAAM,EAAW,EAAQ,KAAK;GAC9B,SAAS,EAAW,EAAQ,QAAQ;GACpC,OAAO,EAAW,EAAQ,MAAM;GACnC;;CAER;AAaD,SAAgB,EAAwB,GAAqB,GAAgD;AACzG,QAAO,EAAkB,GAAY,IAAU,MAAY;AAEvD,EADA,GAAgB,EAChB,EAAI,MAAM,EAAQ;GACpB"}
@@ -1,6 +1,7 @@
1
1
  export * from './mongo.constant.js';
2
2
  export * from './mongo.controller.js';
3
+ export type * from './mongo.controller.type.js';
3
4
  export * from './mongo.dynamic-populate.js';
4
5
  export * from './mongo.populate.js';
5
- export * from './mongo.type.js';
6
+ export type * from './mongo.type.js';
6
7
  export * from './mongo.util.js';
@@ -1,8 +1,7 @@
1
- import { MONGO_MIGRATE_OPTIONS as e, MONGO_SLUG_MAX_ATTEMPTS as t } from "./mongo.constant.js";
2
- import { convertEnumToModelName as n, mongo as r } from "./mongo.util.js";
3
- import { applyNestedPopulate as i } from "./mongo.populate.js";
4
- import { filterDynamicVirtualsFromPopulate as a, isMongooseDoc as o, populateDynamicVirtuals as s, remapDynamicPopulate as c } from "./mongo.dynamic-populate.js";
5
- import { MongooseController as l } from "./mongo.controller.mongoose.js";
6
- import { MongoController as u } from "./mongo.controller.native.js";
7
- import { C_Collection as d, C_Db as f, C_Document as p, C_Model as m } from "./mongo.type.js";
8
- export { d as C_Collection, f as C_Db, p as C_Document, m as C_Model, e as MONGO_MIGRATE_OPTIONS, t as MONGO_SLUG_MAX_ATTEMPTS, u as MongoController, l as MongooseController, i as applyNestedPopulate, n as convertEnumToModelName, a as filterDynamicVirtualsFromPopulate, o as isMongooseDoc, r as mongo, s as populateDynamicVirtuals, c as remapDynamicPopulate };
1
+ import { MONGO_MAX_TIME_MS as e, MONGO_MIGRATE_OPTIONS as t, MONGO_SLUG_MAX_ATTEMPTS as n } from "./mongo.constant.js";
2
+ import { convertEnumToModelName as r, mongo as i } from "./mongo.util.js";
3
+ import { applyNestedPopulate as a } from "./mongo.populate.js";
4
+ import { filterDynamicVirtualsFromPopulate as o, isMongooseDoc as s, populateDynamicVirtuals as c, remapDynamicPopulate as l } from "./mongo.dynamic-populate.js";
5
+ import { MongooseController as u } from "./mongo.controller.mongoose.js";
6
+ import { MongoController as d, createMongoController as f } from "./mongo.controller.native.js";
7
+ export { e as MONGO_MAX_TIME_MS, t as MONGO_MIGRATE_OPTIONS, n as MONGO_SLUG_MAX_ATTEMPTS, d as MongoController, u as MongooseController, a as applyNestedPopulate, r as convertEnumToModelName, f as createMongoController, o as filterDynamicVirtualsFromPopulate, s as isMongooseDoc, i as mongo, c as populateDynamicVirtuals, l as remapDynamicPopulate };
@@ -10,3 +10,8 @@ export declare const MONGO_MIGRATE_OPTIONS = "MONGO_MIGRATE_OPTIONS";
10
10
  * before giving up and returning a fallback slug.
11
11
  */
12
12
  export declare const MONGO_SLUG_MAX_ATTEMPTS = 100;
13
+ /**
14
+ * Default maxTimeMS for MongoDB queries.
15
+ * This constant defines the default maximum execution time for MongoDB queries.
16
+ */
17
+ export declare const MONGO_MAX_TIME_MS = 30000;
@@ -1,6 +1,6 @@
1
1
  //#region src/node/mongo/mongo.constant.ts
2
- var e = "MONGO_MIGRATE_OPTIONS", t = 100;
2
+ var e = "MONGO_MIGRATE_OPTIONS", t = 100, n = 3e4;
3
3
  //#endregion
4
- export { e as MONGO_MIGRATE_OPTIONS, t as MONGO_SLUG_MAX_ATTEMPTS };
4
+ export { n as MONGO_MAX_TIME_MS, e as MONGO_MIGRATE_OPTIONS, t as MONGO_SLUG_MAX_ATTEMPTS };
5
5
 
6
6
  //# sourceMappingURL=mongo.constant.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mongo.constant.js","names":[],"sources":["../../../src/node/mongo/mongo.constant.ts"],"sourcesContent":["/**\n * Environment variable key for MongoDB migration options.\n * This constant defines the environment variable name that can be used to configure\n * MongoDB migration settings and options for database schema management.\n */\nexport const MONGO_MIGRATE_OPTIONS = 'MONGO_MIGRATE_OPTIONS';\n\n/**\n * Maximum number of attempts to generate a unique slug.\n * This constant defines the maximum number of attempts to generate a unique slug\n * before giving up and returning a fallback slug.\n */\nexport const MONGO_SLUG_MAX_ATTEMPTS = 100;\n"],"mappings":";AAKA,IAAa,IAAwB,yBAOxB,IAA0B"}
1
+ {"version":3,"file":"mongo.constant.js","names":[],"sources":["../../../src/node/mongo/mongo.constant.ts"],"sourcesContent":["/**\n * Environment variable key for MongoDB migration options.\n * This constant defines the environment variable name that can be used to configure\n * MongoDB migration settings and options for database schema management.\n */\nexport const MONGO_MIGRATE_OPTIONS = 'MONGO_MIGRATE_OPTIONS';\n\n/**\n * Maximum number of attempts to generate a unique slug.\n * This constant defines the maximum number of attempts to generate a unique slug\n * before giving up and returning a fallback slug.\n */\nexport const MONGO_SLUG_MAX_ATTEMPTS = 100;\n\n/**\n * Default maxTimeMS for MongoDB queries.\n * This constant defines the default maximum execution time for MongoDB queries.\n */\nexport const MONGO_MAX_TIME_MS = 30_000;\n"],"mappings":";AAKA,IAAa,IAAwB,yBAOxB,IAA0B,KAM1B,IAAoB"}
@@ -8,15 +8,18 @@ import { C_Document, I_DeleteOptionsExtended, I_ExtendedModel, I_Input_CheckSlug
8
8
  export declare class MongooseController<T extends Partial<C_Document>> {
9
9
  private model;
10
10
  private defaultLimit;
11
+ private defaultProjection;
11
12
  /**
12
13
  * Creates a new Mongoose controller instance.
13
14
  *
14
15
  * @param model - The Mongoose model to operate on.
15
16
  * @param options - Optional configuration for the controller.
16
17
  * @param options.defaultLimit - Maximum documents returned by findAll when no limit is specified (default: 1,000).
18
+ * @param options.defaultProjection - Default projection to apply to findOne and findAll queries.
17
19
  */
18
20
  constructor(model: I_ExtendedModel<T>, options?: {
19
21
  defaultLimit?: number;
22
+ defaultProjection?: T_ProjectionType<T>;
20
23
  });
21
24
  /**
22
25
  * Gets the model name for logging and error messages.
@@ -3,16 +3,18 @@ import { RESPONSE_STATUS as t } from "../../constant/response-status.js";
3
3
  import { normalizeMongoFilter as n } from "../../util/object/object.util.js";
4
4
  import { generateRandomString as r, generateShortId as i, generateSlug as a } from "../../util/string/string.util.js";
5
5
  import { catchError as o, log as s } from "../log/log.util.js";
6
- import "./mongo.constant.js";
7
- import { filterDynamicVirtualsFromPopulate as c, populateDynamicVirtuals as l } from "./mongo.dynamic-populate.js";
6
+ import { MONGO_MAX_TIME_MS as c } from "./mongo.constant.js";
7
+ import { wrapNotFound as l } from "./mongo.controller.helpers.js";
8
+ import { filterDynamicVirtualsFromPopulate as u, populateDynamicVirtuals as d } from "./mongo.dynamic-populate.js";
8
9
  //#region src/node/mongo/mongo.controller.mongoose.ts
9
- function u(e) {
10
+ function f(e) {
10
11
  return e?.toObject?.() ?? e;
11
12
  }
12
- var d = class {
13
+ var p = class {
13
14
  defaultLimit;
15
+ defaultProjection;
14
16
  constructor(e, t) {
15
- this.model = e, this.defaultLimit = t?.defaultLimit ?? 1e3;
17
+ this.model = e, this.defaultLimit = t?.defaultLimit ?? 1e3, this.defaultProjection = t?.defaultProjection ?? {};
16
18
  }
17
19
  getModelName() {
18
20
  return this.model.modelName;
@@ -33,36 +35,32 @@ var d = class {
33
35
  }
34
36
  async populateDynamic(e, t) {
35
37
  let n = this.getDynamicVirtuals();
36
- return n && n.length > 0 && e.length > 0 ? await l(this.model.base, e, n, t, void 0, this.model) : e;
38
+ return n && n.length > 0 && e.length > 0 ? await d(this.model.base, e, n, t, void 0, this.model) : e;
37
39
  }
38
- async findOne(e = {}, r = {}, i = {}, a) {
40
+ async findOne(e = {}, t = {}, r = {}, i) {
39
41
  try {
40
- let o = n(e), s = this.model.findOne(o, r, i).maxTimeMS(3e4).lean(), l = c(a, this.getDynamicVirtuals());
41
- l && s.populate(l);
42
- let d = await s.exec();
42
+ let a = n(e), o = this.model.findOne(a, Object.keys(t).length > 0 ? t : Object.keys(this.defaultProjection).length > 0 ? this.defaultProjection : t, r).maxTimeMS(c).lean(), s = u(i, this.getDynamicVirtuals());
43
+ s && o.populate(s);
44
+ let d = await o.exec();
43
45
  return d ? {
44
46
  success: !0,
45
- result: u(await this.populateDynamicVirtualsForDocument(d, a))
46
- } : {
47
- success: !1,
48
- message: `No ${this.getModelName()} found.`,
49
- code: t.NOT_FOUND.CODE
50
- };
47
+ result: f(await this.populateDynamicVirtualsForDocument(d, i))
48
+ } : l(this.getModelName());
51
49
  } catch (e) {
52
50
  return o(e);
53
51
  }
54
52
  }
55
53
  async findAll(e = {}, t = {}, r = {}, i) {
56
54
  try {
57
- let a = n(e), o = this.model.find(a, t, r).maxTimeMS(3e4).lean();
55
+ let a = n(e), o = this.model.find(a, Object.keys(t).length > 0 ? t : Object.keys(this.defaultProjection).length > 0 ? this.defaultProjection : t, r).maxTimeMS(c).lean();
58
56
  r.limit || o.limit(this.defaultLimit);
59
- let l = c(i, this.getDynamicVirtuals());
57
+ let l = u(i, this.getDynamicVirtuals());
60
58
  l && o.populate(l);
61
- let d = await o.exec(), f = await this.populateDynamicVirtualsForDocuments(d, i), p = f.length === this.defaultLimit && !r.limit;
62
- return p && s.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
59
+ let d = await o.exec(), p = await this.populateDynamicVirtualsForDocuments(d, i), m = p.length === this.defaultLimit && !r.limit;
60
+ return m && s.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
63
61
  success: !0,
64
- result: f.map((e) => u(e)),
65
- truncated: p
62
+ result: p.map((e) => f(e)),
63
+ truncated: m
66
64
  };
67
65
  } catch (e) {
68
66
  return o(e);
@@ -71,7 +69,7 @@ var d = class {
71
69
  async findPaging(e = {}, t = {}) {
72
70
  try {
73
71
  let r = n(e), i = this.getDynamicVirtuals(), a = { ...t };
74
- t.populate && (a.populate = c(t.populate, i));
72
+ t.populate && (a.populate = u(t.populate, i));
75
73
  let o = await this.model.paginate(r, a);
76
74
  if (i && i.length > 0) {
77
75
  let e = await this.populateDynamicVirtualsForDocuments(o.docs, t.populate);
@@ -79,7 +77,7 @@ var d = class {
79
77
  success: !0,
80
78
  result: {
81
79
  ...o,
82
- docs: e.map((e) => u(e))
80
+ docs: e.map((e) => f(e))
83
81
  }
84
82
  };
85
83
  }
@@ -87,7 +85,7 @@ var d = class {
87
85
  success: !0,
88
86
  result: {
89
87
  ...o,
90
- docs: o.docs.map((e) => u(e))
88
+ docs: o.docs.map((e) => f(e))
91
89
  }
92
90
  };
93
91
  } catch (e) {
@@ -97,13 +95,13 @@ var d = class {
97
95
  async findPagingAggregate(e, t = {}) {
98
96
  try {
99
97
  let n = this.getDynamicVirtuals(), r = { ...t };
100
- t.populate && (r.populate = c(t.populate, n));
98
+ t.populate && (r.populate = u(t.populate, n));
101
99
  let i = await this.model.aggregatePaginate(this.model.aggregate(e), r), a = await this.populateDynamicVirtualsForDocuments(i.docs, t.populate);
102
100
  return {
103
101
  success: !0,
104
102
  result: {
105
103
  ...i,
106
- docs: a.map((e) => u(e))
104
+ docs: a.map((e) => f(e))
107
105
  }
108
106
  };
109
107
  } catch (e) {
@@ -142,20 +140,16 @@ var d = class {
142
140
  return o(e);
143
141
  }
144
142
  }
145
- async updateOne(e = {}, r = {}, i = {}) {
143
+ async updateOne(e = {}, t = {}, r = {}) {
146
144
  try {
147
- let a = n(e), o = await this.model.findOneAndUpdate(a, r, {
145
+ let i = n(e), a = await this.model.findOneAndUpdate(i, t, {
148
146
  new: !0,
149
- ...i
147
+ ...r
150
148
  }).exec();
151
- return o ? {
149
+ return a ? {
152
150
  success: !0,
153
- result: o?.toObject?.() ?? o
154
- } : {
155
- success: !1,
156
- message: `Failed to update ${this.getModelName()}.`,
157
- code: t.NOT_FOUND.CODE
158
- };
151
+ result: a?.toObject?.() ?? a
152
+ } : l(this.getModelName());
159
153
  } catch (e) {
160
154
  return o(e);
161
155
  }
@@ -171,31 +165,23 @@ var d = class {
171
165
  return o(e);
172
166
  }
173
167
  }
174
- async deleteOne(e = {}, r = {}) {
168
+ async deleteOne(e = {}, t = {}) {
175
169
  try {
176
- let i = n(e), a = await this.model.findOneAndDelete(i, r).exec();
177
- return a ? {
170
+ let r = n(e), i = await this.model.findOneAndDelete(r, t).exec();
171
+ return i ? {
178
172
  success: !0,
179
- result: a?.toObject?.() ?? a
180
- } : {
181
- success: !1,
182
- message: `No ${this.getModelName()} found to delete.`,
183
- code: t.NOT_FOUND.CODE
184
- };
173
+ result: i?.toObject?.() ?? i
174
+ } : l(this.getModelName());
185
175
  } catch (e) {
186
176
  return o(e);
187
177
  }
188
178
  }
189
- async deleteMany(e = {}, r = {}) {
179
+ async deleteMany(e = {}, t = {}) {
190
180
  try {
191
- let i = n(e), a = await this.model.deleteMany(i, r).exec();
192
- return a.deletedCount === 0 ? {
193
- success: !1,
194
- message: "No documents found to delete.",
195
- code: t.NOT_FOUND.CODE
196
- } : {
181
+ let r = n(e), i = await this.model.deleteMany(r, t).exec();
182
+ return i.deletedCount === 0 ? l("documents") : {
197
183
  success: !0,
198
- result: a
184
+ result: i
199
185
  };
200
186
  } catch (e) {
201
187
  return o(e);
@@ -326,6 +312,6 @@ var d = class {
326
312
  }
327
313
  };
328
314
  //#endregion
329
- export { d as MongooseController };
315
+ export { p as MongooseController };
330
316
 
331
317
  //# sourceMappingURL=mongo.controller.mongoose.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mongo.controller.mongoose.js","names":[],"sources":["../../../src/node/mongo/mongo.controller.mongoose.ts"],"sourcesContent":["import type { I_Return } from '#typescript/index.js';\n\nimport { RESPONSE_STATUS } from '#constant/index.js';\nimport { isObject } from '#util/common/index.js';\nimport { normalizeMongoFilter } from '#util/index.js';\nimport { generateRandomString, generateShortId, generateSlug } from '#util/string/index.js';\n\nimport type { C_Document, I_DeleteOptionsExtended, I_DynamicVirtualConfig, I_ExtendedModel, I_Input_CheckSlug, I_Input_CreateSlug, I_Input_GenerateSlug, I_PaginateOptionsWithPopulate, I_UpdateOptionsExtended, T_AggregatePaginateResult, T_DeleteResult, T_Input_Populate, T_InsertManyOptions, T_PaginateResult, T_PipelineStage, T_PopulateOptions, T_ProjectionType, T_QueryFilter, T_QueryOptions, T_UpdateQuery, T_UpdateResult } from './mongo.type.js';\n\nimport { catchError, log } from '../log/index.js';\nimport { MONGO_SLUG_MAX_ATTEMPTS } from './mongo.constant.js';\nimport { filterDynamicVirtualsFromPopulate, populateDynamicVirtuals } from './mongo.dynamic-populate.js';\n/**\n * Converts a Mongoose document to a plain object, handling the case where\n * the document may already be a plain object (e.g., from `.lean()`).\n *\n * @param doc - The document or plain object.\n * @returns The plain object representation.\n */\nfunction toPlainObject<T>(doc: T): T {\n return (doc as T & { toObject?: () => T })?.toObject?.() ?? doc;\n}\n\n/** Internal shape of a single virtual config stored on the model. */\ninterface I_VirtualConfig {\n name: string;\n options?: { ref?: unknown };\n}\n\n/**\n * Mongoose controller for database operations with advanced features.\n * This class provides a comprehensive interface for Mongoose operations including\n * pagination, aggregation, slug generation, and short ID creation.\n */\nexport class MongooseController<T extends Partial<C_Document>> {\n private defaultLimit: number;\n\n /**\n * Creates a new Mongoose controller instance.\n *\n * @param model - The Mongoose model to operate on.\n * @param options - Optional configuration for the controller.\n * @param options.defaultLimit - Maximum documents returned by findAll when no limit is specified (default: 1,000).\n */\n constructor(private model: I_ExtendedModel<T>, options?: { defaultLimit?: number }) {\n this.defaultLimit = options?.defaultLimit ?? 1_000;\n }\n\n /**\n * Gets the model name for logging and error messages.\n *\n * @returns The name of the model.\n */\n private getModelName(): string {\n return this.model.modelName;\n }\n\n /**\n * Gets the dynamic virtuals configuration from the model instance.\n *\n * @returns Array of dynamic virtual configurations or undefined if none exist.\n */\n private getDynamicVirtuals(): I_DynamicVirtualConfig<T>[] | undefined {\n const model = this.model as I_ExtendedModel<T> & { _virtualConfigs?: I_VirtualConfig[] };\n\n if (model._virtualConfigs) {\n const dynamicOnly = model._virtualConfigs.filter(\n v => typeof v.options?.ref === 'function',\n ) as unknown as I_DynamicVirtualConfig<T>[];\n\n if (dynamicOnly.length > 0) {\n return dynamicOnly;\n }\n }\n\n const schemaStatics = this.model.schema.statics as { [key: string]: unknown };\n\n return schemaStatics['_dynamicVirtuals'] as I_DynamicVirtualConfig<T>[] | undefined;\n }\n\n /**\n * Populates dynamic virtuals for a single document.\n *\n * @param result - The document to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The document with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocument(result: T, populate?: T_Input_Populate): Promise<T> {\n const populated = await this.populateDynamic([result], populate);\n return populated[0] ?? result;\n }\n\n /**\n * Populates dynamic virtuals for an array of documents.\n *\n * @param results - The documents to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The documents with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocuments(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n return this.populateDynamic(results, populate);\n }\n\n /**\n * Internal helper that populates dynamic virtuals for an array of documents.\n * Shared implementation used by both single-document and multi-document methods.\n */\n private async populateDynamic(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0 && results.length > 0) {\n return await populateDynamicVirtuals(this.model.base, results, dynamicVirtuals, populate, undefined, this.model) as T[];\n }\n\n return results;\n }\n\n /**\n * Finds a single document with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find the document.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found document.\n */\n async findOne(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const query = this.model.findOne(normalizedFilter, projection, options).maxTimeMS(30_000).lean();\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n if (!result) {\n return {\n success: false,\n message: `No ${this.getModelName()} found.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n const finalResult = await this.populateDynamicVirtualsForDocument(result, populate);\n\n return { success: true, result: toPlainObject(finalResult) };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Finds all documents with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found documents.\n */\n async findAll(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T[]>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const query = this.model.find(normalizedFilter, projection, options).maxTimeMS(30_000).lean();\n\n if (!options.limit) {\n query.limit(this.defaultLimit);\n }\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n const finalResult = await this.populateDynamicVirtualsForDocuments(result, populate);\n\n const truncated = finalResult.length === this.defaultLimit && !options.limit;\n\n if (truncated) {\n log.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`);\n }\n\n return { success: true, result: finalResult.map(item => toPlainObject(item)), truncated };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Finds documents with pagination support.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param options - Pagination options including page, limit, and population.\n * @returns A promise that resolves to a standardized response with paginated results.\n */\n async findPaging(\n filter: T_QueryFilter<T> = {},\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_PaginateResult<T>>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.paginate(normalizedFilter, filteredOptions);\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0) {\n const populatedDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: populatedDocs.map(item => toPlainObject(item)) } };\n }\n\n return { success: true, result: { ...result, docs: result.docs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_PaginateResult<T>>(error);\n }\n }\n\n /**\n * Performs aggregation with pagination support.\n *\n * @param pipeline - The aggregation pipeline stages.\n * @param options - Pagination options for the aggregation result.\n * @returns A promise that resolves to a standardized response with paginated aggregation results.\n */\n async findPagingAggregate(\n pipeline: T_PipelineStage[],\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_AggregatePaginateResult<T>>> {\n try {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.aggregatePaginate(\n this.model.aggregate(pipeline),\n filteredOptions,\n );\n\n const finalDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: finalDocs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_AggregatePaginateResult<T>>(error);\n }\n }\n\n /**\n * Counts documents matching the filter criteria.\n *\n * @param filter - The filter criteria to count documents.\n * @returns A promise that resolves to a standardized response with the document count.\n */\n async count(filter: T_QueryFilter<T> = {}): Promise<I_Return<number>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.countDocuments(normalizedFilter);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<number>(error);\n }\n }\n\n /**\n * Creates a single document.\n *\n * @param doc - The document to create.\n * @returns A promise that resolves to a standardized response with the created document.\n */\n async createOne(doc: T | Partial<T>): Promise<I_Return<T>> {\n try {\n const result = await this.model.create(doc as unknown as Parameters<typeof this.model.create>[0]);\n\n return { success: true, result: (result as T)?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Creates multiple documents with bulk insertion.\n *\n * @param docs - An array of documents to create.\n * @param options - Options for the bulk insertion operation.\n * @returns A promise that resolves to a standardized response with the created documents.\n */\n async createMany(\n docs: (T | Partial<T>)[],\n options: T_InsertManyOptions = {},\n ): Promise<I_Return<T[]>> {\n try {\n const createdDocuments = await this.model.insertMany(docs, options);\n\n return { success: true, result: createdDocuments.map(item => item?.toObject?.() ?? item) as T[] };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Updates a single document and returns the updated version.\n *\n * @param filter - The filter criteria to find the document to update.\n * @param update - The update data to apply.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the updated document.\n */\n async updateOne(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndUpdate(normalizedFilter, update, {\n new: true,\n ...options,\n })\n .exec();\n\n if (!result) {\n return {\n success: false,\n message: `Failed to update ${this.getModelName()}.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Updates multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to update.\n * @param update - The update data to apply.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateMany(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .updateMany(normalizedFilter, update, options)\n .exec();\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Deletes a single document and returns the deleted version.\n *\n * @param filter - The filter criteria to find the document to delete.\n * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the deleted document.\n */\n async deleteOne(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndDelete(normalizedFilter, options)\n .exec();\n\n if (!result) {\n return {\n success: false,\n message: `No ${this.getModelName()} found to delete.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Deletes multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to delete.\n * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteMany(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.deleteMany(normalizedFilter, options).exec();\n\n if (result.deletedCount === 0) {\n return {\n success: false,\n message: `No documents found to delete.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n\n /**\n * Creates a unique short ID based on a given ID.\n * This method generates multiple short IDs with increasing lengths and finds the first available one.\n *\n * @param id - The base ID to generate short IDs from.\n * @param length - The initial length for short ID generation (default: 4).\n * @returns A promise that resolves to a standardized response with the unique short ID.\n */\n async createShortId(id: string, length = 4): Promise<I_Return<string>> {\n try {\n const maxRetries = 10;\n const shortIds = Array.from({ length: maxRetries }, (_, index) =>\n generateShortId(id, index + length));\n\n // Use a single $in query instead of 10 parallel exists() calls\n const existingDocs = await this.model\n .find({ shortId: { $in: shortIds } })\n .select('shortId')\n .lean();\n\n const existingShortIds = new Set(\n existingDocs.map((d: Record<string, unknown>) => d['shortId'] as string),\n );\n\n const availableShortId = shortIds.find(s => !existingShortIds.has(s));\n\n if (availableShortId) {\n return { success: true, result: availableShortId };\n }\n\n return {\n success: false,\n message: 'Failed to create a unique shortId',\n code: RESPONSE_STATUS.INTERNAL_SERVER_ERROR.CODE,\n };\n }\n catch (error) {\n return catchError<string>(error);\n }\n }\n\n /**\n * Creates a query for slug existence checking.\n * This method generates a query that checks for slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug query generation including slug, field, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A MongoDB query object for checking slug existence.\n */\n createSlugQuery({ slug, field, isObject, haveHistory = false, filter }: I_Input_GenerateSlug<T>) {\n const baseFilter = { ...(filter ?? {}) };\n\n return isObject\n ? {\n ...baseFilter,\n $or: [\n { [`slug.${field}`]: slug },\n ...(haveHistory ? [{ slugHistory: { $elemMatch: { [`slug.${field}`]: slug } } }] : []),\n ],\n }\n : {\n ...baseFilter,\n $or: [\n { slug },\n ...(haveHistory ? [{ slugHistory: slug }] : []),\n ],\n };\n }\n\n /**\n * Creates a unique slug based on a given string.\n * This method generates multiple slug variations and finds the first available one.\n *\n * @param options - Configuration for slug generation including slug, field, and filter.\n * @param options.slug - The base slug string to make unique.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a unique slug string.\n */\n async createUniqueSlug({ slug, field, isObject, haveHistory, filter }: I_Input_GenerateSlug<T>): Promise<string> {\n if (!slug || typeof slug !== 'string') {\n throw new Error('Invalid slug provided: must be a non-empty string');\n }\n\n const baseSlug = generateSlug(slug);\n\n const baseExists = await this.model.exists(\n this.createSlugQuery({ slug: baseSlug, field, isObject, haveHistory, filter }),\n );\n\n if (!baseExists) {\n return baseSlug;\n }\n\n // Batch query: check all slug variations in a single database call instead of N+1 sequential queries\n const variants = Array.from(\n { length: MONGO_SLUG_MAX_ATTEMPTS },\n (_, i) => `${baseSlug}-${i + 1}`,\n );\n\n const slugQueries = variants.map(s =>\n this.createSlugQuery({ slug: s, field, isObject, haveHistory, filter }),\n );\n\n const slugField = isObject ? `slug.${field as string}` : 'slug';\n const existingDocs = await this.model\n .find({ $or: slugQueries.map(q => q.$or).flat() })\n .select(slugField)\n .lean();\n\n const existingSlugs = new Set(\n existingDocs.map((d: Record<string, unknown>) => {\n if (isObject) {\n const slug = d['slug'] as Record<string, unknown> | undefined;\n return slug?.[field as string];\n }\n return d['slug'];\n }),\n );\n\n const available = variants.find(s => !existingSlugs.has(s));\n\n if (available) {\n return available;\n }\n\n const timestamp = Date.now();\n const randomSuffix = generateRandomString(6);\n\n return `${baseSlug}-${timestamp}-${randomSuffix}`;\n }\n\n /**\n * Creates a slug for a document field.\n * This method handles both simple string fields and object fields with nested slug generation.\n *\n * @param options - Configuration for slug creation including field, source document, and filter.\n * @param options.field - The field name to create a slug for.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a standardized response with the created slug(s).\n */\n async createSlug<R = string>({ field, from, filter, haveHistory }: I_Input_CreateSlug<T>): Promise<I_Return<R>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const uniqueSlug = Object.fromEntries(\n await Promise.all(\n Object.entries(fieldValue).map(async ([key, value]) => {\n const uniqueSlugForKey = await this.createUniqueSlug({\n slug: value as string,\n field: key,\n isObject: true,\n haveHistory,\n filter,\n });\n return [key, uniqueSlugForKey];\n }),\n ),\n );\n\n return { success: true, result: uniqueSlug as R };\n }\n\n const uniqueSlug = await this.createUniqueSlug({\n slug: fieldValue as string,\n field,\n isObject: false,\n haveHistory,\n filter,\n });\n\n return { success: true, result: uniqueSlug as R };\n }\n catch (error) {\n return catchError<R>(error);\n }\n }\n\n /**\n * Checks if a slug already exists in the collection.\n * This method verifies slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug checking including slug, field, source document, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A promise that resolves to a standardized response indicating whether the slug exists.\n */\n async checkSlug({ slug, field, from, filter, haveHistory }: I_Input_CheckSlug<T>): Promise<I_Return<boolean>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const values = Object.values(fieldValue);\n const nestedSlugs = values.map(value => generateSlug(value as string));\n\n const existenceChecks = await Promise.all(\n nestedSlugs.map(nestedSlug =>\n this.model.exists(this.createSlugQuery({\n slug: nestedSlug,\n field,\n isObject: true,\n haveHistory,\n filter,\n })),\n ),\n );\n\n if (existenceChecks.some(exists => exists)) {\n return { success: true, result: true };\n }\n\n return { success: true, result: false };\n }\n\n const baseSlug = generateSlug(slug);\n const exists = await this.model.exists(this.createSlugQuery({\n slug: baseSlug,\n field,\n isObject: false,\n filter,\n }));\n\n return { success: true, result: exists !== null };\n }\n catch (error) {\n return catchError<boolean>(error);\n }\n }\n\n /**\n * Performs aggregation operations on the collection.\n *\n * @param pipeline - The aggregation pipeline stages to execute.\n * @returns A promise that resolves to a standardized response with the aggregation results.\n */\n async aggregate(pipeline: T_PipelineStage[]): Promise<I_Return<T[]>> {\n try {\n const result = await this.model.aggregate<T>(pipeline);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Retrieves distinct values for the specified key from the collection.\n *\n * @param key - The field for which to return distinct values.\n * @param filter - The filter query to apply (optional).\n * @param options - Additional options for the distinct operation (optional).\n * @returns A promise that resolves to a standardized response with the array of distinct values.\n */\n async distinct(\n key: string,\n filter: T_QueryFilter<T> = {},\n options: T_QueryOptions<T> = {},\n ): Promise<I_Return<unknown[]>> {\n try {\n const result = await this.model.distinct(key, filter, options);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<unknown[]>(error);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mongo.controller.mongoose.js","names":[],"sources":["../../../src/node/mongo/mongo.controller.mongoose.ts"],"sourcesContent":["import type { I_Return } from '#typescript/index.js';\n\nimport { RESPONSE_STATUS } from '#constant/index.js';\nimport { isObject } from '#util/common/index.js';\nimport { normalizeMongoFilter } from '#util/index.js';\nimport { generateRandomString, generateShortId, generateSlug } from '#util/string/index.js';\n\nimport type { C_Document, I_DeleteOptionsExtended, I_DynamicVirtualConfig, I_ExtendedModel, I_Input_CheckSlug, I_Input_CreateSlug, I_Input_GenerateSlug, I_PaginateOptionsWithPopulate, I_UpdateOptionsExtended, T_AggregatePaginateResult, T_DeleteResult, T_Input_Populate, T_InsertManyOptions, T_PaginateResult, T_PipelineStage, T_PopulateOptions, T_ProjectionType, T_QueryFilter, T_QueryOptions, T_UpdateQuery, T_UpdateResult } from './mongo.type.js';\n\nimport { catchError, log } from '../log/index.js';\nimport { MONGO_MAX_TIME_MS, MONGO_SLUG_MAX_ATTEMPTS } from './mongo.constant.js';\nimport { wrapNotFound } from './mongo.controller.helpers.js';\nimport { filterDynamicVirtualsFromPopulate, populateDynamicVirtuals } from './mongo.dynamic-populate.js';\n/**\n * Converts a Mongoose document to a plain object, handling the case where\n * the document may already be a plain object (e.g., from `.lean()`).\n *\n * @param doc - The document or plain object.\n * @returns The plain object representation.\n */\nfunction toPlainObject<T>(doc: T): T {\n return (doc as T & { toObject?: () => T })?.toObject?.() ?? doc;\n}\n\n/** Internal shape of a single virtual config stored on the model. */\ninterface I_VirtualConfig {\n name: string;\n options?: { ref?: unknown };\n}\n\n/**\n * Mongoose controller for database operations with advanced features.\n * This class provides a comprehensive interface for Mongoose operations including\n * pagination, aggregation, slug generation, and short ID creation.\n */\nexport class MongooseController<T extends Partial<C_Document>> {\n private defaultLimit: number;\n private defaultProjection: T_ProjectionType<T>;\n\n /**\n * Creates a new Mongoose controller instance.\n *\n * @param model - The Mongoose model to operate on.\n * @param options - Optional configuration for the controller.\n * @param options.defaultLimit - Maximum documents returned by findAll when no limit is specified (default: 1,000).\n * @param options.defaultProjection - Default projection to apply to findOne and findAll queries.\n */\n constructor(private model: I_ExtendedModel<T>, options?: { defaultLimit?: number; defaultProjection?: T_ProjectionType<T> }) {\n this.defaultLimit = options?.defaultLimit ?? 1_000;\n this.defaultProjection = options?.defaultProjection ?? {};\n }\n\n /**\n * Gets the model name for logging and error messages.\n *\n * @returns The name of the model.\n */\n private getModelName(): string {\n return this.model.modelName;\n }\n\n /**\n * Gets the dynamic virtuals configuration from the model instance.\n *\n * @returns Array of dynamic virtual configurations or undefined if none exist.\n */\n private getDynamicVirtuals(): I_DynamicVirtualConfig<T>[] | undefined {\n const model = this.model as I_ExtendedModel<T> & { _virtualConfigs?: I_VirtualConfig[] };\n\n if (model._virtualConfigs) {\n const dynamicOnly = model._virtualConfigs.filter(\n v => typeof v.options?.ref === 'function',\n ) as unknown as I_DynamicVirtualConfig<T>[];\n\n if (dynamicOnly.length > 0) {\n return dynamicOnly;\n }\n }\n\n const schemaStatics = this.model.schema.statics as { [key: string]: unknown };\n\n return schemaStatics['_dynamicVirtuals'] as I_DynamicVirtualConfig<T>[] | undefined;\n }\n\n /**\n * Populates dynamic virtuals for a single document.\n *\n * @param result - The document to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The document with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocument(result: T, populate?: T_Input_Populate): Promise<T> {\n const populated = await this.populateDynamic([result], populate);\n return populated[0] ?? result;\n }\n\n /**\n * Populates dynamic virtuals for an array of documents.\n *\n * @param results - The documents to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The documents with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocuments(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n return this.populateDynamic(results, populate);\n }\n\n /**\n * Internal helper that populates dynamic virtuals for an array of documents.\n * Shared implementation used by both single-document and multi-document methods.\n */\n private async populateDynamic(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0 && results.length > 0) {\n return await populateDynamicVirtuals(this.model.base, results, dynamicVirtuals, populate, undefined, this.model) as T[];\n }\n\n return results;\n }\n\n /**\n * Finds a single document with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find the document.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found document.\n */\n async findOne(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const appliedProjection = Object.keys(projection).length > 0 ? projection : Object.keys(this.defaultProjection).length > 0 ? this.defaultProjection : projection;\n const query = this.model.findOne(normalizedFilter, appliedProjection, options).maxTimeMS(MONGO_MAX_TIME_MS).lean();\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n if (!result) {\n return wrapNotFound(this.getModelName());\n }\n\n const finalResult = await this.populateDynamicVirtualsForDocument(result, populate);\n\n return { success: true, result: toPlainObject(finalResult) };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Finds all documents with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found documents.\n */\n async findAll(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T[]>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const appliedProjection = Object.keys(projection).length > 0 ? projection : Object.keys(this.defaultProjection).length > 0 ? this.defaultProjection : projection;\n const query = this.model.find(normalizedFilter, appliedProjection, options).maxTimeMS(MONGO_MAX_TIME_MS).lean();\n\n if (!options.limit) {\n query.limit(this.defaultLimit);\n }\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n const finalResult = await this.populateDynamicVirtualsForDocuments(result, populate);\n\n const truncated = finalResult.length === this.defaultLimit && !options.limit;\n\n if (truncated) {\n log.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`);\n }\n\n return { success: true, result: finalResult.map(item => toPlainObject(item)), truncated };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Finds documents with pagination support.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param options - Pagination options including page, limit, and population.\n * @returns A promise that resolves to a standardized response with paginated results.\n */\n async findPaging(\n filter: T_QueryFilter<T> = {},\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_PaginateResult<T>>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.paginate(normalizedFilter, filteredOptions);\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0) {\n const populatedDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: populatedDocs.map(item => toPlainObject(item)) } };\n }\n\n return { success: true, result: { ...result, docs: result.docs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_PaginateResult<T>>(error);\n }\n }\n\n /**\n * Performs aggregation with pagination support.\n *\n * @param pipeline - The aggregation pipeline stages.\n * @param options - Pagination options for the aggregation result.\n * @returns A promise that resolves to a standardized response with paginated aggregation results.\n */\n async findPagingAggregate(\n pipeline: T_PipelineStage[],\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_AggregatePaginateResult<T>>> {\n try {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.aggregatePaginate(\n this.model.aggregate(pipeline),\n filteredOptions,\n );\n\n const finalDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: finalDocs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_AggregatePaginateResult<T>>(error);\n }\n }\n\n /**\n * Counts documents matching the filter criteria.\n *\n * @param filter - The filter criteria to count documents.\n * @returns A promise that resolves to a standardized response with the document count.\n */\n async count(filter: T_QueryFilter<T> = {}): Promise<I_Return<number>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.countDocuments(normalizedFilter);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<number>(error);\n }\n }\n\n /**\n * Creates a single document.\n *\n * @param doc - The document to create.\n * @returns A promise that resolves to a standardized response with the created document.\n */\n async createOne(doc: T | Partial<T>): Promise<I_Return<T>> {\n try {\n const result = await this.model.create(doc as unknown as Parameters<typeof this.model.create>[0]);\n\n return { success: true, result: (result as T)?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Creates multiple documents with bulk insertion.\n *\n * @param docs - An array of documents to create.\n * @param options - Options for the bulk insertion operation.\n * @returns A promise that resolves to a standardized response with the created documents.\n */\n async createMany(\n docs: (T | Partial<T>)[],\n options: T_InsertManyOptions = {},\n ): Promise<I_Return<T[]>> {\n try {\n const createdDocuments = await this.model.insertMany(docs, options);\n\n return { success: true, result: createdDocuments.map(item => item?.toObject?.() ?? item) as T[] };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Updates a single document and returns the updated version.\n *\n * @param filter - The filter criteria to find the document to update.\n * @param update - The update data to apply.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the updated document.\n */\n async updateOne(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndUpdate(normalizedFilter, update, {\n new: true,\n ...options,\n })\n .exec();\n\n if (!result) {\n return wrapNotFound(this.getModelName());\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Updates multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to update.\n * @param update - The update data to apply.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateMany(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .updateMany(normalizedFilter, update, options)\n .exec();\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Deletes a single document and returns the deleted version.\n *\n * @param filter - The filter criteria to find the document to delete.\n * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the deleted document.\n */\n async deleteOne(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndDelete(normalizedFilter, options)\n .exec();\n\n if (!result) {\n return wrapNotFound(this.getModelName());\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Deletes multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to delete.\n * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteMany(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.deleteMany(normalizedFilter, options).exec();\n\n if (result.deletedCount === 0) {\n return wrapNotFound('documents');\n }\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n\n /**\n * Creates a unique short ID based on a given ID.\n * This method generates multiple short IDs with increasing lengths and finds the first available one.\n *\n * @param id - The base ID to generate short IDs from.\n * @param length - The initial length for short ID generation (default: 4).\n * @returns A promise that resolves to a standardized response with the unique short ID.\n */\n async createShortId(id: string, length = 4): Promise<I_Return<string>> {\n try {\n const maxRetries = 10;\n const shortIds = Array.from({ length: maxRetries }, (_, index) =>\n generateShortId(id, index + length));\n\n // Use a single $in query instead of 10 parallel exists() calls\n const existingDocs = await this.model\n .find({ shortId: { $in: shortIds } })\n .select('shortId')\n .lean();\n\n const existingShortIds = new Set(\n existingDocs.map((d: Record<string, unknown>) => d['shortId'] as string),\n );\n\n const availableShortId = shortIds.find(s => !existingShortIds.has(s));\n\n if (availableShortId) {\n return { success: true, result: availableShortId };\n }\n\n return {\n success: false,\n message: 'Failed to create a unique shortId',\n code: RESPONSE_STATUS.INTERNAL_SERVER_ERROR.CODE,\n };\n }\n catch (error) {\n return catchError<string>(error);\n }\n }\n\n /**\n * Creates a query for slug existence checking.\n * This method generates a query that checks for slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug query generation including slug, field, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A MongoDB query object for checking slug existence.\n */\n createSlugQuery({ slug, field, isObject, haveHistory = false, filter }: I_Input_GenerateSlug<T>) {\n const baseFilter = { ...(filter ?? {}) };\n\n return isObject\n ? {\n ...baseFilter,\n $or: [\n { [`slug.${field}`]: slug },\n ...(haveHistory ? [{ slugHistory: { $elemMatch: { [`slug.${field}`]: slug } } }] : []),\n ],\n }\n : {\n ...baseFilter,\n $or: [\n { slug },\n ...(haveHistory ? [{ slugHistory: slug }] : []),\n ],\n };\n }\n\n /**\n * Creates a unique slug based on a given string.\n * This method generates multiple slug variations and finds the first available one.\n *\n * @param options - Configuration for slug generation including slug, field, and filter.\n * @param options.slug - The base slug string to make unique.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a unique slug string.\n */\n async createUniqueSlug({ slug, field, isObject, haveHistory, filter }: I_Input_GenerateSlug<T>): Promise<string> {\n if (!slug || typeof slug !== 'string') {\n throw new Error('Invalid slug provided: must be a non-empty string');\n }\n\n const baseSlug = generateSlug(slug);\n\n const baseExists = await this.model.exists(\n this.createSlugQuery({ slug: baseSlug, field, isObject, haveHistory, filter }),\n );\n\n if (!baseExists) {\n return baseSlug;\n }\n\n // Batch query: check all slug variations in a single database call instead of N+1 sequential queries\n const variants = Array.from(\n { length: MONGO_SLUG_MAX_ATTEMPTS },\n (_, i) => `${baseSlug}-${i + 1}`,\n );\n\n const slugQueries = variants.map(s =>\n this.createSlugQuery({ slug: s, field, isObject, haveHistory, filter }),\n );\n\n const slugField = isObject ? `slug.${field as string}` : 'slug';\n const existingDocs = await this.model\n .find({ $or: slugQueries.map(q => q.$or).flat() })\n .select(slugField)\n .lean();\n\n const existingSlugs = new Set(\n existingDocs.map((d: Record<string, unknown>) => {\n if (isObject) {\n const slug = d['slug'] as Record<string, unknown> | undefined;\n return slug?.[field as string];\n }\n return d['slug'];\n }),\n );\n\n const available = variants.find(s => !existingSlugs.has(s));\n\n if (available) {\n return available;\n }\n\n const timestamp = Date.now();\n const randomSuffix = generateRandomString(6);\n\n return `${baseSlug}-${timestamp}-${randomSuffix}`;\n }\n\n /**\n * Creates a slug for a document field.\n * This method handles both simple string fields and object fields with nested slug generation.\n *\n * @param options - Configuration for slug creation including field, source document, and filter.\n * @param options.field - The field name to create a slug for.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a standardized response with the created slug(s).\n */\n async createSlug<R = string>({ field, from, filter, haveHistory }: I_Input_CreateSlug<T>): Promise<I_Return<R>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const uniqueSlug = Object.fromEntries(\n await Promise.all(\n Object.entries(fieldValue).map(async ([key, value]) => {\n const uniqueSlugForKey = await this.createUniqueSlug({\n slug: value as string,\n field: key,\n isObject: true,\n haveHistory,\n filter,\n });\n return [key, uniqueSlugForKey];\n }),\n ),\n );\n\n return { success: true, result: uniqueSlug as R };\n }\n\n const uniqueSlug = await this.createUniqueSlug({\n slug: fieldValue as string,\n field,\n isObject: false,\n haveHistory,\n filter,\n });\n\n return { success: true, result: uniqueSlug as R };\n }\n catch (error) {\n return catchError<R>(error);\n }\n }\n\n /**\n * Checks if a slug already exists in the collection.\n * This method verifies slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug checking including slug, field, source document, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A promise that resolves to a standardized response indicating whether the slug exists.\n */\n async checkSlug({ slug, field, from, filter, haveHistory }: I_Input_CheckSlug<T>): Promise<I_Return<boolean>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const values = Object.values(fieldValue);\n const nestedSlugs = values.map(value => generateSlug(value as string));\n\n const existenceChecks = await Promise.all(\n nestedSlugs.map(nestedSlug =>\n this.model.exists(this.createSlugQuery({\n slug: nestedSlug,\n field,\n isObject: true,\n haveHistory,\n filter,\n })),\n ),\n );\n\n if (existenceChecks.some(exists => exists)) {\n return { success: true, result: true };\n }\n\n return { success: true, result: false };\n }\n\n const baseSlug = generateSlug(slug);\n const exists = await this.model.exists(this.createSlugQuery({\n slug: baseSlug,\n field,\n isObject: false,\n filter,\n }));\n\n return { success: true, result: exists !== null };\n }\n catch (error) {\n return catchError<boolean>(error);\n }\n }\n\n /**\n * Performs aggregation operations on the collection.\n *\n * @param pipeline - The aggregation pipeline stages to execute.\n * @returns A promise that resolves to a standardized response with the aggregation results.\n */\n async aggregate(pipeline: T_PipelineStage[]): Promise<I_Return<T[]>> {\n try {\n const result = await this.model.aggregate<T>(pipeline);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Retrieves distinct values for the specified key from the collection.\n *\n * @param key - The field for which to return distinct values.\n * @param filter - The filter query to apply (optional).\n * @param options - Additional options for the distinct operation (optional).\n * @returns A promise that resolves to a standardized response with the array of distinct values.\n */\n async distinct(\n key: string,\n filter: T_QueryFilter<T> = {},\n options: T_QueryOptions<T> = {},\n ): Promise<I_Return<unknown[]>> {\n try {\n const result = await this.model.distinct(key, filter, options);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<unknown[]>(error);\n }\n }\n}\n"],"mappings":"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"}