@intlayer/backend 8.10.0 → 8.10.1

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 (179) hide show
  1. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/dictionary/markdown.json +10948 -8936
  2. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/interest_of_intlayer.json +1 -14957
  3. package/dist/esm/controllers/ai.controller.mjs +10 -9
  4. package/dist/esm/controllers/ai.controller.mjs.map +1 -1
  5. package/dist/esm/controllers/audit.controller.mjs +1 -1
  6. package/dist/esm/controllers/audit.controller.mjs.map +1 -1
  7. package/dist/esm/controllers/organization.controller.mjs +1 -1
  8. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  9. package/dist/esm/controllers/project.controller.mjs +2 -2
  10. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  11. package/dist/esm/controllers/showcaseProject.controller.mjs +0 -2
  12. package/dist/esm/controllers/showcaseProject.controller.mjs.map +1 -1
  13. package/dist/esm/controllers/translation.controller.mjs +0 -1
  14. package/dist/esm/controllers/translation.controller.mjs.map +1 -1
  15. package/dist/esm/controllers/user.controller.mjs +0 -6
  16. package/dist/esm/controllers/user.controller.mjs.map +1 -1
  17. package/dist/esm/schemas/account.schema.mjs +3 -2
  18. package/dist/esm/schemas/account.schema.mjs.map +1 -1
  19. package/dist/esm/{models/audit.model.mjs → schemas/audit.schema.mjs} +3 -3
  20. package/dist/esm/schemas/audit.schema.mjs.map +1 -0
  21. package/dist/esm/{models/auditJob.model.mjs → schemas/auditJob.schema.mjs} +3 -3
  22. package/dist/esm/schemas/auditJob.schema.mjs.map +1 -0
  23. package/dist/esm/{models/auditPage.model.mjs → schemas/auditPage.schema.mjs} +3 -3
  24. package/dist/esm/schemas/auditPage.schema.mjs.map +1 -0
  25. package/dist/esm/schemas/cliSessionToken.schema.mjs +3 -2
  26. package/dist/esm/schemas/cliSessionToken.schema.mjs.map +1 -1
  27. package/dist/esm/schemas/dictionary.schema.mjs +3 -2
  28. package/dist/esm/schemas/dictionary.schema.mjs.map +1 -1
  29. package/dist/esm/schemas/discussion.schema.mjs +3 -2
  30. package/dist/esm/schemas/discussion.schema.mjs.map +1 -1
  31. package/dist/esm/schemas/oAuth2.schema.mjs +3 -2
  32. package/dist/esm/schemas/oAuth2.schema.mjs.map +1 -1
  33. package/dist/esm/schemas/organization.schema.mjs +3 -2
  34. package/dist/esm/schemas/organization.schema.mjs.map +1 -1
  35. package/dist/esm/schemas/project.schema.mjs +3 -2
  36. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  37. package/dist/esm/schemas/session.schema.mjs +3 -2
  38. package/dist/esm/schemas/session.schema.mjs.map +1 -1
  39. package/dist/esm/schemas/showcaseProject.schema.mjs +3 -2
  40. package/dist/esm/schemas/showcaseProject.schema.mjs.map +1 -1
  41. package/dist/esm/schemas/tag.schema.mjs +3 -2
  42. package/dist/esm/schemas/tag.schema.mjs.map +1 -1
  43. package/dist/esm/schemas/user.schema.mjs +3 -2
  44. package/dist/esm/schemas/user.schema.mjs.map +1 -1
  45. package/dist/esm/services/audit/recursiveAudit.service.mjs +2 -2
  46. package/dist/esm/services/audit/recursiveAudit.service.mjs.map +1 -1
  47. package/dist/esm/services/bitbucket.service.mjs +1 -1
  48. package/dist/esm/services/bitbucket.service.mjs.map +1 -1
  49. package/dist/esm/services/cliSessionToken.service.mjs +1 -1
  50. package/dist/esm/services/cliSessionToken.service.mjs.map +1 -1
  51. package/dist/esm/services/dictionary.service.mjs +1 -1
  52. package/dist/esm/services/dictionary.service.mjs.map +1 -1
  53. package/dist/esm/services/github.service.mjs +1 -1
  54. package/dist/esm/services/github.service.mjs.map +1 -1
  55. package/dist/esm/services/gitlab.service.mjs +1 -1
  56. package/dist/esm/services/gitlab.service.mjs.map +1 -1
  57. package/dist/esm/services/oAuth2.service.mjs +2 -2
  58. package/dist/esm/services/oAuth2.service.mjs.map +1 -1
  59. package/dist/esm/services/organization.service.mjs +1 -1
  60. package/dist/esm/services/organization.service.mjs.map +1 -1
  61. package/dist/esm/services/project.service.mjs +1 -1
  62. package/dist/esm/services/project.service.mjs.map +1 -1
  63. package/dist/esm/services/projectAccessKey.service.mjs +1 -1
  64. package/dist/esm/services/projectAccessKey.service.mjs.map +1 -1
  65. package/dist/esm/services/showcase/showcaseProject.service.mjs +1 -1
  66. package/dist/esm/services/showcase/showcaseProject.service.mjs.map +1 -1
  67. package/dist/esm/services/tag.service.mjs +1 -1
  68. package/dist/esm/services/tag.service.mjs.map +1 -1
  69. package/dist/esm/services/user.service.mjs +1 -1
  70. package/dist/esm/services/user.service.mjs.map +1 -1
  71. package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/dictionary/markdown.json +10948 -8936
  72. package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/interest_of_intlayer.json +1 -14957
  73. package/dist/esm/utils/AI/auditDictionaryField/index.mjs +9 -0
  74. package/dist/esm/utils/AI/auditDictionaryField/index.mjs.map +1 -1
  75. package/dist/esm/utils/AI/getProjectAIOptions.mjs +20 -0
  76. package/dist/esm/utils/AI/getProjectAIOptions.mjs.map +1 -0
  77. package/dist/esm/utils/errors/ErrorHandler.mjs +40 -8
  78. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  79. package/dist/esm/utils/mapper/project.mjs +7 -1
  80. package/dist/esm/utils/mapper/project.mjs.map +1 -1
  81. package/dist/esm/utils/mongoDB/connectDB.mjs +12 -12
  82. package/dist/esm/utils/mongoDB/connectDB.mjs.map +1 -1
  83. package/dist/types/controllers/ai.controller.d.ts.map +1 -1
  84. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  85. package/dist/types/controllers/showcaseProject.controller.d.ts.map +1 -1
  86. package/dist/types/controllers/translation.controller.d.ts.map +1 -1
  87. package/dist/types/controllers/user.controller.d.ts.map +1 -1
  88. package/dist/types/schemas/account.schema.d.ts +3 -2
  89. package/dist/types/schemas/account.schema.d.ts.map +1 -1
  90. package/dist/types/schemas/audit.schema.d.ts +64 -0
  91. package/dist/types/schemas/audit.schema.d.ts.map +1 -0
  92. package/dist/types/schemas/auditJob.schema.d.ts +122 -0
  93. package/dist/types/schemas/auditJob.schema.d.ts.map +1 -0
  94. package/dist/types/schemas/auditPage.schema.d.ts +120 -0
  95. package/dist/types/schemas/auditPage.schema.d.ts.map +1 -0
  96. package/dist/types/schemas/cliSessionToken.schema.d.ts +10 -3
  97. package/dist/types/schemas/cliSessionToken.schema.d.ts.map +1 -1
  98. package/dist/types/schemas/dictionary.schema.d.ts +22 -13
  99. package/dist/types/schemas/dictionary.schema.d.ts.map +1 -1
  100. package/dist/types/schemas/discussion.schema.d.ts +19 -14
  101. package/dist/types/schemas/discussion.schema.d.ts.map +1 -1
  102. package/dist/types/schemas/oAuth2.schema.d.ts +13 -3
  103. package/dist/types/schemas/oAuth2.schema.d.ts.map +1 -1
  104. package/dist/types/schemas/organization.schema.d.ts +7 -6
  105. package/dist/types/schemas/organization.schema.d.ts.map +1 -1
  106. package/dist/types/schemas/plans.schema.d.ts +7 -7
  107. package/dist/types/schemas/project.schema.d.ts +7 -6
  108. package/dist/types/schemas/project.schema.d.ts.map +1 -1
  109. package/dist/types/schemas/session.schema.d.ts +11 -10
  110. package/dist/types/schemas/session.schema.d.ts.map +1 -1
  111. package/dist/types/schemas/showcaseProject.schema.d.ts +16 -15
  112. package/dist/types/schemas/showcaseProject.schema.d.ts.map +1 -1
  113. package/dist/types/schemas/tag.schema.d.ts +9 -8
  114. package/dist/types/schemas/tag.schema.d.ts.map +1 -1
  115. package/dist/types/schemas/user.schema.d.ts +8 -7
  116. package/dist/types/schemas/user.schema.d.ts.map +1 -1
  117. package/dist/types/services/audit/recursiveAudit.service.d.ts +2 -2
  118. package/dist/types/types/project.types.d.ts +2 -1
  119. package/dist/types/types/project.types.d.ts.map +1 -1
  120. package/dist/types/utils/AI/getProjectAIOptions.d.ts +15 -0
  121. package/dist/types/utils/AI/getProjectAIOptions.d.ts.map +1 -0
  122. package/dist/types/utils/errors/ErrorHandler.d.ts +4 -4
  123. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  124. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +3 -3
  125. package/dist/types/utils/mapper/project.d.ts.map +1 -1
  126. package/package.json +5 -5
  127. package/dist/esm/models/account.model.mjs +0 -9
  128. package/dist/esm/models/account.model.mjs.map +0 -1
  129. package/dist/esm/models/audit.model.mjs.map +0 -1
  130. package/dist/esm/models/auditJob.model.mjs.map +0 -1
  131. package/dist/esm/models/auditPage.model.mjs.map +0 -1
  132. package/dist/esm/models/cliSessionToken.model.mjs +0 -9
  133. package/dist/esm/models/cliSessionToken.model.mjs.map +0 -1
  134. package/dist/esm/models/dictionary.model.mjs +0 -9
  135. package/dist/esm/models/dictionary.model.mjs.map +0 -1
  136. package/dist/esm/models/discussion.model.mjs +0 -9
  137. package/dist/esm/models/discussion.model.mjs.map +0 -1
  138. package/dist/esm/models/oAuth2.model.mjs +0 -9
  139. package/dist/esm/models/oAuth2.model.mjs.map +0 -1
  140. package/dist/esm/models/organization.model.mjs +0 -9
  141. package/dist/esm/models/organization.model.mjs.map +0 -1
  142. package/dist/esm/models/project.model.mjs +0 -9
  143. package/dist/esm/models/project.model.mjs.map +0 -1
  144. package/dist/esm/models/session.model.mjs +0 -9
  145. package/dist/esm/models/session.model.mjs.map +0 -1
  146. package/dist/esm/models/showcaseProject.model.mjs +0 -9
  147. package/dist/esm/models/showcaseProject.model.mjs.map +0 -1
  148. package/dist/esm/models/tag.model.mjs +0 -9
  149. package/dist/esm/models/tag.model.mjs.map +0 -1
  150. package/dist/esm/models/user.model.mjs +0 -9
  151. package/dist/esm/models/user.model.mjs.map +0 -1
  152. package/dist/types/models/account.model.d.ts +0 -7
  153. package/dist/types/models/account.model.d.ts.map +0 -1
  154. package/dist/types/models/audit.model.d.ts +0 -18
  155. package/dist/types/models/audit.model.d.ts.map +0 -1
  156. package/dist/types/models/auditJob.model.d.ts +0 -31
  157. package/dist/types/models/auditJob.model.d.ts.map +0 -1
  158. package/dist/types/models/auditPage.model.d.ts +0 -29
  159. package/dist/types/models/auditPage.model.d.ts.map +0 -1
  160. package/dist/types/models/cliSessionToken.model.d.ts +0 -14
  161. package/dist/types/models/cliSessionToken.model.d.ts.map +0 -1
  162. package/dist/types/models/dictionary.model.d.ts +0 -16
  163. package/dist/types/models/dictionary.model.d.ts.map +0 -1
  164. package/dist/types/models/discussion.model.d.ts +0 -12
  165. package/dist/types/models/discussion.model.d.ts.map +0 -1
  166. package/dist/types/models/oAuth2.model.d.ts +0 -18
  167. package/dist/types/models/oAuth2.model.d.ts.map +0 -1
  168. package/dist/types/models/organization.model.d.ts +0 -7
  169. package/dist/types/models/organization.model.d.ts.map +0 -1
  170. package/dist/types/models/project.model.d.ts +0 -7
  171. package/dist/types/models/project.model.d.ts.map +0 -1
  172. package/dist/types/models/session.model.d.ts +0 -7
  173. package/dist/types/models/session.model.d.ts.map +0 -1
  174. package/dist/types/models/showcaseProject.model.d.ts +0 -7
  175. package/dist/types/models/showcaseProject.model.d.ts.map +0 -1
  176. package/dist/types/models/tag.model.d.ts +0 -7
  177. package/dist/types/models/tag.model.d.ts.map +0 -1
  178. package/dist/types/models/user.model.d.ts +0 -7
  179. package/dist/types/models/user.model.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"translation.controller.mjs","names":["dictionaryService.findDictionaries"],"sources":["../../../src/controllers/translation.controller.ts"],"sourcesContent":["import { getMissingLocalesContentFromDictionary } from '@intlayer/core/plugins';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport * as dictionaryService from '@services/dictionary.service';\nimport {\n addTranslationJob,\n getTranslationQueue,\n isTranslationJobPaused,\n translationCancelKey,\n translationPauseKey,\n} from '@services/translationQueue.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { getRedisClient } from '@utils/redis/connectRedis';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { Types } from 'mongoose';\n\nexport type TranslateDictionariesBody = {\n dictionaryIds: string[];\n targetLocales: Locale[];\n mode?: 'complete' | 'review';\n};\nexport type TranslateDictionariesResult = ResponseData<{ jobId: string }>;\n\nexport const translateDictionaries = async (\n request: FastifyRequest<{ Body: TranslateDictionariesBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user } = request.session || {};\n const { dictionaryIds, targetLocales, mode = 'complete' } = request.body;\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n try {\n const validIds = dictionaryIds.filter((id) => Types.ObjectId.isValid(id));\n\n if (validIds.length === 0) {\n return reply.send(\n formatResponse({\n data: null,\n message: 'No valid dictionary IDs provided',\n })\n );\n }\n\n const dictionaries = await dictionaryService.findDictionaries(\n { _id: { $in: validIds.map((id) => new Types.ObjectId(id)) } },\n 0,\n validIds.length,\n undefined,\n false\n );\n\n const dictionaryTargets: { dictionaryId: string; locales: Locale[] }[] = [];\n\n const projectLocales =\n project.configuration?.internationalization?.locales ?? [];\n\n for (const dictionary of dictionaries) {\n if (!dictionary.content) continue;\n\n const versionList = Array.from(dictionary.content.keys());\n const lastVersion = versionList[versionList.length - 1] || 'v1';\n const node = dictionary.content.get(lastVersion);\n\n if (!node) continue;\n\n // In 'complete' mode skip locales that already have full translations.\n // In 'review' mode translate everything regardless.\n let localesToTranslate: Locale[];\n if (mode === 'review') {\n localesToTranslate = targetLocales;\n } else {\n const missingLocales = getMissingLocalesContentFromDictionary(\n { key: dictionary.key, content: node.content },\n projectLocales\n );\n localesToTranslate = targetLocales.filter((locale) =>\n missingLocales.includes(locale)\n );\n }\n\n if (localesToTranslate.length > 0) {\n dictionaryTargets.push({\n dictionaryId: String(dictionary._id),\n locales: localesToTranslate,\n });\n }\n }\n\n if (dictionaryTargets.length === 0) {\n return reply.send(\n formatResponse({\n data: null,\n message: 'All dictionaries are already translated',\n })\n );\n }\n\n const job = await addTranslationJob({\n dictionaryTargets,\n projectId: String(project.id),\n userId: String(user.id),\n mode,\n });\n\n return reply.send(\n formatResponse<{ jobId: string }>({\n data: { jobId: job.id! },\n message: 'Translation started',\n })\n );\n } catch (error) {\n logger.error('Error in translateDictionaries', error);\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport const pauseTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const redis = getRedisClient();\n await redis.set(translationPauseKey(jobId), '1', 'EX', 86400);\n return reply.send(formatResponse({ data: { jobId }, message: 'Paused' }));\n};\n\nexport const resumeTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const redis = getRedisClient();\n await redis.del(translationPauseKey(jobId));\n return reply.send(formatResponse({ data: { jobId }, message: 'Resumed' }));\n};\n\nexport const stopTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const redis = getRedisClient();\n await redis.set(translationCancelKey(jobId), '1', 'EX', 86400);\n await redis.del(translationPauseKey(jobId));\n\n const queue = getTranslationQueue();\n const job = await queue.getJob(jobId);\n if (job) {\n const state = await job.getState();\n if (state === 'waiting' || state === 'delayed') {\n await job.remove();\n }\n }\n return reply.send(formatResponse({ data: { jobId }, message: 'Stopped' }));\n};\n\nexport const retryTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const queue = getTranslationQueue();\n const job = await queue.getJob(jobId);\n if (!job) return reply.status(404).send({ error: 'Job not found' });\n const redis = getRedisClient();\n await redis.del(translationCancelKey(jobId));\n await redis.del(translationPauseKey(jobId));\n await job.retry();\n return reply.send(formatResponse({ data: { jobId }, message: 'Retrying' }));\n};\n\nexport const restartTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const queue = getTranslationQueue();\n const job = await queue.getJob(jobId);\n if (!job) return reply.status(404).send({ error: 'Job not found' });\n const newJob = await addTranslationJob(job.data);\n return reply.send(\n formatResponse({ data: { jobId: newJob.id! }, message: 'Restarted' })\n );\n};\n\nexport const getTranslationStatus = async (\n request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user } = request.session || {};\n\n if (!user) {\n reply.raw.statusCode = 401;\n reply.raw.end();\n return;\n }\n\n reply.hijack();\n\n const headers = reply.getHeaders();\n Object.entries(headers).forEach(([key, value]) => {\n if (value !== undefined) {\n reply.raw.setHeader(key, value);\n }\n });\n\n const sseHeaders = {\n 'Content-Type': 'text/event-stream; charset=utf-8',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n };\n\n Object.entries(sseHeaders).forEach(([key, value]) => {\n reply.raw.setHeader(key, value);\n });\n reply.raw.flushHeaders?.();\n\n reply.raw.write(': connected\\n\\n');\n\n const send = (data: any) => {\n if (!reply.raw.writableEnded && !reply.raw.destroyed) {\n reply.raw.write(`data: ${JSON.stringify(data)}\\n\\n`);\n }\n };\n\n const projectId = project ? String(project.id) : null;\n const userId = String(user.id);\n\n const matchesSession = (job: any) =>\n projectId\n ? String(job.data.projectId) === projectId\n : String(job.data.userId) === userId;\n\n const sendJob = async (job: any) => {\n const state = await job.getState();\n const isPaused = await isTranslationJobPaused(job.id);\n send({\n jobId: job.id,\n state,\n isPaused,\n progress: job.progress,\n data: job.data,\n });\n };\n\n try {\n const translationQueue = getTranslationQueue();\n\n const getRelevantJobs = async () => {\n const jobs = await translationQueue.getJobs([\n 'active',\n 'waiting',\n 'delayed',\n 'completed',\n 'failed',\n ]);\n return jobs.filter(matchesSession);\n };\n\n const jobs = await getRelevantJobs();\n for (const job of jobs) {\n await sendJob(job);\n }\n\n const interval = setInterval(async () => {\n try {\n const currentJobs = await translationQueue.getJobs([\n 'active',\n 'waiting',\n 'delayed',\n 'completed',\n 'failed',\n ]);\n const relevantJobs = currentJobs.filter(matchesSession);\n for (const job of relevantJobs) {\n await sendJob(job);\n }\n } catch (error) {\n logger.error('Error polling translation status', error);\n }\n }, 2000);\n\n request.raw.on('close', () => {\n clearInterval(interval);\n });\n } catch (error) {\n logger.error('Error in translation status stream', error);\n if (!reply.raw.writableEnded && !reply.raw.destroyed) {\n reply.raw.write(\n `event: error\\ndata: ${JSON.stringify({ message: 'Internal Server Error' })}\\n\\n`\n );\n reply.raw.end();\n }\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"translation.controller.mjs","names":["dictionaryService.findDictionaries"],"sources":["../../../src/controllers/translation.controller.ts"],"sourcesContent":["import { getMissingLocalesContentFromDictionary } from '@intlayer/core/plugins';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport * as dictionaryService from '@services/dictionary.service';\nimport {\n addTranslationJob,\n getTranslationQueue,\n isTranslationJobPaused,\n translationCancelKey,\n translationPauseKey,\n} from '@services/translationQueue.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { getRedisClient } from '@utils/redis/connectRedis';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { Types } from 'mongoose';\n\nexport type TranslateDictionariesBody = {\n dictionaryIds: string[];\n targetLocales: Locale[];\n mode?: 'complete' | 'review';\n};\nexport type TranslateDictionariesResult = ResponseData<{ jobId: string }>;\n\nexport const translateDictionaries = async (\n request: FastifyRequest<{ Body: TranslateDictionariesBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user } = request.session || {};\n const { dictionaryIds, targetLocales, mode = 'complete' } = request.body;\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n try {\n const validIds = dictionaryIds.filter((id) => Types.ObjectId.isValid(id));\n\n if (validIds.length === 0) {\n return reply.send(\n formatResponse({\n data: null,\n message: 'No valid dictionary IDs provided',\n })\n );\n }\n\n const dictionaries = await dictionaryService.findDictionaries(\n { _id: { $in: validIds.map((id) => new Types.ObjectId(id)) } },\n 0,\n validIds.length,\n undefined,\n false\n );\n\n const dictionaryTargets: { dictionaryId: string; locales: Locale[] }[] = [];\n\n const projectLocales =\n project.configuration?.internationalization?.locales ?? [];\n\n for (const dictionary of dictionaries) {\n if (!dictionary.content) continue;\n\n const versionList = Array.from(dictionary.content.keys());\n const lastVersion = versionList[versionList.length - 1] || 'v1';\n const node = dictionary.content.get(lastVersion);\n\n if (!node) continue;\n\n // In 'complete' mode skip locales that already have full translations.\n // In 'review' mode translate everything regardless.\n let localesToTranslate: Locale[];\n if (mode === 'review') {\n localesToTranslate = targetLocales;\n } else {\n const missingLocales = getMissingLocalesContentFromDictionary(\n { key: dictionary.key, content: node.content },\n projectLocales\n );\n localesToTranslate = targetLocales.filter((locale) =>\n missingLocales.includes(locale)\n );\n }\n\n if (localesToTranslate.length > 0) {\n dictionaryTargets.push({\n dictionaryId: String(dictionary._id),\n locales: localesToTranslate,\n });\n }\n }\n\n if (dictionaryTargets.length === 0) {\n return reply.send(\n formatResponse({\n data: null,\n message: 'All dictionaries are already translated',\n })\n );\n }\n\n const job = await addTranslationJob({\n dictionaryTargets,\n projectId: String(project.id),\n userId: String(user.id),\n mode,\n });\n\n return reply.send(\n formatResponse<{ jobId: string }>({\n data: { jobId: job.id! },\n message: 'Translation started',\n })\n );\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport const pauseTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const redis = getRedisClient();\n await redis.set(translationPauseKey(jobId), '1', 'EX', 86400);\n return reply.send(formatResponse({ data: { jobId }, message: 'Paused' }));\n};\n\nexport const resumeTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const redis = getRedisClient();\n await redis.del(translationPauseKey(jobId));\n return reply.send(formatResponse({ data: { jobId }, message: 'Resumed' }));\n};\n\nexport const stopTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const redis = getRedisClient();\n await redis.set(translationCancelKey(jobId), '1', 'EX', 86400);\n await redis.del(translationPauseKey(jobId));\n\n const queue = getTranslationQueue();\n const job = await queue.getJob(jobId);\n if (job) {\n const state = await job.getState();\n if (state === 'waiting' || state === 'delayed') {\n await job.remove();\n }\n }\n return reply.send(formatResponse({ data: { jobId }, message: 'Stopped' }));\n};\n\nexport const retryTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const queue = getTranslationQueue();\n const job = await queue.getJob(jobId);\n if (!job) return reply.status(404).send({ error: 'Job not found' });\n const redis = getRedisClient();\n await redis.del(translationCancelKey(jobId));\n await redis.del(translationPauseKey(jobId));\n await job.retry();\n return reply.send(formatResponse({ data: { jobId }, message: 'Retrying' }));\n};\n\nexport const restartTranslationJob = async (\n request: FastifyRequest<{ Params: { jobId: string } }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user } = request.session || {};\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n const { jobId } = request.params;\n const queue = getTranslationQueue();\n const job = await queue.getJob(jobId);\n if (!job) return reply.status(404).send({ error: 'Job not found' });\n const newJob = await addTranslationJob(job.data);\n return reply.send(\n formatResponse({ data: { jobId: newJob.id! }, message: 'Restarted' })\n );\n};\n\nexport const getTranslationStatus = async (\n request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user } = request.session || {};\n\n if (!user) {\n reply.raw.statusCode = 401;\n reply.raw.end();\n return;\n }\n\n reply.hijack();\n\n const headers = reply.getHeaders();\n Object.entries(headers).forEach(([key, value]) => {\n if (value !== undefined) {\n reply.raw.setHeader(key, value);\n }\n });\n\n const sseHeaders = {\n 'Content-Type': 'text/event-stream; charset=utf-8',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no',\n };\n\n Object.entries(sseHeaders).forEach(([key, value]) => {\n reply.raw.setHeader(key, value);\n });\n reply.raw.flushHeaders?.();\n\n reply.raw.write(': connected\\n\\n');\n\n const send = (data: any) => {\n if (!reply.raw.writableEnded && !reply.raw.destroyed) {\n reply.raw.write(`data: ${JSON.stringify(data)}\\n\\n`);\n }\n };\n\n const projectId = project ? String(project.id) : null;\n const userId = String(user.id);\n\n const matchesSession = (job: any) =>\n projectId\n ? String(job.data.projectId) === projectId\n : String(job.data.userId) === userId;\n\n const sendJob = async (job: any) => {\n const state = await job.getState();\n const isPaused = await isTranslationJobPaused(job.id);\n send({\n jobId: job.id,\n state,\n isPaused,\n progress: job.progress,\n data: job.data,\n });\n };\n\n try {\n const translationQueue = getTranslationQueue();\n\n const getRelevantJobs = async () => {\n const jobs = await translationQueue.getJobs([\n 'active',\n 'waiting',\n 'delayed',\n 'completed',\n 'failed',\n ]);\n return jobs.filter(matchesSession);\n };\n\n const jobs = await getRelevantJobs();\n for (const job of jobs) {\n await sendJob(job);\n }\n\n const interval = setInterval(async () => {\n try {\n const currentJobs = await translationQueue.getJobs([\n 'active',\n 'waiting',\n 'delayed',\n 'completed',\n 'failed',\n ]);\n const relevantJobs = currentJobs.filter(matchesSession);\n for (const job of relevantJobs) {\n await sendJob(job);\n }\n } catch (error) {\n logger.error('Error polling translation status', error);\n }\n }, 2000);\n\n request.raw.on('close', () => {\n clearInterval(interval);\n });\n } catch (error) {\n logger.error('Error in translation status stream', error);\n if (!reply.raw.writableEnded && !reply.raw.destroyed) {\n reply.raw.write(\n `event: error\\ndata: ${JSON.stringify({ message: 'Internal Server Error' })}\\n\\n`\n );\n reply.raw.end();\n }\n }\n};\n"],"mappings":"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"}
