@intlayer/backend 7.0.6 → 7.0.8-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 (198) hide show
  1. package/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/intlayer_with_i18next.json +5122 -4096
  2. package/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/intlayer_with_next-i18next.json +5122 -4096
  3. package/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/intlayer_with_next-intl.json +5122 -4096
  4. package/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/intlayer_with_react-i18next.json +5122 -4096
  5. package/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/intlayer_with_react-intl.json +5122 -4096
  6. package/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/intlayer_with_vue-i18n.json +5122 -4096
  7. package/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/react-i18next_vs_react-intl_vs_intlayer.json +8194 -7168
  8. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_nextjs_16.json +1 -1
  9. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_nuxt.json +11266 -10240
  10. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_tanstack.json +9218 -8192
  11. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_vite+react.json +1 -1
  12. package/dist/cjs/_virtual/_utils_asset.cjs +0 -3
  13. package/dist/cjs/controllers/audit.controller.cjs +0 -1
  14. package/dist/cjs/controllers/audit.controller.cjs.map +1 -1
  15. package/dist/cjs/controllers/dictionary.controller.cjs +0 -1
  16. package/dist/cjs/controllers/dictionary.controller.cjs.map +1 -1
  17. package/dist/cjs/controllers/newsletter.controller.cjs +0 -1
  18. package/dist/cjs/controllers/newsletter.controller.cjs.map +1 -1
  19. package/dist/cjs/controllers/oAuth2.controller.cjs +0 -1
  20. package/dist/cjs/controllers/oAuth2.controller.cjs.map +1 -1
  21. package/dist/cjs/controllers/organization.controller.cjs +0 -2
  22. package/dist/cjs/controllers/organization.controller.cjs.map +1 -1
  23. package/dist/cjs/controllers/project.controller.cjs +0 -1
  24. package/dist/cjs/controllers/project.controller.cjs.map +1 -1
  25. package/dist/cjs/controllers/projectAccessKey.controller.cjs +0 -1
  26. package/dist/cjs/controllers/projectAccessKey.controller.cjs.map +1 -1
  27. package/dist/cjs/controllers/stripe.controller.cjs +0 -2
  28. package/dist/cjs/controllers/stripe.controller.cjs.map +1 -1
  29. package/dist/cjs/controllers/tag.controller.cjs +0 -1
  30. package/dist/cjs/controllers/tag.controller.cjs.map +1 -1
  31. package/dist/cjs/controllers/user.controller.cjs +0 -1
  32. package/dist/cjs/controllers/user.controller.cjs.map +1 -1
  33. package/dist/cjs/emails/InviteUserEmail.cjs +0 -2
  34. package/dist/cjs/emails/InviteUserEmail.cjs.map +1 -1
  35. package/dist/cjs/emails/OAuthTokenCreatedEmail.cjs +0 -2
  36. package/dist/cjs/emails/OAuthTokenCreatedEmail.cjs.map +1 -1
  37. package/dist/cjs/emails/PasswordChangeConfirmation.cjs +0 -2
  38. package/dist/cjs/emails/PasswordChangeConfirmation.cjs.map +1 -1
  39. package/dist/cjs/emails/ResetUserPassword.cjs +0 -2
  40. package/dist/cjs/emails/ResetUserPassword.cjs.map +1 -1
  41. package/dist/cjs/emails/SubscriptionPaymentCancellation.cjs +0 -2
  42. package/dist/cjs/emails/SubscriptionPaymentCancellation.cjs.map +1 -1
  43. package/dist/cjs/emails/SubscriptionPaymentError.cjs +0 -2
  44. package/dist/cjs/emails/SubscriptionPaymentError.cjs.map +1 -1
  45. package/dist/cjs/emails/SubscriptionPaymentSuccess.cjs +0 -2
  46. package/dist/cjs/emails/SubscriptionPaymentSuccess.cjs.map +1 -1
  47. package/dist/cjs/emails/ValidateUserEmail.cjs +0 -2
  48. package/dist/cjs/emails/ValidateUserEmail.cjs.map +1 -1
  49. package/dist/cjs/emails/Welcome.cjs +0 -2
  50. package/dist/cjs/emails/Welcome.cjs.map +1 -1
  51. package/dist/cjs/index.cjs +0 -2
  52. package/dist/cjs/index.cjs.map +1 -1
  53. package/dist/cjs/logger/index.cjs +0 -1
  54. package/dist/cjs/logger/index.cjs.map +1 -1
  55. package/dist/cjs/middlewares/sessionAuth.middleware.cjs +0 -1
  56. package/dist/cjs/middlewares/sessionAuth.middleware.cjs.map +1 -1
  57. package/dist/cjs/models/audit.model.cjs +0 -2
  58. package/dist/cjs/models/audit.model.cjs.map +1 -1
  59. package/dist/cjs/models/dictionary.model.cjs +0 -1
  60. package/dist/cjs/models/dictionary.model.cjs.map +1 -1
  61. package/dist/cjs/models/discussion.model.cjs +0 -1
  62. package/dist/cjs/models/discussion.model.cjs.map +1 -1
  63. package/dist/cjs/models/oAuth2.model.cjs +0 -1
  64. package/dist/cjs/models/oAuth2.model.cjs.map +1 -1
  65. package/dist/cjs/models/organization.model.cjs +0 -1
  66. package/dist/cjs/models/organization.model.cjs.map +1 -1
  67. package/dist/cjs/models/project.model.cjs +0 -1
  68. package/dist/cjs/models/project.model.cjs.map +1 -1
  69. package/dist/cjs/models/session.model.cjs +0 -1
  70. package/dist/cjs/models/session.model.cjs.map +1 -1
  71. package/dist/cjs/models/tag.model.cjs +0 -1
  72. package/dist/cjs/models/tag.model.cjs.map +1 -1
  73. package/dist/cjs/models/user.model.cjs +0 -1
  74. package/dist/cjs/models/user.model.cjs.map +1 -1
  75. package/dist/cjs/routes/ai.routes.cjs +0 -1
  76. package/dist/cjs/routes/ai.routes.cjs.map +1 -1
  77. package/dist/cjs/routes/dictionary.routes.cjs +0 -1
  78. package/dist/cjs/routes/dictionary.routes.cjs.map +1 -1
  79. package/dist/cjs/routes/eventListener.routes.cjs +0 -1
  80. package/dist/cjs/routes/eventListener.routes.cjs.map +1 -1
  81. package/dist/cjs/routes/newsletter.routes.cjs +0 -1
  82. package/dist/cjs/routes/newsletter.routes.cjs.map +1 -1
  83. package/dist/cjs/routes/organization.routes.cjs +0 -1
  84. package/dist/cjs/routes/organization.routes.cjs.map +1 -1
  85. package/dist/cjs/routes/project.routes.cjs +0 -1
  86. package/dist/cjs/routes/project.routes.cjs.map +1 -1
  87. package/dist/cjs/routes/search.routes.cjs +0 -1
  88. package/dist/cjs/routes/search.routes.cjs.map +1 -1
  89. package/dist/cjs/routes/stripe.routes.cjs +0 -1
  90. package/dist/cjs/routes/stripe.routes.cjs.map +1 -1
  91. package/dist/cjs/routes/tags.routes.cjs +0 -1
  92. package/dist/cjs/routes/tags.routes.cjs.map +1 -1
  93. package/dist/cjs/routes/user.routes.cjs +0 -1
  94. package/dist/cjs/routes/user.routes.cjs.map +1 -1
  95. package/dist/cjs/schemas/dictionary.schema.cjs +0 -1
  96. package/dist/cjs/schemas/dictionary.schema.cjs.map +1 -1
  97. package/dist/cjs/schemas/discussion.schema.cjs +0 -1
  98. package/dist/cjs/schemas/discussion.schema.cjs.map +1 -1
  99. package/dist/cjs/schemas/oAuth2.schema.cjs +0 -1
  100. package/dist/cjs/schemas/oAuth2.schema.cjs.map +1 -1
  101. package/dist/cjs/schemas/organization.schema.cjs +0 -1
  102. package/dist/cjs/schemas/organization.schema.cjs.map +1 -1
  103. package/dist/cjs/schemas/plans.schema.cjs +0 -1
  104. package/dist/cjs/schemas/plans.schema.cjs.map +1 -1
  105. package/dist/cjs/schemas/project.schema.cjs +0 -2
  106. package/dist/cjs/schemas/project.schema.cjs.map +1 -1
  107. package/dist/cjs/schemas/session.schema.cjs +0 -1
  108. package/dist/cjs/schemas/session.schema.cjs.map +1 -1
  109. package/dist/cjs/schemas/tag.schema.cjs +0 -1
  110. package/dist/cjs/schemas/tag.schema.cjs.map +1 -1
  111. package/dist/cjs/schemas/user.schema.cjs +0 -1
  112. package/dist/cjs/schemas/user.schema.cjs.map +1 -1
  113. package/dist/cjs/services/dictionary.service.cjs +0 -1
  114. package/dist/cjs/services/dictionary.service.cjs.map +1 -1
  115. package/dist/cjs/services/email.service.cjs +0 -3
  116. package/dist/cjs/services/email.service.cjs.map +1 -1
  117. package/dist/cjs/services/oAuth2.service.cjs +0 -1
  118. package/dist/cjs/services/oAuth2.service.cjs.map +1 -1
  119. package/dist/cjs/services/projectAccessKey.service.cjs +0 -1
  120. package/dist/cjs/services/projectAccessKey.service.cjs.map +1 -1
  121. package/dist/cjs/utils/AI/aiSdk.cjs +0 -5
  122. package/dist/cjs/utils/AI/aiSdk.cjs.map +1 -1
  123. package/dist/cjs/utils/AI/askDocQuestion/askDocQuestion.cjs +0 -4
  124. package/dist/cjs/utils/AI/askDocQuestion/askDocQuestion.cjs.map +1 -1
  125. package/dist/cjs/utils/AI/askDocQuestion/indexMarkdownFiles.cjs +0 -6
  126. package/dist/cjs/utils/AI/askDocQuestion/indexMarkdownFiles.cjs.map +1 -1
  127. package/dist/cjs/utils/AI/auditDictionary/index.cjs +0 -3
  128. package/dist/cjs/utils/AI/auditDictionary/index.cjs.map +1 -1
  129. package/dist/cjs/utils/AI/auditDictionaryField/index.cjs +0 -3
  130. package/dist/cjs/utils/AI/auditDictionaryField/index.cjs.map +1 -1
  131. package/dist/cjs/utils/AI/auditDictionaryMetadata/index.cjs +0 -1
  132. package/dist/cjs/utils/AI/auditDictionaryMetadata/index.cjs.map +1 -1
  133. package/dist/cjs/utils/AI/auditTag/index.cjs +0 -1
  134. package/dist/cjs/utils/AI/auditTag/index.cjs.map +1 -1
  135. package/dist/cjs/utils/AI/autocomplete/index.cjs +0 -1
  136. package/dist/cjs/utils/AI/autocomplete/index.cjs.map +1 -1
  137. package/dist/cjs/utils/AI/customQuery/index.cjs +0 -1
  138. package/dist/cjs/utils/AI/customQuery/index.cjs.map +1 -1
  139. package/dist/cjs/utils/AI/translateJSON/index.cjs +0 -3
  140. package/dist/cjs/utils/AI/translateJSON/index.cjs.map +1 -1
  141. package/dist/cjs/utils/accessControl.cjs +1 -1
  142. package/dist/cjs/utils/accessControl.cjs.map +1 -1
  143. package/dist/cjs/utils/auth/getAuth.cjs +0 -4
  144. package/dist/cjs/utils/auth/getAuth.cjs.map +1 -1
  145. package/dist/cjs/utils/errors/ErrorHandler.cjs +0 -2
  146. package/dist/cjs/utils/errors/ErrorHandler.cjs.map +1 -1
  147. package/dist/cjs/utils/errors/ErrorsClass.cjs +0 -1
  148. package/dist/cjs/utils/errors/ErrorsClass.cjs.map +1 -1
  149. package/dist/cjs/utils/mongoDB/connectDB.cjs +1 -2
  150. package/dist/cjs/utils/mongoDB/connectDB.cjs.map +1 -1
  151. package/dist/cjs/webhooks/stripe.webhook.cjs +0 -1
  152. package/dist/cjs/webhooks/stripe.webhook.cjs.map +1 -1
  153. package/dist/esm/index.mjs.map +1 -1
  154. package/dist/esm/utils/accessControl.mjs +1 -1
  155. package/dist/esm/utils/accessControl.mjs.map +1 -1
  156. package/dist/esm/utils/mongoDB/connectDB.mjs +2 -2
  157. package/dist/esm/utils/mongoDB/connectDB.mjs.map +1 -1
  158. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  159. package/dist/types/emails/InviteUserEmail.d.ts +4 -4
  160. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +4 -4
  161. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts.map +1 -1
  162. package/dist/types/emails/PasswordChangeConfirmation.d.ts +4 -4
  163. package/dist/types/emails/PasswordChangeConfirmation.d.ts.map +1 -1
  164. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -4
  165. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
  166. package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -4
  167. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -4
  168. package/dist/types/emails/ValidateUserEmail.d.ts +4 -4
  169. package/dist/types/emails/Welcome.d.ts +4 -4
  170. package/dist/types/emails/Welcome.d.ts.map +1 -1
  171. package/dist/types/export.d.ts +3 -1
  172. package/dist/types/models/dictionary.model.d.ts +4 -4
  173. package/dist/types/models/dictionary.model.d.ts.map +1 -1
  174. package/dist/types/models/discussion.model.d.ts +2 -2
  175. package/dist/types/models/discussion.model.d.ts.map +1 -1
  176. package/dist/types/models/oAuth2.model.d.ts +4 -3
  177. package/dist/types/models/oAuth2.model.d.ts.map +1 -1
  178. package/dist/types/schemas/dictionary.schema.d.ts +6 -6
  179. package/dist/types/schemas/dictionary.schema.d.ts.map +1 -1
  180. package/dist/types/schemas/discussion.schema.d.ts +6 -6
  181. package/dist/types/schemas/oAuth2.schema.d.ts +5 -5
  182. package/dist/types/schemas/organization.schema.d.ts +6 -6
  183. package/dist/types/schemas/organization.schema.d.ts.map +1 -1
  184. package/dist/types/schemas/plans.schema.d.ts +6 -6
  185. package/dist/types/schemas/project.schema.d.ts +6 -6
  186. package/dist/types/schemas/session.schema.d.ts +6 -6
  187. package/dist/types/schemas/tag.schema.d.ts +6 -6
  188. package/dist/types/schemas/user.schema.d.ts +6 -6
  189. package/dist/types/services/email.service.d.ts +10 -10
  190. package/dist/types/utils/accessControl.d.ts +1 -1
  191. package/dist/types/utils/accessControl.d.ts.map +1 -1
  192. package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts +2 -2
  193. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +2 -2
  194. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts +2 -2
  195. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +2 -2
  196. package/dist/types/utils/mongoDB/connectDB.d.ts +2 -2
  197. package/dist/types/utils/mongoDB/connectDB.d.ts.map +1 -1
  198. package/package.json +15 -16
@@ -1 +1 @@
1
- {"version":3,"file":"organization.schema.cjs","names":["Schema","NAME_MIN_LENGTH","NAME_MAX_LENGTH","MEMBERS_MIN_LENGTH","planSchema"],"sources":["../../../src/schemas/organization.schema.ts"],"sourcesContent":["import {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateOrganization';\nimport { Schema } from 'mongoose';\nimport type { OrganizationSchema } from '@/types/organization.types';\nimport { planSchema } from './plans.schema';\n\nexport const organizationSchema = new Schema<OrganizationSchema>(\n {\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n plan: {\n type: planSchema,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\n// Add virtual field for id\norganizationSchema.virtual('id').get(function () {\n return this._id.toString();\n});\n"],"mappings":";;;;;;;AASA,MAAa,qBAAqB,IAAIA,gBACpC;CACE,MAAM;EACJ,MAAM;EACN,UAAU;EACV,WAAWC;EACX,WAAWC;EACZ;CACD,YAAY;EACV,MAAM,CAACF,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWG;EACZ;CACD,WAAW;EACT,MAAM,CAACH,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWG;EACZ;CACD,WAAW;EACT,MAAMH,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,MAAM,EACJ,MAAMI,yCACP;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF;AAGD,mBAAmB,QAAQ,KAAK,CAAC,IAAI,WAAY;AAC/C,QAAO,KAAK,IAAI,UAAU;EAC1B"}
1
+ {"version":3,"file":"organization.schema.cjs","names":["Schema","NAME_MIN_LENGTH","NAME_MAX_LENGTH","MEMBERS_MIN_LENGTH","planSchema"],"sources":["../../../src/schemas/organization.schema.ts"],"sourcesContent":["import {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateOrganization';\nimport { Schema } from 'mongoose';\nimport type { OrganizationSchema } from '@/types/organization.types';\nimport { planSchema } from './plans.schema';\n\nexport const organizationSchema = new Schema<OrganizationSchema>(\n {\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n plan: {\n type: planSchema,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n\n// Add virtual field for id\norganizationSchema.virtual('id').get(function () {\n return this._id.toString();\n});\n"],"mappings":";;;;;;AASA,MAAa,qBAAqB,IAAIA,gBACpC;CACE,MAAM;EACJ,MAAM;EACN,UAAU;EACV,WAAWC;EACX,WAAWC;EACZ;CACD,YAAY;EACV,MAAM,CAACF,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWG;EACZ;CACD,WAAW;EACT,MAAM,CAACH,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWG;EACZ;CACD,WAAW;EACT,MAAMH,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,MAAM,EACJ,MAAMI,yCACP;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF;AAGD,mBAAmB,QAAQ,KAAK,CAAC,IAAI,WAAY;AAC/C,QAAO,KAAK,IAAI,UAAU;EAC1B"}
@@ -1,6 +1,5 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  let mongoose = require("mongoose");
3
- mongoose = require_rolldown_runtime.__toESM(mongoose);
4
3
 
5
4
  //#region src/schemas/plans.schema.ts
