@intlayer/backend 8.12.2 → 8.12.4-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (415) hide show
  1. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/bundle_optimization.json +9954 -6953
  2. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/configuration.json +1 -1
  3. package/dist/esm/controllers/ai.controller.mjs.map +1 -1
  4. package/dist/esm/controllers/audit.controller.mjs.map +1 -1
  5. package/dist/esm/controllers/bitbucket.controller.mjs.map +1 -1
  6. package/dist/esm/controllers/cliSessionToken.controller.mjs.map +1 -1
  7. package/dist/esm/controllers/demo.controller.mjs +32 -25
  8. package/dist/esm/controllers/demo.controller.mjs.map +1 -1
  9. package/dist/esm/controllers/dictionary.controller.mjs +1 -0
  10. package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
  11. package/dist/esm/controllers/environment.controller.mjs.map +1 -1
  12. package/dist/esm/controllers/eventListener.controller.mjs.map +1 -1
  13. package/dist/esm/controllers/github.controller.mjs.map +1 -1
  14. package/dist/esm/controllers/gitlab.controller.mjs.map +1 -1
  15. package/dist/esm/controllers/newsletter.controller.mjs.map +1 -1
  16. package/dist/esm/controllers/oAuth2.controller.mjs.map +1 -1
  17. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  18. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  19. package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
  20. package/dist/esm/controllers/projectMemberAccess.controller.mjs.map +1 -1
  21. package/dist/esm/controllers/recursiveAudit.controller.mjs.map +1 -1
  22. package/dist/esm/controllers/reviewer.controller.mjs.map +1 -1
  23. package/dist/esm/controllers/searchDoc.controller.mjs.map +1 -1
  24. package/dist/esm/controllers/showcaseProject.controller.mjs.map +1 -1
  25. package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
  26. package/dist/esm/controllers/tag.controller.mjs.map +1 -1
  27. package/dist/esm/controllers/translation.controller.mjs.map +1 -1
  28. package/dist/esm/controllers/user.controller.mjs.map +1 -1
  29. package/dist/esm/emails/AffiliateActivatedEmail.mjs.map +1 -1
  30. package/dist/esm/emails/AffiliateConversionEmail.mjs.map +1 -1
  31. package/dist/esm/emails/AffiliateInvitationEmail.mjs.map +1 -1
  32. package/dist/esm/emails/AffiliateWelcomeEmail.mjs.map +1 -1
  33. package/dist/esm/emails/InviteUserEmail.mjs.map +1 -1
  34. package/dist/esm/emails/MagicLinkEmail.mjs.map +1 -1
  35. package/dist/esm/emails/MissionRequestedClientEmail.mjs.map +1 -1
  36. package/dist/esm/emails/MissionRequestedReviewerEmail.mjs.map +1 -1
  37. package/dist/esm/emails/OAuthTokenCreatedEmail.mjs.map +1 -1
  38. package/dist/esm/emails/PasswordChangeConfirmation.mjs.map +1 -1
  39. package/dist/esm/emails/ResetUserPassword.mjs.map +1 -1
  40. package/dist/esm/emails/ReviewerApplicationEmail.mjs.map +1 -1
  41. package/dist/esm/emails/ReviewerApprovedEmail.mjs.map +1 -1
  42. package/dist/esm/emails/ReviewerContactEmail.mjs.map +1 -1
  43. package/dist/esm/emails/SubscriptionPaymentCancellation.mjs.map +1 -1
  44. package/dist/esm/emails/SubscriptionPaymentError.mjs.map +1 -1
  45. package/dist/esm/emails/SubscriptionPaymentSuccess.mjs.map +1 -1
  46. package/dist/esm/emails/ValidateUserEmail.mjs.map +1 -1
  47. package/dist/esm/emails/Welcome.mjs.map +1 -1
  48. package/dist/esm/index.mjs +1 -1
  49. package/dist/esm/index.mjs.map +1 -1
  50. package/dist/esm/logger/index.mjs.map +1 -1
  51. package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
  52. package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
  53. package/dist/esm/routes/ai.routes.mjs.map +1 -1
  54. package/dist/esm/routes/audit.routes.mjs.map +1 -1
  55. package/dist/esm/routes/bitbucket.routes.mjs.map +1 -1
  56. package/dist/esm/routes/demo.routes.mjs.map +1 -1
  57. package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
  58. package/dist/esm/routes/environment.routes.mjs.map +1 -1
  59. package/dist/esm/routes/eventListener.routes.mjs.map +1 -1
  60. package/dist/esm/routes/github.routes.mjs.map +1 -1
  61. package/dist/esm/routes/gitlab.routes.mjs.map +1 -1
  62. package/dist/esm/routes/newsletter.routes.mjs.map +1 -1
  63. package/dist/esm/routes/organization.routes.mjs.map +1 -1
  64. package/dist/esm/routes/paramsSchemas.mjs.map +1 -1
  65. package/dist/esm/routes/project.routes.mjs.map +1 -1
  66. package/dist/esm/routes/reviewer.routes.mjs.map +1 -1
  67. package/dist/esm/routes/search.routes.mjs.map +1 -1
  68. package/dist/esm/routes/showcaseProject.routes.mjs.map +1 -1
  69. package/dist/esm/routes/stripe.routes.mjs.map +1 -1
  70. package/dist/esm/routes/tags.routes.mjs.map +1 -1
  71. package/dist/esm/routes/translate.routes.mjs.map +1 -1
  72. package/dist/esm/routes/user.routes.mjs.map +1 -1
  73. package/dist/esm/schemas/account.schema.mjs.map +1 -1
  74. package/dist/esm/schemas/affiliate.schema.mjs.map +1 -1
  75. package/dist/esm/schemas/affiliateInvitation.schema.mjs.map +1 -1
  76. package/dist/esm/schemas/audit.schema.mjs.map +1 -1
  77. package/dist/esm/schemas/auditJob.schema.mjs.map +1 -1
  78. package/dist/esm/schemas/auditPage.schema.mjs.map +1 -1
  79. package/dist/esm/schemas/cliSessionToken.schema.mjs.map +1 -1
  80. package/dist/esm/schemas/dictionary.schema.mjs.map +1 -1
  81. package/dist/esm/schemas/discussion.schema.mjs.map +1 -1
  82. package/dist/esm/schemas/oAuth2.schema.mjs.map +1 -1
  83. package/dist/esm/schemas/organization.schema.mjs.map +1 -1
  84. package/dist/esm/schemas/plans.schema.mjs.map +1 -1
  85. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  86. package/dist/esm/schemas/promoCode.schema.mjs.map +1 -1
  87. package/dist/esm/schemas/reviewer.schema.mjs.map +1 -1
  88. package/dist/esm/schemas/session.schema.mjs.map +1 -1
  89. package/dist/esm/schemas/showcaseProject.schema.mjs.map +1 -1
  90. package/dist/esm/schemas/tag.schema.mjs.map +1 -1
  91. package/dist/esm/schemas/user.schema.mjs.map +1 -1
  92. package/dist/esm/services/affiliate.service.mjs.map +1 -1
  93. package/dist/esm/services/audit/analysis/analyzeBundleContent.mjs.map +1 -1
  94. package/dist/esm/services/audit/analysis/analyzeLinguisticStructure.mjs.map +1 -1
  95. package/dist/esm/services/audit/analysis/analyzeMetadata.mjs.map +1 -1
  96. package/dist/esm/services/audit/analysis/analyzeRobots.mjs.map +1 -1
  97. package/dist/esm/services/audit/analysis/analyzeSitemap.mjs.map +1 -1
  98. package/dist/esm/services/audit/analysis/analyzeUrlStructure.mjs.map +1 -1
  99. package/dist/esm/services/audit/analysis/calculateScore.mjs.map +1 -1
  100. package/dist/esm/services/audit/checkers/bundleChecker.mjs.map +1 -1
  101. package/dist/esm/services/audit/checkers/linguisticChecker.mjs.map +1 -1
  102. package/dist/esm/services/audit/checkers/metadataChecker.mjs.map +1 -1
  103. package/dist/esm/services/audit/checkers/pageChecker.mjs.map +1 -1
  104. package/dist/esm/services/audit/checkers/robotsChecker.mjs.map +1 -1
  105. package/dist/esm/services/audit/checkers/sitemapChecker.mjs.map +1 -1
  106. package/dist/esm/services/audit/checkers/urlChecker.mjs.map +1 -1
  107. package/dist/esm/services/audit/recursiveAudit.service.mjs.map +1 -1
  108. package/dist/esm/services/audit/seoAudit.service.mjs.map +1 -1
  109. package/dist/esm/services/bitbucket.service.mjs.map +1 -1
  110. package/dist/esm/services/ci.service.mjs.map +1 -1
  111. package/dist/esm/services/cliSessionToken.service.mjs.map +1 -1
  112. package/dist/esm/services/dictionary.service.mjs.map +1 -1
  113. package/dist/esm/services/email.service.mjs.map +1 -1
  114. package/dist/esm/services/environment.service.mjs.map +1 -1
  115. package/dist/esm/services/github.service.mjs.map +1 -1
  116. package/dist/esm/services/gitlab.service.mjs.map +1 -1
  117. package/dist/esm/services/oAuth2.service.mjs.map +1 -1
  118. package/dist/esm/services/organization.service.mjs.map +1 -1
  119. package/dist/esm/services/project/projectScreenshot.service.mjs.map +1 -1
  120. package/dist/esm/services/project.service.mjs.map +1 -1
  121. package/dist/esm/services/projectAccessKey.service.mjs.map +1 -1
  122. package/dist/esm/services/promoCode.service.mjs.map +1 -1
  123. package/dist/esm/services/reviewer/pictureUpload.service.mjs.map +1 -1
  124. package/dist/esm/services/reviewer.service.mjs.map +1 -1
  125. package/dist/esm/services/reviewerMessage.service.mjs.map +1 -1
  126. package/dist/esm/services/reviewerMission.service.mjs.map +1 -1
  127. package/dist/esm/services/session.service.mjs.map +1 -1
  128. package/dist/esm/services/showcase/showcaseProject.service.mjs.map +1 -1
  129. package/dist/esm/services/showcase/showcaseScan.service.mjs.map +1 -1
  130. package/dist/esm/services/showcase/showcaseUploadScreenshot.service.mjs.map +1 -1
  131. package/dist/esm/services/showcase/showcaseVerifyBundle.service.mjs.map +1 -1
  132. package/dist/esm/services/showcase/showcaseVerifyGithub.service.mjs.map +1 -1
  133. package/dist/esm/services/subscription.service.mjs.map +1 -1
  134. package/dist/esm/services/tag.service.mjs.map +1 -1
  135. package/dist/esm/services/translationQueue.service.mjs.map +1 -1
  136. package/dist/esm/services/translationWorker.service.mjs.map +1 -1
  137. package/dist/esm/services/user/avatarUpload.service.mjs.map +1 -1
  138. package/dist/esm/services/user.service.mjs.map +1 -1
  139. package/dist/esm/services/webhook.service.mjs.map +1 -1
  140. package/dist/esm/types/user.types.mjs.map +1 -1
  141. package/dist/esm/utils/AI/askDocQuestion/askDocQuestion.mjs.map +1 -1
  142. package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/bundle_optimization.json +9954 -6953
  143. package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/configuration.json +1 -1
  144. package/dist/esm/utils/AI/askDocQuestion/indexMarkdownFiles.mjs.map +1 -1
  145. package/dist/esm/utils/AI/auditDictionary/index.mjs.map +1 -1
  146. package/dist/esm/utils/AI/auditDictionaryField/index.mjs.map +1 -1
  147. package/dist/esm/utils/AI/auditDictionaryMetadata/index.mjs.map +1 -1
  148. package/dist/esm/utils/AI/auditTag/index.mjs.map +1 -1
  149. package/dist/esm/utils/AI/autocomplete/index.mjs.map +1 -1
  150. package/dist/esm/utils/AI/chat/index.mjs.map +1 -1
  151. package/dist/esm/utils/AI/chat/mcpInProcessTools.mjs.map +1 -1
  152. package/dist/esm/utils/AI/chat/sessionTools.mjs.map +1 -1
  153. package/dist/esm/utils/AI/customQuery/index.mjs.map +1 -1
  154. package/dist/esm/utils/AI/getProjectAIOptions.mjs.map +1 -1
  155. package/dist/esm/utils/AI/translateDictionaryDB.mjs.map +1 -1
  156. package/dist/esm/utils/AI/translateJSON/index.mjs.map +1 -1
  157. package/dist/esm/utils/accessControl.mjs.map +1 -1
  158. package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
  159. package/dist/esm/utils/cors.mjs +2 -13
  160. package/dist/esm/utils/cors.mjs.map +1 -1
  161. package/dist/esm/utils/demoDictionaries.mjs.map +1 -1
  162. package/dist/esm/utils/ensureArrayQueryFilter.mjs.map +1 -1
  163. package/dist/esm/utils/ensureMongoDocumentToObject.mjs.map +1 -1
  164. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  165. package/dist/esm/utils/errors/ErrorsClass.mjs.map +1 -1
  166. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  167. package/dist/esm/utils/errors/index.mjs +1 -0
  168. package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs.map +1 -1
  169. package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs.map +1 -1
  170. package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs.map +1 -1
  171. package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs.map +1 -1
  172. package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs.map +1 -1
  173. package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs.map +1 -1
  174. package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs.map +1 -1
  175. package/dist/esm/utils/getFaviconUrl.mjs.map +1 -1
  176. package/dist/esm/utils/github/connectGithub.mjs.map +1 -1
  177. package/dist/esm/utils/httpStatusCodes.mjs.map +1 -1
  178. package/dist/esm/utils/image/resizeImage.mjs.map +1 -1
  179. package/dist/esm/utils/mapper/dictionary.mjs.map +1 -1
  180. package/dist/esm/utils/mapper/organization.mjs.map +1 -1
  181. package/dist/esm/utils/mapper/project.mjs.map +1 -1
  182. package/dist/esm/utils/mapper/session.mjs.map +1 -1
  183. package/dist/esm/utils/mapper/showcaseProject.mjs.map +1 -1
  184. package/dist/esm/utils/mapper/tag.mjs.map +1 -1
  185. package/dist/esm/utils/mapper/user.mjs.map +1 -1
  186. package/dist/esm/utils/mongoDB/connectDB.mjs.map +1 -1
  187. package/dist/esm/utils/oAuth2.mjs.map +1 -1
  188. package/dist/esm/utils/permissions.mjs.map +1 -1
  189. package/dist/esm/utils/plan.mjs.map +1 -1
  190. package/dist/esm/utils/puppeteer/launchBrowser.mjs.map +1 -1
  191. package/dist/esm/utils/rateLimiter.mjs.map +1 -1
  192. package/dist/esm/utils/redis/connectRedis.mjs.map +1 -1
  193. package/dist/esm/utils/removeObjectKeys.mjs.map +1 -1
  194. package/dist/esm/utils/responseData.mjs.map +1 -1
  195. package/dist/esm/utils/s3/s3Client.mjs.map +1 -1
  196. package/dist/esm/utils/validation/validateDictionary.mjs.map +1 -1
  197. package/dist/esm/utils/validation/validateOrganization.mjs.map +1 -1
  198. package/dist/esm/utils/validation/validateProject.mjs.map +1 -1
  199. package/dist/esm/utils/validation/validateTag.mjs.map +1 -1
  200. package/dist/esm/utils/validation/validateUser.mjs.map +1 -1
  201. package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -1
  202. package/dist/types/controllers/ai.controller.d.ts.map +1 -1
  203. package/dist/types/controllers/bitbucket.controller.d.ts.map +1 -1
  204. package/dist/types/controllers/cliSessionToken.controller.d.ts.map +1 -1
  205. package/dist/types/controllers/demo.controller.d.ts.map +1 -1
  206. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  207. package/dist/types/controllers/environment.controller.d.ts.map +1 -1
  208. package/dist/types/controllers/eventListener.controller.d.ts.map +1 -1
  209. package/dist/types/controllers/github.controller.d.ts.map +1 -1
  210. package/dist/types/controllers/gitlab.controller.d.ts.map +1 -1
  211. package/dist/types/controllers/newsletter.controller.d.ts.map +1 -1
  212. package/dist/types/controllers/oAuth2.controller.d.ts.map +1 -1
  213. package/dist/types/controllers/organization.controller.d.ts.map +1 -1
  214. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  215. package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
  216. package/dist/types/controllers/projectMemberAccess.controller.d.ts.map +1 -1
  217. package/dist/types/controllers/recursiveAudit.controller.d.ts.map +1 -1
  218. package/dist/types/controllers/reviewer.controller.d.ts.map +1 -1
  219. package/dist/types/controllers/searchDoc.controller.d.ts.map +1 -1
  220. package/dist/types/controllers/showcaseProject.controller.d.ts.map +1 -1
  221. package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
  222. package/dist/types/controllers/tag.controller.d.ts.map +1 -1
  223. package/dist/types/controllers/translation.controller.d.ts.map +1 -1
  224. package/dist/types/controllers/user.controller.d.ts.map +1 -1
  225. package/dist/types/emails/AffiliateActivatedEmail.d.ts +20 -18
  226. package/dist/types/emails/AffiliateActivatedEmail.d.ts.map +1 -1
  227. package/dist/types/emails/AffiliateConversionEmail.d.ts +21 -19
  228. package/dist/types/emails/AffiliateConversionEmail.d.ts.map +1 -1
  229. package/dist/types/emails/AffiliateInvitationEmail.d.ts +20 -18
  230. package/dist/types/emails/AffiliateInvitationEmail.d.ts.map +1 -1
  231. package/dist/types/emails/AffiliateWelcomeEmail.d.ts +20 -18
  232. package/dist/types/emails/AffiliateWelcomeEmail.d.ts.map +1 -1
  233. package/dist/types/emails/InviteUserEmail.d.ts +20 -18
  234. package/dist/types/emails/InviteUserEmail.d.ts.map +1 -1
  235. package/dist/types/emails/MagicLinkEmail.d.ts +20 -18
  236. package/dist/types/emails/MagicLinkEmail.d.ts.map +1 -1
  237. package/dist/types/emails/MissionRequestedClientEmail.d.ts +20 -18
  238. package/dist/types/emails/MissionRequestedClientEmail.d.ts.map +1 -1
  239. package/dist/types/emails/MissionRequestedReviewerEmail.d.ts +20 -18
  240. package/dist/types/emails/MissionRequestedReviewerEmail.d.ts.map +1 -1
  241. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +20 -18
  242. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts.map +1 -1
  243. package/dist/types/emails/PasswordChangeConfirmation.d.ts +20 -18
  244. package/dist/types/emails/PasswordChangeConfirmation.d.ts.map +1 -1
  245. package/dist/types/emails/ResetUserPassword.d.ts +20 -18
  246. package/dist/types/emails/ResetUserPassword.d.ts.map +1 -1
  247. package/dist/types/emails/ReviewerApplicationEmail.d.ts +20 -18
  248. package/dist/types/emails/ReviewerApplicationEmail.d.ts.map +1 -1
  249. package/dist/types/emails/ReviewerApprovedEmail.d.ts +20 -18
  250. package/dist/types/emails/ReviewerApprovedEmail.d.ts.map +1 -1
  251. package/dist/types/emails/ReviewerContactEmail.d.ts +3 -1
  252. package/dist/types/emails/ReviewerContactEmail.d.ts.map +1 -1
  253. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +20 -18
  254. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
  255. package/dist/types/emails/SubscriptionPaymentError.d.ts +20 -18
  256. package/dist/types/emails/SubscriptionPaymentError.d.ts.map +1 -1
  257. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +20 -18
  258. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts.map +1 -1
  259. package/dist/types/emails/ValidateUserEmail.d.ts +20 -18
  260. package/dist/types/emails/ValidateUserEmail.d.ts.map +1 -1
  261. package/dist/types/emails/Welcome.d.ts +20 -18
  262. package/dist/types/emails/Welcome.d.ts.map +1 -1
  263. package/dist/types/export.d.ts +1 -1
  264. package/dist/types/logger/index.d.ts +3 -1
  265. package/dist/types/logger/index.d.ts.map +1 -1
  266. package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
  267. package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
  268. package/dist/types/routes/demo.routes.d.ts.map +1 -1
  269. package/dist/types/schemas/account.schema.d.ts +35 -34
  270. package/dist/types/schemas/account.schema.d.ts.map +1 -1
  271. package/dist/types/schemas/affiliate.schema.d.ts +109 -108
  272. package/dist/types/schemas/affiliate.schema.d.ts.map +1 -1
  273. package/dist/types/schemas/affiliateInvitation.schema.d.ts +49 -48
  274. package/dist/types/schemas/affiliateInvitation.schema.d.ts.map +1 -1
  275. package/dist/types/schemas/audit.schema.d.ts.map +1 -1
  276. package/dist/types/schemas/auditJob.schema.d.ts +6 -6
  277. package/dist/types/schemas/auditPage.schema.d.ts +6 -6
  278. package/dist/types/schemas/cliSessionToken.schema.d.ts +14 -13
  279. package/dist/types/schemas/cliSessionToken.schema.d.ts.map +1 -1
  280. package/dist/types/schemas/dictionary.schema.d.ts +60 -59
  281. package/dist/types/schemas/dictionary.schema.d.ts.map +1 -1
  282. package/dist/types/schemas/discussion.schema.d.ts +51 -50
  283. package/dist/types/schemas/discussion.schema.d.ts.map +1 -1
  284. package/dist/types/schemas/oAuth2.schema.d.ts +18 -17
  285. package/dist/types/schemas/oAuth2.schema.d.ts.map +1 -1
  286. package/dist/types/schemas/organization.schema.d.ts +45 -44
  287. package/dist/types/schemas/organization.schema.d.ts.map +1 -1
  288. package/dist/types/schemas/plans.schema.d.ts +45 -44
  289. package/dist/types/schemas/plans.schema.d.ts.map +1 -1
  290. package/dist/types/schemas/project.schema.d.ts +73 -72
  291. package/dist/types/schemas/project.schema.d.ts.map +1 -1
  292. package/dist/types/schemas/promoCode.schema.d.ts +61 -60
  293. package/dist/types/schemas/promoCode.schema.d.ts.map +1 -1
  294. package/dist/types/schemas/reviewer.schema.d.ts +221 -220
  295. package/dist/types/schemas/reviewer.schema.d.ts.map +1 -1
  296. package/dist/types/schemas/session.schema.d.ts +54 -52
  297. package/dist/types/schemas/session.schema.d.ts.map +1 -1
  298. package/dist/types/schemas/showcaseProject.schema.d.ts +61 -60
  299. package/dist/types/schemas/showcaseProject.schema.d.ts.map +1 -1
  300. package/dist/types/schemas/tag.schema.d.ts +45 -44
  301. package/dist/types/schemas/tag.schema.d.ts.map +1 -1
  302. package/dist/types/schemas/user.schema.d.ts +71 -70
  303. package/dist/types/schemas/user.schema.d.ts.map +1 -1
  304. package/dist/types/services/affiliate.service.d.ts.map +1 -1
  305. package/dist/types/services/audit/analysis/analyzeBundleContent.d.ts.map +1 -1
  306. package/dist/types/services/audit/analysis/analyzeLinguisticStructure.d.ts.map +1 -1
  307. package/dist/types/services/audit/analysis/analyzeRobots.d.ts.map +1 -1
  308. package/dist/types/services/audit/analysis/analyzeSitemap.d.ts.map +1 -1
  309. package/dist/types/services/audit/analysis/calculateScore.d.ts.map +1 -1
  310. package/dist/types/services/audit/checkers/bundleChecker.d.ts.map +1 -1
  311. package/dist/types/services/audit/recursiveAudit.service.d.ts +5 -4
  312. package/dist/types/services/audit/recursiveAudit.service.d.ts.map +1 -1
  313. package/dist/types/services/audit/types.d.ts.map +1 -1
  314. package/dist/types/services/bitbucket.service.d.ts.map +1 -1
  315. package/dist/types/services/cliSessionToken.service.d.ts.map +1 -1
  316. package/dist/types/services/dictionary.service.d.ts.map +1 -1
  317. package/dist/types/services/email.service.d.ts.map +1 -1
  318. package/dist/types/services/github.service.d.ts.map +1 -1
  319. package/dist/types/services/gitlab.service.d.ts.map +1 -1
  320. package/dist/types/services/oAuth2.service.d.ts.map +1 -1
  321. package/dist/types/services/organization.service.d.ts.map +1 -1
  322. package/dist/types/services/project/projectScreenshot.service.d.ts.map +1 -1
  323. package/dist/types/services/project.service.d.ts.map +1 -1
  324. package/dist/types/services/promoCode.service.d.ts.map +1 -1
  325. package/dist/types/services/reviewer/pictureUpload.service.d.ts.map +1 -1
  326. package/dist/types/services/reviewer.service.d.ts.map +1 -1
  327. package/dist/types/services/reviewerMessage.service.d.ts.map +1 -1
  328. package/dist/types/services/reviewerMission.service.d.ts.map +1 -1
  329. package/dist/types/services/session.service.d.ts.map +1 -1
  330. package/dist/types/services/showcase/showcaseProject.service.d.ts.map +1 -1
  331. package/dist/types/services/showcase/showcaseScan.service.d.ts.map +1 -1
  332. package/dist/types/services/showcase/showcaseUploadScreenshot.service.d.ts.map +1 -1
  333. package/dist/types/services/showcase/showcaseVerifyBundle.service.d.ts.map +1 -1
  334. package/dist/types/services/showcase/showcaseVerifyGithub.service.d.ts.map +1 -1
  335. package/dist/types/services/subscription.service.d.ts.map +1 -1
  336. package/dist/types/services/tag.service.d.ts.map +1 -1
  337. package/dist/types/services/translationQueue.service.d.ts +2 -1
  338. package/dist/types/services/translationQueue.service.d.ts.map +1 -1
  339. package/dist/types/services/translationWorker.service.d.ts.map +1 -1
  340. package/dist/types/services/user/avatarUpload.service.d.ts.map +1 -1
  341. package/dist/types/services/user.service.d.ts.map +1 -1
  342. package/dist/types/services/webhook.service.d.ts.map +1 -1
  343. package/dist/types/types/Routes.d.ts.map +1 -1
  344. package/dist/types/types/account.types.d.ts.map +1 -1
  345. package/dist/types/types/affiliate.types.d.ts.map +1 -1
  346. package/dist/types/types/affiliateInvitation.types.d.ts.map +1 -1
  347. package/dist/types/types/dictionary.types.d.ts.map +1 -1
  348. package/dist/types/types/discussion.types.d.ts.map +1 -1
  349. package/dist/types/types/oAuth2.types.d.ts.map +1 -1
  350. package/dist/types/types/organization.types.d.ts.map +1 -1
  351. package/dist/types/types/plan.types.d.ts.map +1 -1
  352. package/dist/types/types/project.types.d.ts.map +1 -1
  353. package/dist/types/types/promoCode.types.d.ts.map +1 -1
  354. package/dist/types/types/reviewer.types.d.ts.map +1 -1
  355. package/dist/types/types/session.types.d.ts.map +1 -1
  356. package/dist/types/types/showcaseProject.types.d.ts.map +1 -1
  357. package/dist/types/types/tag.types.d.ts.map +1 -1
  358. package/dist/types/types/user.types.d.ts.map +1 -1
  359. package/dist/types/utils/AI/askDocQuestion/askDocQuestion.d.ts.map +1 -1
  360. package/dist/types/utils/AI/askDocQuestion/indexMarkdownFiles.d.ts.map +1 -1
  361. package/dist/types/utils/AI/auditDictionary/index.d.ts.map +1 -1
  362. package/dist/types/utils/AI/auditDictionaryField/index.d.ts.map +1 -1
  363. package/dist/types/utils/AI/auditDictionaryMetadata/index.d.ts.map +1 -1
  364. package/dist/types/utils/AI/auditTag/index.d.ts.map +1 -1
  365. package/dist/types/utils/AI/autocomplete/index.d.ts.map +1 -1
  366. package/dist/types/utils/AI/chat/index.d.ts.map +1 -1
  367. package/dist/types/utils/AI/chat/mcpInProcessTools.d.ts.map +1 -1
  368. package/dist/types/utils/AI/chat/sessionTools.d.ts +25 -24
  369. package/dist/types/utils/AI/chat/sessionTools.d.ts.map +1 -1
  370. package/dist/types/utils/AI/customQuery/index.d.ts.map +1 -1
  371. package/dist/types/utils/AI/translateDictionaryDB.d.ts.map +1 -1
  372. package/dist/types/utils/AI/translateJSON/index.d.ts.map +1 -1
  373. package/dist/types/utils/auth/getAuth.d.ts.map +1 -1
  374. package/dist/types/utils/cors.d.ts +1 -7
  375. package/dist/types/utils/cors.d.ts.map +1 -1
  376. package/dist/types/utils/demoDictionaries.d.ts.map +1 -1
  377. package/dist/types/utils/ensureArrayQueryFilter.d.ts.map +1 -1
  378. package/dist/types/utils/errors/ErrorHandler.d.ts +8 -6
  379. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  380. package/dist/types/utils/errors/ErrorsClass.d.ts.map +1 -1
  381. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  382. package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts.map +1 -1
  383. package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts.map +1 -1
  384. package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts.map +1 -1
  385. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts.map +1 -1
  386. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts.map +1 -1
  387. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +7 -6
  388. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts.map +1 -1
  389. package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts.map +1 -1
  390. package/dist/types/utils/getFaviconUrl.d.ts.map +1 -1
  391. package/dist/types/utils/github/connectGithub.d.ts.map +1 -1
  392. package/dist/types/utils/httpStatusCodes.d.ts.map +1 -1
  393. package/dist/types/utils/image/resizeImage.d.ts.map +1 -1
  394. package/dist/types/utils/mapper/dictionary.d.ts.map +1 -1
  395. package/dist/types/utils/mapper/project.d.ts.map +1 -1
  396. package/dist/types/utils/mapper/session.d.ts.map +1 -1
  397. package/dist/types/utils/mapper/showcaseProject.d.ts.map +1 -1
  398. package/dist/types/utils/mapper/tag.d.ts.map +1 -1
  399. package/dist/types/utils/mergeFunctionTypes.d.ts.map +1 -1
  400. package/dist/types/utils/mongoDB/connectDB.d.ts.map +1 -1
  401. package/dist/types/utils/mongoDB/types.d.ts.map +1 -1
  402. package/dist/types/utils/oAuth2.d.ts.map +1 -1
  403. package/dist/types/utils/permissions.d.ts +2 -1
  404. package/dist/types/utils/permissions.d.ts.map +1 -1
  405. package/dist/types/utils/plan.d.ts.map +1 -1
  406. package/dist/types/utils/rateLimiter.d.ts.map +1 -1
  407. package/dist/types/utils/redis/connectRedis.d.ts.map +1 -1
  408. package/dist/types/utils/responseData.d.ts.map +1 -1
  409. package/dist/types/utils/s3/s3Client.d.ts.map +1 -1
  410. package/dist/types/utils/validation/validateDictionary.d.ts.map +1 -1
  411. package/dist/types/utils/validation/validateOrganization.d.ts.map +1 -1
  412. package/dist/types/utils/validation/validateProject.d.ts.map +1 -1
  413. package/dist/types/utils/validation/validateTag.d.ts.map +1 -1
  414. package/dist/types/utils/validation/validateUser.d.ts.map +1 -1
  415. package/package.json +17 -17