@@ -330,12 +330,6 @@ const uploadAvatar = async (request, reply) => {
330
330
  });
331
331
  return reply.send(responseData);
332
332
  } catch (error) {
333
- logger.error("uploadAvatar error", {
334
- message: error?.message,
335
- name: error?.name,
336
- code: error?.code,
337
- stack: error?.stack
338
- });
339
333
  return ErrorHandler.handleAppErrorResponse(reply, error);
340
334
  }
341
335
  };
@@ -1 +1 @@
1
- {"version":3,"file":"user.controller.mjs","names":["userService.createUser","userService.findUsers","userService.countUsers","userService.getUserById","userService.getUserByEmail","userService.updateUserById","userService.deleteUser"],"sources":["../../../src/controllers/user.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport { sendEmail } from '@services/email.service';\nimport {\n deleteUserAvatar,\n uploadUserAvatar,\n validateAvatarUpload,\n} from '@services/user/avatarUpload.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getUserFiltersAndPagination,\n type UserFiltersParam,\n} from '@utils/filtersAndPagination/getUserFiltersAndPagination';\nimport { mapUsersToAPI, mapUserToAPI } from '@utils/mapper/user';\nimport { hasPermission } from '@utils/permissions';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { t } from 'fastify-intlayer';\nimport type { User, UserAPI } from '@/types/user.types';\n\nexport type CreateUserBody = { email: string; password?: string };\nexport type CreateUserResult = ResponseData<UserAPI>;\n\n/**\n * Creates a new user.\n */\nexport const createUser = async (\n request: FastifyRequest<{ Body: User }>,\n reply: FastifyReply\n): Promise<void> => {\n const user: User | undefined = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n try {\n const newUser = await userService.createUser(user);\n\n await sendEmail({\n type: 'welcome',\n to: newUser.email,\n username: newUser.name,\n loginLink: `${process.env.APP_URL}/auth/login`,\n });\n\n const formattedUser = mapUserToAPI(newUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User created',\n 'en-GB': 'User created',\n fr: 'Utilisateur créé',\n es: 'Usuario creado',\n ru: 'Пользователь создан',\n ja: 'ユーザーが作成されました',\n ko: '사용자가 생성되었습니다',\n zh: '用户已创建',\n de: 'Benutzer erstellt',\n ar: 'تم إنشاء المستخدم',\n it: 'Utente creato',\n pt: 'Usuário criado',\n hi: 'उपयोगकर्ता बनाया गया',\n tr: 'Kullanıcı oluşturuldu',\n pl: 'Użytkownik został utworzony',\n id: 'Pengguna dibuat',\n vi: 'Người dùng đã được tạo',\n uk: 'Користувача створено',\n }),\n description: t({\n en: 'User created successfully',\n 'en-GB': 'User created successfully',\n fr: 'Utilisateur créé avec succès',\n es: 'Usuario creado con éxito',\n ru: 'Пользователь успешно создан',\n ja: 'ユーザーが正常に作成されました',\n ko: '사용자가 성공적으로 생성되었습니다',\n zh: '用户已成功创建',\n de: 'Benutzer erfolgreich erstellt',\n ar: 'تم إنشاء المستخدم بنجاح',\n it: 'Utente creato con successo',\n pt: 'Usuário criado com sucesso',\n hi: 'उपयोगकर्ता सफलतापूर्वक बनाया गया',\n tr: 'Kullanıcı başarıyla oluşturuldu',\n pl: 'Użytkownik został pomyślnie utworzony',\n id: 'Pengguna berhasil dibuat',\n vi: 'Người dùng đã được tạo thành công',\n uk: 'Користувача успішно створено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetUsersParams = FiltersAndPagination<UserFiltersParam>;\nexport type GetUsersResult = PaginatedResponse<UserAPI>;\n\n/**\n * Retrieves a list of users based on filters and pagination.\n */\nexport const getUsers = async (\n request: FastifyRequest<{ Querystring: GetUsersParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, roles } = request.session || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getUserFiltersAndPagination(request);\n\n try {\n const users = await userService.findUsers(\n filters,\n skip,\n pageSize,\n sortOptions\n );\n\n // Skip permission check when there are no users to protect.\n // An empty result is safe to return without checking roles.\n if (\n users.length > 0 &&\n !hasPermission(\n roles || [],\n 'user:read'\n )({\n ...request.session,\n targetUsers: users,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const totalItems = await userService.countUsers(filters);\n\n const formattedUsers = mapUsersToAPI(users);\n\n const responseData = formatPaginatedResponse<UserAPI>({\n data: formattedUsers,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetUserByIdParams = { userId: UserAPI['id'] };\nexport type GetUserByIdResult = ResponseData<UserAPI>;\n\nexport const getUserById = async (\n request: FastifyRequest<{ Params: GetUserByIdParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { userId } = request.params;\n const { user: sessionUser } = request.session || {};\n\n if (!sessionUser) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (\n String(sessionUser.id) !== String(userId) &&\n sessionUser.role !== 'admin'\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const user = await userService.getUserById(userId);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetUserByEmailParams = { email: string };\nexport type GetUserByEmailResult = ResponseData<UserAPI>;\n\nexport const getUserByEmail = async (\n request: FastifyRequest<{ Params: GetUserByEmailParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { email } = request.params;\n const { user: sessionUser, roles } = request.session || {};\n\n if (!sessionUser) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:read'\n )({\n ...request.session,\n targetUsers: [user],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UpdateUserBody = Partial<UserAPI>;\nexport type UpdateUserResult = ResponseData<UserAPI>;\n\n/**\n * Updates user information (phone number, date of birth).\n */\nexport const updateUser = async (\n request: FastifyRequest<{ Body: UpdateUserBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const userData = request.body;\n const { user, roles } = request.session || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (typeof userData !== 'object') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_DATA_NOT_FOUND'\n );\n }\n\n if (!userData.id) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_INVALID_FIELDS'\n );\n }\n\n const userDB = await userService.getUserById(userData.id);\n\n if (!userDB) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:write'\n )({\n ...request.session,\n targetUsers: [userDB],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const updatedUser = await userService.updateUserById(userDB.id, userData);\n\n logger.info(\n `User updated: Name: ${updatedUser.name}, id: ${String(updatedUser.id)}`\n );\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User updated',\n 'en-GB': 'User updated',\n fr: 'Utilisateur mis à jour',\n es: 'Usuario actualizado',\n ru: 'Пользователь обновлен',\n ja: 'ユーザーが更新されました',\n ko: '사용자가 업데이트되었습니다',\n zh: '用户已更新',\n de: 'Benutzer aktualisiert',\n ar: 'تم تحديث المستخدم',\n it: 'Utente aggiornato',\n pt: 'Usuário atualizado',\n hi: 'उपयोगकर्ता अपडेट किया गया',\n tr: 'Kullanıcı güncellendi',\n pl: 'Użytkownik został zaktualizowany',\n id: 'Pengguna diperbarui',\n vi: 'Người dùng đã được cập nhật',\n uk: 'Користувача оновлено',\n }),\n description: t({\n en: 'User updated successfully',\n 'en-GB': 'User updated successfully',\n fr: 'Utilisateur mis à jour avec succès',\n es: 'Usuario actualizado con éxito',\n ru: 'Пользователь успешно обновлен',\n ja: 'ユーザーが正常に更新されました',\n ko: '사용자가 성공적으로 업데이트되었습니다',\n zh: '用户已成功更新',\n de: 'Benutzer erfolgreich aktualisiert',\n ar: 'تم تحديث المستخدم بنجاح',\n it: 'Utente aggiornato con successo',\n pt: 'Usuário atualizado com sucesso',\n hi: 'उपयोगकर्ता सफलतापूर्वक अपडेट किया गया',\n tr: 'Kullanıcı başarıyla güncellendi',\n pl: 'Użytkownik został pomyślnie zaktualizowany',\n id: 'Pengguna berhasil diperbarui',\n vi: 'Người dùng đã được cập nhật thành công',\n uk: 'Користувача успішно оновлено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type DeleteUserParams = { userId: string };\nexport type DeleteUserResult = ResponseData<UserAPI>;\n\n/**\n * Deletes a user based on the provided ID.\n */\nexport const deleteUser = async (\n request: FastifyRequest<{ Params: DeleteUserParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { userId } = request.params;\n const { roles } = request.session || {};\n\n try {\n const user = await userService.getUserById(userId);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:admin'\n )({\n ...request.session,\n targetUsers: [user],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n await userService.deleteUser(userId);\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User deleted',\n 'en-GB': 'User deleted',\n fr: 'Utilisateur supprimé',\n es: 'Usuario eliminado',\n ru: 'Пользователь удален',\n ja: 'ユーザーが削除されました',\n ko: '사용자가 삭제되었습니다',\n zh: '用户已删除',\n de: 'Benutzer gelöscht',\n ar: 'تم حذف المستخدم',\n it: 'Utente eliminato',\n pt: 'Usuário excluído',\n hi: 'उपयोगकर्ता हटा दिया गया',\n tr: 'Kullanıcı silindi',\n pl: 'Użytkownik został usunięty',\n id: 'Pengguna dihapus',\n vi: 'Người dùng đã bị xóa',\n uk: 'Користувача видалено',\n }),\n description: t({\n en: 'User deleted successfully',\n 'en-GB': 'User deleted successfully',\n fr: 'Utilisateur supprimé avec succès',\n es: 'Usuario eliminado con éxito',\n ru: 'Пользователь успешно удален',\n ja: 'ユーザーが正常に削除されました',\n ko: '사용자가 성공적으로 삭제되었습니다',\n zh: '用户已成功删除',\n de: 'Benutzer erfolgreich gelöscht',\n ar: 'تم حذف المستخدم بنجاح',\n it: 'Utente eliminato con successo',\n pt: 'Usuário excluído com sucesso',\n hi: 'उपयोगकर्ता सफलतापूर्वक हटा दिया गया',\n tr: 'Kullanıcı başarıyla silindi',\n pl: 'Użytkownik został pomyślnie usunięty',\n id: 'Pengguna berhasil dihapus',\n vi: 'Người dùng đã được xóa thành công',\n uk: 'Користувача успішно видалено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UploadUserAvatarResult = ResponseData<UserAPI>;\n\n/**\n * Uploads a new avatar for the authenticated user, stores it in S3, and\n * updates the user's image field. Deletes the previous avatar if it was\n * hosted on our own storage.\n */\nexport const uploadAvatar = async (\n request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { user, roles } = request.session || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n const rawContentType = request.headers['content-type'] ?? '';\n // Strip parameters like \"; charset=utf-8\" to get the bare MIME type\n const contentType = rawContentType.split(';')[0].trim() || 'image/jpeg';\n const contentLength = Number(request.headers['content-length'] ?? 0);\n\n logger.info('uploadAvatar request', {\n contentType,\n contentLength,\n userId: String(user.id),\n });\n\n const validationError = validateAvatarUpload(contentType, contentLength);\n if (validationError) {\n logger.warn('uploadAvatar validation failed', {\n validationError,\n contentType,\n contentLength,\n });\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_INVALID_FIELDS'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:write'\n )({ ...request.session, targetUsers: [user] })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const buffer = request.body;\n const userId = String(user.id);\n\n if (!Buffer.isBuffer(buffer) || buffer.length === 0) {\n logger.error('uploadAvatar: body is not a Buffer', {\n bodyType: typeof buffer,\n isBuffer: Buffer.isBuffer(buffer),\n length: Buffer.isBuffer(buffer) ? buffer.length : 'N/A',\n contentType,\n });\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_INVALID_FIELDS'\n );\n }\n\n // Delete the old avatar from S3 if it was uploaded by us\n if (user.image) {\n await deleteUserAvatar(user.image).catch(() => {});\n }\n\n const imageUrl = await uploadUserAvatar(buffer, userId, contentType);\n\n const updatedUser = await userService.updateUserById(userId, {\n image: imageUrl,\n });\n\n logger.info(`Avatar uploaded for user ${userId}`);\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Avatar uploaded',\n 'en-GB': 'Avatar uploaded',\n fr: 'Avatar mis à jour',\n es: 'Avatar actualizado',\n ru: 'Аватар загружен',\n ja: 'アバターをアップロードしました',\n ko: '아바타가 업로드되었습니다',\n zh: '头像已上传',\n de: 'Avatar hochgeladen',\n ar: 'تم رفع الصورة الرمزية',\n it: 'Avatar caricato',\n pt: 'Avatar enviado',\n hi: 'अवतार अपलोड किया गया',\n tr: 'Avatar yüklendi',\n pl: 'Awatar przesłany',\n id: 'Avatar diunggah',\n vi: 'Ảnh đại diện đã được tải lên',\n uk: 'Аватар завантажено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n logger.error('uploadAvatar error', {\n message: (error as Error)?.message,\n name: (error as Error)?.name,\n code: (error as any)?.code,\n stack: (error as Error)?.stack,\n });\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nlet clients: Array<{\n id: number;\n userId: string;\n res: { raw: FastifyReply['raw'] };\n}> = [];\n\nexport const sendVerificationUpdate = (user: User) => {\n const filteredClients = clients.filter(\n (client) => String(client.userId) === String(user.id)\n );\n\n for (const client of filteredClients) {\n if (user.emailVerified) {\n client.res.raw.write(\n `data: ${JSON.stringify({ userId: user.id, status: 'verified' })}\\n\\n`\n );\n }\n }\n};\n\nexport type VerifyEmailStatusSSEParams = { userId: string };\n\n/**\n * SSE to check the email verification status\n */\nexport const verifyEmailStatusSSE = async (\n request: FastifyRequest<{ Params: VerifyEmailStatusSSEParams }>,\n reply: FastifyReply\n) => {\n const { user: sessionUser, roles } = request.session || {};\n\n const { userId } = request.params; // Get user ID from params\n\n const user = await userService.getUserById(userId);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n // When a session exists, enforce ownership or admin access.\n // When there is no session the user just registered and is waiting for\n // email verification — BetterAuth does not create a session until the\n // email is verified, so we allow unauthenticated access for this endpoint.\n if (\n sessionUser &&\n String(sessionUser.id) !== String(userId) &&\n !hasPermission(\n roles || [],\n 'user:admin'\n )({ ...request.session, targetUsers: [user] })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n // Set headers for SSE\n reply.raw.setHeader('Content-Type', 'text/event-stream;charset=utf-8');\n reply.raw.setHeader('Cache-Control', 'no-cache, no-transform');\n reply.raw.setHeader('Connection', 'keep-alive');\n reply.raw.setHeader('X-Accel-Buffering', 'no'); // For Nginx buffering\n\n // Send initial data to ensure the connection is open\n reply.raw.write(':\\n\\n'); // Comment to keep connection alive\n reply.raw.flushHeaders?.();\n\n const clientId = Date.now();\n\n // Add client to the list\n const newClient = { id: clientId, userId, res: { raw: reply.raw } };\n clients.push(newClient);\n\n sendVerificationUpdate(user);\n\n // Remove client on connection close\n request.raw.on('close', () => {\n clients = clients.filter((client) => client.id !== clientId);\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"user.controller.mjs","names":["userService.createUser","userService.findUsers","userService.countUsers","userService.getUserById","userService.getUserByEmail","userService.updateUserById","userService.deleteUser"],"sources":["../../../src/controllers/user.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport { sendEmail } from '@services/email.service';\nimport {\n deleteUserAvatar,\n uploadUserAvatar,\n validateAvatarUpload,\n} from '@services/user/avatarUpload.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getUserFiltersAndPagination,\n type UserFiltersParam,\n} from '@utils/filtersAndPagination/getUserFiltersAndPagination';\nimport { mapUsersToAPI, mapUserToAPI } from '@utils/mapper/user';\nimport { hasPermission } from '@utils/permissions';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { t } from 'fastify-intlayer';\nimport type { User, UserAPI } from '@/types/user.types';\n\nexport type CreateUserBody = { email: string; password?: string };\nexport type CreateUserResult = ResponseData<UserAPI>;\n\n/**\n * Creates a new user.\n */\nexport const createUser = async (\n request: FastifyRequest<{ Body: User }>,\n reply: FastifyReply\n): Promise<void> => {\n const user: User | undefined = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n try {\n const newUser = await userService.createUser(user);\n\n await sendEmail({\n type: 'welcome',\n to: newUser.email,\n username: newUser.name,\n loginLink: `${process.env.APP_URL}/auth/login`,\n });\n\n const formattedUser = mapUserToAPI(newUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User created',\n 'en-GB': 'User created',\n fr: 'Utilisateur créé',\n es: 'Usuario creado',\n ru: 'Пользователь создан',\n ja: 'ユーザーが作成されました',\n ko: '사용자가 생성되었습니다',\n zh: '用户已创建',\n de: 'Benutzer erstellt',\n ar: 'تم إنشاء المستخدم',\n it: 'Utente creato',\n pt: 'Usuário criado',\n hi: 'उपयोगकर्ता बनाया गया',\n tr: 'Kullanıcı oluşturuldu',\n pl: 'Użytkownik został utworzony',\n id: 'Pengguna dibuat',\n vi: 'Người dùng đã được tạo',\n uk: 'Користувача створено',\n }),\n description: t({\n en: 'User created successfully',\n 'en-GB': 'User created successfully',\n fr: 'Utilisateur créé avec succès',\n es: 'Usuario creado con éxito',\n ru: 'Пользователь успешно создан',\n ja: 'ユーザーが正常に作成されました',\n ko: '사용자가 성공적으로 생성되었습니다',\n zh: '用户已成功创建',\n de: 'Benutzer erfolgreich erstellt',\n ar: 'تم إنشاء المستخدم بنجاح',\n it: 'Utente creato con successo',\n pt: 'Usuário criado com sucesso',\n hi: 'उपयोगकर्ता सफलतापूर्वक बनाया गया',\n tr: 'Kullanıcı başarıyla oluşturuldu',\n pl: 'Użytkownik został pomyślnie utworzony',\n id: 'Pengguna berhasil dibuat',\n vi: 'Người dùng đã được tạo thành công',\n uk: 'Користувача успішно створено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetUsersParams = FiltersAndPagination<UserFiltersParam>;\nexport type GetUsersResult = PaginatedResponse<UserAPI>;\n\n/**\n * Retrieves a list of users based on filters and pagination.\n */\nexport const getUsers = async (\n request: FastifyRequest<{ Querystring: GetUsersParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, roles } = request.session || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getUserFiltersAndPagination(request);\n\n try {\n const users = await userService.findUsers(\n filters,\n skip,\n pageSize,\n sortOptions\n );\n\n // Skip permission check when there are no users to protect.\n // An empty result is safe to return without checking roles.\n if (\n users.length > 0 &&\n !hasPermission(\n roles || [],\n 'user:read'\n )({\n ...request.session,\n targetUsers: users,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const totalItems = await userService.countUsers(filters);\n\n const formattedUsers = mapUsersToAPI(users);\n\n const responseData = formatPaginatedResponse<UserAPI>({\n data: formattedUsers,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetUserByIdParams = { userId: UserAPI['id'] };\nexport type GetUserByIdResult = ResponseData<UserAPI>;\n\nexport const getUserById = async (\n request: FastifyRequest<{ Params: GetUserByIdParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { userId } = request.params;\n const { user: sessionUser } = request.session || {};\n\n if (!sessionUser) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (\n String(sessionUser.id) !== String(userId) &&\n sessionUser.role !== 'admin'\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const user = await userService.getUserById(userId);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetUserByEmailParams = { email: string };\nexport type GetUserByEmailResult = ResponseData<UserAPI>;\n\nexport const getUserByEmail = async (\n request: FastifyRequest<{ Params: GetUserByEmailParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { email } = request.params;\n const { user: sessionUser, roles } = request.session || {};\n\n if (!sessionUser) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:read'\n )({\n ...request.session,\n targetUsers: [user],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UpdateUserBody = Partial<UserAPI>;\nexport type UpdateUserResult = ResponseData<UserAPI>;\n\n/**\n * Updates user information (phone number, date of birth).\n */\nexport const updateUser = async (\n request: FastifyRequest<{ Body: UpdateUserBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const userData = request.body;\n const { user, roles } = request.session || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (typeof userData !== 'object') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_DATA_NOT_FOUND'\n );\n }\n\n if (!userData.id) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_INVALID_FIELDS'\n );\n }\n\n const userDB = await userService.getUserById(userData.id);\n\n if (!userDB) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:write'\n )({\n ...request.session,\n targetUsers: [userDB],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const updatedUser = await userService.updateUserById(userDB.id, userData);\n\n logger.info(\n `User updated: Name: ${updatedUser.name}, id: ${String(updatedUser.id)}`\n );\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User updated',\n 'en-GB': 'User updated',\n fr: 'Utilisateur mis à jour',\n es: 'Usuario actualizado',\n ru: 'Пользователь обновлен',\n ja: 'ユーザーが更新されました',\n ko: '사용자가 업데이트되었습니다',\n zh: '用户已更新',\n de: 'Benutzer aktualisiert',\n ar: 'تم تحديث المستخدم',\n it: 'Utente aggiornato',\n pt: 'Usuário atualizado',\n hi: 'उपयोगकर्ता अपडेट किया गया',\n tr: 'Kullanıcı güncellendi',\n pl: 'Użytkownik został zaktualizowany',\n id: 'Pengguna diperbarui',\n vi: 'Người dùng đã được cập nhật',\n uk: 'Користувача оновлено',\n }),\n description: t({\n en: 'User updated successfully',\n 'en-GB': 'User updated successfully',\n fr: 'Utilisateur mis à jour avec succès',\n es: 'Usuario actualizado con éxito',\n ru: 'Пользователь успешно обновлен',\n ja: 'ユーザーが正常に更新されました',\n ko: '사용자가 성공적으로 업데이트되었습니다',\n zh: '用户已成功更新',\n de: 'Benutzer erfolgreich aktualisiert',\n ar: 'تم تحديث المستخدم بنجاح',\n it: 'Utente aggiornato con successo',\n pt: 'Usuário atualizado com sucesso',\n hi: 'उपयोगकर्ता सफलतापूर्वक अपडेट किया गया',\n tr: 'Kullanıcı başarıyla güncellendi',\n pl: 'Użytkownik został pomyślnie zaktualizowany',\n id: 'Pengguna berhasil diperbarui',\n vi: 'Người dùng đã được cập nhật thành công',\n uk: 'Користувача успішно оновлено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type DeleteUserParams = { userId: string };\nexport type DeleteUserResult = ResponseData<UserAPI>;\n\n/**\n * Deletes a user based on the provided ID.\n */\nexport const deleteUser = async (\n request: FastifyRequest<{ Params: DeleteUserParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { userId } = request.params;\n const { roles } = request.session || {};\n\n try {\n const user = await userService.getUserById(userId);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:admin'\n )({\n ...request.session,\n targetUsers: [user],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n await userService.deleteUser(userId);\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User deleted',\n 'en-GB': 'User deleted',\n fr: 'Utilisateur supprimé',\n es: 'Usuario eliminado',\n ru: 'Пользователь удален',\n ja: 'ユーザーが削除されました',\n ko: '사용자가 삭제되었습니다',\n zh: '用户已删除',\n de: 'Benutzer gelöscht',\n ar: 'تم حذف المستخدم',\n it: 'Utente eliminato',\n pt: 'Usuário excluído',\n hi: 'उपयोगकर्ता हटा दिया गया',\n tr: 'Kullanıcı silindi',\n pl: 'Użytkownik został usunięty',\n id: 'Pengguna dihapus',\n vi: 'Người dùng đã bị xóa',\n uk: 'Користувача видалено',\n }),\n description: t({\n en: 'User deleted successfully',\n 'en-GB': 'User deleted successfully',\n fr: 'Utilisateur supprimé avec succès',\n es: 'Usuario eliminado con éxito',\n ru: 'Пользователь успешно удален',\n ja: 'ユーザーが正常に削除されました',\n ko: '사용자가 성공적으로 삭제되었습니다',\n zh: '用户已成功删除',\n de: 'Benutzer erfolgreich gelöscht',\n ar: 'تم حذف المستخدم بنجاح',\n it: 'Utente eliminato con successo',\n pt: 'Usuário excluído com sucesso',\n hi: 'उपयोगकर्ता सफलतापूर्वक हटा दिया गया',\n tr: 'Kullanıcı başarıyla silindi',\n pl: 'Użytkownik został pomyślnie usunięty',\n id: 'Pengguna berhasil dihapus',\n vi: 'Người dùng đã được xóa thành công',\n uk: 'Користувача успішно видалено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UploadUserAvatarResult = ResponseData<UserAPI>;\n\n/**\n * Uploads a new avatar for the authenticated user, stores it in S3, and\n * updates the user's image field. Deletes the previous avatar if it was\n * hosted on our own storage.\n */\nexport const uploadAvatar = async (\n request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { user, roles } = request.session || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n const rawContentType = request.headers['content-type'] ?? '';\n // Strip parameters like \"; charset=utf-8\" to get the bare MIME type\n const contentType = rawContentType.split(';')[0].trim() || 'image/jpeg';\n const contentLength = Number(request.headers['content-length'] ?? 0);\n\n logger.info('uploadAvatar request', {\n contentType,\n contentLength,\n userId: String(user.id),\n });\n\n const validationError = validateAvatarUpload(contentType, contentLength);\n if (validationError) {\n logger.warn('uploadAvatar validation failed', {\n validationError,\n contentType,\n contentLength,\n });\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_INVALID_FIELDS'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:write'\n )({ ...request.session, targetUsers: [user] })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const buffer = request.body;\n const userId = String(user.id);\n\n if (!Buffer.isBuffer(buffer) || buffer.length === 0) {\n logger.error('uploadAvatar: body is not a Buffer', {\n bodyType: typeof buffer,\n isBuffer: Buffer.isBuffer(buffer),\n length: Buffer.isBuffer(buffer) ? buffer.length : 'N/A',\n contentType,\n });\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_INVALID_FIELDS'\n );\n }\n\n // Delete the old avatar from S3 if it was uploaded by us\n if (user.image) {\n await deleteUserAvatar(user.image).catch(() => {});\n }\n\n const imageUrl = await uploadUserAvatar(buffer, userId, contentType);\n\n const updatedUser = await userService.updateUserById(userId, {\n image: imageUrl,\n });\n\n logger.info(`Avatar uploaded for user ${userId}`);\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Avatar uploaded',\n 'en-GB': 'Avatar uploaded',\n fr: 'Avatar mis à jour',\n es: 'Avatar actualizado',\n ru: 'Аватар загружен',\n ja: 'アバターをアップロードしました',\n ko: '아바타가 업로드되었습니다',\n zh: '头像已上传',\n de: 'Avatar hochgeladen',\n ar: 'تم رفع الصورة الرمزية',\n it: 'Avatar caricato',\n pt: 'Avatar enviado',\n hi: 'अवतार अपलोड किया गया',\n tr: 'Avatar yüklendi',\n pl: 'Awatar przesłany',\n id: 'Avatar diunggah',\n vi: 'Ảnh đại diện đã được tải lên',\n uk: 'Аватар завантажено',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nlet clients: Array<{\n id: number;\n userId: string;\n res: { raw: FastifyReply['raw'] };\n}> = [];\n\nexport const sendVerificationUpdate = (user: User) => {\n const filteredClients = clients.filter(\n (client) => String(client.userId) === String(user.id)\n );\n\n for (const client of filteredClients) {\n if (user.emailVerified) {\n client.res.raw.write(\n `data: ${JSON.stringify({ userId: user.id, status: 'verified' })}\\n\\n`\n );\n }\n }\n};\n\nexport type VerifyEmailStatusSSEParams = { userId: string };\n\n/**\n * SSE to check the email verification status\n */\nexport const verifyEmailStatusSSE = async (\n request: FastifyRequest<{ Params: VerifyEmailStatusSSEParams }>,\n reply: FastifyReply\n) => {\n const { user: sessionUser, roles } = request.session || {};\n\n const { userId } = request.params; // Get user ID from params\n\n const user = await userService.getUserById(userId);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n // When a session exists, enforce ownership or admin access.\n // When there is no session the user just registered and is waiting for\n // email verification — BetterAuth does not create a session until the\n // email is verified, so we allow unauthenticated access for this endpoint.\n if (\n sessionUser &&\n String(sessionUser.id) !== String(userId) &&\n !hasPermission(\n roles || [],\n 'user:admin'\n )({ ...request.session, targetUsers: [user] })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n // Set headers for SSE\n reply.raw.setHeader('Content-Type', 'text/event-stream;charset=utf-8');\n reply.raw.setHeader('Cache-Control', 'no-cache, no-transform');\n reply.raw.setHeader('Connection', 'keep-alive');\n reply.raw.setHeader('X-Accel-Buffering', 'no'); // For Nginx buffering\n\n // Send initial data to ensure the connection is open\n reply.raw.write(':\\n\\n'); // Comment to keep connection alive\n reply.raw.flushHeaders?.();\n\n const clientId = Date.now();\n\n // Add client to the list\n const newClient = { id: clientId, userId, res: { raw: reply.raw } };\n clients.push(newClient);\n\n sendVerificationUpdate(user);\n\n // Remove client on connection close\n request.raw.on('close', () => {\n clients = clients.filter((client) => client.id !== clientId);\n });\n};\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Schema } from "mongoose";
1
+ import { Schema, model } from "mongoose";
2
2
 
3
3
  //#region src/schemas/account.schema.ts
4
4
  const accountSchema = new Schema({
@@ -72,7 +72,8 @@ const accountSchema = new Schema({
72
72
  }
73
73
  }
74
74
  });
75
+ const AccountModel = model("account", accountSchema);
75
76
 
76
77
  //#endregion
77
- export { accountSchema };
78
+ export { AccountModel, accountSchema };
78
79
  //# sourceMappingURL=account.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"account.schema.mjs","names":[],"sources":["../../../src/schemas/account.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type { AccountSchema } from '@/types/account.types';\n\nexport const accountSchema = new Schema<AccountSchema>(\n {\n userId: {\n type: Schema.Types.ObjectId as any,\n required: true,\n ref: 'User',\n },\n accountId: {\n type: String,\n required: true,\n },\n providerId: {\n type: String,\n required: true,\n },\n accessToken: {\n type: String,\n required: false,\n },\n access_token: {\n type: String,\n required: false,\n },\n refreshToken: {\n type: String,\n required: false,\n },\n refresh_token: {\n type: String,\n required: false,\n },\n idToken: {\n type: String,\n required: false,\n },\n expiresAt: {\n type: Date,\n required: false,\n },\n password: {\n type: String,\n required: false,\n },\n scope: {\n type: String,\n required: false,\n },\n },\n {\n timestamps: true,\n collection: 'account', // Explicitly set collection name\n\n toJSON: {\n virtuals: true,\n versionKey: false,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;AAGA,MAAa,gBAAgB,IAAI,OAC/B;CACE,QAAQ;EACN,MAAM,OAAO,MAAM;EACnB,UAAU;EACV,KAAK;CACP;CACA,WAAW;EACT,MAAM;EACN,UAAU;CACZ;CACA,YAAY;EACV,MAAM;EACN,UAAU;CACZ;CACA,aAAa;EACX,MAAM;EACN,UAAU;CACZ;CACA,cAAc;EACZ,MAAM;EACN,UAAU;CACZ;CACA,cAAc;EACZ,MAAM;EACN,UAAU;CACZ;CACA,eAAe;EACb,MAAM;EACN,UAAU;CACZ;CACA,SAAS;EACP,MAAM;EACN,UAAU;CACZ;CACA,WAAW;EACT,MAAM;EACN,UAAU;CACZ;CACA,UAAU;EACR,MAAM;EACN,UAAU;CACZ;CACA,OAAO;EACL,MAAM;EACN,UAAU;CACZ;AACF,GACA;CACE,YAAY;CACZ,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF"}
1
+ {"version":3,"file":"account.schema.mjs","names":[],"sources":["../../../src/schemas/account.schema.ts"],"sourcesContent":["import { model, Schema } from 'mongoose';\nimport type { AccountModelType, AccountSchema } from '@/types/account.types';\n\nexport const accountSchema = new Schema<AccountSchema>(\n {\n userId: {\n type: Schema.Types.ObjectId as any,\n required: true,\n ref: 'User',\n },\n accountId: {\n type: String,\n required: true,\n },\n providerId: {\n type: String,\n required: true,\n },\n accessToken: {\n type: String,\n required: false,\n },\n access_token: {\n type: String,\n required: false,\n },\n refreshToken: {\n type: String,\n required: false,\n },\n refresh_token: {\n type: String,\n required: false,\n },\n idToken: {\n type: String,\n required: false,\n },\n expiresAt: {\n type: Date,\n required: false,\n },\n password: {\n type: String,\n required: false,\n },\n scope: {\n type: String,\n required: false,\n },\n },\n {\n timestamps: true,\n collection: 'account', // Explicitly set collection name\n\n toJSON: {\n virtuals: true,\n versionKey: false,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\nexport const AccountModel = model<AccountSchema, AccountModelType>(\n 'account',\n accountSchema\n);\n"],"mappings":";;;AAGA,MAAa,gBAAgB,IAAI,OAC/B;CACE,QAAQ;EACN,MAAM,OAAO,MAAM;EACnB,UAAU;EACV,KAAK;CACP;CACA,WAAW;EACT,MAAM;EACN,UAAU;CACZ;CACA,YAAY;EACV,MAAM;EACN,UAAU;CACZ;CACA,aAAa;EACX,MAAM;EACN,UAAU;CACZ;CACA,cAAc;EACZ,MAAM;EACN,UAAU;CACZ;CACA,cAAc;EACZ,MAAM;EACN,UAAU;CACZ;CACA,eAAe;EACb,MAAM;EACN,UAAU;CACZ;CACA,SAAS;EACP,MAAM;EACN,UAAU;CACZ;CACA,WAAW;EACT,MAAM;EACN,UAAU;CACZ;CACA,UAAU;EACR,MAAM;EACN,UAAU;CACZ;CACA,OAAO;EACL,MAAM;EACN,UAAU;CACZ;AACF,GACA;CACE,YAAY;CACZ,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAEA,MAAa,eAAe,MAC1B,WACA,aACF"}
@@ -1,6 +1,6 @@
1
1
  import mongoose, { Schema } from "mongoose";
2
2
 
3
- //#region src/models/audit.model.ts
3
+ //#region src/schemas/audit.schema.ts
4
4
  const auditSchema = new Schema({
5
5
  domain: {
6
6
  type: String,
@@ -17,5 +17,5 @@ const auditSchema = new Schema({
17
17
  const AuditModel = mongoose.model("Audit", auditSchema);
18
18
 
19
19
  //#endregion
20
- export { AuditModel };
21
- //# sourceMappingURL=audit.model.mjs.map
20
+ export { AuditModel, auditSchema };
21
+ //# sourceMappingURL=audit.schema.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.schema.mjs","names":[],"sources":["../../../src/schemas/audit.schema.ts"],"sourcesContent":["import mongoose, { type Document, Schema } from 'mongoose';\n\nexport interface IAudit extends Document {\n domain: string;\n score: number;\n createdAt: Date;\n}\n\nexport const auditSchema = new Schema<IAudit>(\n {\n domain: {\n type: String,\n required: true,\n index: true,\n },\n score: {\n type: Number,\n required: true,\n min: 0,\n max: 100,\n },\n },\n {\n timestamps: true,\n }\n);\n\nexport const AuditModel = mongoose.model<IAudit>('Audit', auditSchema);\n"],"mappings":";;;AAQA,MAAa,cAAc,IAAI,OAC7B;CACE,QAAQ;EACN,MAAM;EACN,UAAU;EACV,OAAO;CACT;CACA,OAAO;EACL,MAAM;EACN,UAAU;EACV,KAAK;EACL,KAAK;CACP;AACF,GACA,EACE,YAAY,KACd,CACF;AAEA,MAAa,aAAa,SAAS,MAAc,SAAS,WAAW"}
@@ -1,6 +1,6 @@
1
1
  import mongoose, { Schema } from "mongoose";
2
2
 
3
- //#region src/models/auditJob.model.ts
3
+ //#region src/schemas/auditJob.schema.ts
4
4
  let AuditJobStatus = /* @__PURE__ */ function(AuditJobStatus) {
5
5
  AuditJobStatus["PENDING"] = "pending";
6
6
  AuditJobStatus["RUNNING"] = "running";
@@ -41,5 +41,5 @@ const auditJobSchema = new Schema({
41
41
  const AuditJobModel = mongoose.model("AuditJob", auditJobSchema);
42
42
 
43
43
  //#endregion
44
- export { AuditJobModel, AuditJobStatus };
45
- //# sourceMappingURL=auditJob.model.mjs.map
44
+ export { AuditJobModel, AuditJobStatus, auditJobSchema };
45
+ //# sourceMappingURL=auditJob.schema.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditJob.schema.mjs","names":[],"sources":["../../../src/schemas/auditJob.schema.ts"],"sourcesContent":["import mongoose, { type Document, Schema } from 'mongoose';\n\nexport enum AuditJobStatus {\n PENDING = 'pending',\n RUNNING = 'running',\n PAUSED = 'paused',\n CANCELLED = 'cancelled',\n COMPLETED = 'completed',\n FAILED = 'failed',\n}\n\nexport interface IAuditJob extends Document {\n targetUrl: string;\n userId?: string;\n status: AuditJobStatus;\n progress: number;\n totalPageCount: number;\n completedPageCount: number;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport const auditJobSchema = new Schema<IAuditJob>(\n {\n targetUrl: {\n type: String,\n required: true,\n index: true,\n },\n userId: {\n type: String,\n index: true,\n },\n status: {\n type: String,\n enum: Object.values(AuditJobStatus),\n default: AuditJobStatus.PENDING,\n },\n progress: {\n type: Number,\n default: 0,\n },\n totalPageCount: {\n type: Number,\n default: 0,\n },\n completedPageCount: {\n type: Number,\n default: 0,\n },\n },\n {\n timestamps: true,\n }\n);\n\nexport const AuditJobModel = mongoose.model<IAuditJob>(\n 'AuditJob',\n auditJobSchema\n);\n"],"mappings":";;;AAEA,IAAY,iBAAL;CACL;CACA;CACA;CACA;CACA;CACA;;AACF;AAaA,MAAa,iBAAiB,IAAI,OAChC;CACE,WAAW;EACT,MAAM;EACN,UAAU;EACV,OAAO;CACT;CACA,QAAQ;EACN,MAAM;EACN,OAAO;CACT;CACA,QAAQ;EACN,MAAM;EACN,MAAM,OAAO,OAAO,cAAc;EAClC;CACF;CACA,UAAU;EACR,MAAM;EACN,SAAS;CACX;CACA,gBAAgB;EACd,MAAM;EACN,SAAS;CACX;CACA,oBAAoB;EAClB,MAAM;EACN,SAAS;CACX;AACF,GACA,EACE,YAAY,KACd,CACF;AAEA,MAAa,gBAAgB,SAAS,MACpC,YACA,cACF"}
@@ -1,6 +1,6 @@
1
1
  import mongoose, { Schema } from "mongoose";
2
2
 
3
- //#region src/models/auditPage.model.ts
3
+ //#region src/schemas/auditPage.schema.ts
4
4
  let AuditPageStatus = /* @__PURE__ */ function(AuditPageStatus) {
5
5
  AuditPageStatus["PENDING"] = "pending";
6
6
  AuditPageStatus["RUNNING"] = "running";
@@ -35,5 +35,5 @@ auditPageSchema.index({
35
35
  const AuditPageModel = mongoose.model("AuditPage", auditPageSchema);
36
36
 
37
37
  //#endregion
38
- export { AuditPageModel, AuditPageStatus };
39
- //# sourceMappingURL=auditPage.model.mjs.map
38
+ export { AuditPageModel, AuditPageStatus, auditPageSchema };
39
+ //# sourceMappingURL=auditPage.schema.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditPage.schema.mjs","names":[],"sources":["../../../src/schemas/auditPage.schema.ts"],"sourcesContent":["import mongoose, { type Document, Schema } from 'mongoose';\n\nexport enum AuditPageStatus {\n PENDING = 'pending',\n RUNNING = 'running',\n COMPLETED = 'completed',\n FAILED = 'failed',\n}\n\nexport interface IAuditPage extends Document {\n jobId: mongoose.Types.ObjectId;\n url: string;\n status: AuditPageStatus;\n score?: number;\n results?: any;\n error?: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport const auditPageSchema = new Schema<IAuditPage>(\n {\n jobId: {\n type: Schema.Types.ObjectId,\n ref: 'AuditJob',\n required: true,\n index: true,\n },\n url: {\n type: String,\n required: true,\n },\n status: {\n type: String,\n enum: Object.values(AuditPageStatus),\n default: AuditPageStatus.PENDING,\n },\n score: {\n type: Number,\n },\n results: {\n type: Schema.Types.Mixed,\n },\n error: {\n type: String,\n },\n },\n {\n timestamps: true,\n }\n);\n\nauditPageSchema.index({ jobId: 1, url: 1 }, { unique: true });\n\nexport const AuditPageModel = mongoose.model<IAuditPage>(\n 'AuditPage',\n auditPageSchema\n);\n"],"mappings":";;;AAEA,IAAY,kBAAL;CACL;CACA;CACA;CACA;;AACF;AAaA,MAAa,kBAAkB,IAAI,OACjC;CACE,OAAO;EACL,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACV,OAAO;CACT;CACA,KAAK;EACH,MAAM;EACN,UAAU;CACZ;CACA,QAAQ;EACN,MAAM;EACN,MAAM,OAAO,OAAO,eAAe;EACnC;CACF;CACA,OAAO,EACL,MAAM,OACR;CACA,SAAS,EACP,MAAM,OAAO,MAAM,MACrB;CACA,OAAO,EACL,MAAM,OACR;AACF,GACA,EACE,YAAY,KACd,CACF;AAEA,gBAAgB,MAAM;CAAE,OAAO;CAAG,KAAK;AAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;AAE5D,MAAa,iBAAiB,SAAS,MACrC,aACA,eACF"}
@@ -1,4 +1,4 @@
1
- import { Schema } from "mongoose";
1
+ import { Schema, model } from "mongoose";
2
2
 
3
3
  //#region src/schemas/cliSessionToken.schema.ts
4
4
  const cliSessionTokenSchema = new Schema({
@@ -26,7 +26,8 @@ const cliSessionTokenSchema = new Schema({
26
26
  }
27
27
  }, { timestamps: true });
28
28
  cliSessionTokenSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
29
+ const CliSessionTokenModel = model("cliSessionToken", cliSessionTokenSchema);
29
30
 
30
31
  //#endregion
31
- export { cliSessionTokenSchema };
32
+ export { CliSessionTokenModel, cliSessionTokenSchema };
32
33
  //# sourceMappingURL=cliSessionToken.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cliSessionToken.schema.mjs","names":[],"sources":["../../../src/schemas/cliSessionToken.schema.ts"],"sourcesContent":["import type { Types } from 'mongoose';\nimport { Schema } from 'mongoose';\n\nexport type CliSessionToken = {\n token: string;\n userId: Types.ObjectId;\n organizationId: string;\n projectId: string;\n expiresAt: Date;\n};\n\nexport const cliSessionTokenSchema = new Schema<CliSessionToken>(\n {\n token: { type: String, required: true, unique: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n organizationId: { type: String, required: true },\n projectId: { type: String, required: true },\n expiresAt: { type: Date, required: true },\n },\n { timestamps: true }\n);\n\n// Auto-delete expired tokens via MongoDB TTL\ncliSessionTokenSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });\n"],"mappings":";;;AAWA,MAAa,wBAAwB,IAAI,OACvC;CACE,OAAO;EAAE,MAAM;EAAQ,UAAU;EAAM,QAAQ;CAAK;CACpD,QAAQ;EAAE,MAAM,OAAO,MAAM;EAAU,KAAK;EAAQ,UAAU;CAAK;CACnE,gBAAgB;EAAE,MAAM;EAAQ,UAAU;CAAK;CAC/C,WAAW;EAAE,MAAM;EAAQ,UAAU;CAAK;CAC1C,WAAW;EAAE,MAAM;EAAM,UAAU;CAAK;AAC1C,GACA,EAAE,YAAY,KAAK,CACrB;AAGA,sBAAsB,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"cliSessionToken.schema.mjs","names":[],"sources":["../../../src/schemas/cliSessionToken.schema.ts"],"sourcesContent":["import type { Types } from 'mongoose';\nimport { type Model, model, Schema } from 'mongoose';\n\nexport type CliSessionToken = {\n token: string;\n userId: Types.ObjectId;\n organizationId: string;\n projectId: string;\n expiresAt: Date;\n};\n\nexport const cliSessionTokenSchema = new Schema<CliSessionToken>(\n {\n token: { type: String, required: true, unique: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n organizationId: { type: String, required: true },\n projectId: { type: String, required: true },\n expiresAt: { type: Date, required: true },\n },\n { timestamps: true }\n);\n\n// Auto-delete expired tokens via MongoDB TTL\ncliSessionTokenSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });\n\nexport const CliSessionTokenModel = model<\n CliSessionToken,\n Model<CliSessionToken>\n>('cliSessionToken', cliSessionTokenSchema);\n"],"mappings":";;;AAWA,MAAa,wBAAwB,IAAI,OACvC;CACE,OAAO;EAAE,MAAM;EAAQ,UAAU;EAAM,QAAQ;CAAK;CACpD,QAAQ;EAAE,MAAM,OAAO,MAAM;EAAU,KAAK;EAAQ,UAAU;CAAK;CACnE,gBAAgB;EAAE,MAAM;EAAQ,UAAU;CAAK;CAC/C,WAAW;EAAE,MAAM;EAAQ,UAAU;CAAK;CAC1C,WAAW;EAAE,MAAM;EAAM,UAAU;CAAK;AAC1C,GACA,EAAE,YAAY,KAAK,CACrB;AAGA,sBAAsB,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,oBAAoB,EAAE,CAAC;AAEvE,MAAa,uBAAuB,MAGlC,mBAAmB,qBAAqB"}
@@ -1,4 +1,4 @@
1
- import { Schema } from "mongoose";
1
+ import { Schema, model } from "mongoose";
2
2
 
3
3
  //#region src/schemas/dictionary.schema.ts
4
4
  const versionedContentElSchema = new Schema({
@@ -66,7 +66,8 @@ const dictionarySchema = new Schema({
66
66
  }
67
67
  }
68
68
  });
69
+ const DictionaryModel = model("dictionary", dictionarySchema);
69
70
 
70
71
  //#endregion
71
- export { dictionarySchema };
72
+ export { DictionaryModel, dictionarySchema };
72
73
  //# sourceMappingURL=dictionary.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dictionary.schema.mjs","names":[],"sources":["../../../src/schemas/dictionary.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type {\n DictionarySchema,\n VersionedContentEl,\n} from '@/types/dictionary.types';\n\nconst versionedContentElSchema = new Schema<VersionedContentEl>(\n {\n name: {\n type: String,\n },\n description: {\n type: String,\n },\n content: {\n type: Schema.Types.Mixed,\n required: true,\n },\n },\n {\n timestamps: true,\n }\n);\n\nexport const dictionarySchema = new Schema<DictionarySchema>(\n {\n projectIds: {\n type: [Schema.Types.ObjectId],\n ref: 'Project',\n required: true,\n },\n key: {\n type: String,\n required: true,\n },\n title: {\n type: String,\n default: '',\n },\n description: {\n type: String,\n default: '',\n },\n tags: {\n type: [String],\n default: [],\n },\n content: {\n type: Map,\n of: versionedContentElSchema,\n required: true,\n default: null,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;AAMA,MAAM,2BAA2B,IAAI,OACnC;CACE,MAAM,EACJ,MAAM,OACR;CACA,aAAa,EACX,MAAM,OACR;CACA,SAAS;EACP,MAAM,OAAO,MAAM;EACnB,UAAU;CACZ;AACF,GACA,EACE,YAAY,KACd,CACF;AAEA,MAAa,mBAAmB,IAAI,OAClC;CACE,YAAY;EACV,MAAM,CAAC,OAAO,MAAM,QAAQ;EAC5B,KAAK;EACL,UAAU;CACZ;CACA,KAAK;EACH,MAAM;EACN,UAAU;CACZ;CACA,OAAO;EACL,MAAM;EACN,SAAS;CACX;CACA,aAAa;EACX,MAAM;EACN,SAAS;CACX;CACA,MAAM;EACJ,MAAM,CAAC,MAAM;EACb,SAAS,CAAC;CACZ;CACA,SAAS;EACP,MAAM;EACN,IAAI;EACJ,UAAU;EACV,SAAS;CACX;CACA,WAAW;EACT,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF"}
1
+ {"version":3,"file":"dictionary.schema.mjs","names":[],"sources":["../../../src/schemas/dictionary.schema.ts"],"sourcesContent":["import type { RenameId } from '@utils/mongoDB/types';\nimport { type Model, model, Schema } from 'mongoose';\nimport type {\n Dictionary,\n DictionarySchema,\n VersionedContentEl,\n} from '@/types/dictionary.types';\n\nconst versionedContentElSchema = new Schema<VersionedContentEl>(\n {\n name: {\n type: String,\n },\n description: {\n type: String,\n },\n content: {\n type: Schema.Types.Mixed,\n required: true,\n },\n },\n {\n timestamps: true,\n }\n);\n\nexport const dictionarySchema = new Schema<DictionarySchema>(\n {\n projectIds: {\n type: [Schema.Types.ObjectId],\n ref: 'Project',\n required: true,\n },\n key: {\n type: String,\n required: true,\n },\n title: {\n type: String,\n default: '',\n },\n description: {\n type: String,\n default: '',\n },\n tags: {\n type: [String],\n default: [],\n },\n content: {\n type: Map,\n of: versionedContentElSchema,\n required: true,\n default: null,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\nexport const DictionaryModel = model<RenameId<Dictionary>, Model<Dictionary>>(\n 'dictionary',\n dictionarySchema\n);\n"],"mappings":";;;AAQA,MAAM,2BAA2B,IAAI,OACnC;CACE,MAAM,EACJ,MAAM,OACR;CACA,aAAa,EACX,MAAM,OACR;CACA,SAAS;EACP,MAAM,OAAO,MAAM;EACnB,UAAU;CACZ;AACF,GACA,EACE,YAAY,KACd,CACF;AAEA,MAAa,mBAAmB,IAAI,OAClC;CACE,YAAY;EACV,MAAM,CAAC,OAAO,MAAM,QAAQ;EAC5B,KAAK;EACL,UAAU;CACZ;CACA,KAAK;EACH,MAAM;EACN,UAAU;CACZ;CACA,OAAO;EACL,MAAM;EACN,SAAS;CACX;CACA,aAAa;EACX,MAAM;EACN,SAAS;CACX;CACA,MAAM;EACJ,MAAM,CAAC,MAAM;EACb,SAAS,CAAC;CACZ;CACA,SAAS;EACP,MAAM;EACN,IAAI;EACJ,UAAU;EACV,SAAS;CACX;CACA,WAAW;EACT,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAEA,MAAa,kBAAkB,MAC7B,cACA,gBACF"}
@@ -1,4 +1,4 @@
1
- import { Schema } from "mongoose";
1
+ import { Schema, model } from "mongoose";
2
2
 
3
3
  //#region src/schemas/discussion.schema.ts
4
4
  const discussionSchema = new Schema({
@@ -79,7 +79,8 @@ const discussionSchema = new Schema({
79
79
  }
80
80
  }
81
81
  });
82
+ const DiscussionModel = model("discussion", discussionSchema);
82
83
 
83
84
  //#endregion
84
- export { discussionSchema };
85
+ export { DiscussionModel, discussionSchema };
85
86
  //# sourceMappingURL=discussion.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"discussion.schema.mjs","names":[],"sources":["../../../src/schemas/discussion.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type { DiscussionSchema } from '@/types/discussion.types';\n\nexport const discussionSchema = new Schema<DiscussionSchema>(\n {\n discussionId: {\n type: String,\n required: true,\n unique: true,\n },\n messages: [\n {\n role: {\n type: String,\n required: true,\n enum: ['user', 'assistant', 'system'],\n },\n content: {\n type: String,\n required: true,\n },\n timestamp: {\n type: Date,\n default: Date.now,\n },\n relatedFiles: {\n type: [String],\n },\n },\n ],\n userId: {\n type: Schema.Types.ObjectId,\n ref: 'user',\n required: false,\n },\n projectId: {\n type: Schema.Types.ObjectId,\n ref: 'project',\n required: false,\n },\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'organization',\n required: false,\n },\n title: {\n type: String,\n required: false,\n },\n type: {\n type: String,\n enum: ['doc', 'dashboard'],\n required: false,\n },\n isArchived: {\n type: Boolean,\n default: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;AAGA,MAAa,mBAAmB,IAAI,OAClC;CACE,cAAc;EACZ,MAAM;EACN,UAAU;EACV,QAAQ;CACV;CACA,UAAU,CACR;EACE,MAAM;GACJ,MAAM;GACN,UAAU;GACV,MAAM;IAAC;IAAQ;IAAa;GAAQ;EACtC;EACA,SAAS;GACP,MAAM;GACN,UAAU;EACZ;EACA,WAAW;GACT,MAAM;GACN,SAAS,KAAK;EAChB;EACA,cAAc,EACZ,MAAM,CAAC,MAAM,EACf;CACF,CACF;CACA,QAAQ;EACN,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,WAAW;EACT,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,gBAAgB;EACd,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,OAAO;EACL,MAAM;EACN,UAAU;CACZ;CACA,MAAM;EACJ,MAAM;EACN,MAAM,CAAC,OAAO,WAAW;EACzB,UAAU;CACZ;CACA,YAAY;EACV,MAAM;EACN,SAAS;CACX;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF"}
1
+ {"version":3,"file":"discussion.schema.mjs","names":[],"sources":["../../../src/schemas/discussion.schema.ts"],"sourcesContent":["import type { RenameId } from '@utils/mongoDB/types';\nimport { type Model, model, Schema } from 'mongoose';\nimport type { Discussion, DiscussionSchema } from '@/types/discussion.types';\n\nexport const discussionSchema = new Schema<DiscussionSchema>(\n {\n discussionId: {\n type: String,\n required: true,\n unique: true,\n },\n messages: [\n {\n role: {\n type: String,\n required: true,\n enum: ['user', 'assistant', 'system'],\n },\n content: {\n type: String,\n required: true,\n },\n timestamp: {\n type: Date,\n default: Date.now,\n },\n relatedFiles: {\n type: [String],\n },\n },\n ],\n userId: {\n type: Schema.Types.ObjectId,\n ref: 'user',\n required: false,\n },\n projectId: {\n type: Schema.Types.ObjectId,\n ref: 'project',\n required: false,\n },\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'organization',\n required: false,\n },\n title: {\n type: String,\n required: false,\n },\n type: {\n type: String,\n enum: ['doc', 'dashboard'],\n required: false,\n },\n isArchived: {\n type: Boolean,\n default: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\nexport const DiscussionModel = model<RenameId<Discussion>, Model<Discussion>>(\n 'discussion',\n discussionSchema\n);\n"],"mappings":";;;AAIA,MAAa,mBAAmB,IAAI,OAClC;CACE,cAAc;EACZ,MAAM;EACN,UAAU;EACV,QAAQ;CACV;CACA,UAAU,CACR;EACE,MAAM;GACJ,MAAM;GACN,UAAU;GACV,MAAM;IAAC;IAAQ;IAAa;GAAQ;EACtC;EACA,SAAS;GACP,MAAM;GACN,UAAU;EACZ;EACA,WAAW;GACT,MAAM;GACN,SAAS,KAAK;EAChB;EACA,cAAc,EACZ,MAAM,CAAC,MAAM,EACf;CACF,CACF;CACA,QAAQ;EACN,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,WAAW;EACT,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,gBAAgB;EACd,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,OAAO;EACL,MAAM;EACN,UAAU;CACZ;CACA,MAAM;EACJ,MAAM;EACN,MAAM,CAAC,OAAO,WAAW;EACzB,UAAU;CACZ;CACA,YAAY;EACV,MAAM;EACN,SAAS;CACX;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAEA,MAAa,kBAAkB,MAC7B,cACA,gBACF"}
@@ -1,4 +1,4 @@
1
- import { Schema } from "mongoose";
1
+ import { Schema, model } from "mongoose";
2
2
 
3
3
  //#region src/schemas/oAuth2.schema.ts
4
4
  const accessTokenSchema = new Schema({
@@ -42,7 +42,8 @@ const accessTokenSchema = new Schema({
42
42
  }
43
43
  });
44
44
  accessTokenSchema.index({ createdAt: 1 }, { expireAfterSeconds: 3600 * 24 * 90 });
45
+ const OAuth2AccessTokenModel = model("oAuth2", accessTokenSchema);
45
46
 
46
47
  //#endregion
47
- export { accessTokenSchema };
48
+ export { OAuth2AccessTokenModel, accessTokenSchema };
48
49
  //# sourceMappingURL=oAuth2.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"oAuth2.schema.mjs","names":[],"sources":["../../../src/schemas/oAuth2.schema.ts"],"sourcesContent":["import type { Client, Token as TokenType } from '@node-oauth/oauth2-server';\nimport { Schema } from 'mongoose';\nimport type { User } from '@/types/user.types';\n\nexport type Token = Omit<TokenType, 'client' | 'user'> & {\n clientId: Client['id'];\n userId: User['id'];\n};\n\nexport const accessTokenSchema = new Schema<Token>(\n {\n accessToken: {\n type: String,\n required: true,\n },\n accessTokenExpiresAt: {\n type: Date,\n },\n clientId: {\n type: String,\n ref: 'Project',\n required: true,\n },\n userId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\n// MongoDB TTL fallback: tokens are normally garbage collected by their\n// accessTokenExpiresAt, but if the sliding-refresh keeps a token alive for a\n// long time we still want a hard upper bound from creation.\naccessTokenSchema.index(\n { createdAt: 1 },\n {\n expireAfterSeconds: 60 * 60 * 24 * 90, // 90 Days\n }\n);\n"],"mappings":";;;AASA,MAAa,oBAAoB,IAAI,OACnC;CACE,aAAa;EACX,MAAM;EACN,UAAU;CACZ;CACA,sBAAsB,EACpB,MAAM,KACR;CACA,UAAU;EACR,MAAM;EACN,KAAK;EACL,UAAU;CACZ;CACA,QAAQ;EACN,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAKA,kBAAkB,MAChB,EAAE,WAAW,EAAE,GACf,EACE,oBAAoB,OAAU,KAAK,GACrC,CACF"}
1
+ {"version":3,"file":"oAuth2.schema.mjs","names":[],"sources":["../../../src/schemas/oAuth2.schema.ts"],"sourcesContent":["import type { Client, Token as TokenType } from '@node-oauth/oauth2-server';\nimport { type Model, model, Schema } from 'mongoose';\nimport type { User } from '@/types/user.types';\n\nexport type Token = Omit<TokenType, 'client' | 'user'> & {\n clientId: Client['id'];\n userId: User['id'];\n};\n\nexport const accessTokenSchema = new Schema<Token>(\n {\n accessToken: {\n type: String,\n required: true,\n },\n accessTokenExpiresAt: {\n type: Date,\n },\n clientId: {\n type: String,\n ref: 'Project',\n required: true,\n },\n userId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\n// MongoDB TTL fallback: tokens are normally garbage collected by their\n// accessTokenExpiresAt, but if the sliding-refresh keeps a token alive for a\n// long time we still want a hard upper bound from creation.\naccessTokenSchema.index(\n { createdAt: 1 },\n {\n expireAfterSeconds: 60 * 60 * 24 * 90, // 90 Days\n }\n);\n\nexport const OAuth2AccessTokenModel = model<Token, Model<Token>>(\n 'oAuth2',\n accessTokenSchema\n);\n"],"mappings":";;;AASA,MAAa,oBAAoB,IAAI,OACnC;CACE,aAAa;EACX,MAAM;EACN,UAAU;CACZ;CACA,sBAAsB,EACpB,MAAM,KACR;CACA,UAAU;EACR,MAAM;EACN,KAAK;EACL,UAAU;CACZ;CACA,QAAQ;EACN,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAKA,kBAAkB,MAChB,EAAE,WAAW,EAAE,GACf,EACE,oBAAoB,OAAU,KAAK,GACrC,CACF;AAEA,MAAa,yBAAyB,MACpC,UACA,iBACF"}
@@ -1,6 +1,6 @@
1
1
  import { MEMBERS_MIN_LENGTH, NAME_MAX_LENGTH, NAME_MIN_LENGTH } from "../utils/validation/validateOrganization.mjs";
2
2
  import { planSchema } from "./plans.schema.mjs";
3
- import { Schema } from "mongoose";
3
+ import { Schema, model } from "mongoose";
4
4
 
5
5
  //#region src/schemas/organization.schema.ts
6
6
  const organizationSchema = new Schema({
@@ -60,7 +60,8 @@ const organizationSchema = new Schema({
60
60
  organizationSchema.virtual("id").get(function() {
61
61
  return this._id.toString();
62
62
  });
63
+ const OrganizationModel = model("organization", organizationSchema);
63
64
 
64
65
  //#endregion
65
- export { organizationSchema };
66
+ export { OrganizationModel, organizationSchema };
66
67
  //# sourceMappingURL=organization.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"organization.schema.mjs","names":[],"sources":["../../../src/schemas/organization.schema.ts"],"sourcesContent":["import {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateOrganization';\nimport { Schema } from 'mongoose';\nimport type { OrganizationSchema } from '@/types/organization.types';\nimport { planSchema } from './plans.schema';\n\nexport const organizationSchema = new Schema<OrganizationSchema>(\n {\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n plan: {\n type: planSchema,\n },\n ssoEnabled: {\n type: Boolean,\n default: false,\n },\n domain: {\n type: String,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\n// Add virtual field for id\norganizationSchema.virtual('id').get(function () {\n return this._id.toString();\n});\n"],"mappings":";;;;;AASA,MAAa,qBAAqB,IAAI,OACpC;CACE,MAAM;EACJ,MAAM;EACN,UAAU;EACV;EACA;CACF;CACA,YAAY;EACV,MAAM,CAAC,OAAO,MAAM,QAAQ;EAC5B,KAAK;EACL,UAAU;EACV;CACF;CACA,WAAW;EACT,MAAM,CAAC,OAAO,MAAM,QAAQ;EAC5B,KAAK;EACL,UAAU;EACV;CACF;CACA,WAAW;EACT,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,MAAM,EACJ,MAAM,WACR;CACA,YAAY;EACV,MAAM;EACN,SAAS;CACX;CACA,QAAQ,EACN,MAAM,OACR;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAGA,mBAAmB,QAAQ,IAAI,EAAE,IAAI,WAAY;CAC/C,OAAO,KAAK,IAAI,SAAS;AAC3B,CAAC"}
1
+ {"version":3,"file":"organization.schema.mjs","names":[],"sources":["../../../src/schemas/organization.schema.ts"],"sourcesContent":["import {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateOrganization';\nimport { model, Schema } from 'mongoose';\nimport type {\n OrganizationModelType,\n OrganizationSchema,\n} from '@/types/organization.types';\nimport { planSchema } from './plans.schema';\n\nexport const organizationSchema = new Schema<OrganizationSchema>(\n {\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n plan: {\n type: planSchema,\n },\n ssoEnabled: {\n type: Boolean,\n default: false,\n },\n domain: {\n type: String,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\n// Add virtual field for id\norganizationSchema.virtual('id').get(function () {\n return this._id.toString();\n});\n\nexport const OrganizationModel = model<\n OrganizationSchema,\n OrganizationModelType\n>('organization', organizationSchema);\n"],"mappings":";;;;;AAYA,MAAa,qBAAqB,IAAI,OACpC;CACE,MAAM;EACJ,MAAM;EACN,UAAU;EACV;EACA;CACF;CACA,YAAY;EACV,MAAM,CAAC,OAAO,MAAM,QAAQ;EAC5B,KAAK;EACL,UAAU;EACV;CACF;CACA,WAAW;EACT,MAAM,CAAC,OAAO,MAAM,QAAQ;EAC5B,KAAK;EACL,UAAU;EACV;CACF;CACA,WAAW;EACT,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,MAAM,EACJ,MAAM,WACR;CACA,YAAY;EACV,MAAM;EACN,SAAS;CACX;CACA,QAAQ,EACN,MAAM,OACR;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAGA,mBAAmB,QAAQ,IAAI,EAAE,IAAI,WAAY;CAC/C,OAAO,KAAK,IAAI,SAAS;AAC3B,CAAC;AAED,MAAa,oBAAoB,MAG/B,gBAAgB,kBAAkB"}
@@ -1,5 +1,5 @@
1
1
  import { MEMBERS_MIN_LENGTH, NAME_MAX_LENGTH, NAME_MIN_LENGTH } from "../utils/validation/validateProject.mjs";
2
- import { Schema } from "mongoose";
2
+ import { Schema, model } from "mongoose";
3
3
  import { ALL_LOCALES } from "@intlayer/types/allLocales";
4
4
  import { AiProviders } from "@intlayer/types/config";
5
5
 
@@ -181,7 +181,8 @@ const projectSchema = new Schema({
181
181
  }
182
182
  }
183
183
  });
184
+ const ProjectModel = model("project", projectSchema);
184
185
 
185
186
  //#endregion
186
- export { projectSchema };
187
+ export { ProjectModel, projectSchema };
187
188
  //# sourceMappingURL=project.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"project.schema.mjs","names":[],"sources":["../../../src/schemas/project.schema.ts"],"sourcesContent":["import { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport { AiProviders } from '@intlayer/types/config';\nimport type { RenameId } from '@utils/mongoDB/types';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateProject';\nimport { Schema } from 'mongoose';\nimport type {\n OAuth2Access,\n Project,\n ProjectSchema,\n} from '@/types/project.types';\n\n// Define the oAuth2Access subdocument schema with timestamps\nconst oAuth2AccessSchema = new Schema<RenameId<OAuth2Access>>(\n {\n clientId: { type: String, required: true },\n clientSecret: { type: String, required: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n name: { type: String, required: true },\n expiresAt: { type: Date },\n accessToken: { type: [String], required: true, default: [] },\n grants: { type: [String], required: true, default: [] },\n },\n {\n timestamps: true,\n }\n);\n\n// Schema for generic webhooks (Vercel, Netlify, Custom, etc.)\nconst webhookSchema = new Schema(\n {\n name: { type: String, required: true },\n url: { type: String, required: true },\n enabled: { type: Boolean, default: true },\n secret: { type: String }, // Optional signature secret\n },\n { _id: true }\n);\n\nconst projectConfigSchema = new Schema<Project['configuration']>(\n {\n internationalization: {\n locales: {\n type: [String],\n enum: Object.values(ALL_LOCALES),\n required: true,\n },\n defaultLocale: {\n type: String,\n enum: Object.values(ALL_LOCALES),\n },\n },\n editor: {\n applicationURL: {\n type: String,\n },\n cmsURL: {\n type: String,\n },\n },\n ai: {\n provider: {\n type: String,\n enum: Object.values(AiProviders),\n },\n model: {\n type: String,\n },\n apiKey: {\n type: String,\n },\n applicationContext: {\n type: String,\n },\n baseURL: {\n type: String,\n },\n },\n },\n {\n _id: false, // Prevents the generation of an _id field for this subdocument\n }\n);\n\n// Schema for webhooks/CI configuration (top-level project property, not part of configuration)\nconst webhooksConfigSchema = new Schema<Project['webhooks']>(\n {\n autoTriggerBuilds: { type: Boolean, default: false }, // Master toggle\n webhooks: [webhookSchema], // Generic hooks (Vercel, Netlify, Custom)\n },\n {\n _id: false,\n }\n);\n\nconst repositorySchema = new Schema<Project['repository']>(\n {\n provider: {\n type: String,\n enum: ['github', 'gitlab', 'bitbucket'],\n required: true,\n },\n owner: { type: String, required: true },\n repository: { type: String, required: true },\n branch: { type: String, default: 'main' },\n url: { type: String, required: true },\n configFilePath: { type: String, required: true },\n token: { type: String }, // Repo-scoped OAuth token for CI operations\n // GitHub specific\n installationId: { type: Number },\n // GitLab specific\n projectId: { type: Number },\n instanceUrl: { type: String },\n // Bitbucket specific\n workspace: { type: String },\n },\n {\n _id: false,\n }\n);\n\nexport const projectSchema = new Schema<ProjectSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n configuration: projectConfigSchema,\n oAuth2Access: [oAuth2AccessSchema],\n repository: repositorySchema,\n webhooks: webhooksConfigSchema,\n autoFill: {\n type: Boolean,\n default: false,\n },\n imageUrl: {\n type: String,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"project.schema.mjs","names":[],"sources":["../../../src/schemas/project.schema.ts"],"sourcesContent":["import { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport { AiProviders } from '@intlayer/types/config';\nimport type { RenameId } from '@utils/mongoDB/types';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateProject';\nimport { model, Schema } from 'mongoose';\nimport type {\n OAuth2Access,\n Project,\n ProjectModelType,\n ProjectSchema,\n} from '@/types/project.types';\n\n// Define the oAuth2Access subdocument schema with timestamps\nconst oAuth2AccessSchema = new Schema<RenameId<OAuth2Access>>(\n {\n clientId: { type: String, required: true },\n clientSecret: { type: String, required: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n name: { type: String, required: true },\n expiresAt: { type: Date },\n accessToken: { type: [String], required: true, default: [] },\n grants: { type: [String], required: true, default: [] },\n },\n {\n timestamps: true,\n }\n);\n\n// Schema for generic webhooks (Vercel, Netlify, Custom, etc.)\nconst webhookSchema = new Schema(\n {\n name: { type: String, required: true },\n url: { type: String, required: true },\n enabled: { type: Boolean, default: true },\n secret: { type: String }, // Optional signature secret\n },\n { _id: true }\n);\n\nconst projectConfigSchema = new Schema<Project['configuration']>(\n {\n internationalization: {\n locales: {\n type: [String],\n enum: Object.values(ALL_LOCALES),\n required: true,\n },\n defaultLocale: {\n type: String,\n enum: Object.values(ALL_LOCALES),\n },\n },\n editor: {\n applicationURL: {\n type: String,\n },\n cmsURL: {\n type: String,\n },\n },\n ai: {\n provider: {\n type: String,\n enum: Object.values(AiProviders),\n },\n model: {\n type: String,\n },\n apiKey: {\n type: String,\n },\n applicationContext: {\n type: String,\n },\n baseURL: {\n type: String,\n },\n },\n },\n {\n _id: false, // Prevents the generation of an _id field for this subdocument\n }\n);\n\n// Schema for webhooks/CI configuration (top-level project property, not part of configuration)\nconst webhooksConfigSchema = new Schema<Project['webhooks']>(\n {\n autoTriggerBuilds: { type: Boolean, default: false }, // Master toggle\n webhooks: [webhookSchema], // Generic hooks (Vercel, Netlify, Custom)\n },\n {\n _id: false,\n }\n);\n\nconst repositorySchema = new Schema<Project['repository']>(\n {\n provider: {\n type: String,\n enum: ['github', 'gitlab', 'bitbucket'],\n required: true,\n },\n owner: { type: String, required: true },\n repository: { type: String, required: true },\n branch: { type: String, default: 'main' },\n url: { type: String, required: true },\n configFilePath: { type: String, required: true },\n token: { type: String }, // Repo-scoped OAuth token for CI operations\n // GitHub specific\n installationId: { type: Number },\n // GitLab specific\n projectId: { type: Number },\n instanceUrl: { type: String },\n // Bitbucket specific\n workspace: { type: String },\n },\n {\n _id: false,\n }\n);\n\nexport const projectSchema = new Schema<ProjectSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n configuration: projectConfigSchema,\n oAuth2Access: [oAuth2AccessSchema],\n repository: repositorySchema,\n webhooks: webhooksConfigSchema,\n autoFill: {\n type: Boolean,\n default: false,\n },\n imageUrl: {\n type: String,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\nexport const ProjectModel = model<ProjectSchema, ProjectModelType>(\n 'project',\n projectSchema\n);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Schema } from "mongoose";
1
+ import { Schema, model } from "mongoose";
2
2
 
3
3
  //#region src/schemas/session.schema.ts
4
4
  const sessionSchema = new Schema({
@@ -36,7 +36,8 @@ const sessionSchema = new Schema({
36
36
  }
37
37
  }
38
38
  });
39
+ const SessionModel = model("session", sessionSchema);
39
40
 
40
41
  //#endregion
41
- export { sessionSchema };
42
+ export { SessionModel, sessionSchema };
42
43
  //# sourceMappingURL=session.schema.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.schema.mjs","names":[],"sources":["../../../src/schemas/session.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type { SessionSchema } from '@/types/session.types';\n\nexport const sessionSchema = new Schema<SessionSchema>(\n {\n activeOrganizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: false,\n },\n activeProjectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;AAGA,MAAa,gBAAgB,IAAI,OAC/B;CACE,sBAAsB;EACpB,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,iBAAiB;EACf,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF"}
1
+ {"version":3,"file":"session.schema.mjs","names":[],"sources":["../../../src/schemas/session.schema.ts"],"sourcesContent":["import { model, Schema } from 'mongoose';\nimport type { SessionModelType, SessionSchema } from '@/types/session.types';\n\nexport const sessionSchema = new Schema<SessionSchema>(\n {\n activeOrganizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: false,\n },\n activeProjectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\nexport const SessionModel = model<SessionSchema, SessionModelType>(\n 'session',\n sessionSchema\n);\n"],"mappings":";;;AAGA,MAAa,gBAAgB,IAAI,OAC/B;CACE,sBAAsB;EACpB,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;CACA,iBAAiB;EACf,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;CACZ;AACF,GACA;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI,IAAI,SAAS;GACnB;EACF;CACF;CACA,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;GACzB,OAAO;IACL,GAAG;IACH,IAAI;GACN;EACF;CACF;AACF,CACF;AAEA,MAAa,eAAe,MAC1B,WACA,aACF"}
@@ -1,4 +1,4 @@
1
- import { Schema } from "mongoose";
1
+ import { Schema, model } from "mongoose";
2
2
 
3
3
  //#region src/schemas/showcaseProject.schema.ts
4
4
  const scanDetailsSchema = new Schema({
@@ -106,7 +106,8 @@ const showcaseProjectSchema = new Schema({
106
106
  }
107
107
  }
108
108
  });
109
+ const ShowcaseProjectModel = model("ShowcaseProject", showcaseProjectSchema);
109
110
 
110
111
  //#endregion
111
- export { showcaseProjectSchema };
112
+ export { ShowcaseProjectModel, showcaseProjectSchema };
112
113
  //# sourceMappingURL=showcaseProject.schema.mjs.map