6
5
  const planSchema = new mongoose.Schema({
@@ -1 +1 @@
1
- {"version":3,"file":"plans.schema.cjs","names":["Schema"],"sources":["../../../src/schemas/plans.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type { PlanSchema } from '@/types/plan.types';\n\nexport const planSchema = new Schema<PlanSchema>(\n {\n type: {\n type: String,\n required: true,\n enum: ['PREMIUM', 'ENTERPRISE'],\n },\n period: {\n type: String,\n required: true,\n enum: ['MONTHLY', 'YEARLY'],\n default: 'MONTHLY',\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n subscriptionId: {\n type: String,\n required: true,\n },\n customerId: {\n type: String,\n required: true,\n },\n priceId: {\n type: String,\n required: true,\n },\n status: {\n type: String,\n required: true,\n enum: [\n 'active',\n 'canceled',\n 'past_due',\n 'unpaid',\n 'incomplete',\n 'incomplete_expired',\n 'paused',\n 'trialing',\n ],\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;AAGA,MAAa,aAAa,IAAIA,gBAC5B;CACE,MAAM;EACJ,MAAM;EACN,UAAU;EACV,MAAM,CAAC,WAAW,aAAa;EAChC;CACD,QAAQ;EACN,MAAM;EACN,UAAU;EACV,MAAM,CAAC,WAAW,SAAS;EAC3B,SAAS;EACV;CACD,WAAW;EACT,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,gBAAgB;EACd,MAAM;EACN,UAAU;EACX;CACD,YAAY;EACV,MAAM;EACN,UAAU;EACX;CACD,SAAS;EACP,MAAM;EACN,UAAU;EACX;CACD,QAAQ;EACN,MAAM;EACN,UAAU;EACV,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EACF;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
1
+ {"version":3,"file":"plans.schema.cjs","names":["Schema"],"sources":["../../../src/schemas/plans.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type { PlanSchema } from '@/types/plan.types';\n\nexport const planSchema = new Schema<PlanSchema>(\n {\n type: {\n type: String,\n required: true,\n enum: ['PREMIUM', 'ENTERPRISE'],\n },\n period: {\n type: String,\n required: true,\n enum: ['MONTHLY', 'YEARLY'],\n default: 'MONTHLY',\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n subscriptionId: {\n type: String,\n required: true,\n },\n customerId: {\n type: String,\n required: true,\n },\n priceId: {\n type: String,\n required: true,\n },\n status: {\n type: String,\n required: true,\n enum: [\n 'active',\n 'canceled',\n 'past_due',\n 'unpaid',\n 'incomplete',\n 'incomplete_expired',\n 'paused',\n 'trialing',\n ],\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;AAGA,MAAa,aAAa,IAAIA,gBAC5B;CACE,MAAM;EACJ,MAAM;EACN,UAAU;EACV,MAAM,CAAC,WAAW,aAAa;EAChC;CACD,QAAQ;EACN,MAAM;EACN,UAAU;EACV,MAAM,CAAC,WAAW,SAAS;EAC3B,SAAS;EACV;CACD,WAAW;EACT,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,gBAAgB;EACd,MAAM;EACN,UAAU;EACX;CACD,YAAY;EACV,MAAM;EACN,UAAU;EACX;CACD,SAAS;EACP,MAAM;EACN,UAAU;EACX;CACD,QAAQ;EACN,MAAM;EACN,UAAU;EACV,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EACF;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
@@ -1,9 +1,7 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_utils_validation_validateProject = require('../utils/validation/validateProject.cjs');
3
3
  let mongoose = require("mongoose");
4
- mongoose = require_rolldown_runtime.__toESM(mongoose);
5
4
  let __intlayer_types = require("@intlayer/types");
6
- __intlayer_types = require_rolldown_runtime.__toESM(__intlayer_types);
7
5
 
8
6
  //#region src/schemas/project.schema.ts
9
7
  const oAuth2AccessSchema = new mongoose.Schema({
@@ -1 +1 @@
1
- {"version":3,"file":"project.schema.cjs","names":["Schema","Locales","NAME_MIN_LENGTH","NAME_MAX_LENGTH","MEMBERS_MIN_LENGTH"],"sources":["../../../src/schemas/project.schema.ts"],"sourcesContent":["import { Locales } from '@intlayer/types';\nimport type { RenameId } from '@utils/mongoDB/types';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateProject';\nimport { Schema } from 'mongoose';\nimport type {\n OAuth2Access,\n Project,\n ProjectSchema,\n} from '@/types/project.types';\n\n// Define the oAuth2Access subdocument schema with timestamps\nconst oAuth2AccessSchema = new Schema<RenameId<OAuth2Access>>(\n {\n clientId: { type: String, required: true },\n clientSecret: { type: String, required: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n name: { type: String, required: true },\n expiresAt: { type: Date },\n accessToken: { type: [String], required: true, default: [] },\n grants: { type: [String], required: true, default: [] },\n },\n {\n timestamps: true,\n }\n);\n\nconst projectConfigSchema = new Schema<Project['configuration']>(\n {\n internationalization: {\n locales: {\n type: [String],\n enum: Object.values(Locales.ALL_LOCALES),\n required: true,\n },\n defaultLocale: {\n type: String,\n enum: Object.values(Locales.ALL_LOCALES),\n },\n },\n editor: {\n applicationURL: {\n type: String,\n },\n cmsURL: {\n type: String,\n },\n },\n },\n {\n _id: false, // Prevents the generation of an _id field for this subdocument\n }\n);\n\nexport const projectSchema = new Schema<ProjectSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n configuration: projectConfigSchema,\n oAuth2Access: [oAuth2AccessSchema],\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;;;;AAeA,MAAM,qBAAqB,IAAIA,gBAC7B;CACE,UAAU;EAAE,MAAM;EAAQ,UAAU;EAAM;CAC1C,cAAc;EAAE,MAAM;EAAQ,UAAU;EAAM;CAC9C,QAAQ;EAAE,MAAMA,gBAAO,MAAM;EAAU,KAAK;EAAQ,UAAU;EAAM;CACpE,MAAM;EAAE,MAAM;EAAQ,UAAU;EAAM;CACtC,WAAW,EAAE,MAAM,MAAM;CACzB,aAAa;EAAE,MAAM,CAAC,OAAO;EAAE,UAAU;EAAM,SAAS,EAAE;EAAE;CAC5D,QAAQ;EAAE,MAAM,CAAC,OAAO;EAAE,UAAU;EAAM,SAAS,EAAE;EAAE;CACxD,EACD,EACE,YAAY,MACb,CACF;AAED,MAAM,sBAAsB,IAAIA,gBAC9B;CACE,sBAAsB;EACpB,SAAS;GACP,MAAM,CAAC,OAAO;GACd,MAAM,OAAO,OAAOC,yBAAQ,YAAY;GACxC,UAAU;GACX;EACD,eAAe;GACb,MAAM;GACN,MAAM,OAAO,OAAOA,yBAAQ,YAAY;GACzC;EACF;CACD,QAAQ;EACN,gBAAgB,EACd,MAAM,QACP;EACD,QAAQ,EACN,MAAM,QACP;EACF;CACF,EACD,EACE,KAAK,OACN,CACF;AAED,MAAa,gBAAgB,IAAID,gBAC/B;CACE,gBAAgB;EACd,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,MAAM;EACJ,MAAM;EACN,UAAU;EACV,WAAWE;EACX,WAAWC;EACZ;CACD,eAAe;CACf,cAAc,CAAC,mBAAmB;CAClC,YAAY;EACV,MAAM,CAACH,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWI;EACZ;CACD,WAAW;EACT,MAAM,CAACJ,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWI;EACZ;CACD,WAAW;EACT,MAAMJ,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
1
+ {"version":3,"file":"project.schema.cjs","names":["Schema","Locales","NAME_MIN_LENGTH","NAME_MAX_LENGTH","MEMBERS_MIN_LENGTH"],"sources":["../../../src/schemas/project.schema.ts"],"sourcesContent":["import { Locales } from '@intlayer/types';\nimport type { RenameId } from '@utils/mongoDB/types';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateProject';\nimport { Schema } from 'mongoose';\nimport type {\n OAuth2Access,\n Project,\n ProjectSchema,\n} from '@/types/project.types';\n\n// Define the oAuth2Access subdocument schema with timestamps\nconst oAuth2AccessSchema = new Schema<RenameId<OAuth2Access>>(\n {\n clientId: { type: String, required: true },\n clientSecret: { type: String, required: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n name: { type: String, required: true },\n expiresAt: { type: Date },\n accessToken: { type: [String], required: true, default: [] },\n grants: { type: [String], required: true, default: [] },\n },\n {\n timestamps: true,\n }\n);\n\nconst projectConfigSchema = new Schema<Project['configuration']>(\n {\n internationalization: {\n locales: {\n type: [String],\n enum: Object.values(Locales.ALL_LOCALES),\n required: true,\n },\n defaultLocale: {\n type: String,\n enum: Object.values(Locales.ALL_LOCALES),\n },\n },\n editor: {\n applicationURL: {\n type: String,\n },\n cmsURL: {\n type: String,\n },\n },\n },\n {\n _id: false, // Prevents the generation of an _id field for this subdocument\n }\n);\n\nexport const projectSchema = new Schema<ProjectSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n configuration: projectConfigSchema,\n oAuth2Access: [oAuth2AccessSchema],\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;;AAeA,MAAM,qBAAqB,IAAIA,gBAC7B;CACE,UAAU;EAAE,MAAM;EAAQ,UAAU;EAAM;CAC1C,cAAc;EAAE,MAAM;EAAQ,UAAU;EAAM;CAC9C,QAAQ;EAAE,MAAMA,gBAAO,MAAM;EAAU,KAAK;EAAQ,UAAU;EAAM;CACpE,MAAM;EAAE,MAAM;EAAQ,UAAU;EAAM;CACtC,WAAW,EAAE,MAAM,MAAM;CACzB,aAAa;EAAE,MAAM,CAAC,OAAO;EAAE,UAAU;EAAM,SAAS,EAAE;EAAE;CAC5D,QAAQ;EAAE,MAAM,CAAC,OAAO;EAAE,UAAU;EAAM,SAAS,EAAE;EAAE;CACxD,EACD,EACE,YAAY,MACb,CACF;AAED,MAAM,sBAAsB,IAAIA,gBAC9B;CACE,sBAAsB;EACpB,SAAS;GACP,MAAM,CAAC,OAAO;GACd,MAAM,OAAO,OAAOC,yBAAQ,YAAY;GACxC,UAAU;GACX;EACD,eAAe;GACb,MAAM;GACN,MAAM,OAAO,OAAOA,yBAAQ,YAAY;GACzC;EACF;CACD,QAAQ;EACN,gBAAgB,EACd,MAAM,QACP;EACD,QAAQ,EACN,MAAM,QACP;EACF;CACF,EACD,EACE,KAAK,OACN,CACF;AAED,MAAa,gBAAgB,IAAID,gBAC/B;CACE,gBAAgB;EACd,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,MAAM;EACJ,MAAM;EACN,UAAU;EACV,WAAWE;EACX,WAAWC;EACZ;CACD,eAAe;CACf,cAAc,CAAC,mBAAmB;CAClC,YAAY;EACV,MAAM,CAACH,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWI;EACZ;CACD,WAAW;EACT,MAAM,CAACJ,gBAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAWI;EACZ;CACD,WAAW;EACT,MAAMJ,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
@@ -1,6 +1,5 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  let mongoose = require("mongoose");
3
- mongoose = require_rolldown_runtime.__toESM(mongoose);
4
3
 
5
4
  //#region src/schemas/session.schema.ts
6
5
  const sessionSchema = new mongoose.Schema({
@@ -1 +1 @@
1
- {"version":3,"file":"session.schema.cjs","names":["Schema"],"sources":["../../../src/schemas/session.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type { SessionSchema } from '@/types/session.types';\n\nexport const sessionSchema = new Schema<SessionSchema>(\n {\n activeOrganizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: false,\n },\n activeProjectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;AAGA,MAAa,gBAAgB,IAAIA,gBAC/B;CACE,sBAAsB;EACpB,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,iBAAiB;EACf,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
1
+ {"version":3,"file":"session.schema.cjs","names":["Schema"],"sources":["../../../src/schemas/session.schema.ts"],"sourcesContent":["import { Schema } from 'mongoose';\nimport type { SessionSchema } from '@/types/session.types';\n\nexport const sessionSchema = new Schema<SessionSchema>(\n {\n activeOrganizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: false,\n },\n activeProjectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;AAGA,MAAa,gBAAgB,IAAIA,gBAC/B;CACE,sBAAsB;EACpB,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,iBAAiB;EACf,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
@@ -1,7 +1,6 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_utils_validation_validateTag = require('../utils/validation/validateTag.cjs');
3
3
  let mongoose = require("mongoose");
4
- mongoose = require_rolldown_runtime.__toESM(mongoose);
5
4
 
6
5
  //#region src/schemas/tag.schema.ts
7
6
  const tagSchema = new mongoose.Schema({
@@ -1 +1 @@
1
- {"version":3,"file":"tag.schema.cjs","names":["Schema","KEY_MIN_LENGTH","KEY_MAX_LENGTH","NAME_MIN_LENGTH","NAME_MAX_LENGTH"],"sources":["../../../src/schemas/tag.schema.ts"],"sourcesContent":["import {\n KEY_MAX_LENGTH,\n KEY_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateTag';\nimport { Schema } from 'mongoose';\nimport type { TagSchema } from '@/types/tag.types';\n\nexport const tagSchema = new Schema<TagSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n projectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: true,\n },\n key: {\n type: String,\n required: true,\n minlength: KEY_MIN_LENGTH,\n maxlength: KEY_MAX_LENGTH,\n },\n name: {\n type: String,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n description: {\n type: String,\n },\n instructions: {\n type: String,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;;AASA,MAAa,YAAY,IAAIA,gBAC3B;CACE,gBAAgB;EACd,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,WAAW;EACT,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,KAAK;EACH,MAAM;EACN,UAAU;EACV,WAAWC;EACX,WAAWC;EACZ;CACD,MAAM;EACJ,MAAM;EACN,WAAWC;EACX,WAAWC;EACZ;CACD,aAAa,EACX,MAAM,QACP;CACD,cAAc,EACZ,MAAM,QACP;CACD,WAAW;EACT,MAAMJ,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
1
+ {"version":3,"file":"tag.schema.cjs","names":["Schema","KEY_MIN_LENGTH","KEY_MAX_LENGTH","NAME_MIN_LENGTH","NAME_MAX_LENGTH"],"sources":["../../../src/schemas/tag.schema.ts"],"sourcesContent":["import {\n KEY_MAX_LENGTH,\n KEY_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateTag';\nimport { Schema } from 'mongoose';\nimport type { TagSchema } from '@/types/tag.types';\n\nexport const tagSchema = new Schema<TagSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n projectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: true,\n },\n key: {\n type: String,\n required: true,\n minlength: KEY_MIN_LENGTH,\n maxlength: KEY_MAX_LENGTH,\n },\n name: {\n type: String,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n description: {\n type: String,\n },\n instructions: {\n type: String,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;AASA,MAAa,YAAY,IAAIA,gBAC3B;CACE,gBAAgB;EACd,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,WAAW;EACT,MAAMA,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,KAAK;EACH,MAAM;EACN,UAAU;EACV,WAAWC;EACX,WAAWC;EACZ;CACD,MAAM;EACJ,MAAM;EACN,WAAWC;EACX,WAAWC;EACZ;CACD,aAAa,EACX,MAAM,QACP;CACD,cAAc,EACZ,MAAM,QACP;CACD,WAAW;EACT,MAAMJ,gBAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
@@ -1,7 +1,6 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_utils_validation_validateUser = require('../utils/validation/validateUser.cjs');
3
3
  let mongoose = require("mongoose");
4
- mongoose = require_rolldown_runtime.__toESM(mongoose);
5
4
  let validator = require("validator");
6
5
  validator = require_rolldown_runtime.__toESM(validator);
7
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"user.schema.cjs","names":["Schema","NAMES_MAX_LENGTH","NAMES_MIN_LENGTH"],"sources":["../../../src/schemas/user.schema.ts"],"sourcesContent":["import {\n NAMES_MAX_LENGTH,\n NAMES_MIN_LENGTH,\n} from '@utils/validation/validateUser';\nimport { Schema } from 'mongoose';\nimport validator from 'validator';\nimport type { UserSchema } from '@/types/user.types';\n\nexport const userSchema = new Schema<UserSchema>(\n {\n email: {\n type: String,\n required: true,\n unique: true,\n validate: [validator.isEmail, 'Please fill a valid email address'],\n lowercase: true,\n trim: true,\n },\n name: {\n type: String,\n maxlength: NAMES_MAX_LENGTH,\n minlength: NAMES_MIN_LENGTH,\n },\n phone: {\n type: String,\n maxlength: 20,\n },\n\n customerId: {\n type: String,\n required: false,\n },\n\n emailsList: {\n type: {\n newsLetter: {\n type: Boolean,\n default: false,\n },\n },\n required: false,\n },\n role: {\n type: String,\n enum: ['admin', 'user'],\n default: 'user',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;;;;AAQA,MAAa,aAAa,IAAIA,gBAC5B;CACE,OAAO;EACL,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU,CAAC,kBAAU,SAAS,oCAAoC;EAClE,WAAW;EACX,MAAM;EACP;CACD,MAAM;EACJ,MAAM;EACN,WAAWC;EACX,WAAWC;EACZ;CACD,OAAO;EACL,MAAM;EACN,WAAW;EACZ;CAED,YAAY;EACV,MAAM;EACN,UAAU;EACX;CAED,YAAY;EACV,MAAM,EACJ,YAAY;GACV,MAAM;GACN,SAAS;GACV,EACF;EACD,UAAU;EACX;CACD,MAAM;EACJ,MAAM;EACN,MAAM,CAAC,SAAS,OAAO;EACvB,SAAS;EACT,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
1
+ {"version":3,"file":"user.schema.cjs","names":["Schema","NAMES_MAX_LENGTH","NAMES_MIN_LENGTH"],"sources":["../../../src/schemas/user.schema.ts"],"sourcesContent":["import {\n NAMES_MAX_LENGTH,\n NAMES_MIN_LENGTH,\n} from '@utils/validation/validateUser';\nimport { Schema } from 'mongoose';\nimport validator from 'validator';\nimport type { UserSchema } from '@/types/user.types';\n\nexport const userSchema = new Schema<UserSchema>(\n {\n email: {\n type: String,\n required: true,\n unique: true,\n validate: [validator.isEmail, 'Please fill a valid email address'],\n lowercase: true,\n trim: true,\n },\n name: {\n type: String,\n maxlength: NAMES_MAX_LENGTH,\n minlength: NAMES_MIN_LENGTH,\n },\n phone: {\n type: String,\n maxlength: 20,\n },\n\n customerId: {\n type: String,\n required: false,\n },\n\n emailsList: {\n type: {\n newsLetter: {\n type: Boolean,\n default: false,\n },\n },\n required: false,\n },\n role: {\n type: String,\n enum: ['admin', 'user'],\n default: 'user',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;;;AAQA,MAAa,aAAa,IAAIA,gBAC5B;CACE,OAAO;EACL,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU,CAAC,kBAAU,SAAS,oCAAoC;EAClE,WAAW;EACX,MAAM;EACP;CACD,MAAM;EACJ,MAAM;EACN,WAAWC;EACX,WAAWC;EACZ;CACD,OAAO;EACL,MAAM;EACN,WAAW;EACZ;CAED,YAAY;EACV,MAAM;EACN,UAAU;EACX;CAED,YAAY;EACV,MAAM,EACJ,YAAY;GACV,MAAM;GACN,SAAS;GACV,EACF;EACD,UAAU;EACX;CACD,MAAM;EACJ,MAAM;EACN,MAAM,CAAC,SAAS,OAAO;EACvB,SAAS;EACT,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,IAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
@@ -5,7 +5,6 @@ const require_utils_errors_ErrorsClass = require('../utils/errors/ErrorsClass.cj
5
5
  const require_utils_removeObjectKeys = require('../utils/removeObjectKeys.cjs');
6
6
  const require_utils_validation_validateDictionary = require('../utils/validation/validateDictionary.cjs');
7
7
  let mongoose = require("mongoose");
8
- mongoose = require_rolldown_runtime.__toESM(mongoose);
9
8
 
10
9
  //#region src/services/dictionary.service.ts
11
10
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dictionary.service.cjs","names":["DictionaryModel","Types","GenericError","validateDictionary","existingDictionariesKey: string[]","newDictionariesKey: string[]","removeObjectKeys","ensureMongoDocumentToObject"],"sources":["../../../src/services/dictionary.service.ts"],"sourcesContent":["import { DictionaryModel } from '@models/dictionary.model';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { GenericError } from '@utils/errors';\nimport type { DictionaryFilters } from '@utils/filtersAndPagination/getDictionaryFiltersAndPagination';\nimport { removeObjectKeys } from '@utils/removeObjectKeys';\nimport {\n type DictionaryFields,\n validateDictionary,\n} from '@utils/validation/validateDictionary';\nimport { Types } from 'mongoose';\nimport type {\n Dictionary,\n DictionaryData,\n DictionaryDocument,\n} from '@/types/dictionary.types';\nimport type { Project } from '@/types/project.types';\n\n/**\n * Finds dictionaries based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of dictionaries matching the filters.\n */\nexport const findDictionaries = async (\n filters: DictionaryFilters,\n skip = 0,\n limit = 100,\n sortOptions?: Record<string, 1 | -1>\n): Promise<DictionaryDocument[]> => {\n try {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the filters\n { $match: filters },\n\n // Stage 2: Sort if provided (default handled in filter builder)\n ...(sortOptions && Object.keys(sortOptions).length > 0\n ? [{ $sort: sortOptions }]\n : []),\n\n // Stage 3: Skip for pagination\n { $skip: skip },\n\n // Stage 4: Limit the number of documents\n { $limit: limit },\n ]);\n\n const formattedResults = dictionaries.map(\n (result) => new DictionaryModel(result)\n );\n\n return formattedResults;\n } catch (error) {\n console.error('Error fetching dictionaries:', error);\n throw error;\n }\n};\n\n/**\n * Finds a dictionary by its ID.\n * @param dictionaryId - The ID of the dictionary to find.\n * @returns The dictionary matching the ID.\n */\n/**\n * Finds a dictionary by its ID and includes the 'versions' field.\n * @param dictionaryId - The ID of the dictionary to find.\n * @returns The dictionary matching the ID with available versions.\n */\nexport const getDictionaryById = async (\n dictionaryId: string | Types.ObjectId\n): Promise<DictionaryDocument> => {\n const id = Types.ObjectId.isValid(dictionaryId as string)\n ? new Types.ObjectId(dictionaryId as string)\n : dictionaryId;\n\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by ID\n { $match: { _id: id } },\n\n // Stage 2: Add the 'versions' field\n {\n $addFields: {\n versions: {\n $map: {\n input: { $objectToArray: '$content' },\n as: 'version',\n in: '$$version.k',\n },\n },\n },\n },\n ]);\n\n if (!dictionaries.length) {\n throw new GenericError('DICTIONARY_NOT_FOUND', { dictionaryId });\n }\n\n return new DictionaryModel(dictionaries[0]);\n};\n\n/**\n * Finds a dictionary by its ID.\n * @param dictionaryKey - The ID of the dictionary to find.\n * @returns The dictionary matching the ID.\n */\nexport const getDictionaryByKey = async (\n dictionaryKey: string,\n projectId: string | Types.ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaries = await getDictionariesByKeys([dictionaryKey], projectId);\n\n return dictionaries[0];\n};\n\nexport const getDictionariesByKeys = async (\n dictionaryKeys: string[],\n projectId: string | Types.ObjectId\n): Promise<DictionaryDocument[]> => {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by key\n { $match: { key: { $in: dictionaryKeys }, projectIds: projectId } },\n\n // Stage 2: Add the 'versions' field\n {\n $addFields: {\n versions: {\n $map: {\n input: { $objectToArray: '$content' },\n as: 'version',\n in: '$$version.k',\n },\n },\n },\n },\n ]);\n\n if (!dictionaries) {\n throw new GenericError('DICTIONARY_NOT_FOUND', {\n dictionaryKeys,\n projectId,\n });\n }\n\n const formattedResults = dictionaries.map(\n (result) => new DictionaryModel(result)\n );\n\n return formattedResults;\n};\n\nexport const getDictionariesByTags = async (\n tags: string[],\n projectId: string | Project['id']\n): Promise<DictionaryDocument[]> => {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by tags\n {\n $match: {\n tags: { $in: tags },\n projectIds: projectId,\n },\n },\n\n // Stage 2: Add the 'versions' field\n {\n $addFields: {\n versions: {\n $map: {\n input: { $objectToArray: '$content' },\n as: 'version',\n in: '$$version.k',\n },\n },\n },\n },\n ]);\n\n const formattedResults = dictionaries.map(\n (result) => new DictionaryModel(result)\n );\n\n return formattedResults;\n};\n\n/**\n * Counts the total number of dictionaries that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of dictionaries.\n */\nexport const countDictionaries = async (\n filters: DictionaryFilters\n): Promise<number> => {\n const result = await DictionaryModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('DICTIONARY_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new dictionary in the database.\n * @param dictionary - The dictionary data to create.\n * @returns The created dictionary.\n */\nexport const createDictionary = async (\n dictionary: DictionaryData\n): Promise<DictionaryDocument> => {\n const errors = await validateDictionary(dictionary);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('DICTIONARY_INVALID_FIELDS', {\n errors,\n });\n }\n\n return await DictionaryModel.create(dictionary);\n};\n\ntype GetExistingDictionaryResult = {\n existingDictionariesKey: string[];\n newDictionariesKey: string[];\n};\n\n/**\n * Gets the existing dictionaries from the provided list of keys.\n * @param dictionariesKeys - List of dictionary keys to check.\n * @param projectId - The ID of the project to check the dictionaries against.\n * @returns The existing dictionaries and the new dictionaries.\n */\nexport const getExistingDictionaryKey = async (\n dictionariesKeys: string[],\n projectId: string | Types.ObjectId\n): Promise<GetExistingDictionaryResult> => {\n // Fetch dictionaries from the database where the key is in the provided list\n const existingDictionaries = await DictionaryModel.find({\n key: { $in: dictionariesKeys },\n projectIds: projectId,\n });\n\n // Map existing dictionaries to a LocalDictionary object\n const existingDictionariesKey: string[] = [];\n const newDictionariesKey: string[] = [];\n\n for (const key of dictionariesKeys) {\n const isDictionaryExist = existingDictionaries.some(\n (dictionary) => dictionary.key === key\n );\n\n if (isDictionaryExist) {\n existingDictionariesKey.push(key);\n } else {\n newDictionariesKey.push(key);\n }\n }\n\n return { existingDictionariesKey, newDictionariesKey };\n};\n\n/**\n * Updates an existing dictionary in the database by its ID.\n * @param dictionaryId - The ID of the dictionary to update.\n * @param dictionary - The updated dictionary data.\n * @returns The updated dictionary.\n */\nexport const updateDictionaryById = async (\n dictionaryId: string | Types.ObjectId,\n dictionary: Partial<Dictionary>\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, [\n 'id',\n ]) as unknown as Partial<Dictionary>;\n\n const updatedKeys = Object.keys(dictionaryToUpdate) as DictionaryFields;\n const errors = await validateDictionary(dictionaryToUpdate, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('DICTIONARY_INVALID_FIELDS', {\n dictionaryId,\n errors,\n });\n }\n\n const result = await DictionaryModel.updateOne(\n { _id: dictionaryId },\n dictionaryToUpdate\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('DICTIONARY_UPDATE_FAILED', { dictionaryId });\n }\n\n const updatedDictionary = await getDictionaryById(dictionaryId);\n\n return updatedDictionary;\n};\n\n/**\n * Updates an existing dictionary in the database by its key.\n * @param dictionaryKey - The ID of the dictionary to update.\n * @param dictionary - The updated dictionary data.\n * @returns The updated dictionary.\n */\nexport const updateDictionaryByKey = async (\n dictionaryKey: string,\n dictionary: Partial<Dictionary>,\n projectId: string | Types.ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, [\n 'id',\n ]) as unknown as Partial<Dictionary>;\n\n const updatedKeys = Object.keys(dictionaryToUpdate) as DictionaryFields;\n const errors = await validateDictionary(dictionaryToUpdate, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('DICTIONARY_INVALID_FIELDS', {\n dictionaryKey,\n projectId,\n errors,\n });\n }\n\n const result = await DictionaryModel.updateOne(\n { key: dictionaryKey, projectIds: projectId },\n dictionaryToUpdate\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('DICTIONARY_UPDATE_FAILED', { dictionaryKey });\n }\n\n const updatedDictionary = await getDictionaryByKey(dictionaryKey, projectId);\n\n return updatedDictionary;\n};\n\n/**\n * Deletes a dictionary from the database by its ID.\n * @param dictionaryId - The ID of the dictionary to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteDictionaryById = async (\n dictionaryId: string\n): Promise<DictionaryDocument> => {\n const dictionary = await DictionaryModel.findByIdAndDelete(dictionaryId);\n\n if (!dictionary) {\n throw new GenericError('DICTIONARY_NOT_FOUND', { dictionaryId });\n }\n\n return dictionary;\n};\n\n// Function to extract the numeric part of the version\nconst getVersionNumber = (version: string): number => {\n const match = version.match(/^v(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid version format: ${version}`);\n }\n return parseInt(match[1], 10);\n};\n\nexport const incrementVersion = (dictionary: Dictionary): string => {\n const VERSION_PREFIX = 'v';\n\n const versions = [...(dictionary.content.keys() ?? [])];\n const lastVersion = versions[versions.length - 1];\n\n // Start with the next version number\n let newNumber = getVersionNumber(lastVersion) + 1;\n let newVersion = `${VERSION_PREFIX}${newNumber}`;\n\n // Loop until a unique version is found\n while (versions.includes(newVersion)) {\n newNumber += 1;\n newVersion = `${VERSION_PREFIX}${newNumber}`;\n }\n\n return newVersion;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"dictionary.service.cjs","names":["DictionaryModel","Types","GenericError","validateDictionary","existingDictionariesKey: string[]","newDictionariesKey: string[]","removeObjectKeys","ensureMongoDocumentToObject"],"sources":["../../../src/services/dictionary.service.ts"],"sourcesContent":["import { DictionaryModel } from '@models/dictionary.model';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { GenericError } from '@utils/errors';\nimport type { DictionaryFilters } from '@utils/filtersAndPagination/getDictionaryFiltersAndPagination';\nimport { removeObjectKeys } from '@utils/removeObjectKeys';\nimport {\n type DictionaryFields,\n validateDictionary,\n} from '@utils/validation/validateDictionary';\nimport { Types } from 'mongoose';\nimport type {\n Dictionary,\n DictionaryData,\n DictionaryDocument,\n} from '@/types/dictionary.types';\nimport type { Project } from '@/types/project.types';\n\n/**\n * Finds dictionaries based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of dictionaries matching the filters.\n */\nexport const findDictionaries = async (\n filters: DictionaryFilters,\n skip = 0,\n limit = 100,\n sortOptions?: Record<string, 1 | -1>\n): Promise<DictionaryDocument[]> => {\n try {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the filters\n { $match: filters },\n\n // Stage 2: Sort if provided (default handled in filter builder)\n ...(sortOptions && Object.keys(sortOptions).length > 0\n ? [{ $sort: sortOptions }]\n : []),\n\n // Stage 3: Skip for pagination\n { $skip: skip },\n\n // Stage 4: Limit the number of documents\n { $limit: limit },\n ]);\n\n const formattedResults = dictionaries.map(\n (result) => new DictionaryModel(result)\n );\n\n return formattedResults;\n } catch (error) {\n console.error('Error fetching dictionaries:', error);\n throw error;\n }\n};\n\n/**\n * Finds a dictionary by its ID.\n * @param dictionaryId - The ID of the dictionary to find.\n * @returns The dictionary matching the ID.\n */\n/**\n * Finds a dictionary by its ID and includes the 'versions' field.\n * @param dictionaryId - The ID of the dictionary to find.\n * @returns The dictionary matching the ID with available versions.\n */\nexport const getDictionaryById = async (\n dictionaryId: string | Types.ObjectId\n): Promise<DictionaryDocument> => {\n const id = Types.ObjectId.isValid(dictionaryId as string)\n ? new Types.ObjectId(dictionaryId as string)\n : dictionaryId;\n\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by ID\n { $match: { _id: id } },\n\n // Stage 2: Add the 'versions' field\n {\n $addFields: {\n versions: {\n $map: {\n input: { $objectToArray: '$content' },\n as: 'version',\n in: '$$version.k',\n },\n },\n },\n },\n ]);\n\n if (!dictionaries.length) {\n throw new GenericError('DICTIONARY_NOT_FOUND', { dictionaryId });\n }\n\n return new DictionaryModel(dictionaries[0]);\n};\n\n/**\n * Finds a dictionary by its ID.\n * @param dictionaryKey - The ID of the dictionary to find.\n * @returns The dictionary matching the ID.\n */\nexport const getDictionaryByKey = async (\n dictionaryKey: string,\n projectId: string | Types.ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaries = await getDictionariesByKeys([dictionaryKey], projectId);\n\n return dictionaries[0];\n};\n\nexport const getDictionariesByKeys = async (\n dictionaryKeys: string[],\n projectId: string | Types.ObjectId\n): Promise<DictionaryDocument[]> => {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by key\n { $match: { key: { $in: dictionaryKeys }, projectIds: projectId } },\n\n // Stage 2: Add the 'versions' field\n {\n $addFields: {\n versions: {\n $map: {\n input: { $objectToArray: '$content' },\n as: 'version',\n in: '$$version.k',\n },\n },\n },\n },\n ]);\n\n if (!dictionaries) {\n throw new GenericError('DICTIONARY_NOT_FOUND', {\n dictionaryKeys,\n projectId,\n });\n }\n\n const formattedResults = dictionaries.map(\n (result) => new DictionaryModel(result)\n );\n\n return formattedResults;\n};\n\nexport const getDictionariesByTags = async (\n tags: string[],\n projectId: string | Project['id']\n): Promise<DictionaryDocument[]> => {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by tags\n {\n $match: {\n tags: { $in: tags },\n projectIds: projectId,\n },\n },\n\n // Stage 2: Add the 'versions' field\n {\n $addFields: {\n versions: {\n $map: {\n input: { $objectToArray: '$content' },\n as: 'version',\n in: '$$version.k',\n },\n },\n },\n },\n ]);\n\n const formattedResults = dictionaries.map(\n (result) => new DictionaryModel(result)\n );\n\n return formattedResults;\n};\n\n/**\n * Counts the total number of dictionaries that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of dictionaries.\n */\nexport const countDictionaries = async (\n filters: DictionaryFilters\n): Promise<number> => {\n const result = await DictionaryModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('DICTIONARY_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new dictionary in the database.\n * @param dictionary - The dictionary data to create.\n * @returns The created dictionary.\n */\nexport const createDictionary = async (\n dictionary: DictionaryData\n): Promise<DictionaryDocument> => {\n const errors = await validateDictionary(dictionary);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('DICTIONARY_INVALID_FIELDS', {\n errors,\n });\n }\n\n return await DictionaryModel.create(dictionary);\n};\n\ntype GetExistingDictionaryResult = {\n existingDictionariesKey: string[];\n newDictionariesKey: string[];\n};\n\n/**\n * Gets the existing dictionaries from the provided list of keys.\n * @param dictionariesKeys - List of dictionary keys to check.\n * @param projectId - The ID of the project to check the dictionaries against.\n * @returns The existing dictionaries and the new dictionaries.\n */\nexport const getExistingDictionaryKey = async (\n dictionariesKeys: string[],\n projectId: string | Types.ObjectId\n): Promise<GetExistingDictionaryResult> => {\n // Fetch dictionaries from the database where the key is in the provided list\n const existingDictionaries = await DictionaryModel.find({\n key: { $in: dictionariesKeys },\n projectIds: projectId,\n });\n\n // Map existing dictionaries to a LocalDictionary object\n const existingDictionariesKey: string[] = [];\n const newDictionariesKey: string[] = [];\n\n for (const key of dictionariesKeys) {\n const isDictionaryExist = existingDictionaries.some(\n (dictionary) => dictionary.key === key\n );\n\n if (isDictionaryExist) {\n existingDictionariesKey.push(key);\n } else {\n newDictionariesKey.push(key);\n }\n }\n\n return { existingDictionariesKey, newDictionariesKey };\n};\n\n/**\n * Updates an existing dictionary in the database by its ID.\n * @param dictionaryId - The ID of the dictionary to update.\n * @param dictionary - The updated dictionary data.\n * @returns The updated dictionary.\n */\nexport const updateDictionaryById = async (\n dictionaryId: string | Types.ObjectId,\n dictionary: Partial<Dictionary>\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, [\n 'id',\n ]) as unknown as Partial<Dictionary>;\n\n const updatedKeys = Object.keys(dictionaryToUpdate) as DictionaryFields;\n const errors = await validateDictionary(dictionaryToUpdate, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('DICTIONARY_INVALID_FIELDS', {\n dictionaryId,\n errors,\n });\n }\n\n const result = await DictionaryModel.updateOne(\n { _id: dictionaryId },\n dictionaryToUpdate\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('DICTIONARY_UPDATE_FAILED', { dictionaryId });\n }\n\n const updatedDictionary = await getDictionaryById(dictionaryId);\n\n return updatedDictionary;\n};\n\n/**\n * Updates an existing dictionary in the database by its key.\n * @param dictionaryKey - The ID of the dictionary to update.\n * @param dictionary - The updated dictionary data.\n * @returns The updated dictionary.\n */\nexport const updateDictionaryByKey = async (\n dictionaryKey: string,\n dictionary: Partial<Dictionary>,\n projectId: string | Types.ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, [\n 'id',\n ]) as unknown as Partial<Dictionary>;\n\n const updatedKeys = Object.keys(dictionaryToUpdate) as DictionaryFields;\n const errors = await validateDictionary(dictionaryToUpdate, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('DICTIONARY_INVALID_FIELDS', {\n dictionaryKey,\n projectId,\n errors,\n });\n }\n\n const result = await DictionaryModel.updateOne(\n { key: dictionaryKey, projectIds: projectId },\n dictionaryToUpdate\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('DICTIONARY_UPDATE_FAILED', { dictionaryKey });\n }\n\n const updatedDictionary = await getDictionaryByKey(dictionaryKey, projectId);\n\n return updatedDictionary;\n};\n\n/**\n * Deletes a dictionary from the database by its ID.\n * @param dictionaryId - The ID of the dictionary to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteDictionaryById = async (\n dictionaryId: string\n): Promise<DictionaryDocument> => {\n const dictionary = await DictionaryModel.findByIdAndDelete(dictionaryId);\n\n if (!dictionary) {\n throw new GenericError('DICTIONARY_NOT_FOUND', { dictionaryId });\n }\n\n return dictionary;\n};\n\n// Function to extract the numeric part of the version\nconst getVersionNumber = (version: string): number => {\n const match = version.match(/^v(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid version format: ${version}`);\n }\n return parseInt(match[1], 10);\n};\n\nexport const incrementVersion = (dictionary: Dictionary): string => {\n const VERSION_PREFIX = 'v';\n\n const versions = [...(dictionary.content.keys() ?? [])];\n const lastVersion = versions[versions.length - 1];\n\n // Start with the next version number\n let newNumber = getVersionNumber(lastVersion) + 1;\n let newVersion = `${VERSION_PREFIX}${newNumber}`;\n\n // Loop until a unique version is found\n while (versions.includes(newVersion)) {\n newNumber += 1;\n newVersion = `${VERSION_PREFIX}${newNumber}`;\n }\n\n return newVersion;\n};\n"],"mappings":"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"}
@@ -10,11 +10,8 @@ const require_emails_SubscriptionPaymentSuccess = require('../emails/Subscriptio
10
10
  const require_emails_ValidateUserEmail = require('../emails/ValidateUserEmail.cjs');
11
11
  const require_emails_Welcome = require('../emails/Welcome.cjs');
12
12
  let express_intlayer = require("express-intlayer");
13
- express_intlayer = require_rolldown_runtime.__toESM(express_intlayer);
14
13
  let react_jsx_runtime = require("react/jsx-runtime");
15
- react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
16
14
  let resend = require("resend");
17
- resend = require_rolldown_runtime.__toESM(resend);
18
15
 
19
16
  //#region src/services/email.service.tsx
20
17
  const getEmailComponents = (locale) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"email.service.cjs","names":["InviteUserEmailEN","InviteUserEmailFR","InviteUserEmailES","ValidateUserEmailEN","ValidateUserEmailFR","ValidateUserEmailES","ResetPasswordEmailEN","ResetPasswordEmailFR","ResetPasswordEmailES","WelcomeEmailEN","WelcomeEmailFR","WelcomeEmailES","PasswordChangeConfirmationEmailEN","PasswordChangeConfirmationEmailFR","PasswordChangeConfirmationEmailES","SubscriptionPaymentSuccessEN","SubscriptionPaymentSuccessFR","SubscriptionPaymentSuccessES","SubscriptionPaymentCancellationEN","SubscriptionPaymentCancellationFR","SubscriptionPaymentCancellationES","SubscriptionPaymentErrorEN","SubscriptionPaymentErrorFR","SubscriptionPaymentErrorES","OAuthTokenCreatedEmailEN","OAuthTokenCreatedEmailFR","OAuthTokenCreatedEmailES","resend","Resend","logger"],"sources":["../../../src/services/email.service.tsx"],"sourcesContent":["import {\n InviteUserEmailEN,\n InviteUserEmailES,\n InviteUserEmailFR,\n} from '@emails/InviteUserEmail';\nimport {\n OAuthTokenCreatedEmailEN,\n OAuthTokenCreatedEmailES,\n OAuthTokenCreatedEmailFR,\n} from '@emails/OAuthTokenCreatedEmail';\nimport {\n PasswordChangeConfirmationEmailEN,\n PasswordChangeConfirmationEmailES,\n PasswordChangeConfirmationEmailFR,\n} from '@emails/PasswordChangeConfirmation';\nimport {\n ResetPasswordEmailEN,\n ResetPasswordEmailES,\n ResetPasswordEmailFR,\n} from '@emails/ResetUserPassword';\n\nimport {\n SubscriptionPaymentCancellationEN,\n SubscriptionPaymentCancellationES,\n SubscriptionPaymentCancellationFR,\n} from '@emails/SubscriptionPaymentCancellation';\nimport {\n SubscriptionPaymentErrorEN,\n SubscriptionPaymentErrorES,\n SubscriptionPaymentErrorFR,\n} from '@emails/SubscriptionPaymentError';\nimport {\n SubscriptionPaymentSuccessEN,\n SubscriptionPaymentSuccessES,\n SubscriptionPaymentSuccessFR,\n} from '@emails/SubscriptionPaymentSuccess';\nimport {\n ValidateUserEmailEN,\n ValidateUserEmailES,\n ValidateUserEmailFR,\n} from '@emails/ValidateUserEmail';\nimport {\n WelcomeEmailEN,\n WelcomeEmailES,\n WelcomeEmailFR,\n} from '@emails/Welcome';\nimport type { Locale } from '@intlayer/types';\nimport { logger } from '@logger';\nimport { t } from 'express-intlayer';\nimport type { ComponentProps, JSX } from 'react';\nimport { Resend } from 'resend';\n\ntype EmailComponentsType = (...props: any) => JSX.Element;\ntype EmailComponents = {\n [key: string]: {\n template: EmailComponentsType;\n subject: string;\n };\n};\n\nconst getEmailComponents = (locale?: Locale) =>\n ({\n invite: {\n template: t(\n {\n en: InviteUserEmailEN,\n fr: InviteUserEmailFR,\n es: InviteUserEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'You have been invited to join Intlayer',\n fr: 'Vous êtes invité à rejoindre Intlayer',\n es: 'Has sido invitado a unirte a Intlayer',\n },\n locale\n ),\n },\n validate: {\n template: t(\n {\n en: ValidateUserEmailEN,\n fr: ValidateUserEmailFR,\n es: ValidateUserEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Validate your email for Intlayer',\n fr: 'Validez votre email pour Intlayer',\n es: 'Valida tu correo electrónico para Intlayer',\n },\n locale\n ),\n },\n resetPassword: {\n template: t(\n {\n en: ResetPasswordEmailEN,\n fr: ResetPasswordEmailFR,\n es: ResetPasswordEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Reset your password for Intlayer',\n fr: 'Réinitialisez votre mot de passe pour Intlayer',\n es: 'Restablece tu contraseña para Intlayer',\n },\n locale\n ),\n },\n welcome: {\n template: t(\n {\n en: WelcomeEmailEN,\n fr: WelcomeEmailFR,\n es: WelcomeEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Welcome to Intlayer!',\n fr: 'Bienvenue chez Intlayer!',\n es: '¡Bienvenido a Intlayer!',\n },\n locale\n ),\n },\n passwordChangeConfirmation: {\n template: t(\n {\n en: PasswordChangeConfirmationEmailEN,\n fr: PasswordChangeConfirmationEmailFR,\n es: PasswordChangeConfirmationEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Your Intlayer password has been changed',\n fr: 'Votre mot de passe Intlayer a été modifié',\n es: 'Tu contraseña de Intlayer ha sido cambiada',\n },\n locale\n ),\n },\n subscriptionPaymentSuccess: {\n template: t({\n en: SubscriptionPaymentSuccessEN,\n fr: SubscriptionPaymentSuccessFR,\n es: SubscriptionPaymentSuccessES,\n }),\n subject: t({\n en: 'Your payment for Intlayer subscription is confirmed',\n fr: \"Votre paiement pour l'abonnement Intlayer est confirmé\",\n es: 'Tu pago por la suscripción de Intlayer ha sido confirmado',\n }),\n },\n subscriptionPaymentCancellation: {\n template: t({\n en: SubscriptionPaymentCancellationEN,\n fr: SubscriptionPaymentCancellationFR,\n es: SubscriptionPaymentCancellationES,\n }),\n subject: t({\n en: 'Your Intlayer subscription has been canceled',\n fr: 'Votre abonnement Intlayer a été annulé',\n es: 'Tu suscripción de Intlayer ha sido cancelada',\n }),\n },\n subscriptionPaymentError: {\n template: t({\n en: SubscriptionPaymentErrorEN,\n fr: SubscriptionPaymentErrorFR,\n es: SubscriptionPaymentErrorES,\n }),\n subject: t({\n en: 'There was an issue with your Intlayer subscription payment',\n fr: \"Un problème est survenu avec votre paiement pour l'abonnement Intlayer\",\n es: 'Hubo un problema con el pago de tu suscripción de Intlayer',\n }),\n },\n oAuthTokenCreated: {\n template: t({\n en: OAuthTokenCreatedEmailEN,\n fr: OAuthTokenCreatedEmailFR,\n es: OAuthTokenCreatedEmailES,\n }),\n subject: t({\n en: 'A third-party OAuth application has been added to your Intlayer account',\n fr: 'Une application OAuth tierce a été ajoutée à votre compte Intlayer',\n es: 'Una aplicación OAuth de terceros ha sido añadida a tu cuenta de Intlayer',\n }),\n },\n }) satisfies EmailComponents;\n\ntype EmailType = keyof ReturnType<typeof getEmailComponents>;\n\nexport type SendEmailProps<T extends EmailType> = {\n type: T;\n to: string;\n subject?: string;\n locale?: Locale;\n} & ComponentProps<ReturnType<typeof getEmailComponents>[T]['template']>;\n\nexport const sendEmail = async <T extends EmailType>({\n type,\n to,\n subject,\n locale,\n ...props\n}: SendEmailProps<T>) => {\n const resend = new Resend(process.env.RESEND_API_KEY);\n\n const emailComponents = getEmailComponents(locale);\n\n const { template, subject: baseSubject } = emailComponents[type];\n\n type EmailComponentType = (typeof emailComponents)[T]['template'];\n\n const EmailComponent: EmailComponentType = template;\n\n const react = <EmailComponent {...(props as any)} />;\n\n await resend.emails\n .send({\n from: 'Intlayer <no-reply@intlayer.org>',\n to,\n subject: subject ?? baseSubject,\n react,\n })\n .catch((err) => logger.error(err));\n\n logger.info(`Email sent ${type} to ${to}`);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA4DA,MAAM,sBAAsB,YACzB;CACC,QAAQ;EACN,kCACE;GACE,IAAIA;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,UAAU;EACR,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,eAAe;EACb,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,SAAS;EACP,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,4BAA4B;EAC1B,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,4BAA4B;EAC1B,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACD,iCAAiC;EAC/B,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACD,0BAA0B;EACxB,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACD,mBAAmB;EACjB,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACF;AAWH,MAAa,YAAY,OAA4B,EACnD,MACA,IACA,SACA,OACA,GAAG,YACoB;CACvB,MAAMC,WAAS,IAAIC,cAAO,QAAQ,IAAI,eAAe;CAIrD,MAAM,EAAE,UAAU,SAAS,gBAFH,mBAAmB,OAAO,CAES;CAM3D,MAAM,QAAQ,2CAF6B,YAEb,GAAK,QAAiB;AAEpD,OAAMD,SAAO,OACV,KAAK;EACJ,MAAM;EACN;EACA,SAAS,WAAW;EACpB;EACD,CAAC,CACD,OAAO,QAAQE,4BAAO,MAAM,IAAI,CAAC;AAEpC,6BAAO,KAAK,cAAc,KAAK,MAAM,KAAK"}
1
+ {"version":3,"file":"email.service.cjs","names":["InviteUserEmailEN","InviteUserEmailFR","InviteUserEmailES","ValidateUserEmailEN","ValidateUserEmailFR","ValidateUserEmailES","ResetPasswordEmailEN","ResetPasswordEmailFR","ResetPasswordEmailES","WelcomeEmailEN","WelcomeEmailFR","WelcomeEmailES","PasswordChangeConfirmationEmailEN","PasswordChangeConfirmationEmailFR","PasswordChangeConfirmationEmailES","SubscriptionPaymentSuccessEN","SubscriptionPaymentSuccessFR","SubscriptionPaymentSuccessES","SubscriptionPaymentCancellationEN","SubscriptionPaymentCancellationFR","SubscriptionPaymentCancellationES","SubscriptionPaymentErrorEN","SubscriptionPaymentErrorFR","SubscriptionPaymentErrorES","OAuthTokenCreatedEmailEN","OAuthTokenCreatedEmailFR","OAuthTokenCreatedEmailES","resend","Resend","logger"],"sources":["../../../src/services/email.service.tsx"],"sourcesContent":["import {\n InviteUserEmailEN,\n InviteUserEmailES,\n InviteUserEmailFR,\n} from '@emails/InviteUserEmail';\nimport {\n OAuthTokenCreatedEmailEN,\n OAuthTokenCreatedEmailES,\n OAuthTokenCreatedEmailFR,\n} from '@emails/OAuthTokenCreatedEmail';\nimport {\n PasswordChangeConfirmationEmailEN,\n PasswordChangeConfirmationEmailES,\n PasswordChangeConfirmationEmailFR,\n} from '@emails/PasswordChangeConfirmation';\nimport {\n ResetPasswordEmailEN,\n ResetPasswordEmailES,\n ResetPasswordEmailFR,\n} from '@emails/ResetUserPassword';\n\nimport {\n SubscriptionPaymentCancellationEN,\n SubscriptionPaymentCancellationES,\n SubscriptionPaymentCancellationFR,\n} from '@emails/SubscriptionPaymentCancellation';\nimport {\n SubscriptionPaymentErrorEN,\n SubscriptionPaymentErrorES,\n SubscriptionPaymentErrorFR,\n} from '@emails/SubscriptionPaymentError';\nimport {\n SubscriptionPaymentSuccessEN,\n SubscriptionPaymentSuccessES,\n SubscriptionPaymentSuccessFR,\n} from '@emails/SubscriptionPaymentSuccess';\nimport {\n ValidateUserEmailEN,\n ValidateUserEmailES,\n ValidateUserEmailFR,\n} from '@emails/ValidateUserEmail';\nimport {\n WelcomeEmailEN,\n WelcomeEmailES,\n WelcomeEmailFR,\n} from '@emails/Welcome';\nimport type { Locale } from '@intlayer/types';\nimport { logger } from '@logger';\nimport { t } from 'express-intlayer';\nimport type { ComponentProps, JSX } from 'react';\nimport { Resend } from 'resend';\n\ntype EmailComponentsType = (...props: any) => JSX.Element;\ntype EmailComponents = {\n [key: string]: {\n template: EmailComponentsType;\n subject: string;\n };\n};\n\nconst getEmailComponents = (locale?: Locale) =>\n ({\n invite: {\n template: t(\n {\n en: InviteUserEmailEN,\n fr: InviteUserEmailFR,\n es: InviteUserEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'You have been invited to join Intlayer',\n fr: 'Vous êtes invité à rejoindre Intlayer',\n es: 'Has sido invitado a unirte a Intlayer',\n },\n locale\n ),\n },\n validate: {\n template: t(\n {\n en: ValidateUserEmailEN,\n fr: ValidateUserEmailFR,\n es: ValidateUserEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Validate your email for Intlayer',\n fr: 'Validez votre email pour Intlayer',\n es: 'Valida tu correo electrónico para Intlayer',\n },\n locale\n ),\n },\n resetPassword: {\n template: t(\n {\n en: ResetPasswordEmailEN,\n fr: ResetPasswordEmailFR,\n es: ResetPasswordEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Reset your password for Intlayer',\n fr: 'Réinitialisez votre mot de passe pour Intlayer',\n es: 'Restablece tu contraseña para Intlayer',\n },\n locale\n ),\n },\n welcome: {\n template: t(\n {\n en: WelcomeEmailEN,\n fr: WelcomeEmailFR,\n es: WelcomeEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Welcome to Intlayer!',\n fr: 'Bienvenue chez Intlayer!',\n es: '¡Bienvenido a Intlayer!',\n },\n locale\n ),\n },\n passwordChangeConfirmation: {\n template: t(\n {\n en: PasswordChangeConfirmationEmailEN,\n fr: PasswordChangeConfirmationEmailFR,\n es: PasswordChangeConfirmationEmailES,\n },\n locale\n ),\n subject: t(\n {\n en: 'Your Intlayer password has been changed',\n fr: 'Votre mot de passe Intlayer a été modifié',\n es: 'Tu contraseña de Intlayer ha sido cambiada',\n },\n locale\n ),\n },\n subscriptionPaymentSuccess: {\n template: t({\n en: SubscriptionPaymentSuccessEN,\n fr: SubscriptionPaymentSuccessFR,\n es: SubscriptionPaymentSuccessES,\n }),\n subject: t({\n en: 'Your payment for Intlayer subscription is confirmed',\n fr: \"Votre paiement pour l'abonnement Intlayer est confirmé\",\n es: 'Tu pago por la suscripción de Intlayer ha sido confirmado',\n }),\n },\n subscriptionPaymentCancellation: {\n template: t({\n en: SubscriptionPaymentCancellationEN,\n fr: SubscriptionPaymentCancellationFR,\n es: SubscriptionPaymentCancellationES,\n }),\n subject: t({\n en: 'Your Intlayer subscription has been canceled',\n fr: 'Votre abonnement Intlayer a été annulé',\n es: 'Tu suscripción de Intlayer ha sido cancelada',\n }),\n },\n subscriptionPaymentError: {\n template: t({\n en: SubscriptionPaymentErrorEN,\n fr: SubscriptionPaymentErrorFR,\n es: SubscriptionPaymentErrorES,\n }),\n subject: t({\n en: 'There was an issue with your Intlayer subscription payment',\n fr: \"Un problème est survenu avec votre paiement pour l'abonnement Intlayer\",\n es: 'Hubo un problema con el pago de tu suscripción de Intlayer',\n }),\n },\n oAuthTokenCreated: {\n template: t({\n en: OAuthTokenCreatedEmailEN,\n fr: OAuthTokenCreatedEmailFR,\n es: OAuthTokenCreatedEmailES,\n }),\n subject: t({\n en: 'A third-party OAuth application has been added to your Intlayer account',\n fr: 'Une application OAuth tierce a été ajoutée à votre compte Intlayer',\n es: 'Una aplicación OAuth de terceros ha sido añadida a tu cuenta de Intlayer',\n }),\n },\n }) satisfies EmailComponents;\n\ntype EmailType = keyof ReturnType<typeof getEmailComponents>;\n\nexport type SendEmailProps<T extends EmailType> = {\n type: T;\n to: string;\n subject?: string;\n locale?: Locale;\n} & ComponentProps<ReturnType<typeof getEmailComponents>[T]['template']>;\n\nexport const sendEmail = async <T extends EmailType>({\n type,\n to,\n subject,\n locale,\n ...props\n}: SendEmailProps<T>) => {\n const resend = new Resend(process.env.RESEND_API_KEY);\n\n const emailComponents = getEmailComponents(locale);\n\n const { template, subject: baseSubject } = emailComponents[type];\n\n type EmailComponentType = (typeof emailComponents)[T]['template'];\n\n const EmailComponent: EmailComponentType = template;\n\n const react = <EmailComponent {...(props as any)} />;\n\n await resend.emails\n .send({\n from: 'Intlayer <no-reply@intlayer.org>',\n to,\n subject: subject ?? baseSubject,\n react,\n })\n .catch((err) => logger.error(err));\n\n logger.info(`Email sent ${type} to ${to}`);\n};\n"],"mappings":";;;;;;;;;;;;;;;;AA4DA,MAAM,sBAAsB,YACzB;CACC,QAAQ;EACN,kCACE;GACE,IAAIA;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,UAAU;EACR,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,eAAe;EACb,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,SAAS;EACP,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,4BAA4B;EAC1B,kCACE;GACE,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,EACD,OACD;EACD,iCACE;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,EACD,OACD;EACF;CACD,4BAA4B;EAC1B,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACD,iCAAiC;EAC/B,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACD,0BAA0B;EACxB,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACD,mBAAmB;EACjB,kCAAY;GACV,IAAIC;GACJ,IAAIC;GACJ,IAAIC;GACL,CAAC;EACF,iCAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACF;AAWH,MAAa,YAAY,OAA4B,EACnD,MACA,IACA,SACA,OACA,GAAG,YACoB;CACvB,MAAMC,WAAS,IAAIC,cAAO,QAAQ,IAAI,eAAe;CAIrD,MAAM,EAAE,UAAU,SAAS,gBAFH,mBAAmB,OAAO,CAES;CAM3D,MAAM,QAAQ,2CAF6B,YAEb,GAAK,QAAiB;AAEpD,OAAMD,SAAO,OACV,KAAK;EACJ,MAAM;EACN;EACA,SAAS,WAAW;EACpB;EACD,CAAC,CACD,OAAO,QAAQE,4BAAO,MAAM,IAAI,CAAC;AAEpC,6BAAO,KAAK,cAAc,KAAK,MAAM,KAAK"}
@@ -10,7 +10,6 @@ const require_utils_mapper_project = require('../utils/mapper/project.cjs');
10
10
  const require_models_oAuth2_model = require('../models/oAuth2.model.cjs');
11
11
  const require_utils_oAuth2 = require('../utils/oAuth2.cjs');
12
12
  let node_crypto = require("node:crypto");
13
- node_crypto = require_rolldown_runtime.__toESM(node_crypto);
14
13
 
15
14
  //#region src/services/oAuth2.service.ts
16
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"oAuth2.service.cjs","names":["ProjectModel","GenericError","mapUserToAPI","mapOrganizationToAPI","mapProjectToAPI","getTokenExpireAt","formattedAccessToken: Token","OAuth2AccessTokenModel","getOrganizationById","getUserById","ensureMongoDocumentToObject"],"sources":["../../../src/services/oAuth2.service.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto';\nimport { OAuth2AccessTokenModel } from '@models/oAuth2.model';\nimport { ProjectModel } from '@models/project.model';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { GenericError } from '@utils/errors';\nimport { mapOrganizationToAPI } from '@utils/mapper/organization';\nimport { mapProjectToAPI } from '@utils/mapper/project';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { getTokenExpireAt } from '@utils/oAuth2';\nimport type { Types } from 'mongoose';\nimport type { Callback, Client } from 'oauth2-server';\nimport type { OAuth2Token } from '@/types/oAuth2.types';\nimport type { Organization } from '@/types/organization.types';\nimport type {\n OAuth2Access,\n OAuth2AccessContext,\n Project,\n ProjectDocument,\n} from '@/types/project.types';\nimport type { User, UserAPI, UserDocument } from '@/types/user.types';\nimport type { Token } from '../schemas/oAuth2.schema';\nimport { getOrganizationById } from './organization.service';\nimport { getUserById } from './user.service';\n\n/**\n * Function to generate client credentials\n *\n * @returns The client id and client secret\n */\nexport const generateClientCredentials = (): {\n clientId: string;\n clientSecret: string;\n} => {\n const clientId = randomBytes(16).toString('hex'); // Generate a 16 character hexadecimal string\n const clientSecret = randomBytes(32).toString('hex'); // Generate a 32 character hexadecimal string\n\n return { clientId, clientSecret };\n};\n\n/**\n * Method to get the client and the project\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The an object containing the client, the rights and the project or false if not found\n */\nexport const getClientAndProjectByClientId = async (\n clientId: string\n): Promise<\n | {\n client: Client;\n oAuth2Access: OAuth2Access;\n project: ProjectDocument;\n grants: Token['grants'];\n }\n | false\n> => {\n const project = await ProjectModel.findOne({\n 'oAuth2Access.clientId': clientId,\n });\n\n if (!project) {\n return false;\n }\n\n const oAuth2Access = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!oAuth2Access) {\n return false;\n }\n\n const formattedClient: Client = {\n id: oAuth2Access.clientId,\n clientId,\n clientSecret: oAuth2Access.clientSecret,\n grants: ['client_credentials'],\n };\n\n return {\n client: formattedClient,\n oAuth2Access,\n grants: oAuth2Access.grants,\n project,\n };\n};\n\n/**\n * Get the client and verify that the client secret is correct\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The client or false if not found\n */\nexport const getClient = async (\n clientId: string,\n clientSecret: string\n): Promise<Client | false> => {\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client } = result;\n\n if (!client || client.clientSecret !== clientSecret) {\n return false;\n }\n\n return client;\n};\n\n/**\n * Format an OAuth2Token\n *\n * @param token - The token to format\n * @param client - The client\n * @param user - The user\n * @param project - The project\n * @param organization - The organization\n * @param grants - The grants\n * @returns The formatted token\n */\nexport const formatOAuth2Token = (\n token: Token,\n client: Client,\n user: UserAPI,\n project: Project,\n organization: Organization,\n grants: Token['grants']\n): OAuth2Token => {\n // biome-ignore lint/correctness/noUnusedVariables: Just filter out clientId\n const { clientId, userId, ...restToken } = token;\n\n if (String(userId) !== String(user.id)) {\n throw new GenericError('USER_ID_MISMATCH');\n }\n\n const formattedToken: OAuth2Token = {\n ...restToken,\n client,\n user: mapUserToAPI(user),\n organization: mapOrganizationToAPI(organization),\n project: mapProjectToAPI(project),\n accessToken: token.accessToken,\n accessTokenExpiresAt: token.accessTokenExpiresAt ?? new Date('999-99-99'),\n grants,\n };\n\n return formattedToken;\n};\n\n/**\n * Format a auth token for the database\n *\n * @param token - The oAuth2 token to format\n * @param clientId - The client ID\n * @param userId - The user ID\n * @returns\n */\nexport const formatDBToken = (\n token: OAuth2Token,\n clientId: Client['id'],\n userId: User['id'] | string\n): Token => {\n const formattedToken: Token = {\n id: token.id,\n clientId: clientId,\n userId: userId as Types.ObjectId,\n accessToken: token.accessToken,\n expiresIn: token.accessTokenExpiresAt ?? getTokenExpireAt(),\n };\n\n return formattedToken;\n};\n\n/**\n * Method to save the token\n *\n * @param token - The token\n * @param client - The client\n * @param user - The user\n * @returns The saved token or false if not saved\n */\nexport const saveToken = async (\n token: OAuth2Token,\n client: Client,\n user: UserAPI\n): Promise<OAuth2Token | false> => {\n const formattedAccessToken: Token = formatDBToken(token, client.id, user.id);\n\n const result = await OAuth2AccessTokenModel.create(formattedAccessToken);\n\n if (!result) {\n return false;\n }\n\n const result2 = await getClientAndProjectByClientId(result.clientId);\n\n if (!result2) {\n return false;\n }\n\n const { project } = result2;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedResult = formatOAuth2Token(\n formattedAccessToken,\n client,\n user,\n project,\n organization,\n token.rights\n );\n return formattedResult;\n};\n\n/**\n * Method to get the access token\n *\n * @param accessToken - The access token\n * @returns The access token or false if not found\n */\nexport const getAccessToken = async (\n accessToken: string\n): Promise<OAuth2Token | false> => {\n const token = await OAuth2AccessTokenModel.findOne({\n accessToken,\n });\n\n if (!token) {\n return false;\n }\n\n const { userId, clientId } = token;\n\n const user = await getUserById(userId);\n\n if (!user) {\n return false;\n }\n\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client, project, grants } = result;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedAccessToken = formatOAuth2Token(\n token,\n client,\n user,\n project,\n organization,\n grants\n );\n\n return formattedAccessToken;\n};\n\n/**\n * Method to get the user from the client\n *\n * @param client - The client\n * @returns The user or false if not found\n */\nexport const getUserFromClient = async (\n client: Client\n): Promise<UserDocument | false> => {\n const response = await getClientAndProjectByClientId(client.id);\n\n if (!response) {\n return false;\n }\n\n const { userId } = response.oAuth2Access;\n\n if (!userId) {\n return false;\n }\n\n const user = await getUserById(userId);\n\n return user ?? false;\n};\n\n/**\n * Method to verify the permissions (grants)\n *\n * @param token - The token\n * @param scope - The scope\n * @returns True if the token has the required scope, false otherwise\n */\nexport const verifyScope = async (\n _token: OAuth2Token,\n _scope: string,\n _callback?: Callback<boolean> | undefined\n): Promise<boolean> => {\n // Implement the verification of scopes if necessary\n return true;\n};\n\n/**\n * Validate OAuth2 access token and return user context\n */\nexport const validateOAuth2AccessToken = async (\n accessToken: string\n): Promise<Token> => {\n try {\n const token = await OAuth2AccessTokenModel.findOne({\n accessToken,\n });\n\n if (!token) {\n throw new GenericError('INVALID_ACCESS_TOKEN');\n }\n\n // Check if token is expired\n if (new Date() > new Date(token.expiresIn)) {\n throw new GenericError('EXPIRED_ACCESS_TOKEN');\n }\n\n return ensureMongoDocumentToObject(token);\n } catch (_error) {\n throw new GenericError('INVALID_ACCESS_TOKEN');\n }\n};\n\n/**\n * Validate OAuth2 access token and return user context\n */\nexport const getOAuth2AccessTokenContext = async (\n token: Token\n): Promise<OAuth2AccessContext> => {\n const { userId, clientId } = token;\n\n const user = await getUserById(String(userId));\n\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n throw new GenericError('INVALID_ACCESS_TOKEN');\n }\n\n const { project, grants } = result;\n\n const organization = await getOrganizationById(project.organizationId);\n\n return {\n accessToken: token.accessToken,\n user: user ? mapUserToAPI(user) : undefined,\n project: project ? mapProjectToAPI(project) : undefined,\n organization: organization ? mapOrganizationToAPI(organization) : undefined,\n grants,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"oAuth2.service.cjs","names":["ProjectModel","GenericError","mapUserToAPI","mapOrganizationToAPI","mapProjectToAPI","getTokenExpireAt","formattedAccessToken: Token","OAuth2AccessTokenModel","getOrganizationById","getUserById","ensureMongoDocumentToObject"],"sources":["../../../src/services/oAuth2.service.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto';\nimport { OAuth2AccessTokenModel } from '@models/oAuth2.model';\nimport { ProjectModel } from '@models/project.model';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { GenericError } from '@utils/errors';\nimport { mapOrganizationToAPI } from '@utils/mapper/organization';\nimport { mapProjectToAPI } from '@utils/mapper/project';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { getTokenExpireAt } from '@utils/oAuth2';\nimport type { Types } from 'mongoose';\nimport type { Callback, Client } from 'oauth2-server';\nimport type { OAuth2Token } from '@/types/oAuth2.types';\nimport type { Organization } from '@/types/organization.types';\nimport type {\n OAuth2Access,\n OAuth2AccessContext,\n Project,\n ProjectDocument,\n} from '@/types/project.types';\nimport type { User, UserAPI, UserDocument } from '@/types/user.types';\nimport type { Token } from '../schemas/oAuth2.schema';\nimport { getOrganizationById } from './organization.service';\nimport { getUserById } from './user.service';\n\n/**\n * Function to generate client credentials\n *\n * @returns The client id and client secret\n */\nexport const generateClientCredentials = (): {\n clientId: string;\n clientSecret: string;\n} => {\n const clientId = randomBytes(16).toString('hex'); // Generate a 16 character hexadecimal string\n const clientSecret = randomBytes(32).toString('hex'); // Generate a 32 character hexadecimal string\n\n return { clientId, clientSecret };\n};\n\n/**\n * Method to get the client and the project\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The an object containing the client, the rights and the project or false if not found\n */\nexport const getClientAndProjectByClientId = async (\n clientId: string\n): Promise<\n | {\n client: Client;\n oAuth2Access: OAuth2Access;\n project: ProjectDocument;\n grants: Token['grants'];\n }\n | false\n> => {\n const project = await ProjectModel.findOne({\n 'oAuth2Access.clientId': clientId,\n });\n\n if (!project) {\n return false;\n }\n\n const oAuth2Access = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!oAuth2Access) {\n return false;\n }\n\n const formattedClient: Client = {\n id: oAuth2Access.clientId,\n clientId,\n clientSecret: oAuth2Access.clientSecret,\n grants: ['client_credentials'],\n };\n\n return {\n client: formattedClient,\n oAuth2Access,\n grants: oAuth2Access.grants,\n project,\n };\n};\n\n/**\n * Get the client and verify that the client secret is correct\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The client or false if not found\n */\nexport const getClient = async (\n clientId: string,\n clientSecret: string\n): Promise<Client | false> => {\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client } = result;\n\n if (!client || client.clientSecret !== clientSecret) {\n return false;\n }\n\n return client;\n};\n\n/**\n * Format an OAuth2Token\n *\n * @param token - The token to format\n * @param client - The client\n * @param user - The user\n * @param project - The project\n * @param organization - The organization\n * @param grants - The grants\n * @returns The formatted token\n */\nexport const formatOAuth2Token = (\n token: Token,\n client: Client,\n user: UserAPI,\n project: Project,\n organization: Organization,\n grants: Token['grants']\n): OAuth2Token => {\n // biome-ignore lint/correctness/noUnusedVariables: Just filter out clientId\n const { clientId, userId, ...restToken } = token;\n\n if (String(userId) !== String(user.id)) {\n throw new GenericError('USER_ID_MISMATCH');\n }\n\n const formattedToken: OAuth2Token = {\n ...restToken,\n client,\n user: mapUserToAPI(user),\n organization: mapOrganizationToAPI(organization),\n project: mapProjectToAPI(project),\n accessToken: token.accessToken,\n accessTokenExpiresAt: token.accessTokenExpiresAt ?? new Date('999-99-99'),\n grants,\n };\n\n return formattedToken;\n};\n\n/**\n * Format a auth token for the database\n *\n * @param token - The oAuth2 token to format\n * @param clientId - The client ID\n * @param userId - The user ID\n * @returns\n */\nexport const formatDBToken = (\n token: OAuth2Token,\n clientId: Client['id'],\n userId: User['id'] | string\n): Token => {\n const formattedToken: Token = {\n id: token.id,\n clientId: clientId,\n userId: userId as Types.ObjectId,\n accessToken: token.accessToken,\n expiresIn: token.accessTokenExpiresAt ?? getTokenExpireAt(),\n };\n\n return formattedToken;\n};\n\n/**\n * Method to save the token\n *\n * @param token - The token\n * @param client - The client\n * @param user - The user\n * @returns The saved token or false if not saved\n */\nexport const saveToken = async (\n token: OAuth2Token,\n client: Client,\n user: UserAPI\n): Promise<OAuth2Token | false> => {\n const formattedAccessToken: Token = formatDBToken(token, client.id, user.id);\n\n const result = await OAuth2AccessTokenModel.create(formattedAccessToken);\n\n if (!result) {\n return false;\n }\n\n const result2 = await getClientAndProjectByClientId(result.clientId);\n\n if (!result2) {\n return false;\n }\n\n const { project } = result2;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedResult = formatOAuth2Token(\n formattedAccessToken,\n client,\n user,\n project,\n organization,\n token.rights\n );\n return formattedResult;\n};\n\n/**\n * Method to get the access token\n *\n * @param accessToken - The access token\n * @returns The access token or false if not found\n */\nexport const getAccessToken = async (\n accessToken: string\n): Promise<OAuth2Token | false> => {\n const token = await OAuth2AccessTokenModel.findOne({\n accessToken,\n });\n\n if (!token) {\n return false;\n }\n\n const { userId, clientId } = token;\n\n const user = await getUserById(userId);\n\n if (!user) {\n return false;\n }\n\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client, project, grants } = result;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedAccessToken = formatOAuth2Token(\n token,\n client,\n user,\n project,\n organization,\n grants\n );\n\n return formattedAccessToken;\n};\n\n/**\n * Method to get the user from the client\n *\n * @param client - The client\n * @returns The user or false if not found\n */\nexport const getUserFromClient = async (\n client: Client\n): Promise<UserDocument | false> => {\n const response = await getClientAndProjectByClientId(client.id);\n\n if (!response) {\n return false;\n }\n\n const { userId } = response.oAuth2Access;\n\n if (!userId) {\n return false;\n }\n\n const user = await getUserById(userId);\n\n return user ?? false;\n};\n\n/**\n * Method to verify the permissions (grants)\n *\n * @param token - The token\n * @param scope - The scope\n * @returns True if the token has the required scope, false otherwise\n */\nexport const verifyScope = async (\n _token: OAuth2Token,\n _scope: string,\n _callback?: Callback<boolean> | undefined\n): Promise<boolean> => {\n // Implement the verification of scopes if necessary\n return true;\n};\n\n/**\n * Validate OAuth2 access token and return user context\n */\nexport const validateOAuth2AccessToken = async (\n accessToken: string\n): Promise<Token> => {\n try {\n const token = await OAuth2AccessTokenModel.findOne({\n accessToken,\n });\n\n if (!token) {\n throw new GenericError('INVALID_ACCESS_TOKEN');\n }\n\n // Check if token is expired\n if (new Date() > new Date(token.expiresIn)) {\n throw new GenericError('EXPIRED_ACCESS_TOKEN');\n }\n\n return ensureMongoDocumentToObject(token);\n } catch (_error) {\n throw new GenericError('INVALID_ACCESS_TOKEN');\n }\n};\n\n/**\n * Validate OAuth2 access token and return user context\n */\nexport const getOAuth2AccessTokenContext = async (\n token: Token\n): Promise<OAuth2AccessContext> => {\n const { userId, clientId } = token;\n\n const user = await getUserById(String(userId));\n\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n throw new GenericError('INVALID_ACCESS_TOKEN');\n }\n\n const { project, grants } = result;\n\n const organization = await getOrganizationById(project.organizationId);\n\n return {\n accessToken: token.accessToken,\n user: user ? mapUserToAPI(user) : undefined,\n project: project ? mapProjectToAPI(project) : undefined,\n organization: organization ? mapOrganizationToAPI(organization) : undefined,\n grants,\n };\n};\n"],"mappings":"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"}
@@ -3,7 +3,6 @@ const require_utils_errors_ErrorsClass = require('../utils/errors/ErrorsClass.cj
3
3
  const require_models_project_model = require('../models/project.model.cjs');
4
4
  const require_services_project_service = require('./project.service.cjs');
5
5
  let node_crypto = require("node:crypto");
6
- node_crypto = require_rolldown_runtime.__toESM(node_crypto);
7
6
 
8
7
  //#region src/services/projectAccessKey.service.ts
9
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"projectAccessKey.service.cjs","names":["newAccessKey: OAuth2AccessData","ProjectModel","GenericError","getProjectById"],"sources":["../../../src/services/projectAccessKey.service.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto';\nimport { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport type { Types } from 'mongoose';\nimport type {\n AccessKeyData,\n OAuth2Access,\n OAuth2AccessData,\n Project,\n} from '@/types/project.types';\nimport type { User } from '@/types/user.types';\nimport { getProjectById } from './project.service';\n\n/**\n * Generates cryptographically secure OAuth2 client credentials\n *\n * @returns Object containing clientId and clientSecret\n *\n * Security improvements:\n * - clientId: 32 characters (128 bits of entropy)\n * - clientSecret: 64 characters (256 bits of entropy)\n * - Uses crypto.randomBytes for cryptographically secure random generation\n * - Follows OAuth2 best practices for credential strength\n */\nconst generateClientCredentials = () => ({\n clientId: randomBytes(16).toString('hex'), // 32 character hexadecimal string\n clientSecret: randomBytes(32).toString('hex'), // 64 character hexadecimal string\n});\n\n/**\n * Adds a new access key to a project.\n *\n * @param accessKeyData - The access key data.\n * @param projectId - The ID of the project to add the access key to.\n * @param user - The user adding the access key.\n * @returns The new access key.\n *\n */\nexport const addNewAccessKey = async (\n accessKeyData: AccessKeyData,\n projectId: string | Types.ObjectId,\n user: User\n): Promise<OAuth2Access> => {\n const { clientId, clientSecret } = generateClientCredentials();\n\n const newAccessKey: OAuth2AccessData = {\n ...accessKeyData,\n clientId,\n clientSecret,\n userId: user.id,\n accessToken: [],\n grants: accessKeyData.grants,\n };\n\n const result = await ProjectModel.updateOne(\n { _id: projectId },\n { $push: { oAuth2Access: newAccessKey } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user.id,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user.id,\n });\n }\n\n return newAccessKeyId;\n};\n\nexport const deleteAccessKey = async (\n clientId: string | Types.ObjectId,\n project: Project,\n userId: string | Types.ObjectId\n) => {\n const projectAccess = project.oAuth2Access.find(\n (access) =>\n access.clientId === clientId && String(access.userId) === String(userId)\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project.id,\n });\n }\n\n const result = await ProjectModel.updateOne(\n {\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n },\n { $pull: { oAuth2Access: { clientId } } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_DELETION_FAILED', {\n clientId,\n projectId: project.id,\n });\n }\n\n return projectAccess;\n};\n\nexport const refreshAccessKey = async (\n clientId: string | Types.ObjectId,\n projectId: string | Types.ObjectId,\n userId: string | Types.ObjectId\n): Promise<OAuth2Access> => {\n const project = await ProjectModel.findOne({\n _id: projectId,\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n });\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_FOUND', {\n clientId,\n projectId,\n userId,\n });\n }\n\n const projectAccess = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project.id,\n });\n }\n\n const { clientSecret } = generateClientCredentials();\n\n const result = await ProjectModel.updateOne(\n {\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n },\n {\n $set: {\n 'oAuth2Access.$.clientId': projectAccess.clientId,\n 'oAuth2Access.$.clientSecret': clientSecret,\n },\n }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_UPDATE_FAILED', {\n clientId,\n projectId,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === projectAccess.clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData: updatedProject.oAuth2Access,\n projectId,\n userId,\n });\n }\n\n return newAccessKeyId;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAwBA,MAAM,mCAAmC;CACvC,uCAAsB,GAAG,CAAC,SAAS,MAAM;CACzC,2CAA0B,GAAG,CAAC,SAAS,MAAM;CAC9C;;;;;;;;;;AAWD,MAAa,kBAAkB,OAC7B,eACA,WACA,SAC0B;CAC1B,MAAM,EAAE,UAAU,iBAAiB,2BAA2B;CAE9D,MAAMA,eAAiC;EACrC,GAAG;EACH;EACA;EACA,QAAQ,KAAK;EACb,aAAa,EAAE;EACf,QAAQ,cAAc;EACvB;AAOD,MALe,MAAMC,0CAAa,UAChC,EAAE,KAAK,WAAW,EAClB,EAAE,OAAO,EAAE,cAAc,cAAc,EAAE,CAC1C,EAEU,kBAAkB,EAC3B,OAAM,IAAIC,8CAAa,8BAA8B;EACnD;EACA;EACA,QAAQ,KAAK;EACd,CAAC;CAKJ,MAAM,kBAFiB,MAAMC,gDAAe,UAAU,EAEhB,aAAa,MAChD,WAAW,OAAO,aAAa,SACjC;AAED,KAAI,CAAC,eACH,OAAM,IAAID,8CAAa,8BAA8B;EACnD;EACA;EACA,QAAQ,KAAK;EACd,CAAC;AAGJ,QAAO;;AAGT,MAAa,kBAAkB,OAC7B,UACA,SACA,WACG;CACH,MAAM,gBAAgB,QAAQ,aAAa,MACxC,WACC,OAAO,aAAa,YAAY,OAAO,OAAO,OAAO,KAAK,OAAO,OAAO,CAC3E;AAED,KAAI,CAAC,cACH,OAAM,IAAIA,8CAAa,wBAAwB;EAC7C;EACA,WAAW,QAAQ;EACpB,CAAC;AAWJ,MARe,MAAMD,0CAAa,UAChC;EACE,yBAAyB;EACzB,uBAAuB,OAAO,OAAO;EACtC,EACD,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,EAAE,CAC1C,EAEU,kBAAkB,EAC3B,OAAM,IAAIC,8CAAa,8BAA8B;EACnD;EACA,WAAW,QAAQ;EACpB,CAAC;AAGJ,QAAO;;AAGT,MAAa,mBAAmB,OAC9B,UACA,WACA,WAC0B;CAC1B,MAAM,UAAU,MAAMD,0CAAa,QAAQ;EACzC,KAAK;EACL,yBAAyB;EACzB,uBAAuB,OAAO,OAAO;EACtC,CAAC;AAEF,KAAI,CAAC,QACH,OAAM,IAAIC,8CAAa,qBAAqB;EAC1C;EACA;EACA;EACD,CAAC;CAGJ,MAAM,gBAAgB,QAAQ,aAAa,MACxC,WAAW,OAAO,aAAa,SACjC;AAED,KAAI,CAAC,cACH,OAAM,IAAIA,8CAAa,wBAAwB;EAC7C;EACA,WAAW,QAAQ;EACpB,CAAC;CAGJ,MAAM,EAAE,iBAAiB,2BAA2B;AAepD,MAbe,MAAMD,0CAAa,UAChC;EACE,yBAAyB;EACzB,uBAAuB,OAAO,OAAO;EACtC,EACD,EACE,MAAM;EACJ,2BAA2B,cAAc;EACzC,+BAA+B;EAChC,EACF,CACF,EAEU,kBAAkB,EAC3B,OAAM,IAAIC,8CAAa,4BAA4B;EACjD;EACA;EACD,CAAC;CAGJ,MAAM,iBAAiB,MAAMC,gDAAe,UAAU;CAEtD,MAAM,iBAAiB,eAAe,aAAa,MAChD,WAAW,OAAO,aAAa,cAAc,SAC/C;AAED,KAAI,CAAC,eACH,OAAM,IAAID,8CAAa,8BAA8B;EACnD,eAAe,eAAe;EAC9B;EACA;EACD,CAAC;AAGJ,QAAO"}
1
+ {"version":3,"file":"projectAccessKey.service.cjs","names":["newAccessKey: OAuth2AccessData","ProjectModel","GenericError","getProjectById"],"sources":["../../../src/services/projectAccessKey.service.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto';\nimport { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport type { Types } from 'mongoose';\nimport type {\n AccessKeyData,\n OAuth2Access,\n OAuth2AccessData,\n Project,\n} from '@/types/project.types';\nimport type { User } from '@/types/user.types';\nimport { getProjectById } from './project.service';\n\n/**\n * Generates cryptographically secure OAuth2 client credentials\n *\n * @returns Object containing clientId and clientSecret\n *\n * Security improvements:\n * - clientId: 32 characters (128 bits of entropy)\n * - clientSecret: 64 characters (256 bits of entropy)\n * - Uses crypto.randomBytes for cryptographically secure random generation\n * - Follows OAuth2 best practices for credential strength\n */\nconst generateClientCredentials = () => ({\n clientId: randomBytes(16).toString('hex'), // 32 character hexadecimal string\n clientSecret: randomBytes(32).toString('hex'), // 64 character hexadecimal string\n});\n\n/**\n * Adds a new access key to a project.\n *\n * @param accessKeyData - The access key data.\n * @param projectId - The ID of the project to add the access key to.\n * @param user - The user adding the access key.\n * @returns The new access key.\n *\n */\nexport const addNewAccessKey = async (\n accessKeyData: AccessKeyData,\n projectId: string | Types.ObjectId,\n user: User\n): Promise<OAuth2Access> => {\n const { clientId, clientSecret } = generateClientCredentials();\n\n const newAccessKey: OAuth2AccessData = {\n ...accessKeyData,\n clientId,\n clientSecret,\n userId: user.id,\n accessToken: [],\n grants: accessKeyData.grants,\n };\n\n const result = await ProjectModel.updateOne(\n { _id: projectId },\n { $push: { oAuth2Access: newAccessKey } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user.id,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user.id,\n });\n }\n\n return newAccessKeyId;\n};\n\nexport const deleteAccessKey = async (\n clientId: string | Types.ObjectId,\n project: Project,\n userId: string | Types.ObjectId\n) => {\n const projectAccess = project.oAuth2Access.find(\n (access) =>\n access.clientId === clientId && String(access.userId) === String(userId)\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project.id,\n });\n }\n\n const result = await ProjectModel.updateOne(\n {\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n },\n { $pull: { oAuth2Access: { clientId } } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_DELETION_FAILED', {\n clientId,\n projectId: project.id,\n });\n }\n\n return projectAccess;\n};\n\nexport const refreshAccessKey = async (\n clientId: string | Types.ObjectId,\n projectId: string | Types.ObjectId,\n userId: string | Types.ObjectId\n): Promise<OAuth2Access> => {\n const project = await ProjectModel.findOne({\n _id: projectId,\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n });\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_FOUND', {\n clientId,\n projectId,\n userId,\n });\n }\n\n const projectAccess = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project.id,\n });\n }\n\n const { clientSecret } = generateClientCredentials();\n\n const result = await ProjectModel.updateOne(\n {\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n },\n {\n $set: {\n 'oAuth2Access.$.clientId': projectAccess.clientId,\n 'oAuth2Access.$.clientSecret': clientSecret,\n },\n }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_UPDATE_FAILED', {\n clientId,\n projectId,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === projectAccess.clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData: updatedProject.oAuth2Access,\n projectId,\n userId,\n });\n }\n\n return newAccessKeyId;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAwBA,MAAM,mCAAmC;CACvC,uCAAsB,GAAG,CAAC,SAAS,MAAM;CACzC,2CAA0B,GAAG,CAAC,SAAS,MAAM;CAC9C;;;;;;;;;;AAWD,MAAa,kBAAkB,OAC7B,eACA,WACA,SAC0B;CAC1B,MAAM,EAAE,UAAU,iBAAiB,2BAA2B;CAE9D,MAAMA,eAAiC;EACrC,GAAG;EACH;EACA;EACA,QAAQ,KAAK;EACb,aAAa,EAAE;EACf,QAAQ,cAAc;EACvB;AAOD,MALe,MAAMC,0CAAa,UAChC,EAAE,KAAK,WAAW,EAClB,EAAE,OAAO,EAAE,cAAc,cAAc,EAAE,CAC1C,EAEU,kBAAkB,EAC3B,OAAM,IAAIC,8CAAa,8BAA8B;EACnD;EACA;EACA,QAAQ,KAAK;EACd,CAAC;CAKJ,MAAM,kBAFiB,MAAMC,gDAAe,UAAU,EAEhB,aAAa,MAChD,WAAW,OAAO,aAAa,SACjC;AAED,KAAI,CAAC,eACH,OAAM,IAAID,8CAAa,8BAA8B;EACnD;EACA;EACA,QAAQ,KAAK;EACd,CAAC;AAGJ,QAAO;;AAGT,MAAa,kBAAkB,OAC7B,UACA,SACA,WACG;CACH,MAAM,gBAAgB,QAAQ,aAAa,MACxC,WACC,OAAO,aAAa,YAAY,OAAO,OAAO,OAAO,KAAK,OAAO,OAAO,CAC3E;AAED,KAAI,CAAC,cACH,OAAM,IAAIA,8CAAa,wBAAwB;EAC7C;EACA,WAAW,QAAQ;EACpB,CAAC;AAWJ,MARe,MAAMD,0CAAa,UAChC;EACE,yBAAyB;EACzB,uBAAuB,OAAO,OAAO;EACtC,EACD,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,EAAE,CAC1C,EAEU,kBAAkB,EAC3B,OAAM,IAAIC,8CAAa,8BAA8B;EACnD;EACA,WAAW,QAAQ;EACpB,CAAC;AAGJ,QAAO;;AAGT,MAAa,mBAAmB,OAC9B,UACA,WACA,WAC0B;CAC1B,MAAM,UAAU,MAAMD,0CAAa,QAAQ;EACzC,KAAK;EACL,yBAAyB;EACzB,uBAAuB,OAAO,OAAO;EACtC,CAAC;AAEF,KAAI,CAAC,QACH,OAAM,IAAIC,8CAAa,qBAAqB;EAC1C;EACA;EACA;EACD,CAAC;CAGJ,MAAM,gBAAgB,QAAQ,aAAa,MACxC,WAAW,OAAO,aAAa,SACjC;AAED,KAAI,CAAC,cACH,OAAM,IAAIA,8CAAa,wBAAwB;EAC7C;EACA,WAAW,QAAQ;EACpB,CAAC;CAGJ,MAAM,EAAE,iBAAiB,2BAA2B;AAepD,MAbe,MAAMD,0CAAa,UAChC;EACE,yBAAyB;EACzB,uBAAuB,OAAO,OAAO;EACtC,EACD,EACE,MAAM;EACJ,2BAA2B,cAAc;EACzC,+BAA+B;EAChC,EACF,CACF,EAEU,kBAAkB,EAC3B,OAAM,IAAIC,8CAAa,4BAA4B;EACjD;EACA;EACD,CAAC;CAGJ,MAAM,iBAAiB,MAAMC,gDAAe,UAAU;CAEtD,MAAM,iBAAiB,eAAe,aAAa,MAChD,WAAW,OAAO,aAAa,cAAc,SAC/C;AAED,KAAI,CAAC,eACH,OAAM,IAAID,8CAAa,8BAA8B;EACnD,eAAe,eAAe;EAC9B;EACA;EACD,CAAC;AAGJ,QAAO"}
@@ -1,14 +1,9 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
2
  let __ai_sdk_anthropic = require("@ai-sdk/anthropic");
3
- __ai_sdk_anthropic = require_rolldown_runtime.__toESM(__ai_sdk_anthropic);
4
3
  let __ai_sdk_deepseek = require("@ai-sdk/deepseek");
5
- __ai_sdk_deepseek = require_rolldown_runtime.__toESM(__ai_sdk_deepseek);
6
4
  let __ai_sdk_google = require("@ai-sdk/google");
7
- __ai_sdk_google = require_rolldown_runtime.__toESM(__ai_sdk_google);
8
5
  let __ai_sdk_mistral = require("@ai-sdk/mistral");
9
- __ai_sdk_mistral = require_rolldown_runtime.__toESM(__ai_sdk_mistral);
10
6
  let __ai_sdk_openai = require("@ai-sdk/openai");
11
- __ai_sdk_openai = require_rolldown_runtime.__toESM(__ai_sdk_openai);
12
7
 
13
8
  //#region src/utils/AI/aiSdk.ts
14
9
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"aiSdk.cjs","names":["fallBackModel: Model","DEFAULT_PROVIDER: AIProvider","DEFAULT_TEMPERATURE: number","languageModel: AIConfig['model']"],"sources":["../../../../src/utils/AI/aiSdk.ts"],"sourcesContent":["import { type anthropic, createAnthropic } from '@ai-sdk/anthropic';\nimport { createDeepSeek, type deepseek } from '@ai-sdk/deepseek';\nimport { createGoogleGenerativeAI, type google } from '@ai-sdk/google';\nimport { createMistral, type mistral } from '@ai-sdk/mistral';\nimport { createOpenAI, type openai } from '@ai-sdk/openai';\nimport type {\n AssistantModelMessage,\n generateText,\n SystemModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from 'ai';\nimport type { Response } from 'express';\n\ntype AnthropicModel = Parameters<typeof anthropic>[0];\ntype DeepSeekModel = Parameters<typeof deepseek>[0];\ntype MistralModel = Parameters<typeof mistral>[0];\ntype OpenAIModel = Parameters<typeof openai>[0];\ntype GoogleModel = Parameters<typeof google>[0];\n\nexport type Messages = (\n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage\n)[];\n\n/**\n * Supported AI models\n */\nexport type Model =\n | AnthropicModel\n | DeepSeekModel\n | MistralModel\n | OpenAIModel\n | GoogleModel\n | (string & {});\n\n/**\n * Supported AI SDK providers\n */\nexport enum AIProvider {\n OPENAI = 'openai',\n ANTHROPIC = 'anthropic',\n MISTRAL = 'mistral',\n DEEPSEEK = 'deepseek',\n GEMINI = 'gemini',\n}\n\n/**\n * Common options for all AI providers\n */\nexport type AIOptions = {\n provider?: AIProvider;\n model?: Model;\n temperature?: number;\n apiKey?: string;\n applicationContext?: string;\n};\n\n// Define the structure of messages used in chat completions\nexport type ChatCompletionRequestMessage = {\n role: 'system' | 'user' | 'assistant'; // The role of the message sender\n content: string; // The text content of the message\n timestamp?: Date; // The timestamp of the message\n};\n\ntype AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';\n\nconst getAPIKey = (\n res: Response,\n accessType: AccessType[],\n aiOptions?: AIOptions\n) => {\n const defaultApiKey = process.env.OPENAI_API_KEY;\n\n if (accessType.includes('public')) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n if (accessType.includes('apiKey') && aiOptions?.apiKey) {\n return aiOptions?.apiKey;\n }\n\n if (accessType.includes('registered_user') && res.locals.user) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n // TODO: Implement premium user access\n if (accessType.includes('premium_user') && res.locals.user) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n return undefined;\n};\n\nconst getModel = (\n provider: AIProvider,\n userApiKey: string,\n userModel?: Model,\n defaultModel?: Model\n): Model => {\n // Set default models based on provider\n const fallBackModel: Model = defaultModel ?? 'chatgpt-4o-latest';\n\n switch (provider) {\n case AIProvider.OPENAI:\n defaultModel = 'chatgpt-4o-latest';\n break;\n case AIProvider.ANTHROPIC:\n defaultModel = 'claude-3-haiku-20240307';\n break;\n case AIProvider.MISTRAL:\n defaultModel = 'mistral-large-latest';\n break;\n case AIProvider.DEEPSEEK:\n defaultModel = 'deepseek-coder';\n break;\n case AIProvider.GEMINI:\n defaultModel = 'gemini-1.5-pro';\n break;\n }\n\n // If the user use his own API, let him use the model he wants\n if (Boolean(userApiKey) && Boolean(userModel)) {\n return userModel!;\n }\n\n if (userModel) {\n throw new Error(\n 'The user should use his own API key to use a custom model'\n );\n }\n\n return fallBackModel;\n};\n\nexport type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'>;\n\nconst DEFAULT_PROVIDER: AIProvider = AIProvider.OPENAI as AIProvider;\nconst DEFAULT_TEMPERATURE: number = 1; // ChatGPT 5 accept only temperature 1\n\nexport type AIConfigOptions = {\n userOptions?: AIOptions;\n defaultOptions?: AIOptions;\n accessType?: AccessType[];\n};\n\n/**\n * Get AI model configuration based on the selected provider and options\n * This function handles the configuration for different AI providers\n *\n * @param options Configuration options including provider, API keys, models and temperature\n * @returns Configured AI model ready to use with generateText\n */\nexport const getAIConfig = async (\n res: Response,\n options: AIConfigOptions\n): Promise<AIConfig> => {\n const {\n userOptions,\n defaultOptions,\n accessType = ['registered_user'],\n } = options;\n\n const aiOptions = {\n provider: DEFAULT_PROVIDER,\n temperature: DEFAULT_TEMPERATURE,\n ...defaultOptions,\n ...userOptions,\n } satisfies AIOptions;\n\n const apiKey = getAPIKey(res, accessType, aiOptions);\n\n // Check if API key is provided\n if (!apiKey) {\n throw new Error(`API key for ${aiOptions.provider} is missing`);\n }\n\n const selectedModel = getModel(\n aiOptions.provider,\n apiKey,\n aiOptions.model,\n defaultOptions?.model\n );\n\n const protectedOptions = {\n ...aiOptions,\n apiKey,\n model: selectedModel,\n } satisfies AIOptions;\n\n let languageModel: AIConfig['model'];\n\n switch (protectedOptions.provider) {\n case AIProvider.OPENAI: {\n languageModel = createOpenAI({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.ANTHROPIC: {\n languageModel = createAnthropic({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.MISTRAL: {\n languageModel = createMistral({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.DEEPSEEK: {\n languageModel = createDeepSeek({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.GEMINI: {\n languageModel = createGoogleGenerativeAI({\n apiKey,\n })(selectedModel);\n break;\n }\n\n default: {\n throw new Error(`Provider ${protectedOptions.provider} not supported`);\n }\n }\n\n return {\n model: languageModel,\n temperature: protectedOptions.temperature,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAyCA,IAAY,oDAAL;AACL;AACA;AACA;AACA;AACA;;;AAuBF,MAAM,aACJ,KACA,YACA,cACG;CACH,MAAM,gBAAgB,QAAQ,IAAI;AAElC,KAAI,WAAW,SAAS,SAAS,CAC/B,QAAO,WAAW,UAAU;AAG9B,KAAI,WAAW,SAAS,SAAS,IAAI,WAAW,OAC9C,QAAO,WAAW;AAGpB,KAAI,WAAW,SAAS,kBAAkB,IAAI,IAAI,OAAO,KACvD,QAAO,WAAW,UAAU;AAI9B,KAAI,WAAW,SAAS,eAAe,IAAI,IAAI,OAAO,KACpD,QAAO,WAAW,UAAU;;AAMhC,MAAM,YACJ,UACA,YACA,WACA,iBACU;CAEV,MAAMA,gBAAuB,gBAAgB;AAE7C,SAAQ,UAAR;EACE,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;;AAIJ,KAAI,QAAQ,WAAW,IAAI,QAAQ,UAAU,CAC3C,QAAO;AAGT,KAAI,UACF,OAAM,IAAI,MACR,4DACD;AAGH,QAAO;;AAKT,MAAMC,mBAA+B,WAAW;AAChD,MAAMC,sBAA8B;;;;;;;;AAepC,MAAa,cAAc,OACzB,KACA,YACsB;CACtB,MAAM,EACJ,aACA,gBACA,aAAa,CAAC,kBAAkB,KAC9B;CAEJ,MAAM,YAAY;EAChB,UAAU;EACV,aAAa;EACb,GAAG;EACH,GAAG;EACJ;CAED,MAAM,SAAS,UAAU,KAAK,YAAY,UAAU;AAGpD,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,eAAe,UAAU,SAAS,aAAa;CAGjE,MAAM,gBAAgB,SACpB,UAAU,UACV,QACA,UAAU,OACV,gBAAgB,MACjB;CAED,MAAM,mBAAmB;EACvB,GAAG;EACH;EACA,OAAO;EACR;CAED,IAAIC;AAEJ,SAAQ,iBAAiB,UAAzB;EACE,KAAK,WAAW;AACd,qDAA6B,EAC3B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,2DAAgC,EAC9B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,uDAA8B,EAC5B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,yDAA+B,EAC7B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,iEAAyC,EACvC,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,QACE,OAAM,IAAI,MAAM,YAAY,iBAAiB,SAAS,gBAAgB;;AAI1E,QAAO;EACL,OAAO;EACP,aAAa,iBAAiB;EAC/B"}
1
+ {"version":3,"file":"aiSdk.cjs","names":["fallBackModel: Model","DEFAULT_PROVIDER: AIProvider","DEFAULT_TEMPERATURE: number","languageModel: AIConfig['model']"],"sources":["../../../../src/utils/AI/aiSdk.ts"],"sourcesContent":["import { type anthropic, createAnthropic } from '@ai-sdk/anthropic';\nimport { createDeepSeek, type deepseek } from '@ai-sdk/deepseek';\nimport { createGoogleGenerativeAI, type google } from '@ai-sdk/google';\nimport { createMistral, type mistral } from '@ai-sdk/mistral';\nimport { createOpenAI, type openai } from '@ai-sdk/openai';\nimport type {\n AssistantModelMessage,\n generateText,\n SystemModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from 'ai';\nimport type { Response } from 'express';\n\ntype AnthropicModel = Parameters<typeof anthropic>[0];\ntype DeepSeekModel = Parameters<typeof deepseek>[0];\ntype MistralModel = Parameters<typeof mistral>[0];\ntype OpenAIModel = Parameters<typeof openai>[0];\ntype GoogleModel = Parameters<typeof google>[0];\n\nexport type Messages = (\n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage\n)[];\n\n/**\n * Supported AI models\n */\nexport type Model =\n | AnthropicModel\n | DeepSeekModel\n | MistralModel\n | OpenAIModel\n | GoogleModel\n | (string & {});\n\n/**\n * Supported AI SDK providers\n */\nexport enum AIProvider {\n OPENAI = 'openai',\n ANTHROPIC = 'anthropic',\n MISTRAL = 'mistral',\n DEEPSEEK = 'deepseek',\n GEMINI = 'gemini',\n}\n\n/**\n * Common options for all AI providers\n */\nexport type AIOptions = {\n provider?: AIProvider;\n model?: Model;\n temperature?: number;\n apiKey?: string;\n applicationContext?: string;\n};\n\n// Define the structure of messages used in chat completions\nexport type ChatCompletionRequestMessage = {\n role: 'system' | 'user' | 'assistant'; // The role of the message sender\n content: string; // The text content of the message\n timestamp?: Date; // The timestamp of the message\n};\n\ntype AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';\n\nconst getAPIKey = (\n res: Response,\n accessType: AccessType[],\n aiOptions?: AIOptions\n) => {\n const defaultApiKey = process.env.OPENAI_API_KEY;\n\n if (accessType.includes('public')) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n if (accessType.includes('apiKey') && aiOptions?.apiKey) {\n return aiOptions?.apiKey;\n }\n\n if (accessType.includes('registered_user') && res.locals.user) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n // TODO: Implement premium user access\n if (accessType.includes('premium_user') && res.locals.user) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n return undefined;\n};\n\nconst getModel = (\n provider: AIProvider,\n userApiKey: string,\n userModel?: Model,\n defaultModel?: Model\n): Model => {\n // Set default models based on provider\n const fallBackModel: Model = defaultModel ?? 'chatgpt-4o-latest';\n\n switch (provider) {\n case AIProvider.OPENAI:\n defaultModel = 'chatgpt-4o-latest';\n break;\n case AIProvider.ANTHROPIC:\n defaultModel = 'claude-3-haiku-20240307';\n break;\n case AIProvider.MISTRAL:\n defaultModel = 'mistral-large-latest';\n break;\n case AIProvider.DEEPSEEK:\n defaultModel = 'deepseek-coder';\n break;\n case AIProvider.GEMINI:\n defaultModel = 'gemini-1.5-pro';\n break;\n }\n\n // If the user use his own API, let him use the model he wants\n if (Boolean(userApiKey) && Boolean(userModel)) {\n return userModel!;\n }\n\n if (userModel) {\n throw new Error(\n 'The user should use his own API key to use a custom model'\n );\n }\n\n return fallBackModel;\n};\n\nexport type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'>;\n\nconst DEFAULT_PROVIDER: AIProvider = AIProvider.OPENAI as AIProvider;\nconst DEFAULT_TEMPERATURE: number = 1; // ChatGPT 5 accept only temperature 1\n\nexport type AIConfigOptions = {\n userOptions?: AIOptions;\n defaultOptions?: AIOptions;\n accessType?: AccessType[];\n};\n\n/**\n * Get AI model configuration based on the selected provider and options\n * This function handles the configuration for different AI providers\n *\n * @param options Configuration options including provider, API keys, models and temperature\n * @returns Configured AI model ready to use with generateText\n */\nexport const getAIConfig = async (\n res: Response,\n options: AIConfigOptions\n): Promise<AIConfig> => {\n const {\n userOptions,\n defaultOptions,\n accessType = ['registered_user'],\n } = options;\n\n const aiOptions = {\n provider: DEFAULT_PROVIDER,\n temperature: DEFAULT_TEMPERATURE,\n ...defaultOptions,\n ...userOptions,\n } satisfies AIOptions;\n\n const apiKey = getAPIKey(res, accessType, aiOptions);\n\n // Check if API key is provided\n if (!apiKey) {\n throw new Error(`API key for ${aiOptions.provider} is missing`);\n }\n\n const selectedModel = getModel(\n aiOptions.provider,\n apiKey,\n aiOptions.model,\n defaultOptions?.model\n );\n\n const protectedOptions = {\n ...aiOptions,\n apiKey,\n model: selectedModel,\n } satisfies AIOptions;\n\n let languageModel: AIConfig['model'];\n\n switch (protectedOptions.provider) {\n case AIProvider.OPENAI: {\n languageModel = createOpenAI({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.ANTHROPIC: {\n languageModel = createAnthropic({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.MISTRAL: {\n languageModel = createMistral({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.DEEPSEEK: {\n languageModel = createDeepSeek({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.GEMINI: {\n languageModel = createGoogleGenerativeAI({\n apiKey,\n })(selectedModel);\n break;\n }\n\n default: {\n throw new Error(`Provider ${protectedOptions.provider} not supported`);\n }\n }\n\n return {\n model: languageModel,\n temperature: protectedOptions.temperature,\n };\n};\n"],"mappings":";;;;;;;;;;;AAyCA,IAAY,oDAAL;AACL;AACA;AACA;AACA;AACA;;;AAuBF,MAAM,aACJ,KACA,YACA,cACG;CACH,MAAM,gBAAgB,QAAQ,IAAI;AAElC,KAAI,WAAW,SAAS,SAAS,CAC/B,QAAO,WAAW,UAAU;AAG9B,KAAI,WAAW,SAAS,SAAS,IAAI,WAAW,OAC9C,QAAO,WAAW;AAGpB,KAAI,WAAW,SAAS,kBAAkB,IAAI,IAAI,OAAO,KACvD,QAAO,WAAW,UAAU;AAI9B,KAAI,WAAW,SAAS,eAAe,IAAI,IAAI,OAAO,KACpD,QAAO,WAAW,UAAU;;AAMhC,MAAM,YACJ,UACA,YACA,WACA,iBACU;CAEV,MAAMA,gBAAuB,gBAAgB;AAE7C,SAAQ,UAAR;EACE,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;EACF,KAAK,WAAW;AACd,kBAAe;AACf;;AAIJ,KAAI,QAAQ,WAAW,IAAI,QAAQ,UAAU,CAC3C,QAAO;AAGT,KAAI,UACF,OAAM,IAAI,MACR,4DACD;AAGH,QAAO;;AAKT,MAAMC,mBAA+B,WAAW;AAChD,MAAMC,sBAA8B;;;;;;;;AAepC,MAAa,cAAc,OACzB,KACA,YACsB;CACtB,MAAM,EACJ,aACA,gBACA,aAAa,CAAC,kBAAkB,KAC9B;CAEJ,MAAM,YAAY;EAChB,UAAU;EACV,aAAa;EACb,GAAG;EACH,GAAG;EACJ;CAED,MAAM,SAAS,UAAU,KAAK,YAAY,UAAU;AAGpD,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,eAAe,UAAU,SAAS,aAAa;CAGjE,MAAM,gBAAgB,SACpB,UAAU,UACV,QACA,UAAU,OACV,gBAAgB,MACjB;CAED,MAAM,mBAAmB;EACvB,GAAG;EACH;EACA,OAAO;EACR;CAED,IAAIC;AAEJ,SAAQ,iBAAiB,UAAzB;EACE,KAAK,WAAW;AACd,qDAA6B,EAC3B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,2DAAgC,EAC9B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,uDAA8B,EAC5B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,yDAA+B,EAC7B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,iEAAyC,EACvC,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,QACE,OAAM,IAAI,MAAM,YAAY,iBAAiB,SAAS,gBAAgB;;AAI1E,QAAO;EACL,OAAO;EACP,aAAa,iBAAiB;EAC/B"}
@@ -2,13 +2,9 @@ const require_rolldown_runtime = require('../../../_virtual/rolldown_runtime.cjs
2
2
  const require_utils_AI_aiSdk = require('../aiSdk.cjs');
3
3
  const require__utils_asset = require('../../../_virtual/_utils_asset.cjs');
4
4
  let __intlayer_core = require("@intlayer/core");
5
- __intlayer_core = require_rolldown_runtime.__toESM(__intlayer_core);
6
5
  let __intlayer_docs = require("@intlayer/docs");
7
- __intlayer_docs = require_rolldown_runtime.__toESM(__intlayer_docs);
8
6
  let ai = require("ai");
9
- ai = require_rolldown_runtime.__toESM(ai);
10
7
  let openai = require("openai");
11
- openai = require_rolldown_runtime.__toESM(openai);
12
8
 
13
9
  //#region src/utils/AI/askDocQuestion/askDocQuestion.ts
14
10
  const readEmbeddingsForFile = (fileKey) => {
@@ -1 +1 @@
1
- {"version":3,"file":"askDocQuestion.cjs","names":["readAsset","vectorStore: VectorStoreEl[]","MODEL: AIOptions['model']","MODEL_TEMPERATURE: AIOptions['temperature']","MAX_RELEVANT_CHUNKS_NB: number","MIN_RELEVANT_CHUNKS_SIMILARITY: number","aiDefaultOptions: AIOptions","AIProvider","EMBEDDING_MODEL: OpenAI.EmbeddingModel","OVERLAP_TOKENS: number","MAX_CHUNK_TOKENS: number","CHAR_BY_TOKEN: number","MAX_CHARS: number","OVERLAP_CHARS: number","chunks: string[]","OpenAI","resultForFile: Record<string, number[] | undefined>","initPrompt: ChatCompletionRequestMessage"],"sources":["../../../../../src/utils/AI/askDocQuestion/askDocQuestion.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { getMarkdownMetadata } from '@intlayer/core';\nimport { getBlogs, getDocs, getFrequentQuestions } from '@intlayer/docs';\nimport { streamText } from 'ai';\nimport { OpenAI } from 'openai';\nimport {\n type AIConfig,\n type AIOptions,\n AIProvider,\n type ChatCompletionRequestMessage,\n} from '../aiSdk';\n\nconst readEmbeddingsForFile = (fileKey: string): Record<string, number[]> => {\n try {\n return JSON.parse(\n readAsset(`./embeddings/${fileKey.replace('.md', '.json')}`, 'utf-8')\n ) as Record<string, number[]>;\n } catch {\n return {};\n }\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 * Ask question AI configuration\n */\nconst MODEL: AIOptions['model'] = 'chatgpt-4o-latest'; // Model to use for chat completions\nconst MODEL_TEMPERATURE: AIOptions['temperature'] = 0.1; // Temperature to use for chat completions\nconst MAX_RELEVANT_CHUNKS_NB: number = 20; // Maximum number of relevant chunks to attach to chatGPT context\nconst MIN_RELEVANT_CHUNKS_SIMILARITY: number = 0.42; // Minimum similarity required for a chunk to be considered relevant\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: MODEL,\n temperature: MODEL_TEMPERATURE,\n};\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 console.error('Error generating embedding:', error);\n return [];\n }\n};\n\n/**\n * Calculates the cosine similarity between two vectors.\n * Cosine similarity measures the cosine of the angle between two vectors in an inner product space.\n * Used to determine the similarity between chunks of text.\n *\n * @param vecA - The first vector\n * @param vecB - The second vector\n * @returns The cosine similarity score\n */\nconst cosineSimilarity = (vecA: number[], vecB: number[]): number => {\n // Calculate the dot product of the two vectors\n const dotProduct = vecA.reduce((sum, a, idx) => sum + a * vecB[idx], 0);\n\n // Calculate the magnitude (Euclidean norm) of each vector\n const magnitudeA = Math.sqrt(vecA.reduce((sum, a) => sum + a * a, 0));\n const magnitudeB = Math.sqrt(vecB.reduce((sum, b) => sum + b * b, 0));\n\n // Compute and return the cosine similarity\n return dotProduct / (magnitudeA * magnitudeB);\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 loadMarkdownFiles = async (): Promise<void> => {\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 // Check if the number of chunks has changed for this file\n const existingChunksForFile = Object.keys(existingEmbeddings);\n const currentChunkCount = fileChunks.length;\n const previousChunkCount = existingChunksForFile.length;\n\n let shouldRegenerateFileEmbeddings = false;\n\n // If chunk count differs, we need to regenerate embeddings for this file\n if (currentChunkCount !== previousChunkCount) {\n console.info(\n `File \"${fileKey}\" chunk count changed: ${previousChunkCount} -> ${currentChunkCount}. Regenerating embeddings.`\n );\n\n shouldRegenerateFileEmbeddings = !skipDocEmbeddingsIndex;\n }\n\n // Iterate over each chunk within the current file\n let resultForFile: Record<string, number[] | undefined> = {};\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\n // Retrieve precomputed embedding if available and file hasn't changed\n const docEmbedding = !shouldRegenerateFileEmbeddings\n ? (existingEmbeddings[\n chunkKeyName as keyof typeof existingEmbeddings\n ] as number[] | undefined)\n : undefined;\n\n const embedding = docEmbedding; // Use existing embedding if available and valid\n\n // Update the file-scoped result object with the embedding\n resultForFile = { ...resultForFile, [chunkKeyName]: embedding };\n\n // Store the embedding and content in the in-memory vector store\n vectorStore.push({\n fileKey,\n chunkNumber,\n embedding,\n content: fileChunk,\n docUrl: fileMetadata.url,\n docName: fileMetadata.title,\n });\n\n console.info(`- Loaded: ${fileKey}/${chunkKeyName}/${chunksNumber}`);\n }\n }\n};\n\n// Automatically index Markdown files\nloadMarkdownFiles();\n\n/**\n * Searches the indexed documents for the most relevant chunks based on a query.\n * Utilizes cosine similarity to find the closest matching embeddings.\n *\n * @param query - The search query provided by the user\n * @returns An array of the top matching document chunks' content\n */\nexport const searchChunkReference = async (\n query: string,\n maxResults: number = MAX_RELEVANT_CHUNKS_NB,\n minSimilarity: number = MIN_RELEVANT_CHUNKS_SIMILARITY\n): Promise<VectorStoreEl[]> => {\n // Generate an embedding for the user's query\n const queryEmbedding = await generateEmbedding(query);\n\n // Calculate similarity scores between the query embedding and each document's embedding\n const selection = vectorStore\n .filter((chunk) => chunk.embedding)\n .map((chunk) => ({\n ...chunk,\n similarity: cosineSimilarity(queryEmbedding, chunk.embedding!), // Add similarity score to each doc\n }))\n .filter((chunk) => chunk.similarity > minSimilarity) // Filter out documents with low similarity scores\n .sort((a, b) => b.similarity - a.similarity) // Sort documents by highest similarity first\n .slice(0, maxResults); // Select the top 6 most similar documents\n\n const orderedDocKeys = new Set(selection.map((chunk) => chunk.fileKey));\n\n const orderedVectorStore = vectorStore.sort((a, _b) =>\n orderedDocKeys.has(a.fileKey) ? -1 : 1\n );\n\n const results = orderedVectorStore.filter((chunk) =>\n selection.some(\n (v) => v.fileKey === chunk.fileKey && v.chunkNumber === chunk.chunkNumber\n )\n );\n\n // Return the content of the top matching documents\n return results;\n};\n\nconst CHAT_GPT_PROMPT = readAsset('./PROMPT.md');\n\n// Initial prompt configuration for the chatbot\nexport const initPrompt: ChatCompletionRequestMessage = {\n role: 'system',\n content: CHAT_GPT_PROMPT,\n};\n\nexport type AskDocQuestionResult = {\n response: string;\n relatedFiles: string[];\n};\n\nexport type AskDocQuestionOptions = {\n onMessage?: (chunk: string) => void;\n};\n\n/**\n * Handles the \"Ask a question\" endpoint in an Express.js route.\n * Processes user messages, retrieves relevant documents, and interacts with AI models to generate responses.\n *\n * @param messages - An array of chat messages from the user and assistant\n * @returns The assistant's response as a string\n */\nexport const askDocQuestion = async (\n messages: ChatCompletionRequestMessage[],\n aiConfig: AIConfig,\n options?: AskDocQuestionOptions\n): Promise<AskDocQuestionResult> => {\n // Format the user's question to keep only the relevant keywords\n const query = messages\n .filter((message) => message.role === 'user')\n .map((message) => `- ${message.content}`)\n .join('\\n');\n\n // 1) Find relevant documents based on the user's question\n const relevantFilesReferences = await searchChunkReference(query);\n\n // 2) Integrate the relevant documents into the initial system prompt\n const systemPrompt = initPrompt.content.replace(\n '{{relevantFilesReferences}}',\n relevantFilesReferences.length === 0\n ? 'Not relevant file found related to the question.'\n : relevantFilesReferences\n .map((doc, idx) =>\n [\n '-----',\n '---',\n `chunkId: ${idx}`,\n `docChunk: \"${doc.chunkNumber}/${doc.fileKey.length}\"`,\n `docName: \"${doc.docName}\"`,\n `docUrl: \"${doc.docUrl}\"`,\n `---`,\n doc.content,\n `-----`,\n ].join('\\n')\n )\n .join('\\n\\n') // Insert relevant docs into the prompt\n );\n\n // Format messages for AI SDK\n const aiMessages = [\n {\n role: 'system' as const,\n content: systemPrompt,\n },\n ...messages.slice(-8),\n ];\n\n if (!aiConfig) {\n throw new Error('Failed to initialize AI configuration');\n }\n\n // 3) Use the AI SDK to stream the response\n let fullResponse = '';\n const stream = streamText({\n ...aiConfig,\n messages: aiMessages,\n });\n\n // Process the stream\n for await (const chunk of stream.textStream) {\n fullResponse += chunk;\n options?.onMessage?.(chunk);\n }\n\n // 4) Extract unique related files\n const relatedFiles = [\n ...new Set(relevantFilesReferences.map((doc) => doc.fileKey)),\n ];\n\n // 5) Return the assistant's response to the user\n return {\n response: fullResponse ?? 'Error: No result found',\n relatedFiles,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"askDocQuestion.cjs","names":["readAsset","vectorStore: VectorStoreEl[]","MODEL: AIOptions['model']","MODEL_TEMPERATURE: AIOptions['temperature']","MAX_RELEVANT_CHUNKS_NB: number","MIN_RELEVANT_CHUNKS_SIMILARITY: number","aiDefaultOptions: AIOptions","AIProvider","EMBEDDING_MODEL: OpenAI.EmbeddingModel","OVERLAP_TOKENS: number","MAX_CHUNK_TOKENS: number","CHAR_BY_TOKEN: number","MAX_CHARS: number","OVERLAP_CHARS: number","chunks: string[]","OpenAI","resultForFile: Record<string, number[] | undefined>","initPrompt: ChatCompletionRequestMessage"],"sources":["../../../../../src/utils/AI/askDocQuestion/askDocQuestion.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { getMarkdownMetadata } from '@intlayer/core';\nimport { getBlogs, getDocs, getFrequentQuestions } from '@intlayer/docs';\nimport { streamText } from 'ai';\nimport { OpenAI } from 'openai';\nimport {\n type AIConfig,\n type AIOptions,\n AIProvider,\n type ChatCompletionRequestMessage,\n} from '../aiSdk';\n\nconst readEmbeddingsForFile = (fileKey: string): Record<string, number[]> => {\n try {\n return JSON.parse(\n readAsset(`./embeddings/${fileKey.replace('.md', '.json')}`, 'utf-8')\n ) as Record<string, number[]>;\n } catch {\n return {};\n }\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 * Ask question AI configuration\n */\nconst MODEL: AIOptions['model'] = 'chatgpt-4o-latest'; // Model to use for chat completions\nconst MODEL_TEMPERATURE: AIOptions['temperature'] = 0.1; // Temperature to use for chat completions\nconst MAX_RELEVANT_CHUNKS_NB: number = 20; // Maximum number of relevant chunks to attach to chatGPT context\nconst MIN_RELEVANT_CHUNKS_SIMILARITY: number = 0.42; // Minimum similarity required for a chunk to be considered relevant\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: MODEL,\n temperature: MODEL_TEMPERATURE,\n};\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 console.error('Error generating embedding:', error);\n return [];\n }\n};\n\n/**\n * Calculates the cosine similarity between two vectors.\n * Cosine similarity measures the cosine of the angle between two vectors in an inner product space.\n * Used to determine the similarity between chunks of text.\n *\n * @param vecA - The first vector\n * @param vecB - The second vector\n * @returns The cosine similarity score\n */\nconst cosineSimilarity = (vecA: number[], vecB: number[]): number => {\n // Calculate the dot product of the two vectors\n const dotProduct = vecA.reduce((sum, a, idx) => sum + a * vecB[idx], 0);\n\n // Calculate the magnitude (Euclidean norm) of each vector\n const magnitudeA = Math.sqrt(vecA.reduce((sum, a) => sum + a * a, 0));\n const magnitudeB = Math.sqrt(vecB.reduce((sum, b) => sum + b * b, 0));\n\n // Compute and return the cosine similarity\n return dotProduct / (magnitudeA * magnitudeB);\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 loadMarkdownFiles = async (): Promise<void> => {\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 // Check if the number of chunks has changed for this file\n const existingChunksForFile = Object.keys(existingEmbeddings);\n const currentChunkCount = fileChunks.length;\n const previousChunkCount = existingChunksForFile.length;\n\n let shouldRegenerateFileEmbeddings = false;\n\n // If chunk count differs, we need to regenerate embeddings for this file\n if (currentChunkCount !== previousChunkCount) {\n console.info(\n `File \"${fileKey}\" chunk count changed: ${previousChunkCount} -> ${currentChunkCount}. Regenerating embeddings.`\n );\n\n shouldRegenerateFileEmbeddings = !skipDocEmbeddingsIndex;\n }\n\n // Iterate over each chunk within the current file\n let resultForFile: Record<string, number[] | undefined> = {};\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\n // Retrieve precomputed embedding if available and file hasn't changed\n const docEmbedding = !shouldRegenerateFileEmbeddings\n ? (existingEmbeddings[\n chunkKeyName as keyof typeof existingEmbeddings\n ] as number[] | undefined)\n : undefined;\n\n const embedding = docEmbedding; // Use existing embedding if available and valid\n\n // Update the file-scoped result object with the embedding\n resultForFile = { ...resultForFile, [chunkKeyName]: embedding };\n\n // Store the embedding and content in the in-memory vector store\n vectorStore.push({\n fileKey,\n chunkNumber,\n embedding,\n content: fileChunk,\n docUrl: fileMetadata.url,\n docName: fileMetadata.title,\n });\n\n console.info(`- Loaded: ${fileKey}/${chunkKeyName}/${chunksNumber}`);\n }\n }\n};\n\n// Automatically index Markdown files\nloadMarkdownFiles();\n\n/**\n * Searches the indexed documents for the most relevant chunks based on a query.\n * Utilizes cosine similarity to find the closest matching embeddings.\n *\n * @param query - The search query provided by the user\n * @returns An array of the top matching document chunks' content\n */\nexport const searchChunkReference = async (\n query: string,\n maxResults: number = MAX_RELEVANT_CHUNKS_NB,\n minSimilarity: number = MIN_RELEVANT_CHUNKS_SIMILARITY\n): Promise<VectorStoreEl[]> => {\n // Generate an embedding for the user's query\n const queryEmbedding = await generateEmbedding(query);\n\n // Calculate similarity scores between the query embedding and each document's embedding\n const selection = vectorStore\n .filter((chunk) => chunk.embedding)\n .map((chunk) => ({\n ...chunk,\n similarity: cosineSimilarity(queryEmbedding, chunk.embedding!), // Add similarity score to each doc\n }))\n .filter((chunk) => chunk.similarity > minSimilarity) // Filter out documents with low similarity scores\n .sort((a, b) => b.similarity - a.similarity) // Sort documents by highest similarity first\n .slice(0, maxResults); // Select the top 6 most similar documents\n\n const orderedDocKeys = new Set(selection.map((chunk) => chunk.fileKey));\n\n const orderedVectorStore = vectorStore.sort((a, _b) =>\n orderedDocKeys.has(a.fileKey) ? -1 : 1\n );\n\n const results = orderedVectorStore.filter((chunk) =>\n selection.some(\n (v) => v.fileKey === chunk.fileKey && v.chunkNumber === chunk.chunkNumber\n )\n );\n\n // Return the content of the top matching documents\n return results;\n};\n\nconst CHAT_GPT_PROMPT = readAsset('./PROMPT.md');\n\n// Initial prompt configuration for the chatbot\nexport const initPrompt: ChatCompletionRequestMessage = {\n role: 'system',\n content: CHAT_GPT_PROMPT,\n};\n\nexport type AskDocQuestionResult = {\n response: string;\n relatedFiles: string[];\n};\n\nexport type AskDocQuestionOptions = {\n onMessage?: (chunk: string) => void;\n};\n\n/**\n * Handles the \"Ask a question\" endpoint in an Express.js route.\n * Processes user messages, retrieves relevant documents, and interacts with AI models to generate responses.\n *\n * @param messages - An array of chat messages from the user and assistant\n * @returns The assistant's response as a string\n */\nexport const askDocQuestion = async (\n messages: ChatCompletionRequestMessage[],\n aiConfig: AIConfig,\n options?: AskDocQuestionOptions\n): Promise<AskDocQuestionResult> => {\n // Format the user's question to keep only the relevant keywords\n const query = messages\n .filter((message) => message.role === 'user')\n .map((message) => `- ${message.content}`)\n .join('\\n');\n\n // 1) Find relevant documents based on the user's question\n const relevantFilesReferences = await searchChunkReference(query);\n\n // 2) Integrate the relevant documents into the initial system prompt\n const systemPrompt = initPrompt.content.replace(\n '{{relevantFilesReferences}}',\n relevantFilesReferences.length === 0\n ? 'Not relevant file found related to the question.'\n : relevantFilesReferences\n .map((doc, idx) =>\n [\n '-----',\n '---',\n `chunkId: ${idx}`,\n `docChunk: \"${doc.chunkNumber}/${doc.fileKey.length}\"`,\n `docName: \"${doc.docName}\"`,\n `docUrl: \"${doc.docUrl}\"`,\n `---`,\n doc.content,\n `-----`,\n ].join('\\n')\n )\n .join('\\n\\n') // Insert relevant docs into the prompt\n );\n\n // Format messages for AI SDK\n const aiMessages = [\n {\n role: 'system' as const,\n content: systemPrompt,\n },\n ...messages.slice(-8),\n ];\n\n if (!aiConfig) {\n throw new Error('Failed to initialize AI configuration');\n }\n\n // 3) Use the AI SDK to stream the response\n let fullResponse = '';\n const stream = streamText({\n ...aiConfig,\n messages: aiMessages,\n });\n\n // Process the stream\n for await (const chunk of stream.textStream) {\n fullResponse += chunk;\n options?.onMessage?.(chunk);\n }\n\n // 4) Extract unique related files\n const relatedFiles = [\n ...new Set(relevantFilesReferences.map((doc) => doc.fileKey)),\n ];\n\n // 5) Return the assistant's response to the user\n return {\n response: fullResponse ?? 'Error: No result found',\n relatedFiles,\n };\n};\n"],"mappings":"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"}