@@ -1 +1 @@
1
- {"version":3,"file":"indexMarkdownFiles.mjs","names":[],"sources":["../../../../../src/utils/AI/askDocQuestion/indexMarkdownFiles.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\nimport { getBlogs, getDocs, getFrequentQuestions } from '@intlayer/docs';\nimport { logger } from '@logger';\nimport dotenv from 'dotenv';\nimport { OpenAI } from 'openai';\n\nconst OUTPUT_EMBEDDINGS_DIR = 'src/utils/AI/askDocQuestion/embeddings';\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\ntype EmbeddingStore = Record<string, number[] | string>;\n\nconst contentHash = (text: string): string =>\n createHash('sha256').update(text).digest('hex');\n\nconst readEmbeddingsForFile = (fileKey: string): EmbeddingStore => {\n try {\n return JSON.parse(\n readFileSync(\n `${__dirname}/embeddings/${fileKey.replace('.md', '.json')}`,\n 'utf-8'\n )\n ) as EmbeddingStore;\n } catch {\n return {};\n }\n};\n\nconst writeEmbeddingsForFile = (\n fileKey: string,\n data: EmbeddingStore\n): void => {\n const filePath = join(\n OUTPUT_EMBEDDINGS_DIR,\n `${fileKey.replace('.md', '.json')}`\n );\n const dir = dirname(filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(filePath, JSON.stringify(data));\n};\n\ntype VectorStoreEl = {\n fileKey: string;\n chunkNumber: number;\n content: string;\n embedding: number[];\n docUrl: string;\n docName: string;\n};\n\n/**\n * Simple in-memory vector store to hold document embeddings and their content.\n * Each entry contains:\n * - fileKey: A unique key identifying the file\n * - chunkNumber: The number of the chunk within the document\n * - content: The chunk content\n * - embedding: The numerical embedding vector for the chunk\n */\nconst vectorStore: VectorStoreEl[] = [];\n\n/*\n * Embedding model configuration\n */\nconst EMBEDDING_MODEL: OpenAI.EmbeddingModel = 'text-embedding-3-large'; // Model to use for embedding generation\nconst OVERLAP_TOKENS: number = 200; // Number of tokens to overlap between chunks\nconst MAX_CHUNK_TOKENS: number = 800; // Maximum number of tokens per chunk\nconst CHAR_BY_TOKEN: number = 4.15; // Approximate pessimistically the number of characters per token // Can use `tiktoken` or other tokenizers to calculate it more precisely\nconst MAX_CHARS: number = MAX_CHUNK_TOKENS * CHAR_BY_TOKEN;\nconst OVERLAP_CHARS: number = OVERLAP_TOKENS * CHAR_BY_TOKEN;\n\nconst skipDocEmbeddingsIndex = process.env.SKIP_DOC_EMBEDDINGS_INDEX === 'true';\n\n/**\n * Splits a given text into chunks ensuring each chunk does not exceed MAX_CHARS.\n * @param text - The input text to split.\n * @returns - Array of text chunks.\n */\nconst chunkText = (text: string): string[] => {\n const chunks: string[] = [];\n let start = 0;\n\n while (start < text.length) {\n let end = Math.min(start + MAX_CHARS, text.length);\n\n // Ensure we don't cut words in the middle (find nearest space)\n if (end < text.length) {\n const lastSpace = text.lastIndexOf(' ', end);\n if (lastSpace > start) {\n end = lastSpace;\n }\n }\n\n chunks.push(text.substring(start, end));\n\n // Move start forward correctly\n const nextStart = end - OVERLAP_CHARS;\n if (nextStart <= start) {\n // Prevent infinite loop if overlap is too large\n start = end;\n } else {\n start = nextStart;\n }\n }\n\n return chunks;\n};\n\n/**\n * Generates an embedding for a given text using OpenAI's embedding API.\n * Trims the text if it exceeds the maximum allowed characters.\n *\n * @param text - The input text to generate an embedding for\n * @returns The embedding vector as a number array\n */\nconst generateEmbedding = async (text: string): Promise<number[]> => {\n try {\n const openaiClient = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n const response = await openaiClient.embeddings.create({\n model: EMBEDDING_MODEL,\n input: text,\n });\n\n return response.data[0].embedding;\n } catch (error) {\n logger.error('Error generating embedding:', error);\n return [];\n }\n};\n\n/**\n * Indexes all Markdown documents by generating embeddings for each chunk and storing them in memory.\n * Persists per-document embeddings under `embeddings/<fileKey>.json`.\n * Handles cases where files have been updated and chunk counts have changed.\n */\nexport const indexMarkdownFiles = async (): Promise<void> => {\n const env = process.env.NODE_ENV;\n dotenv.config({\n path: [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env'],\n quiet: true,\n });\n\n // Retrieve documentation and blog posts in English locale\n const frequentQuestions = await getFrequentQuestions();\n const docs = await getDocs();\n const blogs = await getBlogs();\n\n const files = { ...docs, ...blogs, ...frequentQuestions }; // Combine docs and blogs into a single object\n\n // Iterate over each file key (identifier) in the combined files\n for await (const fileKey of Object.keys(files)) {\n // Get the metadata of the file\n const fileMetadata = getMarkdownMetadata(\n files[fileKey as keyof typeof files] as string\n );\n\n // Split the document into chunks based on headings\n const fileChunks = chunkText(\n files[fileKey as keyof typeof files] as string\n );\n\n // Read existing embeddings for this file\n const existingEmbeddings = readEmbeddingsForFile(fileKey);\n\n // Iterate over each chunk within the current file\n let resultForFile: EmbeddingStore = {};\n for await (const chunkIndex of Object.keys(fileChunks)) {\n const chunkNumber = Number(chunkIndex) + 1; // Chunk number starts at 1\n const chunksNumber = fileChunks.length;\n\n const fileChunk = fileChunks[\n chunkIndex as keyof typeof fileChunks\n ] as string;\n\n const chunkKeyName = `chunk_${chunkNumber}`; // Unique key for the chunk within the file\n const chunkHashKey = `chunk_${chunkNumber}_hash`;\n const currentChunkHash = contentHash(fileChunk);\n const storedHash = existingEmbeddings[chunkHashKey] as string | undefined;\n const storedEmbedding = existingEmbeddings[chunkKeyName] as\n | number[]\n | undefined;\n\n const chunkContentChanged = storedHash !== currentChunkHash;\n\n let embedding: number[] | undefined = storedEmbedding;\n\n if (\n !storedEmbedding ||\n (chunkContentChanged && !skipDocEmbeddingsIndex)\n ) {\n embedding = await generateEmbedding(fileChunk); // Generate embedding if not present or content changed\n logger.info(`- Generated new embedding: ${fileKey}/${chunkKeyName}`);\n }\n\n // Update the file-scoped result object with the embedding and hash\n resultForFile = {\n ...resultForFile,\n [chunkKeyName]: embedding ?? [],\n [chunkHashKey]: currentChunkHash,\n };\n\n // Store the embedding and content in the in-memory vector store\n if (embedding) {\n vectorStore.push({\n fileKey,\n chunkNumber,\n embedding,\n content: fileChunk,\n docUrl: fileMetadata.url,\n docName: fileMetadata.title,\n });\n }\n\n logger.info(`- Indexed: ${fileKey}/${chunkKeyName}/${chunksNumber}`);\n }\n\n // Persist per-file embeddings if changed\n try {\n if (\n JSON.stringify(resultForFile) !== JSON.stringify(existingEmbeddings)\n ) {\n writeEmbeddingsForFile(fileKey, resultForFile);\n }\n } catch (error) {\n logger.error(error);\n }\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"indexMarkdownFiles.mjs","names":[],"sources":["../../../../../src/utils/AI/askDocQuestion/indexMarkdownFiles.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\nimport { getBlogs, getDocs, getFrequentQuestions } from '@intlayer/docs';\nimport { logger } from '@logger';\nimport dotenv from 'dotenv';\nimport { OpenAI } from 'openai';\n\nconst OUTPUT_EMBEDDINGS_DIR = 'src/utils/AI/askDocQuestion/embeddings';\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\ntype EmbeddingStore = Record<string, number[] | string>;\n\nconst contentHash = (text: string): string =>\n createHash('sha256').update(text).digest('hex');\n\nconst readEmbeddingsForFile = (fileKey: string): EmbeddingStore => {\n try {\n return JSON.parse(\n readFileSync(\n `${__dirname}/embeddings/${fileKey.replace('.md', '.json')}`,\n 'utf-8'\n )\n ) as EmbeddingStore;\n } catch {\n return {};\n }\n};\n\nconst writeEmbeddingsForFile = (\n fileKey: string,\n data: EmbeddingStore\n): void => {\n const filePath = join(\n OUTPUT_EMBEDDINGS_DIR,\n `${fileKey.replace('.md', '.json')}`\n );\n const dir = dirname(filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(filePath, JSON.stringify(data));\n};\n\ntype VectorStoreEl = {\n fileKey: string;\n chunkNumber: number;\n content: string;\n embedding: number[];\n docUrl: string;\n docName: string;\n};\n\n/**\n * Simple in-memory vector store to hold document embeddings and their content.\n * Each entry contains:\n * - fileKey: A unique key identifying the file\n * - chunkNumber: The number of the chunk within the document\n * - content: The chunk content\n * - embedding: The numerical embedding vector for the chunk\n */\nconst vectorStore: VectorStoreEl[] = [];\n\n/*\n * Embedding model configuration\n */\nconst EMBEDDING_MODEL: OpenAI.EmbeddingModel = 'text-embedding-3-large'; // Model to use for embedding generation\nconst OVERLAP_TOKENS: number = 200; // Number of tokens to overlap between chunks\nconst MAX_CHUNK_TOKENS: number = 800; // Maximum number of tokens per chunk\nconst CHAR_BY_TOKEN: number = 4.15; // Approximate pessimistically the number of characters per token // Can use `tiktoken` or other tokenizers to calculate it more precisely\nconst MAX_CHARS: number = MAX_CHUNK_TOKENS * CHAR_BY_TOKEN;\nconst OVERLAP_CHARS: number = OVERLAP_TOKENS * CHAR_BY_TOKEN;\n\nconst skipDocEmbeddingsIndex = process.env.SKIP_DOC_EMBEDDINGS_INDEX === 'true';\n\n/**\n * Splits a given text into chunks ensuring each chunk does not exceed MAX_CHARS.\n * @param text - The input text to split.\n * @returns - Array of text chunks.\n */\nconst chunkText = (text: string): string[] => {\n const chunks: string[] = [];\n let start = 0;\n\n while (start < text.length) {\n let end = Math.min(start + MAX_CHARS, text.length);\n\n // Ensure we don't cut words in the middle (find nearest space)\n if (end < text.length) {\n const lastSpace = text.lastIndexOf(' ', end);\n if (lastSpace > start) {\n end = lastSpace;\n }\n }\n\n chunks.push(text.substring(start, end));\n\n // Move start forward correctly\n const nextStart = end - OVERLAP_CHARS;\n if (nextStart <= start) {\n // Prevent infinite loop if overlap is too large\n start = end;\n } else {\n start = nextStart;\n }\n }\n\n return chunks;\n};\n\n/**\n * Generates an embedding for a given text using OpenAI's embedding API.\n * Trims the text if it exceeds the maximum allowed characters.\n *\n * @param text - The input text to generate an embedding for\n * @returns The embedding vector as a number array\n */\nconst generateEmbedding = async (text: string): Promise<number[]> => {\n try {\n const openaiClient = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n const response = await openaiClient.embeddings.create({\n model: EMBEDDING_MODEL,\n input: text,\n });\n\n return response.data[0].embedding;\n } catch (error) {\n logger.error('Error generating embedding:', error);\n return [];\n }\n};\n\n/**\n * Indexes all Markdown documents by generating embeddings for each chunk and storing them in memory.\n * Persists per-document embeddings under `embeddings/<fileKey>.json`.\n * Handles cases where files have been updated and chunk counts have changed.\n */\nexport const indexMarkdownFiles = async (): Promise<void> => {\n const env = process.env.NODE_ENV;\n dotenv.config({\n path: [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env'],\n quiet: true,\n });\n\n // Retrieve documentation and blog posts in English locale\n const frequentQuestions = await getFrequentQuestions();\n const docs = await getDocs();\n const blogs = await getBlogs();\n\n const files = { ...docs, ...blogs, ...frequentQuestions }; // Combine docs and blogs into a single object\n\n // Iterate over each file key (identifier) in the combined files\n for await (const fileKey of Object.keys(files)) {\n // Get the metadata of the file\n const fileMetadata = getMarkdownMetadata(\n files[fileKey as keyof typeof files] as string\n );\n\n // Split the document into chunks based on headings\n const fileChunks = chunkText(\n files[fileKey as keyof typeof files] as string\n );\n\n // Read existing embeddings for this file\n const existingEmbeddings = readEmbeddingsForFile(fileKey);\n\n // Iterate over each chunk within the current file\n let resultForFile: EmbeddingStore = {};\n for await (const chunkIndex of Object.keys(fileChunks)) {\n const chunkNumber = Number(chunkIndex) + 1; // Chunk number starts at 1\n const chunksNumber = fileChunks.length;\n\n const fileChunk = fileChunks[\n chunkIndex as keyof typeof fileChunks\n ] as string;\n\n const chunkKeyName = `chunk_${chunkNumber}`; // Unique key for the chunk within the file\n const chunkHashKey = `chunk_${chunkNumber}_hash`;\n const currentChunkHash = contentHash(fileChunk);\n const storedHash = existingEmbeddings[chunkHashKey] as string | undefined;\n const storedEmbedding = existingEmbeddings[chunkKeyName] as\n | number[]\n | undefined;\n\n const chunkContentChanged = storedHash !== currentChunkHash;\n\n let embedding: number[] | undefined = storedEmbedding;\n\n if (\n !storedEmbedding ||\n (chunkContentChanged && !skipDocEmbeddingsIndex)\n ) {\n embedding = await generateEmbedding(fileChunk); // Generate embedding if not present or content changed\n logger.info(`- Generated new embedding: ${fileKey}/${chunkKeyName}`);\n }\n\n // Update the file-scoped result object with the embedding and hash\n resultForFile = {\n ...resultForFile,\n [chunkKeyName]: embedding ?? [],\n [chunkHashKey]: currentChunkHash,\n };\n\n // Store the embedding and content in the in-memory vector store\n if (embedding) {\n vectorStore.push({\n fileKey,\n chunkNumber,\n embedding,\n content: fileChunk,\n docUrl: fileMetadata.url,\n docName: fileMetadata.title,\n });\n }\n\n logger.info(`- Indexed: ${fileKey}/${chunkKeyName}/${chunksNumber}`);\n }\n\n // Persist per-file embeddings if changed\n try {\n if (\n JSON.stringify(resultForFile) !== JSON.stringify(existingEmbeddings)\n ) {\n writeEmbeddingsForFile(fileKey, resultForFile);\n }\n } catch (error) {\n logger.error(error);\n }\n }\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/auditDictionary/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n extractJson,\n generateText,\n} from '@intlayer/ai';\nimport { DEFAULT_LOCALE } from '@intlayer/config/defaultValues';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nexport type AuditOptions = {\n fileContent: string;\n filePath?: string;\n locales: Locale[];\n defaultLocale: Locale;\n tags: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditFileResultData = {\n fileContent: {\n title: string;\n description: string;\n tags: string[];\n };\n tokenUsed: number;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string => {\n return `${locale}: ${getLocaleName(locale, DEFAULT_LOCALE)}`;\n};\n\n/**\n * Formats tag instructions for the AI prompt.\n * Creates a string with all available tags and their descriptions.\n *\n * @param tags - The list of tags to format.\n * @returns A formatted string with tag instructions.\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) return '';\n\n // Prepare the tag instructions.\n return [\n `Based on the dictionary content, identify specific tags from the list below that would be relevant:`,\n tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n'),\n ].join('\\n\\n');\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionary = async ({\n fileContent,\n filePath,\n locales,\n defaultLocale,\n tags,\n aiConfig,\n applicationContext,\n}: AuditOptions): Promise<AuditFileResultData | undefined> => {\n const otherLocales = locales.filter((locale) => locale !== defaultLocale);\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{defaultLocale}}',\n formatLocaleWithName(defaultLocale)\n )\n .replace(\n '{{otherLocales}}',\n `{${otherLocales.map(formatLocaleWithName).join(', ')}}`\n )\n .replace('{{filePath}}', filePath ?? '')\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags));\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [\n {\n role: 'user',\n content: ['**File to Audit:**', fileContent].join('\\n'),\n },\n ],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: extractJson(newContent),\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;;AAsCA,MAAM,kBAAkB,aAAa,KAHnB,QADC,cAAc,OAAO,KAAK,GACV,CAGe,GAAG,aAAa,GAAG,OAAO;AAE5E,MAAa,mBAA8B,CAE3C;;;;;;;AAQA,MAAM,wBAAwB,WAA2B;CACvD,OAAO,GAAG,OAAO,IAAI,cAAc,QAAQ,cAAc;AAC3D;;;;;;;;AASA,MAAM,yBAAyB,SAAwB;CACrD,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,OAAO;CAGvC,OAAO,CACL,uGACA,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,aAAa,CAAC,CAAC,KAAK,MAAM,CAC5E,CAAC,CAAC,KAAK,MAAM;AACf;;;;;;AAOA,MAAa,kBAAkB,OAAO,EACpC,aACA,UACA,SACA,eACA,MACA,UACA,yBAC4D;CAC5D,MAAM,eAAe,QAAQ,QAAQ,WAAW,WAAW,aAAa;CAGxE,MAAM,SAAS,gBAAgB,QAC7B,qBACA,qBAAqB,aAAa,CACpC,CAAC,CACE,QACC,oBACA,IAAI,aAAa,IAAI,oBAAoB,CAAC,CAAC,KAAK,IAAI,EAAE,EACxD,CAAC,CACA,QAAQ,gBAAgB,YAAY,EAAE,CAAC,CACvC,QAAQ,0BAA0B,sBAAsB,EAAE,CAAC,CAC3D,QAAQ,wBAAwB,sBAAsB,IAAI,CAAC;CAG9D,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CACR;GACE,MAAM;GACN,SAAS,CAAC,sBAAsB,WAAW,CAAC,CAAC,KAAK,IAAI;EACxD,CACF;CACF,CAAC;CAED,OAAO,KAAK,GAAG,OAAO,eAAe,EAAE,4BAA4B;CAEnE,OAAO;EACL,aAAa,YAAY,UAAU;EACnC,WAAW,OAAO,eAAe;CACnC;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/auditDictionary/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n extractJson,\n generateText,\n} from '@intlayer/ai';\nimport { DEFAULT_LOCALE } from '@intlayer/config/defaultValues';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nexport type AuditOptions = {\n fileContent: string;\n filePath?: string;\n locales: Locale[];\n defaultLocale: Locale;\n tags: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditFileResultData = {\n fileContent: {\n title: string;\n description: string;\n tags: string[];\n };\n tokenUsed: number;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string => {\n return `${locale}: ${getLocaleName(locale, DEFAULT_LOCALE)}`;\n};\n\n/**\n * Formats tag instructions for the AI prompt.\n * Creates a string with all available tags and their descriptions.\n *\n * @param tags - The list of tags to format.\n * @returns A formatted string with tag instructions.\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) return '';\n\n // Prepare the tag instructions.\n return [\n `Based on the dictionary content, identify specific tags from the list below that would be relevant:`,\n tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n'),\n ].join('\\n\\n');\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionary = async ({\n fileContent,\n filePath,\n locales,\n defaultLocale,\n tags,\n aiConfig,\n applicationContext,\n}: AuditOptions): Promise<AuditFileResultData | undefined> => {\n const otherLocales = locales.filter((locale) => locale !== defaultLocale);\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{defaultLocale}}',\n formatLocaleWithName(defaultLocale)\n )\n .replace(\n '{{otherLocales}}',\n `{${otherLocales.map(formatLocaleWithName).join(', ')}}`\n )\n .replace('{{filePath}}', filePath ?? '')\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags));\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [\n {\n role: 'user',\n content: ['**File to Audit:**', fileContent].join('\\n'),\n },\n ],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: extractJson(newContent),\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;;AAsCA,MAAM,kBAAkB,aAAa,KAHnB,QADC,cAAc,OAAO,KAAK,IACT,CAGe,EAAE,cAAc,EAAE,QAAQ;AAE7E,MAAa,mBAA8B,EAE1C;;;;;;;AAQD,MAAM,wBAAwB,WAA2B;AACvD,QAAO,GAAG,OAAO,IAAI,cAAc,QAAQ,eAAe;;;;;;;;;AAU5D,MAAM,yBAAyB,SAAwB;AACrD,KAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AAGvC,QAAO,CACL,uGACA,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CAAC,KAAK,OAAO,CAC5E,CAAC,KAAK,OAAO;;;;;;;AAQhB,MAAa,kBAAkB,OAAO,EACpC,aACA,UACA,SACA,eACA,MACA,UACA,yBAC4D;CAC5D,MAAM,eAAe,QAAQ,QAAQ,WAAW,WAAW,cAAc;CAGzE,MAAM,SAAS,gBAAgB,QAC7B,qBACA,qBAAqB,cAAc,CACpC,CACE,QACC,oBACA,IAAI,aAAa,IAAI,qBAAqB,CAAC,KAAK,KAAK,CAAC,GACvD,CACA,QAAQ,gBAAgB,YAAY,GAAG,CACvC,QAAQ,0BAA0B,sBAAsB,GAAG,CAC3D,QAAQ,wBAAwB,sBAAsB,KAAK,CAAC;CAG/D,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CACR;GACE,MAAM;GACN,SAAS,CAAC,sBAAsB,YAAY,CAAC,KAAK,KAAK;GACxD,CACF;EACF,CAAC;AAEF,QAAO,KAAK,GAAG,OAAO,eAAe,EAAE,6BAA6B;AAEpE,QAAO;EACL,aAAa,YAAY,WAAW;EACpC,WAAW,OAAO,eAAe;EAClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/auditDictionaryField/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AIConfig, AIOptions } from '@intlayer/ai';\nimport { generateText } from '@intlayer/ai';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as Locales from '@intlayer/types/locales';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport type AuditDictionaryFieldOptions = {\n fileContent: string;\n locales: Locale[];\n keyPath: KeyPath[];\n tags: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditDictionaryFieldResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string => {\n return `${locale}: ${getLocaleName(locale, Locales.ENGLISH)}`;\n};\n\n/**\n * Formats tag instructions for the AI prompt.\n *\n * @param tags - Array of tags to format\n * @returns A formatted string with tag instructions\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryField = async ({\n fileContent,\n applicationContext,\n locales,\n keyPath,\n tags,\n aiConfig,\n}: AuditDictionaryFieldOptions): Promise<\n AuditDictionaryFieldResultData | undefined\n> => {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{otherLocales}}',\n `{${locales.map(formatLocaleWithName).join(', ')}}`\n )\n .replace('{{keyPath}}', JSON.stringify(keyPath))\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags));\n\n console.log({\n prompt,\n fileContent,\n applicationContext,\n locales,\n keyPath,\n tags,\n aiConfig,\n });\n\n if (!aiConfig) {\n logger.error('Failed to configure AI model');\n return undefined;\n }\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [\n {\n role: 'user',\n content: ['**File to Audit:**', fileContent].join('\\n'),\n },\n ],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;;AA8BA,MAAM,kBAAkB,aAAa,KAjBnB,QADC,cAAc,OAAO,KAAK,GACV,CAiBe,GAAG,aAAa,GAAG,OAAO;AAE5E,MAAa,mBAA8B,CAE3C;;;;;;;AAQA,MAAM,wBAAwB,WAA2B;CACvD,OAAO,GAAG,OAAO,IAAI,cAAc,QAAQ,QAAQ,OAAO;AAC5D;;;;;;;AAQA,MAAM,yBAAyB,SAAwB;CACrD,IAAI,CAAC,QAAQ,KAAK,WAAW,GAC3B,OAAO;CAGT,OAAO;;EAEP,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,aAAa,CAAC,CAAC,KAAK,MAAM;AAC5E;;;;;;AAOA,MAAa,uBAAuB,OAAO,EACzC,aACA,oBACA,SACA,SACA,MACA,eAGG;CAEH,MAAM,SAAS,gBAAgB,QAC7B,oBACA,IAAI,QAAQ,IAAI,oBAAoB,CAAC,CAAC,KAAK,IAAI,EAAE,EACnD,CAAC,CACE,QAAQ,eAAe,KAAK,UAAU,OAAO,CAAC,CAAC,CAC/C,QAAQ,0BAA0B,sBAAsB,EAAE,CAAC,CAC3D,QAAQ,wBAAwB,sBAAsB,IAAI,CAAC;CAE9D,QAAQ,IAAI;EACV;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,IAAI,CAAC,UAAU;EACb,OAAO,MAAM,8BAA8B;EAC3C;CACF;CAGA,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CACR;GACE,MAAM;GACN,SAAS,CAAC,sBAAsB,WAAW,CAAC,CAAC,KAAK,IAAI;EACxD,CACF;CACF,CAAC;CAED,OAAO,KAAK,GAAG,OAAO,eAAe,EAAE,4BAA4B;CAEnE,OAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;CACnC;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/auditDictionaryField/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AIConfig, AIOptions } from '@intlayer/ai';\nimport { generateText } from '@intlayer/ai';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as Locales from '@intlayer/types/locales';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport type AuditDictionaryFieldOptions = {\n fileContent: string;\n locales: Locale[];\n keyPath: KeyPath[];\n tags: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditDictionaryFieldResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string => {\n return `${locale}: ${getLocaleName(locale, Locales.ENGLISH)}`;\n};\n\n/**\n * Formats tag instructions for the AI prompt.\n *\n * @param tags - Array of tags to format\n * @returns A formatted string with tag instructions\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryField = async ({\n fileContent,\n applicationContext,\n locales,\n keyPath,\n tags,\n aiConfig,\n}: AuditDictionaryFieldOptions): Promise<\n AuditDictionaryFieldResultData | undefined\n> => {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{otherLocales}}',\n `{${locales.map(formatLocaleWithName).join(', ')}}`\n )\n .replace('{{keyPath}}', JSON.stringify(keyPath))\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags));\n\n console.log({\n prompt,\n fileContent,\n applicationContext,\n locales,\n keyPath,\n tags,\n aiConfig,\n });\n\n if (!aiConfig) {\n logger.error('Failed to configure AI model');\n return undefined;\n }\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [\n {\n role: 'user',\n content: ['**File to Audit:**', fileContent].join('\\n'),\n },\n ],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;;AA8BA,MAAM,kBAAkB,aAAa,KAjBnB,QADC,cAAc,OAAO,KAAK,IACT,CAiBe,EAAE,cAAc,EAAE,QAAQ;AAE7E,MAAa,mBAA8B,EAE1C;;;;;;;AAQD,MAAM,wBAAwB,WAA2B;AACvD,QAAO,GAAG,OAAO,IAAI,cAAc,QAAQ,QAAQ,QAAQ;;;;;;;;AAS7D,MAAM,yBAAyB,SAAwB;AACrD,KAAI,CAAC,QAAQ,KAAK,WAAW,EAC3B,QAAO;AAGT,QAAO;;EAEP,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CAAC,KAAK,OAAO;;;;;;;AAQ7E,MAAa,uBAAuB,OAAO,EACzC,aACA,oBACA,SACA,SACA,MACA,eAGG;CAEH,MAAM,SAAS,gBAAgB,QAC7B,oBACA,IAAI,QAAQ,IAAI,qBAAqB,CAAC,KAAK,KAAK,CAAC,GAClD,CACE,QAAQ,eAAe,KAAK,UAAU,QAAQ,CAAC,CAC/C,QAAQ,0BAA0B,sBAAsB,GAAG,CAC3D,QAAQ,wBAAwB,sBAAsB,KAAK,CAAC;AAE/D,SAAQ,IAAI;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,CAAC,UAAU;AACb,SAAO,MAAM,+BAA+B;AAC5C;;CAIF,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CACR;GACE,MAAM;GACN,SAAS,CAAC,sBAAsB,YAAY,CAAC,KAAK,KAAK;GACxD,CACF;EACF,CAAC;AAEF,QAAO,KAAK,GAAG,OAAO,eAAe,EAAE,6BAA6B;AAEpE,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["auditDictionaryMetadataAI"],"sources":["../../../../../src/utils/AI/auditDictionaryMetadata/index.ts"],"sourcesContent":["import {\n type AIConfig,\n type AIOptions,\n type AuditFileResultData,\n auditDictionaryMetadata as auditDictionaryMetadataAI,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nexport type AuditOptions = {\n fileContent: string;\n tags: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type { AuditFileResultData };\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryMetadata = async (\n options: AuditOptions\n): Promise<AuditFileResultData | undefined> => {\n const result = await auditDictionaryMetadataAI(options);\n\n if (result) {\n logger.info(`${result.tokenUsed} tokens used in the request`);\n }\n\n return result;\n};\n"],"mappings":";;;;AAkBA,MAAa,mBAA8B,CAE3C;;;;;;AAOA,MAAa,0BAA0B,OACrC,YAC6C;CAC7C,MAAM,SAAS,MAAMA,0BAA0B,OAAO;CAEtD,IAAI,QACF,OAAO,KAAK,GAAG,OAAO,UAAU,4BAA4B;CAG9D,OAAO;AACT"}
1
+ {"version":3,"file":"index.mjs","names":["auditDictionaryMetadataAI"],"sources":["../../../../../src/utils/AI/auditDictionaryMetadata/index.ts"],"sourcesContent":["import {\n type AIConfig,\n type AIOptions,\n type AuditFileResultData,\n auditDictionaryMetadata as auditDictionaryMetadataAI,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nexport type AuditOptions = {\n fileContent: string;\n tags: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type { AuditFileResultData };\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryMetadata = async (\n options: AuditOptions\n): Promise<AuditFileResultData | undefined> => {\n const result = await auditDictionaryMetadataAI(options);\n\n if (result) {\n logger.info(`${result.tokenUsed} tokens used in the request`);\n }\n\n return result;\n};\n"],"mappings":";;;;AAkBA,MAAa,mBAA8B,EAE1C;;;;;;AAOD,MAAa,0BAA0B,OACrC,YAC6C;CAC7C,MAAM,SAAS,MAAMA,0BAA0B,QAAQ;AAEvD,KAAI,OACF,QAAO,KAAK,GAAG,OAAO,UAAU,6BAA6B;AAG/D,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/auditTag/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n extractJson,\n generateText,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\nimport type { Dictionary } from '@/types/dictionary.types';\nimport type { TagAPI } from '@/types/tag.types';\n\nexport type AuditOptions = {\n dictionaries: Dictionary[];\n tag: TagAPI;\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type TranslateJSONResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// The prompt template to send to AI models\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a tag by constructing a prompt for AI models.\n * The prompt includes details about the tag and related dictionaries.\n */\nexport const auditTag = async ({\n dictionaries,\n tag,\n aiConfig,\n applicationContext,\n}: AuditOptions): Promise<TranslateJSONResultData | undefined> => {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{tag.description}}',\n tag.description ?? ''\n )\n .replace('{{tag.key}}', tag.key)\n .replace('{{applicationContext}}', applicationContext ?? '');\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [\n {\n role: 'user',\n content: [\n '**Tag to audit:**',\n 'This is the tag that you should consider to audit:',\n JSON.stringify(tag),\n ].join('\\n'),\n },\n ],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: extractJson(newContent),\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;AA6BA,MAAM,kBAAkB,aAAa,KAHnB,QADC,cAAc,OAAO,KAAK,GACV,CAGe,GAAG,aAAa,GAAG,OAAO;AAE5E,MAAa,mBAA8B,CAE3C;;;;;AAMA,MAAa,WAAW,OAAO,EAC7B,cACA,KACA,UACA,yBACgE;CAEhE,MAAM,SAAS,gBAAgB,QAC7B,uBACA,IAAI,eAAe,EACrB,CAAC,CACE,QAAQ,eAAe,IAAI,GAAG,CAAC,CAC/B,QAAQ,0BAA0B,sBAAsB,EAAE;CAG7D,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CACR;GACE,MAAM;GACN,SAAS;IACP;IACA;IACA,KAAK,UAAU,GAAG;GACpB,CAAC,CAAC,KAAK,IAAI;EACb,CACF;CACF,CAAC;CAED,OAAO,KAAK,GAAG,OAAO,eAAe,EAAE,4BAA4B;CAEnE,OAAO;EACL,aAAa,YAAY,UAAU;EACnC,WAAW,OAAO,eAAe;CACnC;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/auditTag/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n extractJson,\n generateText,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\nimport type { Dictionary } from '@/types/dictionary.types';\nimport type { TagAPI } from '@/types/tag.types';\n\nexport type AuditOptions = {\n dictionaries: Dictionary[];\n tag: TagAPI;\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type TranslateJSONResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// The prompt template to send to AI models\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a tag by constructing a prompt for AI models.\n * The prompt includes details about the tag and related dictionaries.\n */\nexport const auditTag = async ({\n dictionaries,\n tag,\n aiConfig,\n applicationContext,\n}: AuditOptions): Promise<TranslateJSONResultData | undefined> => {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{tag.description}}',\n tag.description ?? ''\n )\n .replace('{{tag.key}}', tag.key)\n .replace('{{applicationContext}}', applicationContext ?? '');\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [\n {\n role: 'user',\n content: [\n '**Tag to audit:**',\n 'This is the tag that you should consider to audit:',\n JSON.stringify(tag),\n ].join('\\n'),\n },\n ],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: extractJson(newContent),\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;AA6BA,MAAM,kBAAkB,aAAa,KAHnB,QADC,cAAc,OAAO,KAAK,IACT,CAGe,EAAE,cAAc,EAAE,QAAQ;AAE7E,MAAa,mBAA8B,EAE1C;;;;;AAMD,MAAa,WAAW,OAAO,EAC7B,cACA,KACA,UACA,yBACgE;CAEhE,MAAM,SAAS,gBAAgB,QAC7B,uBACA,IAAI,eAAe,GACpB,CACE,QAAQ,eAAe,IAAI,IAAI,CAC/B,QAAQ,0BAA0B,sBAAsB,GAAG;CAG9D,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CACR;GACE,MAAM;GACN,SAAS;IACP;IACA;IACA,KAAK,UAAU,IAAI;IACpB,CAAC,KAAK,KAAK;GACb,CACF;EACF,CAAC;AAEF,QAAO,KAAK,GAAG,OAAO,eAAe,EAAE,6BAA6B;AAEpE,QAAO;EACL,aAAa,YAAY,WAAW;EACpC,WAAW,OAAO,eAAe;EAClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/autocomplete/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n AIProvider,\n generateText,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\n\nexport type AutocompleteOptions = {\n text: string;\n aiConfig: AIConfig;\n applicationContext?: string;\n contextBefore?: string;\n currentLine?: string;\n contextAfter?: string;\n};\n\nexport type AutocompleteFileResultData = {\n autocompletion: string;\n tokenUsed: number;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n temperature: 0.7,\n};\n\n/**\n * Autocompletes a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const autocomplete = async ({\n text,\n aiConfig,\n applicationContext,\n contextBefore,\n currentLine,\n contextAfter,\n}: AutocompleteOptions): Promise<AutocompleteFileResultData | undefined> => {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{applicationContext}}',\n applicationContext ?? ''\n )\n .replace('{{contextBefore}}', contextBefore ?? '')\n .replace('{{currentLine}}', currentLine ?? '')\n .replace('{{contextAfter}}', contextAfter ?? '');\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [{ role: 'assistant', content: text }],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n autocompletion: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;AA6BA,MAAM,kBAAkB,aAAa,KAHnB,QADC,cAAc,OAAO,KAAK,GACV,CAGe,GAAG,aAAa,GAAG,OAAO;AAE5E,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;CACP,aAAa;AACf;;;;;;AAOA,MAAa,eAAe,OAAO,EACjC,MACA,UACA,oBACA,eACA,aACA,mBAC0E;CAE1E,MAAM,SAAS,gBAAgB,QAC7B,0BACA,sBAAsB,EACxB,CAAC,CACE,QAAQ,qBAAqB,iBAAiB,EAAE,CAAC,CACjD,QAAQ,mBAAmB,eAAe,EAAE,CAAC,CAC7C,QAAQ,oBAAoB,gBAAgB,EAAE;CAGjD,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CAAC;GAAE,MAAM;GAAa,SAAS;EAAK,CAAC;CACjD,CAAC;CAED,OAAO,KAAK,GAAG,OAAO,eAAe,EAAE,4BAA4B;CAEnE,OAAO;EACL,gBAAgB;EAChB,WAAW,OAAO,eAAe;CACnC;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/autocomplete/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n AIProvider,\n generateText,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\n\nexport type AutocompleteOptions = {\n text: string;\n aiConfig: AIConfig;\n applicationContext?: string;\n contextBefore?: string;\n currentLine?: string;\n contextAfter?: string;\n};\n\nexport type AutocompleteFileResultData = {\n autocompletion: string;\n tokenUsed: number;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n temperature: 0.7,\n};\n\n/**\n * Autocompletes a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const autocomplete = async ({\n text,\n aiConfig,\n applicationContext,\n contextBefore,\n currentLine,\n contextAfter,\n}: AutocompleteOptions): Promise<AutocompleteFileResultData | undefined> => {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{applicationContext}}',\n applicationContext ?? ''\n )\n .replace('{{contextBefore}}', contextBefore ?? '')\n .replace('{{currentLine}}', currentLine ?? '')\n .replace('{{contextAfter}}', contextAfter ?? '');\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n system: prompt,\n messages: [{ role: 'assistant', content: text }],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n autocompletion: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;AA6BA,MAAM,kBAAkB,aAAa,KAHnB,QADC,cAAc,OAAO,KAAK,IACT,CAGe,EAAE,cAAc,EAAE,QAAQ;AAE7E,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;CACP,aAAa;CACd;;;;;;AAOD,MAAa,eAAe,OAAO,EACjC,MACA,UACA,oBACA,eACA,aACA,mBAC0E;CAE1E,MAAM,SAAS,gBAAgB,QAC7B,0BACA,sBAAsB,GACvB,CACE,QAAQ,qBAAqB,iBAAiB,GAAG,CACjD,QAAQ,mBAAmB,eAAe,GAAG,CAC7C,QAAQ,oBAAoB,gBAAgB,GAAG;CAGlD,MAAM,EAAE,MAAM,YAAY,UAAU,MAAM,aAAa;EACrD,GAAG;EACH,QAAQ;EACR,UAAU,CAAC;GAAE,MAAM;GAAa,SAAS;GAAM,CAAC;EACjD,CAAC;AAEF,QAAO,KAAK,GAAG,OAAO,eAAe,EAAE,6BAA6B;AAEpE,QAAO;EACL,gBAAgB;EAChB,WAAW,OAAO,eAAe;EAClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/chat/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n AIProvider,\n type ChatCompletionRequestMessage,\n stepCountIs,\n streamText,\n} from '@intlayer/ai';\nimport { loadMCPToolsInProcess } from './mcpInProcessTools';\n\nexport type ChatOptions = {\n onMessage?: (chunk: string) => void;\n tools?: Record<string, any>;\n};\n\nexport type ChatResultData = {\n response: string;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n};\n\n// Keep last ≤8 messages, always starting on a 'user' turn (required by Anthropic).\n// Injects a user-role note so the model knows earlier context was dropped.\nconst truncateMessages = (\n messages: ChatCompletionRequestMessage[]\n): ChatCompletionRequestMessage[] => {\n if (messages.length <= 8) return messages;\n const truncatedCount = messages.length - 7;\n let tail = messages.slice(-7);\n if (tail[0]?.role !== 'user') tail = messages.slice(-6);\n const note: ChatCompletionRequestMessage = {\n role: 'user',\n content: `[Note: ${truncatedCount} earlier message(s) were omitted to stay within the context limit.]`,\n };\n return [note, ...tail];\n};\n\nlet cachedMCPTools: Record<string, any> | undefined;\n\nconst getMCPTools = async (): Promise<Record<string, any>> => {\n if (!cachedMCPTools) {\n cachedMCPTools = await loadMCPToolsInProcess();\n }\n return cachedMCPTools;\n};\n\nexport const chat = async (\n messages: ChatCompletionRequestMessage[],\n aiConfig: AIConfig,\n options?: ChatOptions\n): Promise<ChatResultData> => {\n if (!aiConfig) {\n throw new Error('Failed to initialize AI configuration');\n }\n\n const [mcpTools] = await Promise.all([getMCPTools()]);\n\n const allTools: Record<string, any> = {\n ...mcpTools,\n ...(options?.tools ?? {}),\n };\n const hasTools = Object.keys(allTools).length > 0;\n\n let fullResponse = '';\n\n const stream = streamText({\n ...aiConfig,\n system: PROMPT,\n messages: truncateMessages(messages),\n ...(hasTools && {\n tools: allTools,\n stopWhen: stepCountIs(5),\n }),\n });\n\n for await (const chunk of stream.textStream) {\n fullResponse += chunk;\n options?.onMessage?.(chunk);\n }\n\n return { response: fullResponse || 'Error: No result found' };\n};\n"],"mappings":";;;;;;;AAyBA,MAAM,SAAS,aAAa,KAFV,QADC,cAAc,OAAO,KAAK,GACV,CAEM,GAAG,aAAa,GAAG,OAAO;AAEnE,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;AACT;AAIA,MAAM,oBACJ,aACmC;CACnC,IAAI,SAAS,UAAU,GAAG,OAAO;CACjC,MAAM,iBAAiB,SAAS,SAAS;CACzC,IAAI,OAAO,SAAS,MAAM,EAAE;CAC5B,IAAI,KAAK,EAAE,EAAE,SAAS,QAAQ,OAAO,SAAS,MAAM,EAAE;CAKtD,OAAO,CAAC;EAHN,MAAM;EACN,SAAS,UAAU,eAAe;CAEzB,GAAG,GAAG,IAAI;AACvB;AAEA,IAAI;AAEJ,MAAM,cAAc,YAA0C;CAC5D,IAAI,CAAC,gBACH,iBAAiB,MAAM,sBAAsB;CAE/C,OAAO;AACT;AAEA,MAAa,OAAO,OAClB,UACA,UACA,YAC4B;CAC5B,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,uCAAuC;CAGzD,MAAM,CAAC,YAAY,MAAM,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC;CAEpD,MAAM,WAAgC;EACpC,GAAG;EACH,GAAI,SAAS,SAAS,CAAC;CACzB;CACA,MAAM,WAAW,OAAO,KAAK,QAAQ,CAAC,CAAC,SAAS;CAEhD,IAAI,eAAe;CAEnB,MAAM,SAAS,WAAW;EACxB,GAAG;EACH,QAAQ;EACR,UAAU,iBAAiB,QAAQ;EACnC,GAAI,YAAY;GACd,OAAO;GACP,UAAU,YAAY,CAAC;EACzB;CACF,CAAC;CAED,WAAW,MAAM,SAAS,OAAO,YAAY;EAC3C,gBAAgB;EAChB,SAAS,YAAY,KAAK;CAC5B;CAEA,OAAO,EAAE,UAAU,gBAAgB,yBAAyB;AAC9D"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/utils/AI/chat/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AIConfig,\n type AIOptions,\n AIProvider,\n type ChatCompletionRequestMessage,\n stepCountIs,\n streamText,\n} from '@intlayer/ai';\nimport { loadMCPToolsInProcess } from './mcpInProcessTools';\n\nexport type ChatOptions = {\n onMessage?: (chunk: string) => void;\n tools?: Record<string, any>;\n};\n\nexport type ChatResultData = {\n response: string;\n};\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst PROMPT = readFileSync(join(__dirname, './PROMPT.md'), 'utf-8');\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n};\n\n// Keep last ≤8 messages, always starting on a 'user' turn (required by Anthropic).\n// Injects a user-role note so the model knows earlier context was dropped.\nconst truncateMessages = (\n messages: ChatCompletionRequestMessage[]\n): ChatCompletionRequestMessage[] => {\n if (messages.length <= 8) return messages;\n const truncatedCount = messages.length - 7;\n let tail = messages.slice(-7);\n if (tail[0]?.role !== 'user') tail = messages.slice(-6);\n const note: ChatCompletionRequestMessage = {\n role: 'user',\n content: `[Note: ${truncatedCount} earlier message(s) were omitted to stay within the context limit.]`,\n };\n return [note, ...tail];\n};\n\nlet cachedMCPTools: Record<string, any> | undefined;\n\nconst getMCPTools = async (): Promise<Record<string, any>> => {\n if (!cachedMCPTools) {\n cachedMCPTools = await loadMCPToolsInProcess();\n }\n return cachedMCPTools;\n};\n\nexport const chat = async (\n messages: ChatCompletionRequestMessage[],\n aiConfig: AIConfig,\n options?: ChatOptions\n): Promise<ChatResultData> => {\n if (!aiConfig) {\n throw new Error('Failed to initialize AI configuration');\n }\n\n const [mcpTools] = await Promise.all([getMCPTools()]);\n\n const allTools: Record<string, any> = {\n ...mcpTools,\n ...(options?.tools ?? {}),\n };\n const hasTools = Object.keys(allTools).length > 0;\n\n let fullResponse = '';\n\n const stream = streamText({\n ...aiConfig,\n system: PROMPT,\n messages: truncateMessages(messages),\n ...(hasTools && {\n tools: allTools,\n stopWhen: stepCountIs(5),\n }),\n });\n\n for await (const chunk of stream.textStream) {\n fullResponse += chunk;\n options?.onMessage?.(chunk);\n }\n\n return { response: fullResponse || 'Error: No result found' };\n};\n"],"mappings":";;;;;;;AAyBA,MAAM,SAAS,aAAa,KAFV,QADC,cAAc,OAAO,KAAK,IACT,CAEM,EAAE,cAAc,EAAE,QAAQ;AAEpE,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;CACR;AAID,MAAM,oBACJ,aACmC;AACnC,KAAI,SAAS,UAAU,EAAG,QAAO;CACjC,MAAM,iBAAiB,SAAS,SAAS;CACzC,IAAI,OAAO,SAAS,MAAM,GAAG;AAC7B,KAAI,KAAK,IAAI,SAAS,OAAQ,QAAO,SAAS,MAAM,GAAG;AAKvD,QAAO,CAAC;EAHN,MAAM;EACN,SAAS,UAAU,eAAe;EAExB,EAAE,GAAG,KAAK;;AAGxB,IAAI;AAEJ,MAAM,cAAc,YAA0C;AAC5D,KAAI,CAAC,eACH,kBAAiB,MAAM,uBAAuB;AAEhD,QAAO;;AAGT,MAAa,OAAO,OAClB,UACA,UACA,YAC4B;AAC5B,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,wCAAwC;CAG1D,MAAM,CAAC,YAAY,MAAM,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC;CAErD,MAAM,WAAgC;EACpC,GAAG;EACH,GAAI,SAAS,SAAS,EAAE;EACzB;CACD,MAAM,WAAW,OAAO,KAAK,SAAS,CAAC,SAAS;CAEhD,IAAI,eAAe;CAEnB,MAAM,SAAS,WAAW;EACxB,GAAG;EACH,QAAQ;EACR,UAAU,iBAAiB,SAAS;EACpC,GAAI,YAAY;GACd,OAAO;GACP,UAAU,YAAY,EAAE;GACzB;EACF,CAAC;AAEF,YAAW,MAAM,SAAS,OAAO,YAAY;AAC3C,kBAAgB;AAChB,WAAS,YAAY,MAAM;;AAG7B,QAAO,EAAE,UAAU,gBAAgB,0BAA0B"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcpInProcessTools.mjs","names":["z"],"sources":["../../../../../src/utils/AI/chat/mcpInProcessTools.ts"],"sourcesContent":["import { jsonSchema, tool } from '@intlayer/ai';\nimport { loadAPITools, loadDocsTools } from '@intlayer/mcp/tools';\nimport z from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\n\ntype ZodShape = Record<string, z.ZodTypeAny>;\n\ntype CollectedTool = {\n description: string;\n inputShape: ZodShape;\n handler: (params: any) => Promise<{\n content: { type: string; text: string }[];\n isError?: boolean;\n }>;\n};\n\nconst createToolCollector = () => {\n const collected: Record<string, CollectedTool> = {};\n\n const server = {\n registerTool(name: string, config: any, handler: CollectedTool['handler']) {\n const inputShape: ZodShape = {};\n for (const [key, value] of Object.entries(config.inputSchema ?? {})) {\n if (value instanceof z.ZodType) {\n inputShape[key] = value as z.ZodTypeAny;\n }\n }\n collected[name] = {\n description: config.description ?? config.title ?? name,\n inputShape,\n handler,\n };\n },\n };\n\n return { server, collected };\n};\n\nconst shapeToJsonSchema = (shape: ZodShape) => {\n const raw = zodToJsonSchema(z.object(shape) as any, {\n target: 'jsonSchema7',\n }) as Record<string, any>;\n return jsonSchema({ type: 'object', ...raw });\n};\n\nconst resultToString = (result: {\n content: { type: string; text: string }[];\n}) => result.content.map((c) => c.text).join('\\n');\n\nexport type LoadMCPInProcessOptions = {\n includeAPI?: boolean;\n};\n\nexport const loadMCPToolsInProcess = async (\n options?: LoadMCPInProcessOptions\n): Promise<Record<string, any>> => {\n const { server, collected } = createToolCollector();\n\n await loadDocsTools(server);\n\n if (options?.includeAPI) {\n loadAPITools(server);\n }\n\n const tools: Record<string, any> = {};\n\n for (const [name, { description, inputShape, handler }] of Object.entries(\n collected\n )) {\n tools[name] = tool({\n description,\n inputSchema:\n Object.keys(inputShape).length > 0\n ? shapeToJsonSchema(inputShape)\n : jsonSchema({ type: 'object', properties: {} }),\n execute: async (params) => resultToString(await handler(params)),\n });\n }\n\n return tools;\n};\n"],"mappings":";;;;;;AAgBA,MAAM,4BAA4B;CAChC,MAAM,YAA2C,CAAC;CAkBlD,OAAO;EAAE,UAfP,aAAa,MAAc,QAAa,SAAmC;GACzE,MAAM,aAAuB,CAAC;GAC9B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,eAAe,CAAC,CAAC,GAChE,IAAI,iBAAiBA,IAAE,SACrB,WAAW,OAAO;GAGtB,UAAU,QAAQ;IAChB,aAAa,OAAO,eAAe,OAAO,SAAS;IACnD;IACA;GACF;EACF,EAGY;EAAG;CAAU;AAC7B;AAEA,MAAM,qBAAqB,UAAoB;CAI7C,OAAO,WAAW;EAAE,MAAM;EAAU,GAHxB,gBAAgBA,IAAE,OAAO,KAAK,GAAU,EAClD,QAAQ,cACV,CACyC;CAAE,CAAC;AAC9C;AAEA,MAAM,kBAAkB,WAElB,OAAO,QAAQ,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI;AAMjD,MAAa,wBAAwB,OACnC,YACiC;CACjC,MAAM,EAAE,QAAQ,cAAc,oBAAoB;CAElD,MAAM,cAAc,MAAM;CAE1B,IAAI,SAAS,YACX,aAAa,MAAM;CAGrB,MAAM,QAA6B,CAAC;CAEpC,KAAK,MAAM,CAAC,MAAM,EAAE,aAAa,YAAY,cAAc,OAAO,QAChE,SACF,GACE,MAAM,QAAQ,KAAK;EACjB;EACA,aACE,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,IAC7B,kBAAkB,UAAU,IAC5B,WAAW;GAAE,MAAM;GAAU,YAAY,CAAC;EAAE,CAAC;EACnD,SAAS,OAAO,WAAW,eAAe,MAAM,QAAQ,MAAM,CAAC;CACjE,CAAC;CAGH,OAAO;AACT"}
1
+ {"version":3,"file":"mcpInProcessTools.mjs","names":["z"],"sources":["../../../../../src/utils/AI/chat/mcpInProcessTools.ts"],"sourcesContent":["import { jsonSchema, tool } from '@intlayer/ai';\nimport { loadAPITools, loadDocsTools } from '@intlayer/mcp/tools';\nimport z from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\n\ntype ZodShape = Record<string, z.ZodTypeAny>;\n\ntype CollectedTool = {\n description: string;\n inputShape: ZodShape;\n handler: (params: any) => Promise<{\n content: { type: string; text: string }[];\n isError?: boolean;\n }>;\n};\n\nconst createToolCollector = () => {\n const collected: Record<string, CollectedTool> = {};\n\n const server = {\n registerTool(name: string, config: any, handler: CollectedTool['handler']) {\n const inputShape: ZodShape = {};\n for (const [key, value] of Object.entries(config.inputSchema ?? {})) {\n if (value instanceof z.ZodType) {\n inputShape[key] = value as z.ZodTypeAny;\n }\n }\n collected[name] = {\n description: config.description ?? config.title ?? name,\n inputShape,\n handler,\n };\n },\n };\n\n return { server, collected };\n};\n\nconst shapeToJsonSchema = (shape: ZodShape) => {\n const raw = zodToJsonSchema(z.object(shape) as any, {\n target: 'jsonSchema7',\n }) as Record<string, any>;\n return jsonSchema({ type: 'object', ...raw });\n};\n\nconst resultToString = (result: {\n content: { type: string; text: string }[];\n}) => result.content.map((c) => c.text).join('\\n');\n\nexport type LoadMCPInProcessOptions = {\n includeAPI?: boolean;\n};\n\nexport const loadMCPToolsInProcess = async (\n options?: LoadMCPInProcessOptions\n): Promise<Record<string, any>> => {\n const { server, collected } = createToolCollector();\n\n await loadDocsTools(server);\n\n if (options?.includeAPI) {\n loadAPITools(server);\n }\n\n const tools: Record<string, any> = {};\n\n for (const [name, { description, inputShape, handler }] of Object.entries(\n collected\n )) {\n tools[name] = tool({\n description,\n inputSchema:\n Object.keys(inputShape).length > 0\n ? shapeToJsonSchema(inputShape)\n : jsonSchema({ type: 'object', properties: {} }),\n execute: async (params) => resultToString(await handler(params)),\n });\n }\n\n return tools;\n};\n"],"mappings":";;;;;;AAgBA,MAAM,4BAA4B;CAChC,MAAM,YAA2C,EAAE;AAkBnD,QAAO;EAAE,UAfP,aAAa,MAAc,QAAa,SAAmC;GACzE,MAAM,aAAuB,EAAE;AAC/B,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,eAAe,EAAE,CAAC,CACjE,KAAI,iBAAiBA,IAAE,QACrB,YAAW,OAAO;AAGtB,aAAU,QAAQ;IAChB,aAAa,OAAO,eAAe,OAAO,SAAS;IACnD;IACA;IACD;KAIU;EAAE;EAAW;;AAG9B,MAAM,qBAAqB,UAAoB;AAI7C,QAAO,WAAW;EAAE,MAAM;EAAU,GAHxB,gBAAgBA,IAAE,OAAO,MAAM,EAAS,EAClD,QAAQ,eACT,CACyC;EAAE,CAAC;;AAG/C,MAAM,kBAAkB,WAElB,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK;AAMlD,MAAa,wBAAwB,OACnC,YACiC;CACjC,MAAM,EAAE,QAAQ,cAAc,qBAAqB;AAEnD,OAAM,cAAc,OAAO;AAE3B,KAAI,SAAS,WACX,cAAa,OAAO;CAGtB,MAAM,QAA6B,EAAE;AAErC,MAAK,MAAM,CAAC,MAAM,EAAE,aAAa,YAAY,cAAc,OAAO,QAChE,UACD,CACC,OAAM,QAAQ,KAAK;EACjB;EACA,aACE,OAAO,KAAK,WAAW,CAAC,SAAS,IAC7B,kBAAkB,WAAW,GAC7B,WAAW;GAAE,MAAM;GAAU,YAAY,EAAE;GAAE,CAAC;EACpD,SAAS,OAAO,WAAW,eAAe,MAAM,QAAQ,OAAO,CAAC;EACjE,CAAC;AAGJ,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"sessionTools.mjs","names":["dictionaryService.findDictionaries","dictionaryService.countDictionaries","dictionaryService.getDictionaryByKey","dictionaryService.createDictionary","dictionaryService.updateDictionaryByKey","dictionaryService.deleteDictionaryById","projectService.getProjectById","projectService.findProjects","projectService.updateProjectById","organizationService.findOrganizations","organizationService.countOrganizations","organizationService.getOrganizationById","organizationService.updateOrganizationById","tagService.findTags","tagService.countTags","tagService.getTagsByKeys","tagService.createTag","tagService.updateTagById","tagService.deleteTagById","userService.getUserById","userService.updateUserById"],"sources":["../../../../../src/utils/AI/chat/sessionTools.ts"],"sourcesContent":["import { jsonSchema, tool } from '@intlayer/ai';\nimport * as dictionaryService from '@services/dictionary.service';\nimport * as organizationService from '@services/organization.service';\nimport * as projectService from '@services/project.service';\nimport * as tagService from '@services/tag.service';\nimport * as userService from '@services/user.service';\nimport { hasPermission, type Roles } from '@utils/permissions';\nimport { Types } from 'mongoose';\n\nexport type ClientAction =\n | { type: 'navigate'; path: string }\n | { type: 'invalidate_queries' }\n | { type: 'select_organization'; organizationId: string }\n | { type: 'unselect_organization' }\n | { type: 'select_project'; projectId: string }\n | { type: 'unselect_project' };\n\ntype SessionContext = {\n projectId?: string;\n organizationId?: string;\n userId?: string;\n roles?: Roles[];\n session?: any;\n onAction?: (action: ClientAction) => void;\n};\n\nconst paginationSchema = jsonSchema<{ page?: number; pageSize?: number }>({\n type: 'object',\n properties: {\n page: { type: 'number', description: 'Page number (1-based)' },\n pageSize: { type: 'number', description: 'Items per page (default 20)' },\n },\n});\n\nexport const createSessionTools = ({\n projectId,\n organizationId,\n userId,\n onAction,\n roles,\n session,\n}: SessionContext) => ({\n // ---- DICTIONARY READ TOOLS ----\n\n list_dictionaries: tool({\n description:\n 'List all dictionaries in the current project. Returns keys, IDs, titles, and metadata.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n const skip = (page - 1) * pageSize;\n const [dictionaries, total] = await Promise.all([\n dictionaryService.findDictionaries(\n { projectIds: [projectId] } as any,\n skip,\n pageSize,\n undefined,\n false\n ),\n dictionaryService.countDictionaries({ projectIds: [projectId] } as any),\n ]);\n\n return JSON.stringify({\n data: dictionaries.map((dictionary) => ({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n })),\n total,\n page,\n pageSize,\n });\n },\n }),\n\n get_dictionary: tool({\n description: 'Get a dictionary by its key, including its full content.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The dictionary key' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n params.key,\n projectId\n );\n\n if (!dictionary)\n return JSON.stringify({\n error: `Dictionary \"${params.key}\" not found`,\n });\n\n return JSON.stringify({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n content: dictionary.content,\n });\n } catch {\n return JSON.stringify({\n error: `Dictionary \"${params.key}\" not found`,\n });\n }\n },\n }),\n\n // ---- DICTIONARY WRITE TOOLS ----\n\n create_dictionary: tool({\n description: 'Create a new dictionary in the current project.',\n inputSchema: jsonSchema<{\n key: string;\n title?: string;\n description?: string;\n content?: Record<string, unknown>;\n }>({\n type: 'object',\n properties: {\n key: {\n type: 'string',\n description: 'Unique key identifying this dictionary',\n },\n title: { type: 'string', description: 'Human-readable title' },\n description: {\n type: 'string',\n description: 'Purpose of the dictionary',\n },\n content: {\n type: 'object',\n description: 'Initial content of the dictionary',\n },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n if (!userId)\n return JSON.stringify({ error: 'No user authenticated in session' });\n\n if (!hasPermission(roles || [], 'dictionary:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const dictionary = await dictionaryService.createDictionary({\n key: params.key,\n projectIds: [new Types.ObjectId(projectId)],\n title: params.title,\n description: params.description,\n content: params.content as any,\n creatorId: new Types.ObjectId(userId),\n });\n\n return JSON.stringify({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_dictionary: tool({\n description: 'Update an existing dictionary by its key.',\n inputSchema: jsonSchema<{\n key: string;\n title?: string;\n description?: string;\n content?: Record<string, unknown>;\n tags?: string[];\n }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The dictionary key to update' },\n title: { type: 'string', description: 'New title' },\n description: { type: 'string', description: 'New description' },\n content: { type: 'object', description: 'New content object' },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Tag IDs to associate with this dictionary',\n },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const { key, ...updates } = params;\n const dictionary = await dictionaryService.updateDictionaryByKey(\n key,\n updates as any,\n projectId\n );\n\n return JSON.stringify({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n delete_dictionary: tool({\n description: 'Delete a dictionary by its key.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The dictionary key to delete' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:admin')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n params.key,\n projectId\n );\n\n if (!dictionary)\n return JSON.stringify({\n error: `Dictionary \"${params.key}\" not found`,\n });\n\n await dictionaryService.deleteDictionaryById(String(dictionary.id));\n return JSON.stringify({ success: true, key: params.key });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- PROJECT TOOLS ----\n\n get_project: tool({\n description: 'Get details of the current project.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'project:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const project = await projectService.getProjectById(projectId);\n return JSON.stringify({\n id: project.id,\n name: project.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n list_projects: tool({\n description: 'List all projects in the current organization.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'project:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n const skip = (page - 1) * pageSize;\n const projects = await projectService.findProjects(\n { organizationId } as any,\n skip,\n pageSize\n );\n\n return JSON.stringify({\n data: projects.map((project) => ({\n id: project.id,\n name: project.name,\n })),\n page,\n pageSize,\n });\n },\n }),\n\n update_project: tool({\n description: 'Update the current project.',\n inputSchema: jsonSchema<{ name?: string }>({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'New project name' },\n },\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'project:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const project = await projectService.updateProjectById(\n projectId,\n params as any\n );\n return JSON.stringify({ id: project.id, name: project.name });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n select_project: tool({\n description:\n 'Select a project by ID to set it as the active project for the session. Subsequent tools will operate on this project.',\n inputSchema: jsonSchema<{ projectId: string }>({\n type: 'object',\n properties: {\n projectId: { type: 'string', description: 'The project ID to select' },\n },\n required: ['projectId'],\n }),\n execute: async (params): Promise<string> => {\n try {\n const project = await projectService.getProjectById(params.projectId);\n\n if (\n !hasPermission(\n roles || [],\n 'project:read'\n )({\n ...session,\n targetProjects: [project],\n })\n ) {\n return JSON.stringify({ error: 'Permission denied' });\n }\n\n onAction?.({ type: 'select_project', projectId: params.projectId });\n return JSON.stringify({ success: true, projectId: params.projectId });\n } catch {\n return JSON.stringify({\n error: `Project \"${params.projectId}\" not found or access denied`,\n });\n }\n },\n }),\n\n unselect_project: tool({\n description: 'Clear the active project from the session.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n onAction?.({ type: 'unselect_project' });\n return JSON.stringify({ success: true });\n },\n }),\n\n // ---- ORGANIZATION TOOLS ----\n\n list_organizations: tool({\n description: 'List all organizations the current user is a member of.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!userId)\n return JSON.stringify({ error: 'No user authenticated in session' });\n\n const skip = (page - 1) * pageSize;\n const [organizations, total] = await Promise.all([\n organizationService.findOrganizations(\n { membersIds: { $in: [userId] } } as any,\n skip,\n pageSize\n ),\n organizationService.countOrganizations({\n membersIds: { $in: [userId] },\n } as any),\n ]);\n\n return JSON.stringify({\n data: organizations.map((org) => ({\n id: org.id,\n name: org.name,\n })),\n total,\n page,\n pageSize,\n });\n },\n }),\n\n select_organization: tool({\n description:\n 'Select an organization by ID to set it as the active organization for the session. Subsequent tools will operate on this organization.',\n inputSchema: jsonSchema<{ organizationId: string }>({\n type: 'object',\n properties: {\n organizationId: {\n type: 'string',\n description: 'The organization ID to select',\n },\n },\n required: ['organizationId'],\n }),\n execute: async (params): Promise<string> => {\n try {\n const organization = await organizationService.getOrganizationById(\n params.organizationId\n );\n\n if (\n !hasPermission(\n roles || [],\n 'organization:read'\n )({\n ...session,\n targetOrganizations: [organization],\n })\n ) {\n return JSON.stringify({ error: 'Permission denied' });\n }\n\n onAction?.({\n type: 'select_organization',\n organizationId: params.organizationId,\n });\n return JSON.stringify({\n success: true,\n organizationId: params.organizationId,\n });\n } catch {\n return JSON.stringify({\n error: `Organization \"${params.organizationId}\" not found or access denied`,\n });\n }\n },\n }),\n\n unselect_organization: tool({\n description: 'Clear the active organization from the session.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n onAction?.({ type: 'unselect_organization' });\n return JSON.stringify({ success: true });\n },\n }),\n\n get_organization: tool({\n description: 'Get details of the current organization.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'organization:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n return JSON.stringify({\n id: organization.id,\n name: organization.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_organization: tool({\n description: 'Update the current organization.',\n inputSchema: jsonSchema<{ name?: string }>({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'New organization name' },\n },\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'organization:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const organization = await organizationService.updateOrganizationById(\n organizationId,\n params as any\n );\n return JSON.stringify({ id: organization.id, name: organization.name });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- TAG TOOLS ----\n\n list_tags: tool({\n description:\n 'List all tags in the current organization. Tags group dictionaries and provide AI context.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n const skip = (page - 1) * pageSize;\n const [tags, total] = await Promise.all([\n tagService.findTags({ organizationId } as any, skip, pageSize),\n tagService.countTags({ organizationId } as any),\n ]);\n\n return JSON.stringify({\n data: tags.map((tag) => ({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n })),\n total,\n page,\n pageSize,\n });\n },\n }),\n\n get_tag: tool({\n description: 'Get a tag by its key.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The tag key' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tags = await tagService.getTagsByKeys(\n [params.key],\n organizationId\n );\n\n if (!tags || tags.length === 0)\n return JSON.stringify({ error: `Tag \"${params.key}\" not found` });\n\n const tag = tags[0];\n return JSON.stringify({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n create_tag: tool({\n description: 'Create a new tag in the current organization.',\n inputSchema: jsonSchema<{\n key: string;\n name?: string;\n description?: string;\n instructions?: string;\n }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'Unique key for the tag' },\n name: { type: 'string', description: 'Display name of the tag' },\n description: {\n type: 'string',\n description: 'What this tag represents',\n },\n instructions: {\n type: 'string',\n description: 'AI instructions associated with this tag',\n },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n if (!userId)\n return JSON.stringify({ error: 'No user authenticated in session' });\n\n if (!hasPermission(roles || [], 'tag:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tag = await tagService.createTag({\n key: params.key,\n name: params.name,\n description: params.description,\n instructions: params.instructions,\n organizationId: new Types.ObjectId(organizationId),\n projectId: new Types.ObjectId(projectId),\n creatorId: new Types.ObjectId(userId),\n });\n\n return JSON.stringify({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_tag: tool({\n description: 'Update a tag by its key.',\n inputSchema: jsonSchema<{\n key: string;\n name?: string;\n description?: string;\n instructions?: string;\n }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The tag key to update' },\n name: { type: 'string', description: 'New display name' },\n description: { type: 'string', description: 'New description' },\n instructions: { type: 'string', description: 'New AI instructions' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tags = await tagService.getTagsByKeys(\n [params.key],\n organizationId\n );\n\n if (!tags || tags.length === 0)\n return JSON.stringify({ error: `Tag \"${params.key}\" not found` });\n\n const { key: _key, ...updates } = params;\n const tag = await tagService.updateTagById(\n String(tags[0].id),\n updates as any\n );\n\n return JSON.stringify({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n delete_tag: tool({\n description: 'Delete a tag by its key.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The tag key to delete' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:admin')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tags = await tagService.getTagsByKeys(\n [params.key],\n organizationId\n );\n\n if (!tags || tags.length === 0)\n return JSON.stringify({ error: `Tag \"${params.key}\" not found` });\n\n await tagService.deleteTagById(String(tags[0].id));\n return JSON.stringify({ success: true, key: params.key });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- USER TOOLS ----\n\n get_user: tool({\n description: 'Get the current user profile.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n if (!userId) return JSON.stringify({ error: 'No user in session' });\n\n if (!hasPermission(roles || [], 'user:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const user = await userService.getUserById(userId);\n if (!user) return JSON.stringify({ error: 'User not found' });\n\n return JSON.stringify({\n id: user.id,\n email: user.email,\n name: user.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_user: tool({\n description: 'Update the current user profile.',\n inputSchema: jsonSchema<{ name?: string }>({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'New display name' },\n },\n }),\n execute: async (params): Promise<string> => {\n if (!userId) return JSON.stringify({ error: 'No user in session' });\n\n if (!hasPermission(roles || [], 'user:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const user = await userService.updateUserById(userId, params as any);\n return JSON.stringify({\n id: user.id,\n email: user.email,\n name: user.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- CLIENT NAVIGATION & DATA ACTIONS ----\n\n navigate_to: tool({\n description:\n 'Navigate the user to a specific dashboard page. Use this after creating or updating a resource to bring the user to the relevant page (e.g. after creating a dictionary, navigate to /dictionaries/{key}).',\n inputSchema: jsonSchema<{ path: string }>({\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description:\n 'The dashboard path to navigate to, e.g. /dictionaries/my-key, /tags/my-tag, /projects, /organizations',\n },\n },\n required: ['path'],\n }),\n execute: async (params): Promise<string> => {\n onAction?.({ type: 'navigate', path: params.path });\n return JSON.stringify({ success: true, path: params.path });\n },\n }),\n\n invalidate_queries: tool({\n description:\n 'Invalidate cached data in the dashboard so the UI refetches fresh data from the server. Call this after any write operation (create, update, delete) so the user sees up-to-date information.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n onAction?.({ type: 'invalidate_queries' });\n return JSON.stringify({ success: true });\n },\n }),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"sessionTools.mjs","names":["dictionaryService.findDictionaries","dictionaryService.countDictionaries","dictionaryService.getDictionaryByKey","dictionaryService.createDictionary","dictionaryService.updateDictionaryByKey","dictionaryService.deleteDictionaryById","projectService.getProjectById","projectService.findProjects","projectService.updateProjectById","organizationService.findOrganizations","organizationService.countOrganizations","organizationService.getOrganizationById","organizationService.updateOrganizationById","tagService.findTags","tagService.countTags","tagService.getTagsByKeys","tagService.createTag","tagService.updateTagById","tagService.deleteTagById","userService.getUserById","userService.updateUserById"],"sources":["../../../../../src/utils/AI/chat/sessionTools.ts"],"sourcesContent":["import { jsonSchema, tool } from '@intlayer/ai';\nimport * as dictionaryService from '@services/dictionary.service';\nimport * as organizationService from '@services/organization.service';\nimport * as projectService from '@services/project.service';\nimport * as tagService from '@services/tag.service';\nimport * as userService from '@services/user.service';\nimport { hasPermission, type Roles } from '@utils/permissions';\nimport { Types } from 'mongoose';\n\nexport type ClientAction =\n | { type: 'navigate'; path: string }\n | { type: 'invalidate_queries' }\n | { type: 'select_organization'; organizationId: string }\n | { type: 'unselect_organization' }\n | { type: 'select_project'; projectId: string }\n | { type: 'unselect_project' };\n\ntype SessionContext = {\n projectId?: string;\n organizationId?: string;\n userId?: string;\n roles?: Roles[];\n session?: any;\n onAction?: (action: ClientAction) => void;\n};\n\nconst paginationSchema = jsonSchema<{ page?: number; pageSize?: number }>({\n type: 'object',\n properties: {\n page: { type: 'number', description: 'Page number (1-based)' },\n pageSize: { type: 'number', description: 'Items per page (default 20)' },\n },\n});\n\nexport const createSessionTools = ({\n projectId,\n organizationId,\n userId,\n onAction,\n roles,\n session,\n}: SessionContext) => ({\n // ---- DICTIONARY READ TOOLS ----\n\n list_dictionaries: tool({\n description:\n 'List all dictionaries in the current project. Returns keys, IDs, titles, and metadata.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n const skip = (page - 1) * pageSize;\n const [dictionaries, total] = await Promise.all([\n dictionaryService.findDictionaries(\n { projectIds: [projectId] } as any,\n skip,\n pageSize,\n undefined,\n false\n ),\n dictionaryService.countDictionaries({ projectIds: [projectId] } as any),\n ]);\n\n return JSON.stringify({\n data: dictionaries.map((dictionary) => ({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n })),\n total,\n page,\n pageSize,\n });\n },\n }),\n\n get_dictionary: tool({\n description: 'Get a dictionary by its key, including its full content.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The dictionary key' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n params.key,\n projectId\n );\n\n if (!dictionary)\n return JSON.stringify({\n error: `Dictionary \"${params.key}\" not found`,\n });\n\n return JSON.stringify({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n content: dictionary.content,\n });\n } catch {\n return JSON.stringify({\n error: `Dictionary \"${params.key}\" not found`,\n });\n }\n },\n }),\n\n // ---- DICTIONARY WRITE TOOLS ----\n\n create_dictionary: tool({\n description: 'Create a new dictionary in the current project.',\n inputSchema: jsonSchema<{\n key: string;\n title?: string;\n description?: string;\n content?: Record<string, unknown>;\n }>({\n type: 'object',\n properties: {\n key: {\n type: 'string',\n description: 'Unique key identifying this dictionary',\n },\n title: { type: 'string', description: 'Human-readable title' },\n description: {\n type: 'string',\n description: 'Purpose of the dictionary',\n },\n content: {\n type: 'object',\n description: 'Initial content of the dictionary',\n },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n if (!userId)\n return JSON.stringify({ error: 'No user authenticated in session' });\n\n if (!hasPermission(roles || [], 'dictionary:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const dictionary = await dictionaryService.createDictionary({\n key: params.key,\n projectIds: [new Types.ObjectId(projectId)],\n title: params.title,\n description: params.description,\n content: params.content as any,\n creatorId: new Types.ObjectId(userId),\n });\n\n return JSON.stringify({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_dictionary: tool({\n description: 'Update an existing dictionary by its key.',\n inputSchema: jsonSchema<{\n key: string;\n title?: string;\n description?: string;\n content?: Record<string, unknown>;\n tags?: string[];\n }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The dictionary key to update' },\n title: { type: 'string', description: 'New title' },\n description: { type: 'string', description: 'New description' },\n content: { type: 'object', description: 'New content object' },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Tag IDs to associate with this dictionary',\n },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const { key, ...updates } = params;\n const dictionary = await dictionaryService.updateDictionaryByKey(\n key,\n updates as any,\n projectId\n );\n\n return JSON.stringify({\n id: dictionary.id,\n key: dictionary.key,\n title: dictionary.title,\n description: dictionary.description,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n delete_dictionary: tool({\n description: 'Delete a dictionary by its key.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The dictionary key to delete' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'dictionary:admin')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n params.key,\n projectId\n );\n\n if (!dictionary)\n return JSON.stringify({\n error: `Dictionary \"${params.key}\" not found`,\n });\n\n await dictionaryService.deleteDictionaryById(String(dictionary.id));\n return JSON.stringify({ success: true, key: params.key });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- PROJECT TOOLS ----\n\n get_project: tool({\n description: 'Get details of the current project.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'project:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const project = await projectService.getProjectById(projectId);\n return JSON.stringify({\n id: project.id,\n name: project.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n list_projects: tool({\n description: 'List all projects in the current organization.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'project:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n const skip = (page - 1) * pageSize;\n const projects = await projectService.findProjects(\n { organizationId } as any,\n skip,\n pageSize\n );\n\n return JSON.stringify({\n data: projects.map((project) => ({\n id: project.id,\n name: project.name,\n })),\n page,\n pageSize,\n });\n },\n }),\n\n update_project: tool({\n description: 'Update the current project.',\n inputSchema: jsonSchema<{ name?: string }>({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'New project name' },\n },\n }),\n execute: async (params): Promise<string> => {\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n\n if (!hasPermission(roles || [], 'project:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const project = await projectService.updateProjectById(\n projectId,\n params as any\n );\n return JSON.stringify({ id: project.id, name: project.name });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n select_project: tool({\n description:\n 'Select a project by ID to set it as the active project for the session. Subsequent tools will operate on this project.',\n inputSchema: jsonSchema<{ projectId: string }>({\n type: 'object',\n properties: {\n projectId: { type: 'string', description: 'The project ID to select' },\n },\n required: ['projectId'],\n }),\n execute: async (params): Promise<string> => {\n try {\n const project = await projectService.getProjectById(params.projectId);\n\n if (\n !hasPermission(\n roles || [],\n 'project:read'\n )({\n ...session,\n targetProjects: [project],\n })\n ) {\n return JSON.stringify({ error: 'Permission denied' });\n }\n\n onAction?.({ type: 'select_project', projectId: params.projectId });\n return JSON.stringify({ success: true, projectId: params.projectId });\n } catch {\n return JSON.stringify({\n error: `Project \"${params.projectId}\" not found or access denied`,\n });\n }\n },\n }),\n\n unselect_project: tool({\n description: 'Clear the active project from the session.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n onAction?.({ type: 'unselect_project' });\n return JSON.stringify({ success: true });\n },\n }),\n\n // ---- ORGANIZATION TOOLS ----\n\n list_organizations: tool({\n description: 'List all organizations the current user is a member of.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!userId)\n return JSON.stringify({ error: 'No user authenticated in session' });\n\n const skip = (page - 1) * pageSize;\n const [organizations, total] = await Promise.all([\n organizationService.findOrganizations(\n { membersIds: { $in: [userId] } } as any,\n skip,\n pageSize\n ),\n organizationService.countOrganizations({\n membersIds: { $in: [userId] },\n } as any),\n ]);\n\n return JSON.stringify({\n data: organizations.map((org) => ({\n id: org.id,\n name: org.name,\n })),\n total,\n page,\n pageSize,\n });\n },\n }),\n\n select_organization: tool({\n description:\n 'Select an organization by ID to set it as the active organization for the session. Subsequent tools will operate on this organization.',\n inputSchema: jsonSchema<{ organizationId: string }>({\n type: 'object',\n properties: {\n organizationId: {\n type: 'string',\n description: 'The organization ID to select',\n },\n },\n required: ['organizationId'],\n }),\n execute: async (params): Promise<string> => {\n try {\n const organization = await organizationService.getOrganizationById(\n params.organizationId\n );\n\n if (\n !hasPermission(\n roles || [],\n 'organization:read'\n )({\n ...session,\n targetOrganizations: [organization],\n })\n ) {\n return JSON.stringify({ error: 'Permission denied' });\n }\n\n onAction?.({\n type: 'select_organization',\n organizationId: params.organizationId,\n });\n return JSON.stringify({\n success: true,\n organizationId: params.organizationId,\n });\n } catch {\n return JSON.stringify({\n error: `Organization \"${params.organizationId}\" not found or access denied`,\n });\n }\n },\n }),\n\n unselect_organization: tool({\n description: 'Clear the active organization from the session.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n onAction?.({ type: 'unselect_organization' });\n return JSON.stringify({ success: true });\n },\n }),\n\n get_organization: tool({\n description: 'Get details of the current organization.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'organization:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n return JSON.stringify({\n id: organization.id,\n name: organization.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_organization: tool({\n description: 'Update the current organization.',\n inputSchema: jsonSchema<{ name?: string }>({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'New organization name' },\n },\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'organization:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const organization = await organizationService.updateOrganizationById(\n organizationId,\n params as any\n );\n return JSON.stringify({ id: organization.id, name: organization.name });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- TAG TOOLS ----\n\n list_tags: tool({\n description:\n 'List all tags in the current organization. Tags group dictionaries and provide AI context.',\n inputSchema: paginationSchema,\n execute: async (params): Promise<string> => {\n const page = params.page ?? 1;\n const pageSize = params.pageSize ?? 20;\n\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n const skip = (page - 1) * pageSize;\n const [tags, total] = await Promise.all([\n tagService.findTags({ organizationId } as any, skip, pageSize),\n tagService.countTags({ organizationId } as any),\n ]);\n\n return JSON.stringify({\n data: tags.map((tag) => ({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n })),\n total,\n page,\n pageSize,\n });\n },\n }),\n\n get_tag: tool({\n description: 'Get a tag by its key.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The tag key' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tags = await tagService.getTagsByKeys(\n [params.key],\n organizationId\n );\n\n if (!tags || tags.length === 0)\n return JSON.stringify({ error: `Tag \"${params.key}\" not found` });\n\n const tag = tags[0];\n return JSON.stringify({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n create_tag: tool({\n description: 'Create a new tag in the current organization.',\n inputSchema: jsonSchema<{\n key: string;\n name?: string;\n description?: string;\n instructions?: string;\n }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'Unique key for the tag' },\n name: { type: 'string', description: 'Display name of the tag' },\n description: {\n type: 'string',\n description: 'What this tag represents',\n },\n instructions: {\n type: 'string',\n description: 'AI instructions associated with this tag',\n },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n if (!projectId)\n return JSON.stringify({ error: 'No project selected in session' });\n if (!userId)\n return JSON.stringify({ error: 'No user authenticated in session' });\n\n if (!hasPermission(roles || [], 'tag:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tag = await tagService.createTag({\n key: params.key,\n name: params.name,\n description: params.description,\n instructions: params.instructions,\n organizationId: new Types.ObjectId(organizationId),\n projectId: new Types.ObjectId(projectId),\n creatorId: new Types.ObjectId(userId),\n });\n\n return JSON.stringify({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_tag: tool({\n description: 'Update a tag by its key.',\n inputSchema: jsonSchema<{\n key: string;\n name?: string;\n description?: string;\n instructions?: string;\n }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The tag key to update' },\n name: { type: 'string', description: 'New display name' },\n description: { type: 'string', description: 'New description' },\n instructions: { type: 'string', description: 'New AI instructions' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tags = await tagService.getTagsByKeys(\n [params.key],\n organizationId\n );\n\n if (!tags || tags.length === 0)\n return JSON.stringify({ error: `Tag \"${params.key}\" not found` });\n\n const { key: _key, ...updates } = params;\n const tag = await tagService.updateTagById(\n String(tags[0].id),\n updates as any\n );\n\n return JSON.stringify({\n id: tag.id,\n key: tag.key,\n name: tag.name,\n description: tag.description,\n instructions: tag.instructions,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n delete_tag: tool({\n description: 'Delete a tag by its key.',\n inputSchema: jsonSchema<{ key: string }>({\n type: 'object',\n properties: {\n key: { type: 'string', description: 'The tag key to delete' },\n },\n required: ['key'],\n }),\n execute: async (params): Promise<string> => {\n if (!organizationId)\n return JSON.stringify({ error: 'No organization selected in session' });\n\n if (!hasPermission(roles || [], 'tag:admin')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const tags = await tagService.getTagsByKeys(\n [params.key],\n organizationId\n );\n\n if (!tags || tags.length === 0)\n return JSON.stringify({ error: `Tag \"${params.key}\" not found` });\n\n await tagService.deleteTagById(String(tags[0].id));\n return JSON.stringify({ success: true, key: params.key });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- USER TOOLS ----\n\n get_user: tool({\n description: 'Get the current user profile.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n if (!userId) return JSON.stringify({ error: 'No user in session' });\n\n if (!hasPermission(roles || [], 'user:read')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const user = await userService.getUserById(userId);\n if (!user) return JSON.stringify({ error: 'User not found' });\n\n return JSON.stringify({\n id: user.id,\n email: user.email,\n name: user.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n update_user: tool({\n description: 'Update the current user profile.',\n inputSchema: jsonSchema<{ name?: string }>({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'New display name' },\n },\n }),\n execute: async (params): Promise<string> => {\n if (!userId) return JSON.stringify({ error: 'No user in session' });\n\n if (!hasPermission(roles || [], 'user:write')(session))\n return JSON.stringify({ error: 'Permission denied' });\n\n try {\n const user = await userService.updateUserById(userId, params as any);\n return JSON.stringify({\n id: user.id,\n email: user.email,\n name: user.name,\n });\n } catch (err) {\n return JSON.stringify({ error: String(err) });\n }\n },\n }),\n\n // ---- CLIENT NAVIGATION & DATA ACTIONS ----\n\n navigate_to: tool({\n description:\n 'Navigate the user to a specific dashboard page. Use this after creating or updating a resource to bring the user to the relevant page (e.g. after creating a dictionary, navigate to /dictionaries/{key}).',\n inputSchema: jsonSchema<{ path: string }>({\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description:\n 'The dashboard path to navigate to, e.g. /dictionaries/my-key, /tags/my-tag, /projects, /organizations',\n },\n },\n required: ['path'],\n }),\n execute: async (params): Promise<string> => {\n onAction?.({ type: 'navigate', path: params.path });\n return JSON.stringify({ success: true, path: params.path });\n },\n }),\n\n invalidate_queries: tool({\n description:\n 'Invalidate cached data in the dashboard so the UI refetches fresh data from the server. Call this after any write operation (create, update, delete) so the user sees up-to-date information.',\n inputSchema: jsonSchema<Record<string, never>>({\n type: 'object',\n properties: {},\n }),\n execute: async (_params): Promise<string> => {\n onAction?.({ type: 'invalidate_queries' });\n return JSON.stringify({ success: true });\n },\n }),\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["customQueryAI"],"sources":["../../../../../src/utils/AI/customQuery/index.ts"],"sourcesContent":["import {\n type AIConfig,\n type AIOptions,\n type CustomQueryResultData,\n customQuery as customQueryAI,\n type Messages,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\n\nexport type CustomQueryOptions = {\n messages: Messages;\n aiConfig: AIConfig;\n};\n\nexport type { CustomQueryResultData };\n\nexport const aiDefaultOptions: AIOptions = {\n model: 'gpt-4o-mini',\n // Keep default options\n};\n\n/**\n * CustomQuerys a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const customQuery = async (\n options: CustomQueryOptions\n): Promise<CustomQueryResultData | undefined> => {\n const result = await customQueryAI(options);\n\n if (result) {\n logger.info(`${result.tokenUsed} tokens used in the request`);\n }\n\n return result;\n};\n"],"mappings":";;;;AAgBA,MAAa,mBAA8B,EACzC,OAAO,cAET;;;;;;AAOA,MAAa,cAAc,OACzB,YAC+C;CAC/C,MAAM,SAAS,MAAMA,cAAc,OAAO;CAE1C,IAAI,QACF,OAAO,KAAK,GAAG,OAAO,UAAU,4BAA4B;CAG9D,OAAO;AACT"}
1
+ {"version":3,"file":"index.mjs","names":["customQueryAI"],"sources":["../../../../../src/utils/AI/customQuery/index.ts"],"sourcesContent":["import {\n type AIConfig,\n type AIOptions,\n type CustomQueryResultData,\n customQuery as customQueryAI,\n type Messages,\n} from '@intlayer/ai';\nimport { logger } from '@logger';\n\nexport type CustomQueryOptions = {\n messages: Messages;\n aiConfig: AIConfig;\n};\n\nexport type { CustomQueryResultData };\n\nexport const aiDefaultOptions: AIOptions = {\n model: 'gpt-4o-mini',\n // Keep default options\n};\n\n/**\n * CustomQuerys a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const customQuery = async (\n options: CustomQueryOptions\n): Promise<CustomQueryResultData | undefined> => {\n const result = await customQueryAI(options);\n\n if (result) {\n logger.info(`${result.tokenUsed} tokens used in the request`);\n }\n\n return result;\n};\n"],"mappings":";;;;AAgBA,MAAa,mBAA8B,EACzC,OAAO,eAER;;;;;;AAOD,MAAa,cAAc,OACzB,YAC+C;CAC/C,MAAM,SAAS,MAAMA,cAAc,QAAQ;AAE3C,KAAI,OACF,QAAO,KAAK,GAAG,OAAO,UAAU,6BAA6B;AAG/D,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"getProjectAIOptions.mjs","names":[],"sources":["../../../../src/utils/AI/getProjectAIOptions.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/ai';\nimport { getProjectById } from '@services/project.service';\nimport type { Project, ProjectAPI } from '@/types/project.types';\n\n/**\n * Returns the project's AI options with the real (unmasked) API key.\n *\n * The session project has its API key masked for security. This function\n * detects a masked key and re-fetches the project from the DB to recover\n * the real key for use in server-side AI calls.\n */\nexport const getProjectAIOptions = async (\n project: Project | ProjectAPI | null | undefined\n): Promise<AIOptions | undefined> => {\n if (!project?.configuration?.ai) return undefined;\n\n const sessionOptions = project.configuration.ai as AIOptions;\n\n if (!sessionOptions.apiKey?.includes('*')) {\n return sessionOptions;\n }\n\n const realProject = await getProjectById(String(project.id));\n return (\n (realProject?.configuration?.ai as AIOptions | undefined) ?? sessionOptions\n );\n};\n"],"mappings":";;;;;;;;;;AAWA,MAAa,sBAAsB,OACjC,YACmC;CACnC,IAAI,CAAC,SAAS,eAAe,IAAI,OAAO;CAExC,MAAM,iBAAiB,QAAQ,cAAc;CAE7C,IAAI,CAAC,eAAe,QAAQ,SAAS,GAAG,GACtC,OAAO;CAIT,QACG,MAFuB,eAAe,OAAO,QAAQ,EAAE,CAAC,EAE7C,EAAE,eAAe,MAAgC;AAEjE"}
1
+ {"version":3,"file":"getProjectAIOptions.mjs","names":[],"sources":["../../../../src/utils/AI/getProjectAIOptions.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/ai';\nimport { getProjectById } from '@services/project.service';\nimport type { Project, ProjectAPI } from '@/types/project.types';\n\n/**\n * Returns the project's AI options with the real (unmasked) API key.\n *\n * The session project has its API key masked for security. This function\n * detects a masked key and re-fetches the project from the DB to recover\n * the real key for use in server-side AI calls.\n */\nexport const getProjectAIOptions = async (\n project: Project | ProjectAPI | null | undefined\n): Promise<AIOptions | undefined> => {\n if (!project?.configuration?.ai) return undefined;\n\n const sessionOptions = project.configuration.ai as AIOptions;\n\n if (!sessionOptions.apiKey?.includes('*')) {\n return sessionOptions;\n }\n\n const realProject = await getProjectById(String(project.id));\n return (\n (realProject?.configuration?.ai as AIOptions | undefined) ?? sessionOptions\n );\n};\n"],"mappings":";;;;;;;;;;AAWA,MAAa,sBAAsB,OACjC,YACmC;AACnC,KAAI,CAAC,SAAS,eAAe,GAAI,QAAO;CAExC,MAAM,iBAAiB,QAAQ,cAAc;AAE7C,KAAI,CAAC,eAAe,QAAQ,SAAS,IAAI,CACvC,QAAO;AAIT,SACG,MAFuB,eAAe,OAAO,QAAQ,GAAG,CAAC,GAE5C,eAAe,MAAgC"}
@@ -1 +1 @@
1
- {"version":3,"file":"translateDictionaryDB.mjs","names":[],"sources":["../../../../src/utils/AI/translateDictionaryDB.ts"],"sourcesContent":["import type { AIConfig } from '@intlayer/ai';\nimport {\n chunkJSON,\n type JSONObject,\n mergeChunks,\n reconstructFromSingleChunk,\n reduceObjectFormat,\n verifyIdenticObjectFormat,\n} from '@intlayer/chokidar/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport { translateJSON } from './translateJSON';\n\nconst CHUNK_SIZE = 3000;\nconst MAX_RETRY = 3;\nconst RETRY_DELAY = 2000;\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst retry = async <T>(\n fn: () => Promise<T>,\n retries = MAX_RETRY\n): Promise<T> => {\n try {\n return await fn();\n } catch (error) {\n if (retries <= 0) throw error;\n await sleep(RETRY_DELAY);\n return retry(fn, retries - 1);\n }\n};\n\nexport class AbortError extends Error {\n constructor() {\n super('Aborted');\n this.name = 'AbortError';\n }\n}\n\nexport type TranslateDictionaryDBOptions = {\n content: JSONObject | JSONArray;\n sourceLocale: Locale;\n targetLocales: Locale[];\n aiConfig: AIConfig;\n mode?: 'complete' | 'review';\n dictionaryDescription?: string;\n applicationContext?: string;\n /** Called between chunks. Return true to abort the translation. */\n shouldStop?: () => Promise<boolean> | boolean;\n /** Called just before each chunk starts translating. */\n onChunkStart?: (params: {\n locale: Locale;\n chunkIndex: number;\n totalChunks: number;\n }) => Promise<void> | void;\n};\n\ntype JSONValue = string | number | boolean | null | JSONObject | JSONArray;\n\ninterface JSONArray extends Array<JSONValue> {}\n\nexport const translateDictionaryDB = async ({\n content,\n sourceLocale,\n targetLocales,\n aiConfig,\n mode = 'complete',\n dictionaryDescription,\n applicationContext,\n shouldStop,\n onChunkStart,\n}: TranslateDictionaryDBOptions): Promise<\n Record<Locale, JSONObject | JSONArray>\n> => {\n const chunks = chunkJSON(content, CHUNK_SIZE);\n const results: Record<Locale, JSONObject | JSONArray> = {} as Record<\n Locale,\n JSONObject | JSONArray\n >;\n\n for (const targetLocale of targetLocales) {\n logger.info(`Translating to ${targetLocale}... (${chunks.length} chunks)`);\n\n const chunkResults: any[] = [];\n\n // Process chunks sequentially to avoid rate limits per dictionary\n for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {\n const chunk = chunks[chunkIndex];\n\n // Notify caller of chunk start (for progress reporting)\n if (onChunkStart) {\n await onChunkStart({\n locale: targetLocale,\n chunkIndex,\n totalChunks: chunks.length,\n });\n }\n\n // Check for pause / cancel between every chunk\n if (shouldStop && (await shouldStop())) {\n throw new AbortError();\n }\n\n const chunkContent = reconstructFromSingleChunk(chunk);\n // Helper: if chunkContent is string/number/null, wrap it?\n // chunkJSON guarantees root is object/array.\n\n const presetOutputContent = reduceObjectFormat(\n chunkContent, // In a real scenario, we might want to pass existing translation here\n chunkContent\n ) as any;\n\n const translatedChunk = await retry(async () => {\n const result = await translateJSON({\n entryFileContent: chunkContent,\n presetOutputContent,\n entryLocale: sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiConfig,\n dictionaryDescription,\n applicationContext,\n tags: [], // Tags handling could be added if needed\n });\n\n if (!result?.fileContent) {\n throw new Error('No content returned from AI');\n }\n\n const verification = verifyIdenticObjectFormat(\n result.fileContent,\n chunkContent\n );\n\n if (!verification.isIdentic) {\n throw new Error(`Format verification failed: ${verification.error}`);\n }\n\n return result.fileContent;\n });\n\n chunkResults.push(translatedChunk);\n }\n\n results[targetLocale] = mergeChunks(chunkResults);\n }\n\n return results;\n};\n"],"mappings":";;;;;AAaA,MAAM,aAAa;AACnB,MAAM,YAAY;AAClB,MAAM,cAAc;AAEpB,MAAM,SAAS,OAAe,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;AAE9E,MAAM,QAAQ,OACZ,IACA,UAAU,cACK;CACf,IAAI;EACF,OAAO,MAAM,GAAG;CAClB,SAAS,OAAO;EACd,IAAI,WAAW,GAAG,MAAM;EACxB,MAAM,MAAM,WAAW;EACvB,OAAO,MAAM,IAAI,UAAU,CAAC;CAC9B;AACF;AAEA,IAAa,aAAb,cAAgC,MAAM;CACpC,cAAc;EACZ,MAAM,SAAS;EACf,KAAK,OAAO;CACd;AACF;AAwBA,MAAa,wBAAwB,OAAO,EAC1C,SACA,cACA,eACA,UACA,OAAO,YACP,uBACA,oBACA,YACA,mBAGG;CACH,MAAM,SAAS,UAAU,SAAS,UAAU;CAC5C,MAAM,UAAkD,CAAC;CAKzD,KAAK,MAAM,gBAAgB,eAAe;EACxC,OAAO,KAAK,kBAAkB,aAAa,OAAO,OAAO,OAAO,SAAS;EAEzE,MAAM,eAAsB,CAAC;EAG7B,KAAK,IAAI,aAAa,GAAG,aAAa,OAAO,QAAQ,cAAc;GACjE,MAAM,QAAQ,OAAO;GAGrB,IAAI,cACF,MAAM,aAAa;IACjB,QAAQ;IACR;IACA,aAAa,OAAO;GACtB,CAAC;GAIH,IAAI,cAAe,MAAM,WAAW,GAClC,MAAM,IAAI,WAAW;GAGvB,MAAM,eAAe,2BAA2B,KAAK;GAIrD,MAAM,sBAAsB,mBAC1B,cACA,YACF;GAEA,MAAM,kBAAkB,MAAM,MAAM,YAAY;IAC9C,MAAM,SAAS,MAAM,cAAc;KACjC,kBAAkB;KAClB;KACA,aAAa;KACb,cAAc;KACd;KACA;KACA;KACA;KACA,MAAM,CAAC;IACT,CAAC;IAED,IAAI,CAAC,QAAQ,aACX,MAAM,IAAI,MAAM,6BAA6B;IAG/C,MAAM,eAAe,0BACnB,OAAO,aACP,YACF;IAEA,IAAI,CAAC,aAAa,WAChB,MAAM,IAAI,MAAM,+BAA+B,aAAa,OAAO;IAGrE,OAAO,OAAO;GAChB,CAAC;GAED,aAAa,KAAK,eAAe;EACnC;EAEA,QAAQ,gBAAgB,YAAY,YAAY;CAClD;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"translateDictionaryDB.mjs","names":[],"sources":["../../../../src/utils/AI/translateDictionaryDB.ts"],"sourcesContent":["import type { AIConfig } from '@intlayer/ai';\nimport {\n chunkJSON,\n type JSONObject,\n mergeChunks,\n reconstructFromSingleChunk,\n reduceObjectFormat,\n verifyIdenticObjectFormat,\n} from '@intlayer/chokidar/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport { translateJSON } from './translateJSON';\n\nconst CHUNK_SIZE = 3000;\nconst MAX_RETRY = 3;\nconst RETRY_DELAY = 2000;\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst retry = async <T>(\n fn: () => Promise<T>,\n retries = MAX_RETRY\n): Promise<T> => {\n try {\n return await fn();\n } catch (error) {\n if (retries <= 0) throw error;\n await sleep(RETRY_DELAY);\n return retry(fn, retries - 1);\n }\n};\n\nexport class AbortError extends Error {\n constructor() {\n super('Aborted');\n this.name = 'AbortError';\n }\n}\n\nexport type TranslateDictionaryDBOptions = {\n content: JSONObject | JSONArray;\n sourceLocale: Locale;\n targetLocales: Locale[];\n aiConfig: AIConfig;\n mode?: 'complete' | 'review';\n dictionaryDescription?: string;\n applicationContext?: string;\n /** Called between chunks. Return true to abort the translation. */\n shouldStop?: () => Promise<boolean> | boolean;\n /** Called just before each chunk starts translating. */\n onChunkStart?: (params: {\n locale: Locale;\n chunkIndex: number;\n totalChunks: number;\n }) => Promise<void> | void;\n};\n\ntype JSONValue = string | number | boolean | null | JSONObject | JSONArray;\n\ninterface JSONArray extends Array<JSONValue> {}\n\nexport const translateDictionaryDB = async ({\n content,\n sourceLocale,\n targetLocales,\n aiConfig,\n mode = 'complete',\n dictionaryDescription,\n applicationContext,\n shouldStop,\n onChunkStart,\n}: TranslateDictionaryDBOptions): Promise<\n Record<Locale, JSONObject | JSONArray>\n> => {\n const chunks = chunkJSON(content, CHUNK_SIZE);\n const results: Record<Locale, JSONObject | JSONArray> = {} as Record<\n Locale,\n JSONObject | JSONArray\n >;\n\n for (const targetLocale of targetLocales) {\n logger.info(`Translating to ${targetLocale}... (${chunks.length} chunks)`);\n\n const chunkResults: any[] = [];\n\n // Process chunks sequentially to avoid rate limits per dictionary\n for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {\n const chunk = chunks[chunkIndex];\n\n // Notify caller of chunk start (for progress reporting)\n if (onChunkStart) {\n await onChunkStart({\n locale: targetLocale,\n chunkIndex,\n totalChunks: chunks.length,\n });\n }\n\n // Check for pause / cancel between every chunk\n if (shouldStop && (await shouldStop())) {\n throw new AbortError();\n }\n\n const chunkContent = reconstructFromSingleChunk(chunk);\n // Helper: if chunkContent is string/number/null, wrap it?\n // chunkJSON guarantees root is object/array.\n\n const presetOutputContent = reduceObjectFormat(\n chunkContent, // In a real scenario, we might want to pass existing translation here\n chunkContent\n ) as any;\n\n const translatedChunk = await retry(async () => {\n const result = await translateJSON({\n entryFileContent: chunkContent,\n presetOutputContent,\n entryLocale: sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiConfig,\n dictionaryDescription,\n applicationContext,\n tags: [], // Tags handling could be added if needed\n });\n\n if (!result?.fileContent) {\n throw new Error('No content returned from AI');\n }\n\n const verification = verifyIdenticObjectFormat(\n result.fileContent,\n chunkContent\n );\n\n if (!verification.isIdentic) {\n throw new Error(`Format verification failed: ${verification.error}`);\n }\n\n return result.fileContent;\n });\n\n chunkResults.push(translatedChunk);\n }\n\n results[targetLocale] = mergeChunks(chunkResults);\n }\n\n return results;\n};\n"],"mappings":";;;;;AAaA,MAAM,aAAa;AACnB,MAAM,YAAY;AAClB,MAAM,cAAc;AAEpB,MAAM,SAAS,OAAe,IAAI,SAAS,YAAY,WAAW,SAAS,GAAG,CAAC;AAE/E,MAAM,QAAQ,OACZ,IACA,UAAU,cACK;AACf,KAAI;AACF,SAAO,MAAM,IAAI;UACV,OAAO;AACd,MAAI,WAAW,EAAG,OAAM;AACxB,QAAM,MAAM,YAAY;AACxB,SAAO,MAAM,IAAI,UAAU,EAAE;;;AAIjC,IAAa,aAAb,cAAgC,MAAM;CACpC,cAAc;AACZ,QAAM,UAAU;AAChB,OAAK,OAAO;;;AA0BhB,MAAa,wBAAwB,OAAO,EAC1C,SACA,cACA,eACA,UACA,OAAO,YACP,uBACA,oBACA,YACA,mBAGG;CACH,MAAM,SAAS,UAAU,SAAS,WAAW;CAC7C,MAAM,UAAkD,EAAE;AAK1D,MAAK,MAAM,gBAAgB,eAAe;AACxC,SAAO,KAAK,kBAAkB,aAAa,OAAO,OAAO,OAAO,UAAU;EAE1E,MAAM,eAAsB,EAAE;AAG9B,OAAK,IAAI,aAAa,GAAG,aAAa,OAAO,QAAQ,cAAc;GACjE,MAAM,QAAQ,OAAO;AAGrB,OAAI,aACF,OAAM,aAAa;IACjB,QAAQ;IACR;IACA,aAAa,OAAO;IACrB,CAAC;AAIJ,OAAI,cAAe,MAAM,YAAY,CACnC,OAAM,IAAI,YAAY;GAGxB,MAAM,eAAe,2BAA2B,MAAM;GAItD,MAAM,sBAAsB,mBAC1B,cACA,aACD;GAED,MAAM,kBAAkB,MAAM,MAAM,YAAY;IAC9C,MAAM,SAAS,MAAM,cAAc;KACjC,kBAAkB;KAClB;KACA,aAAa;KACb,cAAc;KACd;KACA;KACA;KACA;KACA,MAAM,EAAE;KACT,CAAC;AAEF,QAAI,CAAC,QAAQ,YACX,OAAM,IAAI,MAAM,8BAA8B;IAGhD,MAAM,eAAe,0BACnB,OAAO,aACP,aACD;AAED,QAAI,CAAC,aAAa,UAChB,OAAM,IAAI,MAAM,+BAA+B,aAAa,QAAQ;AAGtE,WAAO,OAAO;KACd;AAEF,gBAAa,KAAK,gBAAgB;;AAGpC,UAAQ,gBAAgB,YAAY,aAAa;;AAGnD,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["translateJSONAI"],"sources":["../../../../../src/utils/AI/translateJSON/index.ts"],"sourcesContent":["import {\n type AIConfig,\n type AIOptions,\n AIProvider,\n type TranslateJSONResultData,\n translateJSON as translateJSONAI,\n} from '@intlayer/ai';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nexport type TranslateJSONOptions<T = JSON> = {\n entryFileContent: T;\n presetOutputContent: Partial<T>;\n dictionaryDescription?: string;\n entryLocale: Locale;\n outputLocale: Locale;\n tags: Tag[];\n aiConfig: AIConfig;\n mode: 'complete' | 'review';\n applicationContext?: string;\n};\n\nexport { AIProvider, type TranslateJSONResultData };\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-5-mini',\n};\n\n/**\n * TranslateJSONs a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const translateJSON = async <T = JSON>(\n options: TranslateJSONOptions<T>\n): Promise<TranslateJSONResultData<T> | undefined> => {\n const result = await translateJSONAI(options);\n\n if (result) {\n logger.info(`${result.tokenUsed} tokens used in the request`);\n }\n\n return result;\n};\n"],"mappings":";;;;AAyBA,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;AACT;;;;;;AAOA,MAAa,gBAAgB,OAC3B,YACoD;CACpD,MAAM,SAAS,MAAMA,gBAAgB,OAAO;CAE5C,IAAI,QACF,OAAO,KAAK,GAAG,OAAO,UAAU,4BAA4B;CAG9D,OAAO;AACT"}
1
+ {"version":3,"file":"index.mjs","names":["translateJSONAI"],"sources":["../../../../../src/utils/AI/translateJSON/index.ts"],"sourcesContent":["import {\n type AIConfig,\n type AIOptions,\n AIProvider,\n type TranslateJSONResultData,\n translateJSON as translateJSONAI,\n} from '@intlayer/ai';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { logger } from '@logger';\nimport type { Tag } from '@/types/tag.types';\n\nexport type TranslateJSONOptions<T = JSON> = {\n entryFileContent: T;\n presetOutputContent: Partial<T>;\n dictionaryDescription?: string;\n entryLocale: Locale;\n outputLocale: Locale;\n tags: Tag[];\n aiConfig: AIConfig;\n mode: 'complete' | 'review';\n applicationContext?: string;\n};\n\nexport { AIProvider, type TranslateJSONResultData };\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-5-mini',\n};\n\n/**\n * TranslateJSONs a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const translateJSON = async <T = JSON>(\n options: TranslateJSONOptions<T>\n): Promise<TranslateJSONResultData<T> | undefined> => {\n const result = await translateJSONAI(options);\n\n if (result) {\n logger.info(`${result.tokenUsed} tokens used in the request`);\n }\n\n return result;\n};\n"],"mappings":";;;;AAyBA,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;CACR;;;;;;AAOD,MAAa,gBAAgB,OAC3B,YACoD;CACpD,MAAM,SAAS,MAAMA,gBAAgB,QAAQ;AAE7C,KAAI,OACF,QAAO,KAAK,GAAG,OAAO,UAAU,6BAA6B;AAG/D,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"accessControl.mjs","names":[],"sources":["../../../src/utils/accessControl.ts"],"sourcesContent":["import { logger } from '@logger';\n\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { HttpStatusCodes } from './httpStatusCodes';\n\nexport enum AccessRule {\n none = 'none',\n authenticated = 'authenticated',\n admin = 'admin',\n noneAuthenticated = 'not-authenticated',\n hasOrganization = 'has-organization',\n hasProject = 'has-project',\n hasBearer = 'has-bearer',\n oauth2 = 'oauth2',\n}\n\nexport const accessControl = <R extends AccessRule | AccessRule[]>(\n req: FastifyRequest,\n accessRule: R\n) => {\n const accessRuleArray: AccessRule[] = Array.isArray(accessRule)\n ? accessRule\n : [accessRule];\n\n const user = req.session?.user;\n const organization = req.session?.organization;\n const project = req.session?.project;\n const authType = req.session?.authType;\n\n // If 'none' access rule is present, immediately return success\n if (accessRuleArray.includes(AccessRule.none)) {\n return {\n success: true,\n message: null,\n data: { user, organization, project, authType },\n };\n }\n\n let success = true;\n const messages: string[] = [];\n\n // Check for 'authenticated' access rule\n if (accessRuleArray.includes(AccessRule.authenticated)) {\n if (!user) {\n success = false;\n messages.push('User is not authenticated');\n }\n }\n\n // Check for 'admin' access rule\n // if (accessRuleArray.includes(AccessRule.admin)) {\n // if (!user?.role.includes('admin')) {\n // success = false;\n // messages.push('User is not an admin');\n // }\n // }\n\n // Check for 'not-authenticated' access rule\n if (accessRuleArray.includes(AccessRule.noneAuthenticated)) {\n if (user) {\n success = false;\n messages.push('User is authenticated');\n }\n }\n\n // Check for 'has-organization' access rule\n if (accessRuleArray.includes(AccessRule.hasOrganization)) {\n if (!organization) {\n success = false;\n messages.push('Organization is not set');\n }\n }\n\n // Check for 'has-project' access rule\n if (accessRuleArray.includes(AccessRule.hasProject)) {\n if (!project) {\n success = false;\n messages.push('Project is not set');\n }\n }\n\n // Check for 'oauth2' access rule\n if (accessRuleArray.includes(AccessRule.oauth2)) {\n if (authType !== 'oauth2') {\n success = false;\n messages.push('OAuth2 authentication is required');\n }\n }\n\n // Handle unknown access rules\n const knownRules = Object.values(AccessRule);\n const unknownRules = accessRuleArray.filter(\n (rule) => !knownRules.includes(rule)\n );\n if (unknownRules.length > 0) {\n success = false;\n messages.push(`Unknown access rules: ${unknownRules.join(', ')}`);\n }\n\n return {\n success,\n message: messages.join(', '),\n data: { user, organization, project, authType },\n };\n};\n\n/**\n * Middleware to control API access based on access rules.\n *\n * This middleware allows for multiple access rules to be passed, either as individual `AccessRule` or\n * an array of `AccessRule` groups. Access is granted if at least one of the following conditions is met:\n *\n * - The user satisfies all `AccessRule` within any group of rules passed as an array.\n * - The user satisfies any single `AccessRule` passed individually.\n *\n * Example usage:\n *\n * ```typescript\n * // Allow access if the user has both `hasProject` and `hasOrganization`, or if they have `admin` rights\n * app.use('/protected-route', apiAccessControlMiddleWare([AccessRule.hasProject, AccessRule.hasOrganization], AccessRule.admin));\n * ```\n *\n * In this example:\n * - The user will be granted access if they have both `hasProject` and `hasOrganization`.\n * - Alternatively, the user will also be granted access if they have `admin` privileges.\n *\n * @param {...(AccessRule | AccessRule[])[]} accessRules - One or more access rules or groups of access rules.\n * - Single `AccessRule`: The user must satisfy this rule for access to be granted.\n * - Array of `AccessRule`: The user must satisfy all rules in the array for access to be granted.\n * @returns {Function} Express middleware function that checks if the user has the required access.\n *\n * If the user does not meet any of the provided access rules, a 403 Forbidden status is returned.\n *\n * @example\n * // Example 1: Require admin privileges\n * app.use('/admin', apiAccessControlMiddleWare(AccessRule.admin));\n *\n * @example\n * // Example 2: Require both project and organization access, or admin privileges\n * app.use('/dashboard', apiAccessControlMiddleWare([AccessRule.hasProject, AccessRule.hasOrganization], AccessRule.admin));\n */\nexport const accessControlMiddleWare =\n (...accessRules: (AccessRule | AccessRule[])[]) =>\n async (req: FastifyRequest, reply: FastifyReply): Promise<void> => {\n let hasAccess = false;\n\n // Iterate over each access rule group (either single AccessRule or an array of AccessRules)\n for (const ruleGroup of accessRules) {\n if (Array.isArray(ruleGroup)) {\n // If ruleGroup is an array, check if all rules in the group are satisfied\n const accessResults = ruleGroup.map(\n (rule) => accessControl(req, rule).success\n );\n hasAccess = accessResults.every((result) => result); // All rules must be satisfied in this case\n } else {\n // Single rule: just check this one\n const accessResult = accessControl(req, ruleGroup);\n if (accessResult.success) {\n hasAccess = true;\n }\n }\n\n // If access is granted at any point, stop further checks\n if (hasAccess) {\n break;\n }\n }\n\n // If no access rule group was satisfied, deny access\n if (!hasAccess) {\n logger.error('Access denied');\n\n const errorStatusCode = HttpStatusCodes.FORBIDDEN_403;\n reply.status(errorStatusCode).send('Access denied');\n return;\n }\n };\n"],"mappings":";;;;AAKA,IAAY,aAAL;CACL;CACA;CACA;CACA;CACA;CACA;CACA;CACA;;AACF;AAEA,MAAa,iBACX,KACA,eACG;CACH,MAAM,kBAAgC,MAAM,QAAQ,UAAU,IAC1D,aACA,CAAC,UAAU;CAEf,MAAM,OAAO,IAAI,SAAS;CAC1B,MAAM,eAAe,IAAI,SAAS;CAClC,MAAM,UAAU,IAAI,SAAS;CAC7B,MAAM,WAAW,IAAI,SAAS;CAG9B,IAAI,gBAAgB,eAAwB,GAC1C,OAAO;EACL,SAAS;EACT,SAAS;EACT,MAAM;GAAE;GAAM;GAAc;GAAS;EAAS;CAChD;CAGF,IAAI,UAAU;CACd,MAAM,WAAqB,CAAC;CAG5B,IAAI,gBAAgB,wBAAiC,GACnD;MAAI,CAAC,MAAM;GACT,UAAU;GACV,SAAS,KAAK,2BAA2B;EAC3C;;CAYF,IAAI,gBAAgB,4BAAqC,GACvD;MAAI,MAAM;GACR,UAAU;GACV,SAAS,KAAK,uBAAuB;EACvC;;CAIF,IAAI,gBAAgB,2BAAmC,GACrD;MAAI,CAAC,cAAc;GACjB,UAAU;GACV,SAAS,KAAK,yBAAyB;EACzC;;CAIF,IAAI,gBAAgB,sBAA8B,GAChD;MAAI,CAAC,SAAS;GACZ,UAAU;GACV,SAAS,KAAK,oBAAoB;EACpC;;CAIF,IAAI,gBAAgB,iBAA0B,GAC5C;MAAI,aAAa,UAAU;GACzB,UAAU;GACV,SAAS,KAAK,mCAAmC;EACnD;;CAIF,MAAM,aAAa,OAAO,OAAO,UAAU;CAC3C,MAAM,eAAe,gBAAgB,QAClC,SAAS,CAAC,WAAW,SAAS,IAAI,CACrC;CACA,IAAI,aAAa,SAAS,GAAG;EAC3B,UAAU;EACV,SAAS,KAAK,yBAAyB,aAAa,KAAK,IAAI,GAAG;CAClE;CAEA,OAAO;EACL;EACA,SAAS,SAAS,KAAK,IAAI;EAC3B,MAAM;GAAE;GAAM;GAAc;GAAS;EAAS;CAChD;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,2BACV,GAAG,gBACJ,OAAO,KAAqB,UAAuC;CACjE,IAAI,YAAY;CAGhB,KAAK,MAAM,aAAa,aAAa;EACnC,IAAI,MAAM,QAAQ,SAAS,GAKzB,YAHsB,UAAU,KAC7B,SAAS,cAAc,KAAK,IAAI,CAAC,CAAC,OAEb,CAAC,CAAC,OAAO,WAAW,MAAM;OAIlD,IADqB,cAAc,KAAK,SACzB,CAAC,CAAC,SACf,YAAY;EAKhB,IAAI,WACF;CAEJ;CAGA,IAAI,CAAC,WAAW;EACd,OAAO,MAAM,eAAe;EAE5B,MAAM;EACN,MAAM,OAAO,eAAe,CAAC,CAAC,KAAK,eAAe;EAClD;CACF;AACF"}
1
+ {"version":3,"file":"accessControl.mjs","names":[],"sources":["../../../src/utils/accessControl.ts"],"sourcesContent":["import { logger } from '@logger';\n\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { HttpStatusCodes } from './httpStatusCodes';\n\nexport enum AccessRule {\n none = 'none',\n authenticated = 'authenticated',\n admin = 'admin',\n noneAuthenticated = 'not-authenticated',\n hasOrganization = 'has-organization',\n hasProject = 'has-project',\n hasBearer = 'has-bearer',\n oauth2 = 'oauth2',\n}\n\nexport const accessControl = <R extends AccessRule | AccessRule[]>(\n req: FastifyRequest,\n accessRule: R\n) => {\n const accessRuleArray: AccessRule[] = Array.isArray(accessRule)\n ? accessRule\n : [accessRule];\n\n const user = req.session?.user;\n const organization = req.session?.organization;\n const project = req.session?.project;\n const authType = req.session?.authType;\n\n // If 'none' access rule is present, immediately return success\n if (accessRuleArray.includes(AccessRule.none)) {\n return {\n success: true,\n message: null,\n data: { user, organization, project, authType },\n };\n }\n\n let success = true;\n const messages: string[] = [];\n\n // Check for 'authenticated' access rule\n if (accessRuleArray.includes(AccessRule.authenticated)) {\n if (!user) {\n success = false;\n messages.push('User is not authenticated');\n }\n }\n\n // Check for 'admin' access rule\n // if (accessRuleArray.includes(AccessRule.admin)) {\n // if (!user?.role.includes('admin')) {\n // success = false;\n // messages.push('User is not an admin');\n // }\n // }\n\n // Check for 'not-authenticated' access rule\n if (accessRuleArray.includes(AccessRule.noneAuthenticated)) {\n if (user) {\n success = false;\n messages.push('User is authenticated');\n }\n }\n\n // Check for 'has-organization' access rule\n if (accessRuleArray.includes(AccessRule.hasOrganization)) {\n if (!organization) {\n success = false;\n messages.push('Organization is not set');\n }\n }\n\n // Check for 'has-project' access rule\n if (accessRuleArray.includes(AccessRule.hasProject)) {\n if (!project) {\n success = false;\n messages.push('Project is not set');\n }\n }\n\n // Check for 'oauth2' access rule\n if (accessRuleArray.includes(AccessRule.oauth2)) {\n if (authType !== 'oauth2') {\n success = false;\n messages.push('OAuth2 authentication is required');\n }\n }\n\n // Handle unknown access rules\n const knownRules = Object.values(AccessRule);\n const unknownRules = accessRuleArray.filter(\n (rule) => !knownRules.includes(rule)\n );\n if (unknownRules.length > 0) {\n success = false;\n messages.push(`Unknown access rules: ${unknownRules.join(', ')}`);\n }\n\n return {\n success,\n message: messages.join(', '),\n data: { user, organization, project, authType },\n };\n};\n\n/**\n * Middleware to control API access based on access rules.\n *\n * This middleware allows for multiple access rules to be passed, either as individual `AccessRule` or\n * an array of `AccessRule` groups. Access is granted if at least one of the following conditions is met:\n *\n * - The user satisfies all `AccessRule` within any group of rules passed as an array.\n * - The user satisfies any single `AccessRule` passed individually.\n *\n * Example usage:\n *\n * ```typescript\n * // Allow access if the user has both `hasProject` and `hasOrganization`, or if they have `admin` rights\n * app.use('/protected-route', apiAccessControlMiddleWare([AccessRule.hasProject, AccessRule.hasOrganization], AccessRule.admin));\n * ```\n *\n * In this example:\n * - The user will be granted access if they have both `hasProject` and `hasOrganization`.\n * - Alternatively, the user will also be granted access if they have `admin` privileges.\n *\n * @param {...(AccessRule | AccessRule[])[]} accessRules - One or more access rules or groups of access rules.\n * - Single `AccessRule`: The user must satisfy this rule for access to be granted.\n * - Array of `AccessRule`: The user must satisfy all rules in the array for access to be granted.\n * @returns {Function} Express middleware function that checks if the user has the required access.\n *\n * If the user does not meet any of the provided access rules, a 403 Forbidden status is returned.\n *\n * @example\n * // Example 1: Require admin privileges\n * app.use('/admin', apiAccessControlMiddleWare(AccessRule.admin));\n *\n * @example\n * // Example 2: Require both project and organization access, or admin privileges\n * app.use('/dashboard', apiAccessControlMiddleWare([AccessRule.hasProject, AccessRule.hasOrganization], AccessRule.admin));\n */\nexport const accessControlMiddleWare =\n (...accessRules: (AccessRule | AccessRule[])[]) =>\n async (req: FastifyRequest, reply: FastifyReply): Promise<void> => {\n let hasAccess = false;\n\n // Iterate over each access rule group (either single AccessRule or an array of AccessRules)\n for (const ruleGroup of accessRules) {\n if (Array.isArray(ruleGroup)) {\n // If ruleGroup is an array, check if all rules in the group are satisfied\n const accessResults = ruleGroup.map(\n (rule) => accessControl(req, rule).success\n );\n hasAccess = accessResults.every((result) => result); // All rules must be satisfied in this case\n } else {\n // Single rule: just check this one\n const accessResult = accessControl(req, ruleGroup);\n if (accessResult.success) {\n hasAccess = true;\n }\n }\n\n // If access is granted at any point, stop further checks\n if (hasAccess) {\n break;\n }\n }\n\n // If no access rule group was satisfied, deny access\n if (!hasAccess) {\n logger.error('Access denied');\n\n const errorStatusCode = HttpStatusCodes.FORBIDDEN_403;\n reply.status(errorStatusCode).send('Access denied');\n return;\n }\n };\n"],"mappings":";;;;AAKA,IAAY,aAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;KACD;AAED,MAAa,iBACX,KACA,eACG;CACH,MAAM,kBAAgC,MAAM,QAAQ,WAAW,GAC3D,aACA,CAAC,WAAW;CAEhB,MAAM,OAAO,IAAI,SAAS;CAC1B,MAAM,eAAe,IAAI,SAAS;CAClC,MAAM,UAAU,IAAI,SAAS;CAC7B,MAAM,WAAW,IAAI,SAAS;AAG9B,KAAI,gBAAgB,gBAAyB,CAC3C,QAAO;EACL,SAAS;EACT,SAAS;EACT,MAAM;GAAE;GAAM;GAAc;GAAS;GAAU;EAChD;CAGH,IAAI,UAAU;CACd,MAAM,WAAqB,EAAE;AAG7B,KAAI,gBAAgB,yBAAkC,EACpD;MAAI,CAAC,MAAM;AACT,aAAU;AACV,YAAS,KAAK,4BAA4B;;;AAa9C,KAAI,gBAAgB,6BAAsC,EACxD;MAAI,MAAM;AACR,aAAU;AACV,YAAS,KAAK,wBAAwB;;;AAK1C,KAAI,gBAAgB,4BAAoC,EACtD;MAAI,CAAC,cAAc;AACjB,aAAU;AACV,YAAS,KAAK,0BAA0B;;;AAK5C,KAAI,gBAAgB,uBAA+B,EACjD;MAAI,CAAC,SAAS;AACZ,aAAU;AACV,YAAS,KAAK,qBAAqB;;;AAKvC,KAAI,gBAAgB,kBAA2B,EAC7C;MAAI,aAAa,UAAU;AACzB,aAAU;AACV,YAAS,KAAK,oCAAoC;;;CAKtD,MAAM,aAAa,OAAO,OAAO,WAAW;CAC5C,MAAM,eAAe,gBAAgB,QAClC,SAAS,CAAC,WAAW,SAAS,KAAK,CACrC;AACD,KAAI,aAAa,SAAS,GAAG;AAC3B,YAAU;AACV,WAAS,KAAK,yBAAyB,aAAa,KAAK,KAAK,GAAG;;AAGnE,QAAO;EACL;EACA,SAAS,SAAS,KAAK,KAAK;EAC5B,MAAM;GAAE;GAAM;GAAc;GAAS;GAAU;EAChD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCH,MAAa,2BACV,GAAG,gBACJ,OAAO,KAAqB,UAAuC;CACjE,IAAI,YAAY;AAGhB,MAAK,MAAM,aAAa,aAAa;AACnC,MAAI,MAAM,QAAQ,UAAU,CAK1B,aAHsB,UAAU,KAC7B,SAAS,cAAc,KAAK,KAAK,CAAC,QAEZ,CAAC,OAAO,WAAW,OAAO;WAG9B,cAAc,KAAK,UACxB,CAAC,QACf,aAAY;AAKhB,MAAI,UACF;;AAKJ,KAAI,CAAC,WAAW;AACd,SAAO,MAAM,gBAAgB;EAE7B,MAAM;AACN,QAAM,OAAO,gBAAgB,CAAC,KAAK,gBAAgB;AACnD"}