@intlayer/backend 3.5.3 → 3.5.5

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 (71) hide show
  1. package/dist/cjs/controllers/ai.controller.cjs +86 -0
  2. package/dist/cjs/controllers/ai.controller.cjs.map +1 -0
  3. package/dist/cjs/controllers/project.controller.cjs.map +1 -1
  4. package/dist/cjs/export.cjs.map +1 -1
  5. package/dist/cjs/index.cjs +2 -0
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/middlewares/request.middleware.cjs +4 -0
  8. package/dist/cjs/middlewares/request.middleware.cjs.map +1 -1
  9. package/dist/cjs/routes/ai.routes.cjs +42 -0
  10. package/dist/cjs/routes/ai.routes.cjs.map +1 -0
  11. package/dist/cjs/types/project.types.cjs.map +1 -1
  12. package/dist/cjs/utils/audit/CJS_FORMAT.md +23 -0
  13. package/dist/cjs/utils/audit/JSON_FORMAT.md +26 -0
  14. package/dist/cjs/utils/audit/JSX_FORMAT.md +28 -0
  15. package/dist/cjs/utils/audit/MJS_FORMAT.md +23 -0
  16. package/dist/cjs/utils/audit/PROMPT.md +146 -0
  17. package/dist/cjs/utils/audit/TSX_FORMAT.md +28 -0
  18. package/dist/cjs/utils/audit/TS_FORMAT.md +22 -0
  19. package/dist/cjs/utils/audit/index.cjs +96 -0
  20. package/dist/cjs/utils/audit/index.cjs.map +1 -0
  21. package/dist/cjs/utils/errors/ErrorHandler.cjs +1 -1
  22. package/dist/cjs/utils/errors/ErrorHandler.cjs.map +1 -1
  23. package/dist/cjs/utils/errors/errorCodes.cjs +13 -0
  24. package/dist/cjs/utils/errors/errorCodes.cjs.map +1 -1
  25. package/dist/esm/controllers/ai.controller.mjs +52 -0
  26. package/dist/esm/controllers/ai.controller.mjs.map +1 -0
  27. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  28. package/dist/esm/export.mjs.map +1 -1
  29. package/dist/esm/index.mjs +2 -0
  30. package/dist/esm/index.mjs.map +1 -1
  31. package/dist/esm/middlewares/request.middleware.mjs +4 -0
  32. package/dist/esm/middlewares/request.middleware.mjs.map +1 -1
  33. package/dist/esm/routes/ai.routes.mjs +17 -0
  34. package/dist/esm/routes/ai.routes.mjs.map +1 -0
  35. package/dist/esm/utils/audit/CJS_FORMAT.md +23 -0
  36. package/dist/esm/utils/audit/JSON_FORMAT.md +26 -0
  37. package/dist/esm/utils/audit/JSX_FORMAT.md +28 -0
  38. package/dist/esm/utils/audit/MJS_FORMAT.md +23 -0
  39. package/dist/esm/utils/audit/PROMPT.md +146 -0
  40. package/dist/esm/utils/audit/TSX_FORMAT.md +28 -0
  41. package/dist/esm/utils/audit/TS_FORMAT.md +22 -0
  42. package/dist/esm/utils/audit/index.mjs +71 -0
  43. package/dist/esm/utils/audit/index.mjs.map +1 -0
  44. package/dist/esm/utils/errors/ErrorHandler.mjs +1 -1
  45. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  46. package/dist/esm/utils/errors/errorCodes.mjs +13 -0
  47. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  48. package/dist/types/controllers/ai.controller.d.ts +20 -0
  49. package/dist/types/controllers/ai.controller.d.ts.map +1 -0
  50. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  51. package/dist/types/export.d.ts +1 -0
  52. package/dist/types/export.d.ts.map +1 -1
  53. package/dist/types/index.d.ts.map +1 -1
  54. package/dist/types/routes/ai.routes.d.ts +10 -0
  55. package/dist/types/routes/ai.routes.d.ts.map +1 -0
  56. package/dist/types/types/project.types.d.ts +3 -0
  57. package/dist/types/types/project.types.d.ts.map +1 -1
  58. package/dist/types/utils/audit/index.d.ts +28 -0
  59. package/dist/types/utils/audit/index.d.ts.map +1 -0
  60. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  61. package/dist/types/utils/errors/errorCodes.d.ts +13 -0
  62. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  63. package/package.json +7 -5
  64. package/dist/types/middlewares/admin.middleware.d.ts +0 -10
  65. package/dist/types/middlewares/admin.middleware.d.ts.map +0 -1
  66. package/dist/types/models/plan.moddel.d.ts +0 -11
  67. package/dist/types/models/plan.moddel.d.ts.map +0 -1
  68. package/dist/types/services/plans.service.d.ts +0 -35
  69. package/dist/types/services/plans.service.d.ts.map +0 -1
  70. package/dist/types/webhooks/stripe.d.ts +0 -3
  71. package/dist/types/webhooks/stripe.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as projectService from '@services/project.service';\nimport * as sessionAuthService from '@services/sessionAuth.service';\nimport * as userService from '@services/user.service';\nimport { AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getProjectFiltersAndPagination,\n type ProjectFilters,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { getPLanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n type ResponseData,\n type PaginatedResponse,\n formatResponse,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport type { ObjectId } from 'mongoose';\nimport { User } from 'oauth2-server';\nimport type {\n Project,\n ProjectAPI,\n ProjectCreationData,\n ProjectData,\n} from '@/types/project.types';\n\nexport type GetProjectsParams = FiltersAndPagination<ProjectFiltersParams>;\nexport type GetProjectsResult = PaginatedResponse<ProjectAPI>;\n\n/**\n * Retrieves a list of projects based on filters and pagination.\n */\nexport const getProjects = async (\n req: Request<GetProjectsParams>,\n res: ResponseWithInformation<GetProjectsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, projectRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!projectRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_READ');\n return;\n }\n\n const restrictedFilter: ProjectFilters = {\n ...filters,\n membersIds: { $in: [...(filters.membersIds ?? []), String(user._id)] },\n organizationId: String(organization._id),\n };\n\n try {\n const projects = await projectService.findProjects(\n restrictedFilter,\n skip,\n pageSize\n );\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(\n projects,\n user,\n res.locals.isProjectAdmin\n );\n\n const responseData = formatPaginatedResponse<ProjectAPI>({\n data: formattedProjects,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddProjectBody = ProjectCreationData;\nexport type AddProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Adds a new project to the database.\n */\nexport const addProject = async (\n req: Request<any, any, AddProjectBody>,\n res: ResponseWithInformation<AddProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, isOrganizationAdmin, projectRights } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_WRITE');\n return;\n }\n\n if (!projectData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n }\n\n const { plan } = organization;\n\n if (!plan) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_NOT_FOUND', {\n organizationId: organization._id,\n });\n return;\n }\n\n const planType = getPLanDetails(plan);\n\n if (planType.numberOfProjects) {\n const projectCount = await projectService.countProjects({\n organizationId: organization._id,\n });\n\n if (projectCount >= planType.numberOfProjects) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PLAN_PROJECT_LIMIT_REACHED',\n {\n organizationId: organization._id,\n }\n );\n return;\n }\n\n return;\n }\n\n const project: ProjectData = {\n membersIds: [user._id],\n adminsIds: [user._id],\n creatorId: user._id,\n organizationId: organization._id,\n ...projectData,\n };\n\n try {\n const newProject = await projectService.createProject(project);\n\n const formattedProject = mapProjectToAPI(newProject, user, true);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project created successfully',\n fr: 'Projet créé avec succès',\n es: 'Proyecto creado con éxito',\n }),\n description: t({\n en: 'Your project has been created successfully',\n fr: 'Votre projet a été créé avec succès',\n es: 'Su proyecto ha sido creado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateProjectBody = Partial<ProjectData> & { _id: string };\nexport type UpdateProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Updates an existing project in the database.\n */\nexport const updateProject = async (\n req: Request<any, any, UpdateProjectBody>,\n res: ResponseWithInformation<UpdateProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, projectRights, project, user, isProjectAdmin } =\n res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n if (!projectRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_WRITE');\n return;\n }\n\n if (String(project._id) !== String(projectData._id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_MISMATCH');\n return;\n }\n\n if (String(project.organizationId) !== String(organization._id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_IN_ORGANIZATION');\n return;\n }\n\n try {\n const updatedProject = await projectService.updateProjectById(\n project._id,\n project\n );\n\n const formattedProject = mapProjectToAPI(\n updatedProject,\n user,\n isProjectAdmin\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project updated successfully',\n fr: 'Projet mis à jour avec succès',\n es: 'Proyecto actualizado con éxito',\n }),\n description: t({\n en: 'Your project has been updated successfully',\n fr: 'Votre projet a été mis à jour avec succès',\n es: 'Su proyecto ha sido actualizado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\ntype UserAndAdmin = { user: User; isAdmin: boolean };\nexport type ProjectMemberByIdOption = {\n userId: string | ObjectId;\n isAdmin?: boolean;\n};\n\nexport type UpdateProjectMembersBody = Partial<{\n membersIds: ProjectMemberByIdOption[];\n}>;\nexport type UpdateProjectMembersResult = ResponseData<ProjectAPI>;\n\n/**\n * Update members to the dictionary in the database.\n */\nexport const updateProjectMembers = async (\n req: Request<any, any, UpdateProjectMembersBody>,\n res: ResponseWithInformation<UpdateProjectMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, isProjectAdmin, organization, projectRights } =\n res.locals;\n const { membersIds } = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_PROJECT'\n );\n return;\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_MEMBER');\n return;\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_ADMIN');\n return;\n }\n\n try {\n const existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds\n ?.filter(\n (member) =>\n // Remove members that are not in the organization\n !organization?.membersIds.includes(member.userId as ObjectId)\n )\n .map((member) => member.userId);\n\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => ({\n user,\n isAdmin:\n membersIds.find(\n (member) => String(member.userId) === String(user._id)\n )?.isAdmin ?? false,\n }));\n\n existingUsers.push(...userMap);\n }\n }\n\n const formattedMembers: ObjectId[] = existingUsers.map(\n (user) => user.user._id\n );\n const formattedAdmin: ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user._id);\n\n const updatedOrganization = await projectService.updateProjectById(\n project._id,\n {\n ...project,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n }\n );\n\n const formattedProject = mapProjectToAPI(\n updatedOrganization,\n user,\n isProjectAdmin\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project members updated successfully',\n fr: 'Membres du projet mis à jour avec succès',\n es: 'Miembros del proyecto actualizados con éxito',\n }),\n description: t({\n en: 'Your project members have been updated successfully',\n fr: 'Les membres de votre projet ont été mis à jour avec succès',\n es: 'Los miembros de su proyecto han sido actualizados con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Deletes a project from the database by its ID.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const deleteProject = async (\n _req: Request,\n res: ResponseWithInformation<DeleteProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, project, projectRights, isProjectAdmin } =\n res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n try {\n const projectToDelete = await projectService.getProjectById(project._id);\n\n if (projectToDelete.organizationId !== organization._id) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n return;\n }\n\n const deletedProject = await projectService.deleteProjectById(project._id);\n\n if (!deletedProject) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED', {\n projectId: project._id,\n });\n\n return;\n }\n\n logger.info(`Project deleted: ${String(deletedProject._id)}`);\n\n const formattedProject = mapProjectToAPI(\n deletedProject,\n user,\n isProjectAdmin\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project deleted successfully',\n fr: 'Projet supprimé avec succès',\n es: 'Proyecto eliminado con éxito',\n }),\n description: t({\n en: 'Your project has been deleted successfully',\n fr: 'Votre projet a été supprimé avec succès',\n es: 'Su proyecto ha sido eliminado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type SelectProjectParam = { projectId: ObjectId | string };\nexport type SelectProjectResult = ResponseData<Project>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n req: Request<SelectProjectParam>,\n res: ResponseWithInformation<SelectProjectResult>,\n _next: NextFunction\n) => {\n const { projectId } = req.params;\n\n if (!projectId) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_NOT_FOUND');\n return;\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n sessionAuthService.setProjectAuth(res, project);\n\n const responseData = formatResponse<Project>({\n message: t({\n en: 'Project selected successfully',\n fr: 'Projet sélectionné avec succès',\n es: 'Proyecto seleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been selected successfully',\n fr: 'Votre projet a été sélectionné avec succès',\n es: 'Su proyecto ha sido seleccionado con éxito',\n }),\n data: project,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UnselectProjectResult = ResponseData<null>;\n\n/**\n * Unselect a project.\n */\nexport const unselectProject = (\n _req: Request,\n res: ResponseWithInformation<UnselectProjectResult>,\n _next: NextFunction\n) => {\n try {\n sessionAuthService.clearProjectAuth(res);\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Project unselected successfully',\n fr: 'Projet désélectionné avec succès',\n es: 'Proyecto deseleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been unselected successfully',\n fr: 'Votre projet a été désélectionné avec succès',\n es: 'Su proyecto ha sido deseleccionado con éxito',\n }),\n data: null,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":["user"]}
1
+ {"version":3,"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as projectService from '@services/project.service';\nimport * as sessionAuthService from '@services/sessionAuth.service';\nimport * as userService from '@services/user.service';\nimport { AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getProjectFiltersAndPagination,\n type ProjectFilters,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { getPLanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n type ResponseData,\n type PaginatedResponse,\n formatResponse,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport { Locales } from 'intlayer';\nimport type { ObjectId } from 'mongoose';\nimport { User } from 'oauth2-server';\nimport type {\n Project,\n ProjectAPI,\n ProjectCreationData,\n ProjectData,\n} from '@/types/project.types';\n\nexport type GetProjectsParams = FiltersAndPagination<ProjectFiltersParams>;\nexport type GetProjectsResult = PaginatedResponse<ProjectAPI>;\n\n/**\n * Retrieves a list of projects based on filters and pagination.\n */\nexport const getProjects = async (\n req: Request<GetProjectsParams>,\n res: ResponseWithInformation<GetProjectsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, projectRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!projectRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_READ');\n return;\n }\n\n const restrictedFilter: ProjectFilters = {\n ...filters,\n membersIds: { $in: [...(filters.membersIds ?? []), String(user._id)] },\n organizationId: String(organization._id),\n };\n\n try {\n const projects = await projectService.findProjects(\n restrictedFilter,\n skip,\n pageSize\n );\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(\n projects,\n user,\n res.locals.isProjectAdmin\n );\n\n const responseData = formatPaginatedResponse<ProjectAPI>({\n data: formattedProjects,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddProjectBody = ProjectCreationData;\nexport type AddProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Adds a new project to the database.\n */\nexport const addProject = async (\n req: Request<any, any, AddProjectBody>,\n res: ResponseWithInformation<AddProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, isOrganizationAdmin, projectRights } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_WRITE');\n return;\n }\n\n if (!projectData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n }\n\n const { plan } = organization;\n\n if (!plan) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_NOT_FOUND', {\n organizationId: organization._id,\n });\n return;\n }\n\n const planType = getPLanDetails(plan);\n\n if (planType.numberOfProjects) {\n const projectCount = await projectService.countProjects({\n organizationId: organization._id,\n });\n\n if (projectCount >= planType.numberOfProjects) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PLAN_PROJECT_LIMIT_REACHED',\n {\n organizationId: organization._id,\n }\n );\n return;\n }\n\n return;\n }\n\n const project: ProjectData = {\n membersIds: [user._id],\n adminsIds: [user._id],\n creatorId: user._id,\n organizationId: organization._id,\n ...projectData,\n };\n\n try {\n const newProject = await projectService.createProject(project);\n\n const formattedProject = mapProjectToAPI(newProject, user, true);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project created successfully',\n fr: 'Projet créé avec succès',\n es: 'Proyecto creado con éxito',\n }),\n description: t({\n en: 'Your project has been created successfully',\n fr: 'Votre projet a été créé avec succès',\n es: 'Su proyecto ha sido creado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateProjectBody = Partial<ProjectData> & { _id: string };\nexport type UpdateProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Updates an existing project in the database.\n */\nexport const updateProject = async (\n req: Request<any, any, UpdateProjectBody>,\n res: ResponseWithInformation<UpdateProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, projectRights, project, user, isProjectAdmin } =\n res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n if (!projectRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_WRITE');\n return;\n }\n\n if (String(project._id) !== String(projectData._id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_MISMATCH');\n return;\n }\n\n if (String(project.organizationId) !== String(organization._id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_IN_ORGANIZATION');\n return;\n }\n\n try {\n const updatedProject = await projectService.updateProjectById(\n project._id,\n project\n );\n\n const formattedProject = mapProjectToAPI(\n updatedProject,\n user,\n isProjectAdmin\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project updated successfully',\n fr: 'Projet mis à jour avec succès',\n es: 'Proyecto actualizado con éxito',\n }),\n description: t({\n en: 'Your project has been updated successfully',\n fr: 'Votre projet a été mis à jour avec succès',\n es: 'Su proyecto ha sido actualizado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\ntype UserAndAdmin = { user: User; isAdmin: boolean };\nexport type ProjectMemberByIdOption = {\n userId: string | ObjectId;\n isAdmin?: boolean;\n};\n\nexport type UpdateProjectMembersBody = Partial<{\n membersIds: ProjectMemberByIdOption[];\n}>;\nexport type UpdateProjectMembersResult = ResponseData<ProjectAPI>;\n\n/**\n * Update members to the dictionary in the database.\n */\nexport const updateProjectMembers = async (\n req: Request<any, any, UpdateProjectMembersBody>,\n res: ResponseWithInformation<UpdateProjectMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, isProjectAdmin, organization, projectRights } =\n res.locals;\n const { membersIds } = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_PROJECT'\n );\n return;\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_MEMBER');\n return;\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_ADMIN');\n return;\n }\n\n try {\n const existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds\n ?.filter(\n (member) =>\n // Remove members that are not in the organization\n !organization?.membersIds.includes(member.userId as ObjectId)\n )\n .map((member) => member.userId);\n\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => ({\n user,\n isAdmin:\n membersIds.find(\n (member) => String(member.userId) === String(user._id)\n )?.isAdmin ?? false,\n }));\n\n existingUsers.push(...userMap);\n }\n }\n\n const formattedMembers: ObjectId[] = existingUsers.map(\n (user) => user.user._id\n );\n const formattedAdmin: ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user._id);\n\n const updatedOrganization = await projectService.updateProjectById(\n project._id,\n {\n ...project,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n }\n );\n\n const formattedProject = mapProjectToAPI(\n updatedOrganization,\n user,\n isProjectAdmin\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project members updated successfully',\n fr: 'Membres du projet mis à jour avec succès',\n es: 'Miembros del proyecto actualizados con éxito',\n }),\n description: t({\n en: 'Your project members have been updated successfully',\n fr: 'Les membres de votre projet ont été mis à jour avec succès',\n es: 'Los miembros de su proyecto han sido actualizados con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Deletes a project from the database by its ID.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const deleteProject = async (\n _req: Request,\n res: ResponseWithInformation<DeleteProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, project, projectRights, isProjectAdmin } =\n res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n try {\n const projectToDelete = await projectService.getProjectById(project._id);\n\n if (projectToDelete.organizationId !== organization._id) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n return;\n }\n\n const deletedProject = await projectService.deleteProjectById(project._id);\n\n if (!deletedProject) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED', {\n projectId: project._id,\n });\n\n return;\n }\n\n logger.info(`Project deleted: ${String(deletedProject._id)}`);\n\n const formattedProject = mapProjectToAPI(\n deletedProject,\n user,\n isProjectAdmin\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project deleted successfully',\n fr: 'Projet supprimé avec succès',\n es: 'Proyecto eliminado con éxito',\n }),\n description: t({\n en: 'Your project has been deleted successfully',\n fr: 'Votre projet a été supprimé avec succès',\n es: 'Su proyecto ha sido eliminado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type SelectProjectParam = { projectId: ObjectId | string };\nexport type SelectProjectResult = ResponseData<Project>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n req: Request<SelectProjectParam>,\n res: ResponseWithInformation<SelectProjectResult>,\n _next: NextFunction\n) => {\n const { projectId } = req.params;\n\n if (!projectId) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_NOT_FOUND');\n return;\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n sessionAuthService.setProjectAuth(res, project);\n\n const responseData = formatResponse<Project>({\n message: t({\n en: 'Project selected successfully',\n fr: 'Projet sélectionné avec succès',\n es: 'Proyecto seleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been selected successfully',\n fr: 'Votre projet a été sélectionné avec succès',\n es: 'Su proyecto ha sido seleccionado con éxito',\n }),\n data: project,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UnselectProjectResult = ResponseData<null>;\n\n/**\n * Unselect a project.\n */\nexport const unselectProject = (\n _req: Request,\n res: ResponseWithInformation<UnselectProjectResult>,\n _next: NextFunction\n) => {\n try {\n sessionAuthService.clearProjectAuth(res);\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Project unselected successfully',\n fr: 'Projet désélectionné avec succès',\n es: 'Proyecto deseleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been unselected successfully',\n fr: 'Votre projet a été désélectionné avec succès',\n es: 'Su proyecto ha sido deseleccionado con éxito',\n }),\n data: null,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":["user"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/export.ts"],"sourcesContent":["// Routes\nexport { userRoutes } from '@routes/user.routes';\nexport { organizationRoutes } from '@routes/organization.routes';\nexport { projectRoutes } from '@routes/project.routes';\nexport { dictionaryRoutes } from '@routes/dictionary.routes';\nexport { sessionAuthRoutes } from '@routes/sessionAuth.routes';\n\n// Controllers types\nexport type * from '@controllers/sessionAuth.controller';\nexport type * from '@controllers/oAuth2.controller';\nexport type * from '@controllers/organization.controller';\nexport type * from '@controllers/project.controller';\nexport type * from '@controllers/projectAccessKey.controller';\nexport type * from '@controllers/user.controller';\nexport type * from '@controllers/dictionary.controller';\nexport type * from '@controllers/stripe.controller';\n\n// Objects types\nexport type * from '@/types/organization.types';\nexport type * from '@/types/project.types';\nexport type * from '@/types/user.types';\nexport type * from '@/types/dictionary.types';\nexport type * from '@/types/plan.types';\n\n// Utils\nexport * from '@utils/cookies';\nexport * from '@utils/httpStatusCodes';\n"],"mappings":"AACA,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAoBlC,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/export.ts"],"sourcesContent":["// Routes\nexport { userRoutes } from '@routes/user.routes';\nexport { organizationRoutes } from '@routes/organization.routes';\nexport { projectRoutes } from '@routes/project.routes';\nexport { dictionaryRoutes } from '@routes/dictionary.routes';\nexport { sessionAuthRoutes } from '@routes/sessionAuth.routes';\n\n// Controllers types\nexport type * from '@controllers/sessionAuth.controller';\nexport type * from '@controllers/oAuth2.controller';\nexport type * from '@controllers/organization.controller';\nexport type * from '@controllers/project.controller';\nexport type * from '@controllers/projectAccessKey.controller';\nexport type * from '@controllers/user.controller';\nexport type * from '@controllers/dictionary.controller';\nexport type * from '@controllers/stripe.controller';\nexport type * from '@controllers/ai.controller';\n\n// Objects types\nexport type * from '@/types/organization.types';\nexport type * from '@/types/project.types';\nexport type * from '@/types/user.types';\nexport type * from '@/types/dictionary.types';\nexport type * from '@/types/plan.types';\n\n// Utils\nexport * from '@utils/cookies';\nexport * from '@utils/httpStatusCodes';\n"],"mappings":"AACA,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAqBlC,cAAc;AACd,cAAc;","names":[]}
@@ -22,6 +22,7 @@ import { projectRouter } from './routes/project.routes.mjs';
22
22
  import { sessionAuthRouter } from './routes/sessionAuth.routes.mjs';
23
23
  import { userRouter } from './routes/user.routes.mjs';
24
24
  import { stripeRouter } from './routes/stripe.routes.mjs';
25
+ import { aiRouter } from './routes/ai.routes.mjs';
25
26
  import { stripeWebhook } from './webhooks/stripe.webhook.mjs';
26
27
  import { getOAuth2Token } from './controllers/oAuth2.controller.mjs';
27
28
  import {
@@ -111,6 +112,7 @@ app.use("/api/organization", organizationRouter);
111
112
  app.use("/api/project", projectRouter);
112
113
  app.use("/api/dictionary", dictionaryRouter);
113
114
  app.use("/api/stripe", stripeRouter);
115
+ app.use("/api/ai", aiRouter);
114
116
  app.listen(process.env.PORT, () => {
115
117
  logger.info(`Listening on port ${process.env.PORT}`);
116
118
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/* eslint-disable import/order */\n\n// Libraries\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport cors, { type CorsOptions } from 'cors';\nimport dotenv from 'dotenv';\nimport express, { type Express } from 'express';\nimport { intlayer, t } from 'express-intlayer';\nimport helmet from 'helmet';\n\n// Middlewares\nimport {\n attachOAuthInstance,\n authenticateOAuth2,\n RequestWithOAuth2Information,\n} from '@middlewares/oAuth2.middleware';\nimport { logAPIRequestURL } from '@middlewares/request.middleware';\nimport {\n checkUser,\n checkOrganization,\n checkProject,\n checkAdmin,\n ResponseWithInformation,\n} from '@middlewares/sessionAuth.middleware';\n\n// Routes\nimport { dictionaryRouter } from '@routes/dictionary.routes';\nimport { organizationRouter } from '@routes/organization.routes';\nimport { projectRouter } from '@routes/project.routes';\nimport { sessionAuthRouter } from '@routes/sessionAuth.routes';\nimport { userRouter } from '@routes/user.routes';\nimport { stripeRouter } from '@routes/stripe.routes';\n\n// Webhooks\nimport { stripeWebhook } from '@webhooks/stripe.webhook';\n\n// Controllers\nimport { getOAuth2Token } from '@controllers/oAuth2.controller';\nimport {\n getSessionInformation,\n setCSRFToken,\n} from '@controllers/sessionAuth.controller';\n\n// Utils\nimport { doubleCsrfProtection } from '@utils/CSRF';\nimport { connectDB } from '@utils/mongoDB/connectDB';\n\n// Logger\nimport { logger } from './logger';\n\nconst app: Express = express();\n\napp.disable('x-powered-by'); // Disabled to prevent attackers from knowing that the app is running Express\napp.use(helmet());\n\n// Environment variables\nconst env = app.get('env');\n\nlogger.info(`run as ${env}`);\n\ndotenv.config({ path: ['.env', `.env.${env}`] });\n\n// Parse incoming requests with cookies\napp.use(cookieParser());\n\n// Load internationalization request handler\napp.use(intlayer());\n\nconst isDev = env === 'development';\n\n// Connect to MongoDB\nconnectDB();\n\n// Stripe\napp.post(\n '/webhook/stripe',\n express.raw({ type: 'application/json' }),\n stripeWebhook\n);\n\n// Compress all HTTP responses\napp.use(compression());\n\n// Parse incoming requests with JSON payloads\napp.use(express.json({ limit: '50mb' }));\n\n// Parse incoming requests with urlencoded payloads\napp.use(express.urlencoded({ extended: true }));\n\n// CORS\nconst whitelist: string[] = [process.env.CLIENT_URL!];\nconst corsOptions: CorsOptions = {\n origin: whitelist,\n credentials: true,\n allowedHeaders: [\n 'authorization',\n 'Content-Type',\n 'credentials',\n 'cache-control',\n 'Access-Control-Allow-Origin',\n 'private-state-token-redemption',\n 'private-state-token-issuance',\n 'browsing-topics',\n ],\n\n exposedHeaders: [''],\n preflightContinue: false,\n methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',\n};\napp.use(cors(corsOptions));\nlogger.info('url whitelist : ', whitelist.join(', '));\n\n// Liveness check\napp.get('/', (_req, res) => {\n res.send(\n t({\n en: 'Ok - locale: en',\n fr: 'Ok - locale: fr',\n es: 'Ok - locale: es',\n })\n );\n});\n\n// middleware - jwt & session auth\napp.use(/(.*)/, checkUser);\napp.use(/(.*)/, checkOrganization);\napp.use(/(.*)/, checkProject);\napp.use(/(.*)/, checkAdmin);\n\n// debug\nif (isDev) {\n app.use(logAPIRequestURL);\n}\n\n// Sessions\napp.get('/session', getSessionInformation);\napp.use('/api/auth', sessionAuthRouter);\n\n// CSRF\napp.get('/csrf-token', setCSRFToken);\n\n// oAuth2\napp.use(/(.*)/, attachOAuthInstance);\napp.post('/oauth2/token', getOAuth2Token); // Route to get the token\napp.use(/(.*)/, (req, res, next) => {\n // If the request is not already authenticated check the oAuth2 token\n if (!res.locals.authType) {\n return authenticateOAuth2(\n req as RequestWithOAuth2Information,\n res as ResponseWithInformation,\n next\n );\n }\n next();\n});\n\n// CSRF protection\napp.use(/(.*)/, (req, res, next) => {\n // If the request is authenticated using the session auth check the CSRF token\n if (res.locals.authType === 'session') {\n return doubleCsrfProtection(req, res, next);\n }\n next();\n});\n\n// Routes\napp.use('/api/user', userRouter);\napp.use('/api/organization', organizationRouter);\napp.use('/api/project', projectRouter);\napp.use('/api/dictionary', dictionaryRouter);\napp.use('/api/stripe', stripeRouter);\n\n// Server\napp.listen(process.env.PORT, () => {\n logger.info(`Listening on port ${process.env.PORT}`);\n});\n\n// Export tu use as serverless function\nexport default app;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/* eslint-disable import/order */\n\n// Libraries\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport cors, { type CorsOptions } from 'cors';\nimport dotenv from 'dotenv';\nimport express, { type Express } from 'express';\nimport { intlayer, t } from 'express-intlayer';\nimport helmet from 'helmet';\n\n// Middlewares\nimport {\n attachOAuthInstance,\n authenticateOAuth2,\n RequestWithOAuth2Information,\n} from '@middlewares/oAuth2.middleware';\nimport { logAPIRequestURL } from '@middlewares/request.middleware';\nimport {\n checkUser,\n checkOrganization,\n checkProject,\n checkAdmin,\n ResponseWithInformation,\n} from '@middlewares/sessionAuth.middleware';\n\n// Routes\nimport { dictionaryRouter } from '@routes/dictionary.routes';\nimport { organizationRouter } from '@routes/organization.routes';\nimport { projectRouter } from '@routes/project.routes';\nimport { sessionAuthRouter } from '@routes/sessionAuth.routes';\nimport { userRouter } from '@routes/user.routes';\nimport { stripeRouter } from '@routes/stripe.routes';\nimport { aiRouter } from '@routes/ai.routes';\n\n// Webhooks\nimport { stripeWebhook } from '@webhooks/stripe.webhook';\n\n// Controllers\nimport { getOAuth2Token } from '@controllers/oAuth2.controller';\nimport {\n getSessionInformation,\n setCSRFToken,\n} from '@controllers/sessionAuth.controller';\n\n// Utils\nimport { doubleCsrfProtection } from '@utils/CSRF';\nimport { connectDB } from '@utils/mongoDB/connectDB';\n\n// Logger\nimport { logger } from './logger';\n\nconst app: Express = express();\n\napp.disable('x-powered-by'); // Disabled to prevent attackers from knowing that the app is running Express\napp.use(helmet());\n\n// Environment variables\nconst env = app.get('env');\n\nlogger.info(`run as ${env}`);\n\ndotenv.config({ path: ['.env', `.env.${env}`] });\n\n// Parse incoming requests with cookies\napp.use(cookieParser());\n\n// Load internationalization request handler\napp.use(intlayer());\n\nconst isDev = env === 'development';\n\n// Connect to MongoDB\nconnectDB();\n\n// Stripe\napp.post(\n '/webhook/stripe',\n express.raw({ type: 'application/json' }),\n stripeWebhook\n);\n\n// Compress all HTTP responses\napp.use(compression());\n\n// Parse incoming requests with JSON payloads\napp.use(express.json({ limit: '50mb' }));\n\n// Parse incoming requests with urlencoded payloads\napp.use(express.urlencoded({ extended: true }));\n\n// CORS\nconst whitelist: string[] = [process.env.CLIENT_URL!];\nconst corsOptions: CorsOptions = {\n origin: whitelist,\n credentials: true,\n allowedHeaders: [\n 'authorization',\n 'Content-Type',\n 'credentials',\n 'cache-control',\n 'Access-Control-Allow-Origin',\n 'private-state-token-redemption',\n 'private-state-token-issuance',\n 'browsing-topics',\n ],\n\n exposedHeaders: [''],\n preflightContinue: false,\n methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',\n};\napp.use(cors(corsOptions));\nlogger.info('url whitelist : ', whitelist.join(', '));\n\n// Liveness check\napp.get('/', (_req, res) => {\n res.send(\n t({\n en: 'Ok - locale: en',\n fr: 'Ok - locale: fr',\n es: 'Ok - locale: es',\n })\n );\n});\n\n// middleware - jwt & session auth\napp.use(/(.*)/, checkUser);\napp.use(/(.*)/, checkOrganization);\napp.use(/(.*)/, checkProject);\napp.use(/(.*)/, checkAdmin);\n\n// debug\nif (isDev) {\n app.use(logAPIRequestURL);\n}\n\n// Sessions\napp.get('/session', getSessionInformation);\napp.use('/api/auth', sessionAuthRouter);\n\n// CSRF\napp.get('/csrf-token', setCSRFToken);\n\n// oAuth2\napp.use(/(.*)/, attachOAuthInstance);\napp.post('/oauth2/token', getOAuth2Token); // Route to get the token\napp.use(/(.*)/, (req, res, next) => {\n // If the request is not already authenticated check the oAuth2 token\n if (!res.locals.authType) {\n return authenticateOAuth2(\n req as RequestWithOAuth2Information,\n res as ResponseWithInformation,\n next\n );\n }\n next();\n});\n\n// CSRF protection\napp.use(/(.*)/, (req, res, next) => {\n // If the request is authenticated using the session auth check the CSRF token\n if (res.locals.authType === 'session') {\n return doubleCsrfProtection(req, res, next);\n }\n next();\n});\n\n// Routes\napp.use('/api/user', userRouter);\napp.use('/api/organization', organizationRouter);\napp.use('/api/project', projectRouter);\napp.use('/api/dictionary', dictionaryRouter);\napp.use('/api/stripe', stripeRouter);\napp.use('/api/ai', aiRouter);\n\n// Server\napp.listen(process.env.PORT, () => {\n logger.info(`Listening on port ${process.env.PORT}`);\n});\n\n// Export tu use as serverless function\nexport default app;\n"],"mappings":"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","names":[]}
@@ -1,3 +1,4 @@
1
+ import { logger } from './../logger/index.mjs';
1
2
  const logAPIRequestURL = (req, res, next) => {
2
3
  const queryDetails = {
3
4
  params: req.params,
@@ -5,6 +6,9 @@ const logAPIRequestURL = (req, res, next) => {
5
6
  body: req.body,
6
7
  locals: res.locals
7
8
  };
9
+ logger.info(
10
+ `API Request - ${req.method} - ${req.originalUrl} - ${JSON.stringify(queryDetails, null, 2)}`
11
+ );
8
12
  next();
9
13
  };
10
14
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/middlewares/request.middleware.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { Request, NextFunction } from 'express';\nimport type { ResponseWithInformation } from './sessionAuth.middleware';\n\nexport const logAPIRequestURL = (\n req: Request,\n res: ResponseWithInformation,\n next: NextFunction\n): void => {\n const queryDetails = {\n params: req.params,\n query: req.query,\n body: req.body,\n locals: res.locals,\n };\n\n // logger.info(\n // `API Request - ${req.method} - ${req.originalUrl} - ${JSON.stringify(queryDetails, null, 2)}`\n // );\n\n next();\n};\n"],"mappings":"AAIO,MAAM,mBAAmB,CAC9B,KACA,KACA,SACS;AACT,QAAM,eAAe;AAAA,IACnB,QAAQ,IAAI;AAAA,IACZ,OAAO,IAAI;AAAA,IACX,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,EACd;AAMA,OAAK;AACP;","names":[]}
1
+ {"version":3,"sources":["../../../src/middlewares/request.middleware.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { Request, NextFunction } from 'express';\nimport type { ResponseWithInformation } from './sessionAuth.middleware';\n\nexport const logAPIRequestURL = (\n req: Request,\n res: ResponseWithInformation,\n next: NextFunction\n): void => {\n const queryDetails = {\n params: req.params,\n query: req.query,\n body: req.body,\n locals: res.locals,\n };\n\n logger.info(\n `API Request - ${req.method} - ${req.originalUrl} - ${JSON.stringify(queryDetails, null, 2)}`\n );\n\n next();\n};\n"],"mappings":"AAAA,SAAS,cAAc;AAIhB,MAAM,mBAAmB,CAC9B,KACA,KACA,SACS;AACT,QAAM,eAAe;AAAA,IACnB,QAAQ,IAAI;AAAA,IACZ,OAAO,IAAI;AAAA,IACX,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,EACd;AAEA,SAAO;AAAA,IACL,iBAAiB,IAAI,MAAM,MAAM,IAAI,WAAW,MAAM,KAAK,UAAU,cAAc,MAAM,CAAC,CAAC;AAAA,EAC7F;AAEA,OAAK;AACP;","names":[]}
@@ -0,0 +1,17 @@
1
+ import { auditFile } from './../controllers/ai.controller.mjs';
2
+ import { Router } from "express";
3
+ const aiRouter = Router();
4
+ const baseURL = `${process.env.BACKEND_URL}/api/ai`;
5
+ const aiRoutes = {
6
+ auditFile: {
7
+ urlModel: "/audit",
8
+ url: `${baseURL}/audit`,
9
+ method: "POST"
10
+ }
11
+ };
12
+ aiRouter.post(aiRoutes.auditFile.urlModel, auditFile);
13
+ export {
14
+ aiRouter,
15
+ aiRoutes
16
+ };
17
+ //# sourceMappingURL=ai.routes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/routes/ai.routes.ts"],"sourcesContent":["import { auditFile } from '@controllers/ai.controller';\nimport { Router } from 'express';\nimport { Routes } from '@/types/Routes';\n\nexport const aiRouter: Router = Router();\n\nconst baseURL = `${process.env.BACKEND_URL}/api/ai`;\n\nexport const aiRoutes = {\n auditFile: {\n urlModel: '/audit',\n url: `${baseURL}/audit`,\n method: 'POST',\n },\n} satisfies Routes;\n\naiRouter.post(aiRoutes.auditFile.urlModel, auditFile);\n"],"mappings":"AAAA,SAAS,iBAAiB;AAC1B,SAAS,cAAc;AAGhB,MAAM,WAAmB,OAAO;AAEvC,MAAM,UAAU,GAAG,QAAQ,IAAI,WAAW;AAEnC,MAAM,WAAW;AAAA,EACtB,WAAW;AAAA,IACT,UAAU;AAAA,IACV,KAAK,GAAG,OAAO;AAAA,IACf,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,KAAK,SAAS,UAAU,UAAU,SAAS;","names":[]}
@@ -0,0 +1,23 @@
1
+ ```javascript
2
+ const { t, enu } = require("intlayer");
3
+
4
+ /** @type {import('intlayer').IntlayerConfig} */
5
+ module.exports = {
6
+ key: "my-key",
7
+ content: {
8
+ exampleText: t({
9
+ en: "Example of content in English",
10
+ fr: "Example de contenu en français",
11
+ es: "Ejemplo de contenido en español",
12
+ }),
13
+ numberOfCar: enu({
14
+ "<-1": "Less than minus one car",
15
+ "-1": "Minus one car",
16
+ 0: "No cars",
17
+ 1: "One car",
18
+ ">5": "Some cars",
19
+ ">19": "Many cars",
20
+ }),
21
+ },
22
+ };
23
+ ```
@@ -0,0 +1,26 @@
1
+ ```json
2
+ {
3
+ "key": "my-key",
4
+ "content": {
5
+ "profileText": {
6
+ "NodeType": "translation",
7
+ "translation": {
8
+ "en": "Manage profile",
9
+ "fr": "Gérer le profil",
10
+ "es": "Administrar perfil"
11
+ }
12
+ },
13
+ "numberOfCar": {
14
+ "NodeType": "enumeration",
15
+ "enumeration": {
16
+ "<-1": "Less than minus one car",
17
+ "-1": "Minus one car",
18
+ "0": "No cars",
19
+ "1": "One car",
20
+ ">5": "Some cars",
21
+ ">19": "Many cars"
22
+ }
23
+ }
24
+ }
25
+ }
26
+ ```
@@ -0,0 +1,28 @@
1
+ ```tsx
2
+ import React from "react";
3
+ import { t, enu, type DeclarationContent } from "intlayer";
4
+
5
+ export default {
6
+ key: "my-key",
7
+ content: {
8
+ exampleText: t({
9
+ en: "Example of content in English",
10
+ fr: "Example de contenu en français",
11
+ es: "Ejemplo de contenido en español",
12
+ }),
13
+ exampleOfReactNode: t({
14
+ en: <h1>Example of ReactNode in English</h1>,
15
+ fr: <h1>Example de ReactNode en français</h1>,
16
+ es: <h1>Ejemplo de ReactNode en español</h1>,
17
+ }),
18
+ numberOfCar: enu({
19
+ "<-1": "Less than minus one car",
20
+ "-1": "Minus one car",
21
+ "0": "No cars",
22
+ "1": "One car",
23
+ ">5": "Some cars",
24
+ ">19": "Many cars",
25
+ }),
26
+ },
27
+ };
28
+ ```
@@ -0,0 +1,23 @@
1
+ ```javascript
2
+ import { t, enu } from "intlayer";
3
+
4
+ /** @type {import('intlayer').IntlayerConfig} */
5
+ export default {
6
+ key: "my-key",
7
+ content: {
8
+ exampleText: t({
9
+ en: "Example of content in English",
10
+ fr: "Example de contenu en français",
11
+ es: "Ejemplo de contenido en español",
12
+ }),
13
+ numberOfCar: enu({
14
+ "<-1": "Less than minus one car",
15
+ "-1": "Minus one car",
16
+ 0: "No cars",
17
+ 1: "One car",
18
+ ">5": "Some cars",
19
+ ">19": "Many cars",
20
+ }),
21
+ },
22
+ };
23
+ ```
@@ -0,0 +1,146 @@
1
+ You are an expert in internationalization and content management. Your task is to audit the content declaration files in the project and identify any potential issues or inconsistencies. Provide a detailed report of any issues found, including the file path, line number, and a brief explanation of the issue.
2
+
3
+ **Instructions:**
4
+
5
+ 1. **File Location:**
6
+
7
+ - The content declaration files are located in the `{{filePath}}` directory relative to the project root.
8
+
9
+ 2. **Locales:**
10
+
11
+ - Default locale: {{defaultLocale}}
12
+ - Required Locales: {{otherLocales}} (add the missing locales in `t({ ... })` function)
13
+
14
+ 3. **Content Declaration Format:**
15
+
16
+ - Example format:
17
+
18
+ {{declarationsContentTemplate}}
19
+
20
+ 4. **Audit Requirements:**
21
+
22
+ - **Consistency:** Ensure that all keys have translations for all specified locales.
23
+ - **Missing Content:** Identify any missing translations and specify the expected content.
24
+ - **Misplaced Content:** Detect if any translations are placed under incorrect keys.
25
+ - **Type Compliance:** Verify that the content types match the declarations (e.g., strings, string arrays).
26
+
27
+ 5. **Modification Guidelines:**
28
+
29
+ - **Do Not Alter Structure:** If the file structure is correct, do not modify it. Only add, update, or remove content declarations as necessary.
30
+ - **Do Not Change a value type** If a key value is like `exampleKey: "exampleValue"`, avoid a maximum to not change the value type to `exampleKey: t({ en: "exampleValue" })`.
31
+ - **Return Only Final File Content:** Provide the updated file content without any additional comments or explanations.
32
+ - **Ensure No Translations are Missing:** If an element is a multilingual content and a translation is missing, add it. Including localized content as `es-MX` or `en-UK`.
33
+ - **Manage Localizations:** If the required languages contains similar languages, as `en` and `en-GB`, consider `en` as English US and `en-GB` as English UK, and insert or review both translations to maintain clarity and correctness.
34
+ - **Order Translations:** If the translations are not in the same order as the required languages list, consider reordering the translations to maintain clarity and correctness.
35
+ - **Escape Special Characters:** If the translations contain special characters, escape them using the appropriate escape sequence.
36
+
37
+ 6. **Example Scenario:**
38
+
39
+ - **Example 1:**
40
+
41
+ - **Input File:**
42
+
43
+ ```typescript
44
+ import { t, type DeclarationContent } from "intlayer";
45
+
46
+ export default {
47
+ key: "creative-work-structured-data",
48
+ content: {
49
+ audienceType: t({
50
+ en: "Developers, Content Managers",
51
+ fr: "Développeurs, Responsables de contenu",
52
+ es: "Desarrolladores, Gestores de Contenido",
53
+ }),
54
+ },
55
+ } satisfies DeclarationContent;
56
+ ```
57
+
58
+ - **Expected Output (No Changes Needed):**
59
+
60
+ ```typescript
61
+ import { t, type DeclarationContent } from "intlayer";
62
+
63
+ export default {
64
+ key: "creative-work-structured-data",
65
+ content: {
66
+ audienceType: t({
67
+ en: "Developers, Content Managers",
68
+ fr: "Développeurs, Responsables de contenu",
69
+ es: "Desarrolladores, Gestores de Contenido",
70
+ }),
71
+ },
72
+ } satisfies DeclarationContent;
73
+ ```
74
+
75
+ - **Incorrect Output (Unwanted Structural Change):**
76
+
77
+ ```typescript
78
+ import { t, type DeclarationContent } from "intlayer";
79
+
80
+ export default {
81
+ key: "creative-work-structured-data",
82
+ content: {
83
+ audienceType: t({
84
+ en: "Developers, Content Managers",
85
+ fr: "Développeurs, Responsables de contenu",
86
+ es: "Desarrolladores, Gestores de Contenido",
87
+ }),
88
+ // Missing multilingual content for 'projectDescription'
89
+ projectDescription: t({
90
+ en: "This project involves structured data for creative work.",
91
+ fr: "Ce projet implique des données structurées pour le travail créatif.",
92
+ es: "Este proyecto involucra datos estructurados para trabajo creativo.",
93
+ }),
94
+ },
95
+ } satisfies DeclarationContent;
96
+ ```
97
+
98
+ - **Clarification:** In this scenario, since the input file is already valid and complete, the expected output should be identical to the input without any additional fields or comments.
99
+
100
+ - **Example 2:**
101
+
102
+ - **Input File:**
103
+
104
+ ```typescript
105
+ import { t } from "react-intlayer";
106
+
107
+ const content = {
108
+ key: "creative-work-structured-data",
109
+ content: {
110
+ audienceType: t({
111
+ en: "Developers, Content Managers",
112
+ es: "Desarrolladores, Gestores de Contenido",
113
+ }),
114
+ },
115
+ };
116
+ ```
117
+
118
+ - **Expected Output (No Changes Needed):**
119
+
120
+ ```typescript
121
+ import { t, type DeclarationContent } from "intlayer";
122
+
123
+ const content = {
124
+ key: "creative-work-structured-data",
125
+ content: {
126
+ audienceType: t({
127
+ en: "Developers, Content Managers",
128
+ fr: "Développeurs, Responsables de contenu",
129
+ es: "Desarrolladores, Gestores de Contenido",
130
+ }),
131
+ },
132
+ } satisfies DeclarationContent;
133
+ ```
134
+
135
+ - **Clarification:** In this scenario:
136
+ - A missing translation for the `audienceType` key was added.
137
+ - The import of the `t` function was imported from `react-intlayer` instead of `intlayer`.
138
+ - A type `DeclarationContent` was added to the file to strengthen the content declaration.
139
+
140
+ **File to Audit:**
141
+
142
+ {{fileContent}}
143
+
144
+ **Expected Response:**
145
+
146
+ After auditing, provide only the final content of the file as plain text without any Markdown or code block formatting. If no changes are needed, return the file content exactly as it is.
@@ -0,0 +1,28 @@
1
+ ```tsx
2
+ import React, { type ReactNode } from "react";
3
+ import { t, enu, type DeclarationContent } from "intlayer";
4
+
5
+ export default {
6
+ key: "my-key",
7
+ content: {
8
+ exampleText: t({
9
+ en: "Example of content in English",
10
+ fr: "Example de contenu en français",
11
+ es: "Ejemplo de contenido en español",
12
+ }),
13
+ exampleOfReactNode: t<ReactNode>({
14
+ en: <h1>Example of ReactNode in English</h1>,
15
+ fr: <h1>Example de ReactNode en français</h1>,
16
+ es: <h1>Ejemplo de ReactNode en español</h1>,
17
+ }),
18
+ numberOfCar: enu({
19
+ "<-1": "Less than minus one car",
20
+ "-1": "Minus one car",
21
+ "0": "No cars",
22
+ "1": "One car",
23
+ ">5": "Some cars",
24
+ ">19": "Many cars",
25
+ }),
26
+ },
27
+ } satisfies DeclarationContent;
28
+ ```
@@ -0,0 +1,22 @@
1
+ ```typescript
2
+ import { t, enu, type DeclarationContent } from "intlayer";
3
+
4
+ export default {
5
+ key: "my-key",
6
+ content: {
7
+ exampleText: t({
8
+ en: "Example of content in English",
9
+ fr: "Example de contenu en français",
10
+ es: "Ejemplo de contenido en español",
11
+ }),
12
+ numberOfCar: enu({
13
+ "<-1": "Less than minus one car",
14
+ "-1": "Minus one car",
15
+ "0": "No cars",
16
+ "1": "One car",
17
+ ">5": "Some cars",
18
+ ">19": "Many cars",
19
+ }),
20
+ },
21
+ } satisfies DeclarationContent;
22
+ ```
@@ -0,0 +1,71 @@
1
+ import { readFileSync } from "fs";
2
+ import { dirname, join } from "path";
3
+ import { fileURLToPath } from "url";
4
+ import { getLocaleName } from "@intlayer/core";
5
+ import { logger } from './../../logger/index.mjs';
6
+ import { OpenAI } from "openai";
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const getFileContent = (relativeFilePath) => {
9
+ const absolutePath = join(__dirname, relativeFilePath);
10
+ const fileContent = readFileSync(absolutePath, "utf-8");
11
+ return fileContent;
12
+ };
13
+ const FILE_TEMPLATE = {
14
+ ts: getFileContent("./TS_FORMAT.md"),
15
+ tsx: getFileContent("./TSX_FORMAT.md"),
16
+ js: getFileContent("./MJS_FORMAT.md"),
17
+ mjs: getFileContent("./MJS_FORMAT.md"),
18
+ cjs: getFileContent("./CJS_FORMAT.md"),
19
+ jsx: getFileContent("./JSX_FORMAT.md"),
20
+ json: getFileContent("./JSON_FORMAT.md")
21
+ };
22
+ const CHAT_GPT_PROMPT = getFileContent("./PROMPT.md");
23
+ const formatLocaleWithName = (locale) => {
24
+ const localeName = getLocaleName(locale);
25
+ return `${locale}: ${localeName}`;
26
+ };
27
+ const auditFile = async ({
28
+ fileContent,
29
+ filePath,
30
+ model,
31
+ openAiApiKey,
32
+ customPrompt,
33
+ locales,
34
+ defaultLocale
35
+ }) => {
36
+ try {
37
+ const openai = new OpenAI({
38
+ apiKey: openAiApiKey
39
+ });
40
+ const splitted = (filePath ?? ".json").split(".");
41
+ const fileExtension = splitted[splitted.length - 1];
42
+ const prompt = customPrompt ?? CHAT_GPT_PROMPT.replace("{{filePath}}", filePath ?? "Not provided").replace(
43
+ "{{defaultLocale}}",
44
+ `{${formatLocaleWithName(defaultLocale)}}`
45
+ ).replace(
46
+ "{{otherLocales}}",
47
+ `{${locales.map(formatLocaleWithName).join(", ")}}`
48
+ ).replace(
49
+ "{{declarationsContentTemplate}}",
50
+ FILE_TEMPLATE[fileExtension]
51
+ ).replace("{{fileContent}}", fileContent);
52
+ const chatCompletion = await openai.chat.completions.create({
53
+ model: model ?? "gpt-4o-mini",
54
+ messages: [{ role: "system", content: prompt }]
55
+ });
56
+ const newContent = chatCompletion.choices[0].message?.content;
57
+ logger.info(
58
+ `${chatCompletion.usage?.total_tokens} tokens used in the request`
59
+ );
60
+ return {
61
+ fileContent: newContent ?? "",
62
+ tokenUsed: chatCompletion.usage?.total_tokens ?? 0
63
+ };
64
+ } catch (error) {
65
+ console.error(error);
66
+ }
67
+ };
68
+ export {
69
+ auditFile
70
+ };
71
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/utils/audit/index.ts"],"sourcesContent":["import { readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { getLocaleName } from '@intlayer/core';\nimport { logger } from '@logger';\nimport { Locales } from 'intlayer';\nimport { OpenAI } from 'openai';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport type AuditOptions = {\n locales: Locales[];\n defaultLocale: Locales;\n fileContent: string;\n filePath?: string;\n model?: string;\n openAiApiKey: string;\n customPrompt?: string;\n};\nexport type AuditFileResultData = { fileContent: string; tokenUsed: number };\n\n/**\n * Reads the content of a file synchronously.\n *\n * @function\n * @param relativeFilePath - The relative or absolute path to the target file.\n * @returns The entire contents of the specified file as a UTF-8 encoded string.\n */\nconst getFileContent = (relativeFilePath: string): string => {\n const absolutePath = join(__dirname, relativeFilePath);\n const fileContent = readFileSync(absolutePath, 'utf-8');\n return fileContent;\n};\n\nconst FILE_TEMPLATE: Record<string, string> = {\n ts: getFileContent('./TS_FORMAT.md'),\n tsx: getFileContent('./TSX_FORMAT.md'),\n js: getFileContent('./MJS_FORMAT.md'),\n mjs: getFileContent('./MJS_FORMAT.md'),\n cjs: getFileContent('./CJS_FORMAT.md'),\n jsx: getFileContent('./JSX_FORMAT.md'),\n json: getFileContent('./JSON_FORMAT.md'),\n};\n\n// The prompt template to send to ChatGPT, requesting an audit of content declaration files.\nconst CHAT_GPT_PROMPT = getFileContent('./PROMPT.md');\n\n/**\n * Formats a locale with its full name and returns a string representation.\n *\n * @function\n * @param locale - A locale from the project's configuration (e.g., 'en-US', 'fr-FR').\n * @returns A formatted string combining the locale's name and code. Example: \"English (US): en-US\".\n */\nconst formatLocaleWithName = (locale: Locales): string => {\n // getLocaleName returns a human-readable name for the locale.\n const localeName = getLocaleName(locale);\n\n // Concatenate both the readable name and the locale code.\n return `${locale}: ${localeName}`;\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for ChatGPT.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies. It prints the prompt for each file,\n * and could be adapted to send requests to the ChatGPT model.\n *\n * @async\n * @function\n * @param filePath - The relative or absolute path to the target file.\n * @param options - Optional configuration for the audit process.\n * @returns This function returns a Promise that resolves once the audit is complete.\n */\nexport const auditFile = async ({\n fileContent,\n filePath,\n model,\n openAiApiKey,\n customPrompt,\n locales,\n defaultLocale,\n}: AuditOptions): Promise<AuditFileResultData | undefined> => {\n try {\n // Optionally, you could initialize and configure the OpenAI client here, if you intend to make API calls.\n // Uncomment and configure the following lines if you have `openai` installed and want to call the API:\n\n const openai = new OpenAI({\n apiKey: openAiApiKey,\n });\n\n // Read the file's content.\n const splitted = (filePath ?? '.json').split('.');\n const fileExtension = splitted[splitted.length - 1];\n\n // Prepare the prompt for ChatGPT by replacing placeholders with actual values.\n const prompt =\n customPrompt ??\n CHAT_GPT_PROMPT.replace('{{filePath}}', filePath ?? 'Not provided')\n .replace(\n '{{defaultLocale}}',\n `{${formatLocaleWithName(defaultLocale)}}`\n )\n .replace(\n '{{otherLocales}}',\n `{${locales.map(formatLocaleWithName).join(', ')}}`\n )\n .replace(\n '{{declarationsContentTemplate}}',\n FILE_TEMPLATE[fileExtension]\n )\n .replace('{{fileContent}}', fileContent);\n\n // Example of how you might request a completion from ChatGPT:\n const chatCompletion = await openai.chat.completions.create({\n model: model ?? 'gpt-4o-mini',\n messages: [{ role: 'system', content: prompt }],\n });\n\n const newContent = chatCompletion.choices[0].message?.content;\n\n logger.info(\n `${chatCompletion.usage?.total_tokens} tokens used in the request`\n );\n\n return {\n fileContent: newContent ?? '',\n tokenUsed: chatCompletion.usage?.total_tokens ?? 0,\n };\n } catch (error) {\n console.error(error);\n }\n};\n"],"mappings":"AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AAEvB,SAAS,cAAc;AAEvB,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAoBxD,MAAM,iBAAiB,CAAC,qBAAqC;AAC3D,QAAM,eAAe,KAAK,WAAW,gBAAgB;AACrD,QAAM,cAAc,aAAa,cAAc,OAAO;AACtD,SAAO;AACT;AAEA,MAAM,gBAAwC;AAAA,EAC5C,IAAI,eAAe,gBAAgB;AAAA,EACnC,KAAK,eAAe,iBAAiB;AAAA,EACrC,IAAI,eAAe,iBAAiB;AAAA,EACpC,KAAK,eAAe,iBAAiB;AAAA,EACrC,KAAK,eAAe,iBAAiB;AAAA,EACrC,KAAK,eAAe,iBAAiB;AAAA,EACrC,MAAM,eAAe,kBAAkB;AACzC;AAGA,MAAM,kBAAkB,eAAe,aAAa;AASpD,MAAM,uBAAuB,CAAC,WAA4B;AAExD,QAAM,aAAa,cAAc,MAAM;AAGvC,SAAO,GAAG,MAAM,KAAK,UAAU;AACjC;AAcO,MAAM,YAAY,OAAO;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAA8D;AAC5D,MAAI;AAIF,UAAM,SAAS,IAAI,OAAO;AAAA,MACxB,QAAQ;AAAA,IACV,CAAC;AAGD,UAAM,YAAY,YAAY,SAAS,MAAM,GAAG;AAChD,UAAM,gBAAgB,SAAS,SAAS,SAAS,CAAC;AAGlD,UAAM,SACJ,gBACA,gBAAgB,QAAQ,gBAAgB,YAAY,cAAc,EAC/D;AAAA,MACC;AAAA,MACA,IAAI,qBAAqB,aAAa,CAAC;AAAA,IACzC,EACC;AAAA,MACC;AAAA,MACA,IAAI,QAAQ,IAAI,oBAAoB,EAAE,KAAK,IAAI,CAAC;AAAA,IAClD,EACC;AAAA,MACC;AAAA,MACA,cAAc,aAAa;AAAA,IAC7B,EACC,QAAQ,mBAAmB,WAAW;AAG3C,UAAM,iBAAiB,MAAM,OAAO,KAAK,YAAY,OAAO;AAAA,MAC1D,OAAO,SAAS;AAAA,MAChB,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,IAChD,CAAC;AAED,UAAM,aAAa,eAAe,QAAQ,CAAC,EAAE,SAAS;AAEtD,WAAO;AAAA,MACL,GAAG,eAAe,OAAO,YAAY;AAAA,IACvC;AAEA,WAAO;AAAA,MACL,aAAa,cAAc;AAAA,MAC3B,WAAW,eAAe,OAAO,gBAAgB;AAAA,IACnD;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,KAAK;AAAA,EACrB;AACF;","names":[]}
@@ -1,9 +1,9 @@
1
1
  import { logger } from './../../logger/index.mjs';
2
2
  import { formatPaginatedResponse, formatResponse } from './../../utils/responseData.mjs';
3
3
  import { t } from "express-intlayer";
4
+ import { Locales } from "intlayer";
4
5
  import { errorData } from './errorCodes.mjs';
5
6
  import { HttpStatusCodes } from './../../export.mjs';
6
- import { Locales } from "intlayer";
7
7
  class ErrorHandler {
8
8
  /**
9
9
  * Handles generic error responses by formatting and sending a JSON response.