@intlayer/backend 5.1.7 → 5.1.8
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.
- package/dist/cjs/controllers/dictionary.controller.cjs +5 -7
- package/dist/cjs/controllers/dictionary.controller.cjs.map +1 -1
- package/dist/cjs/controllers/{event-listener.cjs → eventListener.controller.cjs} +27 -8
- package/dist/cjs/controllers/eventListener.controller.cjs.map +1 -0
- package/dist/cjs/export.cjs.map +1 -1
- package/dist/cjs/index.cjs +2 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/routes/{event-listener.routes.cjs → eventListener.routes.cjs} +6 -6
- package/dist/cjs/routes/eventListener.routes.cjs.map +1 -0
- package/dist/cjs/services/dictionary.service.cjs +11 -30
- package/dist/cjs/services/dictionary.service.cjs.map +1 -1
- package/dist/cjs/types/dictionary.types.cjs.map +1 -1
- package/dist/cjs/utils/AI/askDocQuestion/embeddings.json +4298 -612
- package/dist/cjs/utils/errors/errorCodes.cjs +18 -1
- package/dist/cjs/utils/errors/errorCodes.cjs.map +1 -1
- package/dist/esm/controllers/dictionary.controller.mjs +5 -7
- package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
- package/dist/esm/controllers/{event-listener.mjs → eventListener.controller.mjs} +24 -5
- package/dist/esm/controllers/eventListener.controller.mjs.map +1 -0
- package/dist/esm/export.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/routes/{event-listener.routes.mjs → eventListener.routes.mjs} +2 -2
- package/dist/esm/routes/eventListener.routes.mjs.map +1 -0
- package/dist/esm/services/dictionary.service.mjs +11 -30
- package/dist/esm/services/dictionary.service.mjs.map +1 -1
- package/dist/esm/utils/AI/askDocQuestion/embeddings.json +4298 -612
- package/dist/esm/utils/errors/errorCodes.mjs +18 -1
- package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
- package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
- package/dist/types/controllers/{event-listener.d.ts → eventListener.controller.d.ts} +8 -1
- package/dist/types/controllers/eventListener.controller.d.ts.map +1 -0
- package/dist/types/export.d.ts +1 -0
- package/dist/types/export.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/models/dictionary.model.d.ts +0 -1
- package/dist/types/models/dictionary.model.d.ts.map +1 -1
- package/dist/types/routes/{event-listener.routes.d.ts → eventListener.routes.d.ts} +1 -1
- package/dist/types/routes/eventListener.routes.d.ts.map +1 -0
- package/dist/types/schemas/dictionary.schema.d.ts +0 -1
- package/dist/types/schemas/dictionary.schema.d.ts.map +1 -1
- package/dist/types/services/dictionary.service.d.ts.map +1 -1
- package/dist/types/types/dictionary.types.d.ts +0 -1
- package/dist/types/types/dictionary.types.d.ts.map +1 -1
- package/dist/types/utils/errors/errorCodes.d.ts +18 -1
- package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/cjs/controllers/event-listener.cjs.map +0 -1
- package/dist/cjs/routes/event-listener.routes.cjs.map +0 -1
- package/dist/esm/controllers/event-listener.mjs.map +0 -1
- package/dist/esm/routes/event-listener.routes.mjs.map +0 -1
- package/dist/types/controllers/event-listener.d.ts.map +0 -1
- package/dist/types/routes/event-listener.routes.d.ts.map +0 -1
|
@@ -45,7 +45,7 @@ var import_getDictionaryFiltersAndPagination = require('./../utils/filtersAndPag
|
|
|
45
45
|
var import_dictionary = require('./../utils/mapper/dictionary.cjs');
|
|
46
46
|
var import_responseData = require('./../utils/responseData.cjs');
|
|
47
47
|
var import_express_intlayer = require("express-intlayer");
|
|
48
|
-
var eventListener = __toESM(require('./../controllers/
|
|
48
|
+
var eventListener = __toESM(require('./../controllers/eventListener.controller.cjs'), 1);
|
|
49
49
|
const getDictionaries = async (req, res, _next) => {
|
|
50
50
|
const { user, project, dictionaryRights } = res.locals;
|
|
51
51
|
const { filters, pageSize, skip, page, getNumberOfPages } = (0, import_getDictionaryFiltersAndPagination.getDictionaryFiltersAndPagination)(req);
|
|
@@ -294,12 +294,10 @@ const pushDictionaries = async (req, res, _next) => {
|
|
|
294
294
|
let newContent = existingDictionaryDB.content;
|
|
295
295
|
if (!isSameContent) {
|
|
296
296
|
const newContentVersion = dictionaryService.incrementVersion(existingDictionaryDB);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
};
|
|
297
|
+
existingDictionaryDB.content.set(newContentVersion, {
|
|
298
|
+
content: dictionaryDataEl.content ?? {}
|
|
299
|
+
});
|
|
300
|
+
newContent = existingDictionaryDB.content;
|
|
303
301
|
}
|
|
304
302
|
const dictionary = {
|
|
305
303
|
...(0, import_ensureMongoDocumentToObject.ensureMongoDocumentToObject)(existingDictionaryDB),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/controllers/dictionary.controller.ts"],"sourcesContent":["import type {\n ContentNode,\n Dictionary as LocalDictionary,\n} from '@intlayer/core';\nimport { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as dictionaryService from '@services/dictionary.service';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport {\n type DictionaryFiltersParams,\n getDictionaryFiltersAndPagination,\n} from '@utils/filtersAndPagination/getDictionaryFiltersAndPagination';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport { mapDictionaryToAPI } from '@utils/mapper/dictionary';\nimport {\n formatPaginatedResponse,\n type ResponseData,\n type PaginatedResponse,\n formatResponse,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport * as eventListener from '@/controllers/event-listener';\nimport type {\n Dictionary,\n DictionaryAPI,\n DictionaryCreationData,\n DictionaryData,\n VersionedContent,\n} from '@/types/dictionary.types';\n\nexport type GetDictionariesParams =\n FiltersAndPagination<DictionaryFiltersParams>;\nexport type GetDictionariesResult = PaginatedResponse<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaries = async (\n req: Request<GetDictionariesParams>,\n res: ResponseWithInformation<GetDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, dictionaryRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getDictionaryFiltersAndPagination(req);\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n if (!dictionaryRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_READ');\n return;\n }\n\n try {\n const dictionaries = await dictionaryService.findDictionaries(\n filters,\n skip,\n pageSize\n );\n const totalItems = await dictionaryService.countDictionaries(filters);\n\n const dictionariesAPI = dictionaries.map((el) =>\n mapDictionaryToAPI(el, project._id)\n );\n\n const responseData = formatPaginatedResponse<DictionaryAPI>({\n data: dictionariesAPI,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionariesKeysResult = ResponseData<string[]>;\n\n/**\n * Retrieves a list of dictionaries keys based on filters and pagination.\n */\nexport const getDictionariesKeys = async (\n _req: Request,\n res: ResponseWithInformation<GetDictionariesKeysResult>,\n _next: NextFunction\n) => {\n const { project, dictionaryRights } = res.locals;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!dictionaryRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_READ');\n return;\n }\n\n try {\n const dictionariesKeys = await dictionaryService.getDictionariesKeys(\n project._id\n );\n\n const responseData = formatResponse<string[]>({\n data: dictionariesKeys,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionaryParams = { dictionaryKey: string };\nexport type GetDictionaryQuery = { version?: string };\nexport type GetDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaryByKey = async (\n req: Request<GetDictionaryParams, any, any, GetDictionaryQuery>,\n res: ResponseWithInformation<GetDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, dictionaryRights } = res.locals;\n const { dictionaryKey } = req.params;\n const version = req.query.version;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n if (!dictionaryRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_READ');\n return;\n }\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n dictionaryKey,\n project._id\n );\n\n if (!dictionary.projectIds.map(String).includes(String(project._id))) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const apiResult = mapDictionaryToAPI(dictionary, project._id, version);\n\n const responseData = formatResponse<DictionaryAPI>({\n data: apiResult,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddDictionaryBody = { dictionary: DictionaryCreationData };\nexport type AddDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Adds a new dictionary to the database.\n */\nexport const addDictionary = async (\n req: Request<any, any, AddDictionaryBody>,\n res: ResponseWithInformation<AddDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, dictionaryRights } = res.locals;\n const dictionaryData = req.body.dictionary;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project._id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n if (!dictionaryRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_ADMIN');\n return;\n }\n\n const dictionary: DictionaryData = {\n key: dictionaryData.key,\n title: dictionaryData.title,\n description: dictionaryData.description,\n content: new Map([\n ['v1', { content: dictionaryData.content ?? ({} as ContentNode) }],\n ]),\n creatorId: user._id,\n filePath: {\n [String(project._id)]: dictionaryData.filePath ?? '',\n },\n projectIds: dictionaryData.projectIds ?? [String(project._id)],\n };\n\n try {\n const newDictionary = await dictionaryService.createDictionary(dictionary);\n\n const apiResult = mapDictionaryToAPI(newDictionary, project._id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary created successfully',\n fr: 'Dictionnaire créé avec succès',\n es: 'Diccionario creado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been created successfully',\n fr: 'Votre dictionnaire a été créé avec succès',\n es: 'Su diccionario ha sido creado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: mapDictionaryToAPI(newDictionary, project._id),\n status: 'ADDED',\n },\n ]);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type PushDictionariesBody = {\n dictionaries: LocalDictionary[];\n};\ntype PushDictionariesResultData = {\n newDictionaries: string[];\n updatedDictionaries: string[];\n error: { dictionaryId: string; message: string }[];\n};\nexport type PushDictionariesResult = ResponseData<PushDictionariesResultData>;\n\n/**\n * Check each dictionaries, add the new ones and update the existing ones.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response containing the created dictionary.\n */\nexport const pushDictionaries = async (\n req: Request<any, any, PushDictionariesBody>,\n res: ResponseWithInformation<PushDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, dictionaryRights } = res.locals;\n const dictionaryData = req.body.dictionaries;\n const dictionariesKeys = dictionaryData.map((dictionary) => dictionary.key);\n\n if (\n typeof dictionaryData === 'object' &&\n Array.isArray(dictionaryData) &&\n dictionaryData.length === 0\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARIES_NOT_PROVIDED');\n return;\n } else if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_WRITE');\n return;\n }\n\n if (!dictionaryRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_ADMIN');\n return;\n }\n\n try {\n const { existingDictionariesKey, newDictionariesKey } =\n await dictionaryService.getExistingDictionaryKey(\n dictionariesKeys,\n project._id\n );\n\n const existingDictionaries = dictionaryData.filter((dictionary) =>\n existingDictionariesKey.includes(dictionary.key)\n );\n const newDictionaries = dictionaryData.filter((dictionary) =>\n newDictionariesKey.includes(dictionary.key)\n );\n\n const newDictionariesResult: DictionaryAPI[] = [];\n const updatedDictionariesResult: DictionaryAPI[] = [];\n const errorResult: PushDictionariesResultData['error'] = [];\n\n for (const dictionaryDataEl of newDictionaries) {\n const dictionary: DictionaryData = {\n title: dictionaryDataEl.title,\n description: dictionaryDataEl.description,\n projectIds: [String(project._id)],\n creatorId: user._id,\n content: new Map([\n ['v1', { content: dictionaryDataEl.content ?? ({} as ContentNode) }],\n ]),\n filePath: {\n [String(project._id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const newDictionary =\n await dictionaryService.createDictionary(dictionary);\n newDictionariesResult.push(\n mapDictionaryToAPI(newDictionary, project._id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n\n if (existingDictionariesKey.length >= 0) {\n const existingDictionariesDB =\n await dictionaryService.getDictionariesByKeys(\n existingDictionariesKey,\n project._id\n );\n\n for (const dictionaryDataEl of existingDictionaries) {\n const existingDictionaryDB = existingDictionariesDB.find(\n (dictionaryDB) => dictionaryDB.key === dictionaryDataEl.key\n )!;\n\n const versionList = [...(existingDictionaryDB.content.keys() ?? [])];\n const lastVersion = versionList[versionList.length - 1];\n\n const lastContent =\n (existingDictionaryDB.content.get(lastVersion)\n ?.content as DictionaryAPI['content']) ?? null;\n\n const isSameContent =\n JSON.stringify(lastContent) ===\n JSON.stringify(dictionaryDataEl.content);\n\n let newContent: VersionedContent = existingDictionaryDB.content;\n\n if (!isSameContent) {\n const newContentVersion =\n dictionaryService.incrementVersion(existingDictionaryDB);\n\n newContent = {\n ...newContent,\n [newContentVersion]: {\n content: dictionaryDataEl.content,\n },\n };\n }\n\n const dictionary: DictionaryData = {\n ...ensureMongoDocumentToObject(existingDictionaryDB),\n ...dictionaryDataEl,\n content: newContent,\n projectIds: [String(project._id)],\n creatorId: user._id,\n filePath: {\n [String(project._id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const updatedDictionary =\n await dictionaryService.updateDictionaryByKey(\n dictionaryDataEl.key,\n dictionary,\n project._id\n );\n updatedDictionariesResult.push(\n mapDictionaryToAPI(updatedDictionary, project._id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n }\n\n const result: PushDictionariesResultData = {\n newDictionaries: newDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n updatedDictionaries: updatedDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n error: errorResult,\n };\n\n const responseData = formatResponse<PushDictionariesResultData>({\n message: t({\n en: 'Dictionaries updated successfully',\n fr: 'Dictionnaires mis à jour avec succès',\n es: 'Diccionarios actualizados con éxito',\n }),\n description: t({\n en: 'Your dictionaries have been updated successfully',\n fr: 'Vos dictionnaires ont été mis à jour avec succès',\n es: 'Sus diccionarios han sido actualizados con éxito',\n }),\n data: result,\n });\n\n eventListener.sendDictionaryUpdate([\n ...newDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'ADDED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ...updatedDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'UPDATED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateDictionaryParam = { dictionaryId: string };\nexport type UpdateDictionaryBody = Partial<Dictionary>;\nexport type UpdateDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Updates an existing dictionary in the database.\n */\nexport const updateDictionary = async (\n req: Request<UpdateDictionaryParam, any, UpdateDictionaryBody>,\n res: ResponseWithInformation<UpdateDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { dictionaryId } = req.params;\n const { project, dictionaryRights } = res.locals;\n const dictionaryData = req.body;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project._id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n if (typeof dictionaryId === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!dictionaryRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_WRITE');\n return;\n }\n\n try {\n const updatedDictionary = await dictionaryService.updateDictionaryById(\n dictionaryId,\n dictionaryData\n );\n\n const apiResult = mapDictionaryToAPI(updatedDictionary, project._id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary updated successfully',\n fr: 'Dictionnaire mis à jour avec succès',\n es: 'Diccionario actualizado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been updated successfully',\n fr: 'Votre dictionnaire a été mis à jour avec succès',\n es: 'Su diccionario ha sido actualizado con éxito',\n }),\n data: apiResult,\n });\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'UPDATED',\n },\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteDictionaryParam = { dictionaryId: string };\nexport type DeleteDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Deletes a dictionary from the database by its ID.\n */\nexport const deleteDictionary = async (\n req: Request<DeleteDictionaryParam>,\n res: ResponseWithInformation<DeleteDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, dictionaryRights } = res.locals;\n const { dictionaryId } = req.params as Partial<DeleteDictionaryParam>;\n\n if (!dictionaryId) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_ADMIN');\n return;\n }\n\n try {\n const dictionaryToDelete =\n await dictionaryService.getDictionaryById(dictionaryId);\n\n if (!dictionaryToDelete.projectIds.includes(project._id)) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const deletedDictionary =\n await dictionaryService.deleteDictionaryById(dictionaryId);\n\n if (!deletedDictionary) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_NOT_FOUND', {\n dictionaryId,\n });\n return;\n }\n\n logger.info(`Dictionary deleted: ${String(deletedDictionary._id)}`);\n\n const apiResult = mapDictionaryToAPI(deletedDictionary, project._id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary deleted successfully',\n fr: 'Dictionnaire supprimé avec succès',\n es: 'Diccionario eliminado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been deleted successfully',\n fr: 'Votre dictionnaire a été supprimé avec succès',\n es: 'Su diccionario ha sido eliminado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'DELETED',\n },\n ]);\n\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/controllers/dictionary.controller.ts"],"sourcesContent":["import type {\n ContentNode,\n Dictionary as LocalDictionary,\n} from '@intlayer/core';\nimport { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as dictionaryService from '@services/dictionary.service';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport {\n type DictionaryFiltersParams,\n getDictionaryFiltersAndPagination,\n} from '@utils/filtersAndPagination/getDictionaryFiltersAndPagination';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport { mapDictionaryToAPI } from '@utils/mapper/dictionary';\nimport {\n formatPaginatedResponse,\n type ResponseData,\n type PaginatedResponse,\n formatResponse,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport * as eventListener from '@controllers/eventListener.controller';\nimport type {\n Dictionary,\n DictionaryAPI,\n DictionaryCreationData,\n DictionaryData,\n VersionedContent,\n} from '@/types/dictionary.types';\n\nexport type GetDictionariesParams =\n FiltersAndPagination<DictionaryFiltersParams>;\nexport type GetDictionariesResult = PaginatedResponse<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaries = async (\n req: Request<GetDictionariesParams>,\n res: ResponseWithInformation<GetDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, dictionaryRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getDictionaryFiltersAndPagination(req);\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n if (!dictionaryRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_READ');\n return;\n }\n\n try {\n const dictionaries = await dictionaryService.findDictionaries(\n filters,\n skip,\n pageSize\n );\n const totalItems = await dictionaryService.countDictionaries(filters);\n\n const dictionariesAPI = dictionaries.map((el) =>\n mapDictionaryToAPI(el, project._id)\n );\n\n const responseData = formatPaginatedResponse<DictionaryAPI>({\n data: dictionariesAPI,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionariesKeysResult = ResponseData<string[]>;\n\n/**\n * Retrieves a list of dictionaries keys based on filters and pagination.\n */\nexport const getDictionariesKeys = async (\n _req: Request,\n res: ResponseWithInformation<GetDictionariesKeysResult>,\n _next: NextFunction\n) => {\n const { project, dictionaryRights } = res.locals;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!dictionaryRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_READ');\n return;\n }\n\n try {\n const dictionariesKeys = await dictionaryService.getDictionariesKeys(\n project._id\n );\n\n const responseData = formatResponse<string[]>({\n data: dictionariesKeys,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionaryParams = { dictionaryKey: string };\nexport type GetDictionaryQuery = { version?: string };\nexport type GetDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaryByKey = async (\n req: Request<GetDictionaryParams, any, any, GetDictionaryQuery>,\n res: ResponseWithInformation<GetDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, dictionaryRights } = res.locals;\n const { dictionaryKey } = req.params;\n const version = req.query.version;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n if (!dictionaryRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_READ');\n return;\n }\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n dictionaryKey,\n project._id\n );\n\n if (!dictionary.projectIds.map(String).includes(String(project._id))) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const apiResult = mapDictionaryToAPI(dictionary, project._id, version);\n\n const responseData = formatResponse<DictionaryAPI>({\n data: apiResult,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddDictionaryBody = { dictionary: DictionaryCreationData };\nexport type AddDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Adds a new dictionary to the database.\n */\nexport const addDictionary = async (\n req: Request<any, any, AddDictionaryBody>,\n res: ResponseWithInformation<AddDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, dictionaryRights } = res.locals;\n const dictionaryData = req.body.dictionary;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project._id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n if (!dictionaryRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_ADMIN');\n return;\n }\n\n const dictionary: DictionaryData = {\n key: dictionaryData.key,\n title: dictionaryData.title,\n description: dictionaryData.description,\n content: new Map([\n ['v1', { content: dictionaryData.content ?? ({} as ContentNode) }],\n ]),\n creatorId: user._id,\n filePath: {\n [String(project._id)]: dictionaryData.filePath ?? '',\n },\n projectIds: dictionaryData.projectIds ?? [String(project._id)],\n };\n\n try {\n const newDictionary = await dictionaryService.createDictionary(dictionary);\n\n const apiResult = mapDictionaryToAPI(newDictionary, project._id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary created successfully',\n fr: 'Dictionnaire créé avec succès',\n es: 'Diccionario creado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been created successfully',\n fr: 'Votre dictionnaire a été créé avec succès',\n es: 'Su diccionario ha sido creado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: mapDictionaryToAPI(newDictionary, project._id),\n status: 'ADDED',\n },\n ]);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type PushDictionariesBody = {\n dictionaries: LocalDictionary[];\n};\ntype PushDictionariesResultData = {\n newDictionaries: string[];\n updatedDictionaries: string[];\n error: { dictionaryId: string; message: string }[];\n};\nexport type PushDictionariesResult = ResponseData<PushDictionariesResultData>;\n\n/**\n * Check each dictionaries, add the new ones and update the existing ones.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response containing the created dictionary.\n */\nexport const pushDictionaries = async (\n req: Request<any, any, PushDictionariesBody>,\n res: ResponseWithInformation<PushDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, dictionaryRights } = res.locals;\n const dictionaryData = req.body.dictionaries;\n const dictionariesKeys = dictionaryData.map((dictionary) => dictionary.key);\n\n if (\n typeof dictionaryData === 'object' &&\n Array.isArray(dictionaryData) &&\n dictionaryData.length === 0\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARIES_NOT_PROVIDED');\n return;\n } else if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_WRITE');\n return;\n }\n\n if (!dictionaryRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_ADMIN');\n return;\n }\n\n try {\n const { existingDictionariesKey, newDictionariesKey } =\n await dictionaryService.getExistingDictionaryKey(\n dictionariesKeys,\n project._id\n );\n\n const existingDictionaries = dictionaryData.filter((dictionary) =>\n existingDictionariesKey.includes(dictionary.key)\n );\n const newDictionaries = dictionaryData.filter((dictionary) =>\n newDictionariesKey.includes(dictionary.key)\n );\n\n const newDictionariesResult: DictionaryAPI[] = [];\n const updatedDictionariesResult: DictionaryAPI[] = [];\n const errorResult: PushDictionariesResultData['error'] = [];\n\n for (const dictionaryDataEl of newDictionaries) {\n const dictionary: DictionaryData = {\n title: dictionaryDataEl.title,\n description: dictionaryDataEl.description,\n projectIds: [String(project._id)],\n creatorId: user._id,\n content: new Map([\n ['v1', { content: dictionaryDataEl.content ?? ({} as ContentNode) }],\n ]),\n filePath: {\n [String(project._id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const newDictionary =\n await dictionaryService.createDictionary(dictionary);\n newDictionariesResult.push(\n mapDictionaryToAPI(newDictionary, project._id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n\n if (existingDictionariesKey.length >= 0) {\n const existingDictionariesDB =\n await dictionaryService.getDictionariesByKeys(\n existingDictionariesKey,\n project._id\n );\n\n for (const dictionaryDataEl of existingDictionaries) {\n const existingDictionaryDB = existingDictionariesDB.find(\n (dictionaryDB) => dictionaryDB.key === dictionaryDataEl.key\n )!;\n\n const versionList = [...(existingDictionaryDB.content.keys() ?? [])];\n const lastVersion = versionList[versionList.length - 1];\n\n const lastContent =\n (existingDictionaryDB.content.get(lastVersion)\n ?.content as DictionaryAPI['content']) ?? null;\n\n const isSameContent =\n JSON.stringify(lastContent) ===\n JSON.stringify(dictionaryDataEl.content);\n\n let newContent: VersionedContent = existingDictionaryDB.content;\n\n if (!isSameContent) {\n const newContentVersion =\n dictionaryService.incrementVersion(existingDictionaryDB);\n\n existingDictionaryDB.content.set(newContentVersion, {\n content: dictionaryDataEl.content ?? ({} as ContentNode),\n });\n\n newContent = existingDictionaryDB.content;\n }\n\n const dictionary: DictionaryData = {\n ...ensureMongoDocumentToObject(existingDictionaryDB),\n ...dictionaryDataEl,\n content: newContent,\n projectIds: [String(project._id)],\n creatorId: user._id,\n filePath: {\n [String(project._id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const updatedDictionary =\n await dictionaryService.updateDictionaryByKey(\n dictionaryDataEl.key,\n dictionary,\n project._id\n );\n updatedDictionariesResult.push(\n mapDictionaryToAPI(updatedDictionary, project._id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n }\n\n const result: PushDictionariesResultData = {\n newDictionaries: newDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n updatedDictionaries: updatedDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n error: errorResult,\n };\n\n const responseData = formatResponse<PushDictionariesResultData>({\n message: t({\n en: 'Dictionaries updated successfully',\n fr: 'Dictionnaires mis à jour avec succès',\n es: 'Diccionarios actualizados con éxito',\n }),\n description: t({\n en: 'Your dictionaries have been updated successfully',\n fr: 'Vos dictionnaires ont été mis à jour avec succès',\n es: 'Sus diccionarios han sido actualizados con éxito',\n }),\n data: result,\n });\n\n eventListener.sendDictionaryUpdate([\n ...newDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'ADDED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ...updatedDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'UPDATED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateDictionaryParam = { dictionaryId: string };\nexport type UpdateDictionaryBody = Partial<Dictionary>;\nexport type UpdateDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Updates an existing dictionary in the database.\n */\nexport const updateDictionary = async (\n req: Request<UpdateDictionaryParam, any, UpdateDictionaryBody>,\n res: ResponseWithInformation<UpdateDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { dictionaryId } = req.params;\n const { project, dictionaryRights } = res.locals;\n const dictionaryData = req.body;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project._id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n if (typeof dictionaryId === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!dictionaryRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_WRITE');\n return;\n }\n\n try {\n const updatedDictionary = await dictionaryService.updateDictionaryById(\n dictionaryId,\n dictionaryData\n );\n\n const apiResult = mapDictionaryToAPI(updatedDictionary, project._id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary updated successfully',\n fr: 'Dictionnaire mis à jour avec succès',\n es: 'Diccionario actualizado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been updated successfully',\n fr: 'Votre dictionnaire a été mis à jour avec succès',\n es: 'Su diccionario ha sido actualizado con éxito',\n }),\n data: apiResult,\n });\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'UPDATED',\n },\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteDictionaryParam = { dictionaryId: string };\nexport type DeleteDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Deletes a dictionary from the database by its ID.\n */\nexport const deleteDictionary = async (\n req: Request<DeleteDictionaryParam>,\n res: ResponseWithInformation<DeleteDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, dictionaryRights } = res.locals;\n const { dictionaryId } = req.params as Partial<DeleteDictionaryParam>;\n\n if (!dictionaryId) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_ADMIN');\n return;\n }\n\n try {\n const dictionaryToDelete =\n await dictionaryService.getDictionaryById(dictionaryId);\n\n if (!dictionaryToDelete.projectIds.includes(project._id)) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const deletedDictionary =\n await dictionaryService.deleteDictionaryById(dictionaryId);\n\n if (!deletedDictionary) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_NOT_FOUND', {\n dictionaryId,\n });\n return;\n }\n\n logger.info(`Dictionary deleted: ${String(deletedDictionary._id)}`);\n\n const apiResult = mapDictionaryToAPI(deletedDictionary, project._id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary deleted successfully',\n fr: 'Dictionnaire supprimé avec succès',\n es: 'Diccionario eliminado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been deleted successfully',\n fr: 'Votre dictionnaire a été supprimé avec succès',\n es: 'Su diccionario ha sido eliminado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'DELETED',\n },\n ]);\n\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
|
|
@@ -26,41 +26,57 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
mod
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var
|
|
30
|
-
__export(
|
|
29
|
+
var eventListener_controller_exports = {};
|
|
30
|
+
__export(eventListener_controller_exports, {
|
|
31
31
|
listenChangeSSE: () => listenChangeSSE,
|
|
32
32
|
sendDictionaryUpdate: () => sendDictionaryUpdate
|
|
33
33
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
34
|
+
module.exports = __toCommonJS(eventListener_controller_exports);
|
|
35
35
|
var oAuth2Service = __toESM(require('./../services/oAuth2.service.cjs'), 1);
|
|
36
36
|
var import_errors = require('./../utils/errors/index.cjs');
|
|
37
|
+
var import_logger = require('./../logger/index.cjs');
|
|
37
38
|
let clients = [];
|
|
39
|
+
const MAX_SSE_CONNECTIONS = 10;
|
|
38
40
|
const sendDictionaryUpdate = (args) => {
|
|
39
41
|
const projectIds = args.flatMap((arg) => arg.dictionary.projectIds);
|
|
40
42
|
const filteredClients = clients.filter(
|
|
41
43
|
(client) => projectIds.map((id) => String(id)).includes(String(client.projectId))
|
|
42
44
|
);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
const data = args.map((arg) => ({
|
|
46
|
+
object: "DICTIONARY",
|
|
47
|
+
status: arg.status,
|
|
48
|
+
data: arg.dictionary
|
|
49
|
+
}));
|
|
50
|
+
process.nextTick(() => {
|
|
51
|
+
for (const client of filteredClients) {
|
|
52
|
+
client.res.write(`data: ${JSON.stringify(data)}
|
|
45
53
|
|
|
46
54
|
`);
|
|
47
|
-
|
|
55
|
+
client.res.flush?.();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
48
58
|
};
|
|
49
59
|
const listenChangeSSE = async (req, res) => {
|
|
50
60
|
const { accessToken } = req.params;
|
|
51
61
|
if (!accessToken) {
|
|
52
62
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_AUTHENTICATED");
|
|
63
|
+
return;
|
|
53
64
|
}
|
|
54
65
|
const tokenInformation = await oAuth2Service.getAccessToken(accessToken);
|
|
55
66
|
if (!tokenInformation) {
|
|
56
67
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "AUTH_ERROR");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (clients.length >= MAX_SSE_CONNECTIONS) {
|
|
71
|
+
import_errors.ErrorHandler.handleGenericErrorResponse(res, "TOO_MANY_CONNECTIONS");
|
|
72
|
+
return;
|
|
57
73
|
}
|
|
58
74
|
res.setHeader("Content-Type", "text/event-stream;charset=utf-8");
|
|
59
75
|
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
60
76
|
res.setHeader("Connection", "keep-alive");
|
|
61
77
|
res.setHeader("X-Accel-Buffering", "no");
|
|
62
78
|
res.write(":\n\n");
|
|
63
|
-
res.flushHeaders();
|
|
79
|
+
res.flushHeaders?.();
|
|
64
80
|
const clientId = Date.now();
|
|
65
81
|
const newClient = {
|
|
66
82
|
id: clientId,
|
|
@@ -68,6 +84,9 @@ const listenChangeSSE = async (req, res) => {
|
|
|
68
84
|
res
|
|
69
85
|
};
|
|
70
86
|
clients.push(newClient);
|
|
87
|
+
import_logger.logger.info(
|
|
88
|
+
`New client connected to SSE. Total clients: ${clients.length ?? 0}`
|
|
89
|
+
);
|
|
71
90
|
req.on("close", () => {
|
|
72
91
|
clients = clients.filter((client) => client.id !== clientId);
|
|
73
92
|
});
|
|
@@ -77,4 +96,4 @@ const listenChangeSSE = async (req, res) => {
|
|
|
77
96
|
listenChangeSSE,
|
|
78
97
|
sendDictionaryUpdate
|
|
79
98
|
});
|
|
80
|
-
//# sourceMappingURL=
|
|
99
|
+
//# sourceMappingURL=eventListener.controller.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/controllers/eventListener.controller.ts"],"sourcesContent":["import type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport type { Token } from '@schemas/oAuth2.schema';\nimport * as oAuth2Service from '@services/oAuth2.service';\nimport { ErrorHandler } from '@utils/errors';\nimport type { Response, Request } from 'express';\nimport type { DictionaryAPI } from '@/types/dictionary.types';\nimport { logger } from '@logger';\n\nexport type Object = 'DICTIONARY';\nexport type Status = 'ADDED' | 'UPDATED' | 'DELETED' | 'CREATED';\n\nexport type MessageEventData = {\n object: Object;\n status: Status;\n data: any;\n};\n\nlet clients: Array<{ id: number; projectId: string; res: Response }> = [];\nconst MAX_SSE_CONNECTIONS = 10;\n\nexport type SendDictionaryUpdateArg = {\n dictionary: DictionaryAPI;\n status: 'ADDED' | 'UPDATED' | 'DELETED' | 'CREATED';\n};\n\nexport const sendDictionaryUpdate = (args: SendDictionaryUpdateArg[]) => {\n const projectIds = args.flatMap((arg) => arg.dictionary.projectIds);\n\n const filteredClients = clients.filter((client) =>\n projectIds.map((id) => String(id)).includes(String(client.projectId))\n );\n\n const data: MessageEventData[] = args.map((arg) => ({\n object: 'DICTIONARY',\n status: arg.status,\n data: arg.dictionary,\n }));\n\n process.nextTick(() => {\n for (const client of filteredClients) {\n client.res.write(`data: ${JSON.stringify(data)}\\n\\n`);\n client.res.flush?.(); // Ensure the data is sent immediately\n }\n });\n};\n\nexport type CheckDictionaryChangeSSEParams = { accessToken: string };\n\n/**\n * SSE to check the email verification status\n */\nexport const listenChangeSSE = async (\n req: Request<CheckDictionaryChangeSSEParams, any, any>,\n res: ResponseWithInformation\n) => {\n const { accessToken } = req.params;\n\n if (!accessToken) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_AUTHENTICATED');\n return;\n }\n\n const tokenInformation = await oAuth2Service.getAccessToken(accessToken);\n\n if (!tokenInformation) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUTH_ERROR');\n return;\n }\n\n if (clients.length >= MAX_SSE_CONNECTIONS) {\n ErrorHandler.handleGenericErrorResponse(res, 'TOO_MANY_CONNECTIONS');\n return;\n }\n\n // Set headers for SSE\n res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');\n res.setHeader('Cache-Control', 'no-cache, no-transform');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no'); // For Nginx buffering\n\n // Send initial data to ensure the connection is open\n res.write(':\\n\\n'); // Comment to keep connection alive\n res.flushHeaders?.();\n\n const clientId = Date.now();\n\n // Add client to the list\n const newClient = {\n id: clientId,\n projectId: String((tokenInformation as unknown as Token).project._id),\n res,\n };\n clients.push(newClient);\n\n logger.info(\n `New client connected to SSE. Total clients: ${clients.length ?? 0}`\n );\n\n // Remove client on connection close\n req.on('close', () => {\n clients = clients.filter((client) => client.id !== clientId);\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA+B;AAC/B,oBAA6B;AAG7B,oBAAuB;AAWvB,IAAI,UAAmE,CAAC;AACxE,MAAM,sBAAsB;AAOrB,MAAM,uBAAuB,CAAC,SAAoC;AACvE,QAAM,aAAa,KAAK,QAAQ,CAAC,QAAQ,IAAI,WAAW,UAAU;AAElE,QAAM,kBAAkB,QAAQ;AAAA,IAAO,CAAC,WACtC,WAAW,IAAI,CAAC,OAAO,OAAO,EAAE,CAAC,EAAE,SAAS,OAAO,OAAO,SAAS,CAAC;AAAA,EACtE;AAEA,QAAM,OAA2B,KAAK,IAAI,CAAC,SAAS;AAAA,IAClD,QAAQ;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,EACZ,EAAE;AAEF,UAAQ,SAAS,MAAM;AACrB,eAAW,UAAU,iBAAiB;AACpC,aAAO,IAAI,MAAM,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA;AAAA,CAAM;AACpD,aAAO,IAAI,QAAQ;AAAA,IACrB;AAAA,EACF,CAAC;AACH;AAOO,MAAM,kBAAkB,OAC7B,KACA,QACG;AACH,QAAM,EAAE,YAAY,IAAI,IAAI;AAE5B,MAAI,CAAC,aAAa;AAChB,+BAAa,2BAA2B,KAAK,wBAAwB;AACrE;AAAA,EACF;AAEA,QAAM,mBAAmB,MAAM,cAAc,eAAe,WAAW;AAEvE,MAAI,CAAC,kBAAkB;AACrB,+BAAa,2BAA2B,KAAK,YAAY;AACzD;AAAA,EACF;AAEA,MAAI,QAAQ,UAAU,qBAAqB;AACzC,+BAAa,2BAA2B,KAAK,sBAAsB;AACnE;AAAA,EACF;AAGA,MAAI,UAAU,gBAAgB,iCAAiC;AAC/D,MAAI,UAAU,iBAAiB,wBAAwB;AACvD,MAAI,UAAU,cAAc,YAAY;AACxC,MAAI,UAAU,qBAAqB,IAAI;AAGvC,MAAI,MAAM,OAAO;AACjB,MAAI,eAAe;AAEnB,QAAM,WAAW,KAAK,IAAI;AAG1B,QAAM,YAAY;AAAA,IAChB,IAAI;AAAA,IACJ,WAAW,OAAQ,iBAAsC,QAAQ,GAAG;AAAA,IACpE;AAAA,EACF;AACA,UAAQ,KAAK,SAAS;AAEtB,uBAAO;AAAA,IACL,+CAA+C,QAAQ,UAAU,CAAC;AAAA,EACpE;AAGA,MAAI,GAAG,SAAS,MAAM;AACpB,cAAU,QAAQ,OAAO,CAAC,WAAW,OAAO,OAAO,QAAQ;AAAA,EAC7D,CAAC;AACH;","names":[]}
|
package/dist/cjs/export.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/export.ts"],"sourcesContent":["// Routes\nexport { getUserRoutes } from '@routes/user.routes';\nexport { getOrganizationRoutes } from '@routes/organization.routes';\nexport { getProjectRoutes } from '@routes/project.routes';\nexport { getDictionaryRoutes } from '@routes/dictionary.routes';\nexport { getSessionAuthRoutes } from '@routes/sessionAuth.routes';\n\n// Controllers types\nexport type * from '@controllers/sessionAuth.controller';\nexport type * from '@controllers/oAuth2.controller';\nexport type * from '@controllers/organization.controller';\nexport type * from '@controllers/project.controller';\nexport type * from '@controllers/projectAccessKey.controller';\nexport type * from '@controllers/user.controller';\nexport type * from '@controllers/dictionary.controller';\nexport type * from '@controllers/stripe.controller';\nexport type * from '@controllers/ai.controller';\nexport type * from '@controllers/tag.controller';\n\n// Objects types\nexport type * from '@/types/organization.types';\nexport type * from '@/types/project.types';\nexport type * from '@/types/user.types';\nexport type * from '@/types/dictionary.types';\nexport type * from '@/types/plan.types';\nexport type * from '@/types/tag.types';\nexport type * from '@/types/oAuth2.types';\n\n// Utils\nexport * from '@utils/cookies';\nexport * from '@utils/httpStatusCodes';\nexport * from '@utils/responseData';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAA8B;AAC9B,0BAAsC;AACtC,qBAAiC;AACjC,wBAAoC;AACpC,yBAAqC;
|
|
1
|
+
{"version":3,"sources":["../../src/export.ts"],"sourcesContent":["// Routes\nexport { getUserRoutes } from '@routes/user.routes';\nexport { getOrganizationRoutes } from '@routes/organization.routes';\nexport { getProjectRoutes } from '@routes/project.routes';\nexport { getDictionaryRoutes } from '@routes/dictionary.routes';\nexport { getSessionAuthRoutes } from '@routes/sessionAuth.routes';\n\n// Controllers types\nexport type * from '@controllers/sessionAuth.controller';\nexport type * from '@controllers/oAuth2.controller';\nexport type * from '@controllers/organization.controller';\nexport type * from '@controllers/eventListener.controller';\nexport type * from '@controllers/project.controller';\nexport type * from '@controllers/projectAccessKey.controller';\nexport type * from '@controllers/user.controller';\nexport type * from '@controllers/dictionary.controller';\nexport type * from '@controllers/stripe.controller';\nexport type * from '@controllers/ai.controller';\nexport type * from '@controllers/tag.controller';\n\n// Objects types\nexport type * from '@/types/organization.types';\nexport type * from '@/types/project.types';\nexport type * from '@/types/user.types';\nexport type * from '@/types/dictionary.types';\nexport type * from '@/types/plan.types';\nexport type * from '@/types/tag.types';\nexport type * from '@/types/oAuth2.types';\n\n// Utils\nexport * from '@utils/cookies';\nexport * from '@utils/httpStatusCodes';\nexport * from '@utils/responseData';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAA8B;AAC9B,0BAAsC;AACtC,qBAAiC;AACjC,wBAAoC;AACpC,yBAAqC;AAyBrC,2BAAc,2BA9Bd;AA+BA,2BAAc,mCA/Bd;AAgCA,2BAAc,gCAhCd;","names":[]}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -49,7 +49,7 @@ var import_sessionAuth2 = require('./routes/sessionAuth.routes.cjs');
|
|
|
49
49
|
var import_user = require('./routes/user.routes.cjs');
|
|
50
50
|
var import_stripe = require('./routes/stripe.routes.cjs');
|
|
51
51
|
var import_ai = require('./routes/ai.routes.cjs');
|
|
52
|
-
var
|
|
52
|
+
var import_eventListener = require('./routes/eventListener.routes.cjs');
|
|
53
53
|
var import_stripe2 = require('./webhooks/stripe.webhook.cjs');
|
|
54
54
|
var import_oAuth22 = require('./controllers/oAuth2.controller.cjs');
|
|
55
55
|
var import_sessionAuth3 = require('./controllers/sessionAuth.controller.cjs');
|
|
@@ -147,7 +147,7 @@ app.use("/api/tag", import_tags.tagRouter);
|
|
|
147
147
|
app.use("/api/dictionary", import_dictionary.dictionaryRouter);
|
|
148
148
|
app.use("/api/stripe", import_stripe.stripeRouter);
|
|
149
149
|
app.use("/api/ai", import_ai.aiRouter);
|
|
150
|
-
app.use("/api/event-listener",
|
|
150
|
+
app.use("/api/event-listener", import_eventListener.eventListenerRouter);
|
|
151
151
|
app.listen(process.env.PORT, () => {
|
|
152
152
|
import_logger.logger.info(`Listening on port ${process.env.PORT}`);
|
|
153
153
|
});
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// Libraries\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport cors, { type CorsOptions } from 'cors';\nimport dotenv from 'dotenv';\nimport express, { type Express } from 'express';\nimport { intlayer, t } from 'express-intlayer';\nimport helmet from 'helmet';\n\n// Middlewares\nimport {\n type RequestWithOAuth2Information,\n attachOAuthInstance,\n authenticateOAuth2,\n} from '@middlewares/oAuth2.middleware';\nimport { logAPIRequestURL } from '@middlewares/request.middleware';\nimport {\n type ResponseWithInformation,\n checkUser,\n checkOrganization,\n checkProject,\n checkAdmin,\n} from '@middlewares/sessionAuth.middleware';\n\n// Routes\nimport { dictionaryRouter } from '@routes/dictionary.routes';\nimport { organizationRouter } from '@routes/organization.routes';\nimport { projectRouter } from '@routes/project.routes';\nimport { tagRouter } from '@routes/tags.routes';\nimport { sessionAuthRouter } from '@routes/sessionAuth.routes';\nimport { userRouter } from '@routes/user.routes';\nimport { stripeRouter } from '@routes/stripe.routes';\nimport { aiRouter } from '@routes/ai.routes';\nimport { eventListenerRouter } from '@routes/eventListener.routes';\n\n// Webhooks\nimport { stripeWebhook } from '@webhooks/stripe.webhook';\n\n// Controllers\nimport { getOAuth2Token } from '@controllers/oAuth2.controller';\nimport {\n getSessionInformation,\n setCSRFToken,\n} from '@controllers/sessionAuth.controller';\n\n// Utils\nimport { doubleCsrfProtection } from '@utils/CSRF';\nimport { connectDB } from '@utils/mongoDB/connectDB';\n\n// Logger\nimport { logger } from './logger/index';\n\nconst app: Express = express();\n\napp.disable('x-powered-by'); // Disabled to prevent attackers from knowing that the app is running Express\napp.use(helmet());\n\n// Environment variables\nconst env = app.get('env');\n\nlogger.info(`run as ${env}`);\n\ndotenv.config({\n path: [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env'],\n});\n\n// Parse incoming requests with cookies\napp.use(cookieParser());\n\n// Load internationalization request handler\napp.use(intlayer());\n\nconst isDev = env === 'development';\n\n// Connect to MongoDB\nconnectDB();\n\n// Stripe\napp.post(\n '/webhook/stripe',\n express.raw({ type: 'application/json' }),\n stripeWebhook\n);\n\n// Compress all HTTP responses\napp.use(compression());\n\n// Parse incoming requests with JSON payloads\napp.use(express.json({ limit: '50mb' }));\n\n// Parse incoming requests with urlencoded payloads\napp.use(express.urlencoded({ extended: true }));\n\nconst whitelist = [process.env.CLIENT_URL!];\n\n// CORS\nconst corsOptions: CorsOptions = {\n origin: (origin, callback) => {\n // Allow requests with no origin (like mobile apps or curl requests)\n if (!origin) return callback(null, true);\n\n if (whitelist.includes(origin)) {\n logger.info('whitelisted origin', origin);\n return callback(null, true);\n }\n\n logger.info('non whitelisted origin', origin);\n // Reflect the request's origin (echo back the origin header)\n callback(null, origin);\n },\n allowedHeaders: [\n 'authorization',\n 'Content-Type',\n 'credentials',\n 'cache-control',\n 'Access-Control-Allow-Origin',\n 'private-state-token-redemption',\n 'private-state-token-issuance',\n 'browsing-topics',\n ],\n exposedHeaders: [''],\n preflightContinue: false,\n methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',\n credentials: true,\n};\napp.use(cors(corsOptions));\n\n// Liveness check\napp.get('/', (_req, res) => {\n res.send(\n t({\n en: 'Ok - locale: en',\n fr: 'Ok - locale: fr',\n es: 'Ok - locale: es',\n })\n );\n});\n\n// middleware - jwt & session auth\napp.use(/(.*)/, checkUser);\napp.use(/(.*)/, checkOrganization);\napp.use(/(.*)/, checkProject);\napp.use(/(.*)/, checkAdmin);\n\n// debug\nif (isDev) {\n app.use(logAPIRequestURL);\n}\n\n// Sessions\napp.get('/session', getSessionInformation);\napp.use('/api/auth', sessionAuthRouter);\n\n// CSRF\napp.get('/csrf-token', setCSRFToken);\n\n// oAuth2\napp.use(/(.*)/, attachOAuthInstance);\napp.post('/oauth2/token', getOAuth2Token); // Route to get the token\napp.use(/(.*)/, (req, res, next) => {\n // If the request is not already authenticated check the oAuth2 token\n if (!res.locals.authType) {\n return authenticateOAuth2(\n req as RequestWithOAuth2Information,\n res as ResponseWithInformation,\n next\n );\n }\n next();\n});\n\n// CSRF protection\napp.use(/(.*)/, (req, res, next) => {\n // If the request is authenticated using the session auth check the CSRF token\n if (res.locals.authType === 'session') {\n return doubleCsrfProtection(req, res, next);\n }\n next();\n});\n\n// Routes\napp.use('/api/user', userRouter);\napp.use('/api/organization', organizationRouter);\napp.use('/api/project', projectRouter);\napp.use('/api/tag', tagRouter);\napp.use('/api/dictionary', dictionaryRouter);\napp.use('/api/stripe', stripeRouter);\napp.use('/api/ai', aiRouter);\napp.use('/api/event-listener', eventListenerRouter);\n\n// Server\napp.listen(process.env.PORT, () => {\n logger.info(`Listening on port ${process.env.PORT}`);\n});\n\n// Export tu use as serverless function\nexport default app;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,yBAAwB;AACxB,2BAAyB;AACzB,kBAAuC;AACvC,oBAAmB;AACnB,qBAAsC;AACtC,8BAA4B;AAC5B,oBAAmB;AAGnB,oBAIO;AACP,qBAAiC;AACjC,yBAMO;AAGP,wBAAiC;AACjC,0BAAmC;AACnC,qBAA8B;AAC9B,kBAA0B;AAC1B,IAAAA,sBAAkC;AAClC,kBAA2B;AAC3B,oBAA6B;AAC7B,gBAAyB;AACzB,2BAAoC;AAGpC,IAAAC,iBAA8B;AAG9B,IAAAC,iBAA+B;AAC/B,IAAAF,sBAGO;AAGP,kBAAqC;AACrC,uBAA0B;AAG1B,oBAAuB;AAEvB,MAAM,UAAe,eAAAG,SAAQ;AAE7B,IAAI,QAAQ,cAAc;AAC1B,IAAI,QAAI,cAAAC,SAAO,CAAC;AAGhB,MAAM,MAAM,IAAI,IAAI,KAAK;AAEzB,qBAAO,KAAK,UAAU,GAAG,EAAE;AAE3B,cAAAC,QAAO,OAAO;AAAA,EACZ,MAAM,CAAC,QAAQ,GAAG,UAAU,QAAQ,GAAG,IAAI,cAAc,MAAM;AACjE,CAAC;AAGD,IAAI,QAAI,qBAAAC,SAAa,CAAC;AAGtB,IAAI,QAAI,kCAAS,CAAC;AAElB,MAAM,QAAQ,QAAQ;AAAA,IAGtB,4BAAU;AAGV,IAAI;AAAA,EACF;AAAA,EACA,eAAAH,QAAQ,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAAA,EACxC;AACF;AAGA,IAAI,QAAI,mBAAAI,SAAY,CAAC;AAGrB,IAAI,IAAI,eAAAJ,QAAQ,KAAK,EAAE,OAAO,OAAO,CAAC,CAAC;AAGvC,IAAI,IAAI,eAAAA,QAAQ,WAAW,EAAE,UAAU,KAAK,CAAC,CAAC;AAE9C,MAAM,YAAY,CAAC,QAAQ,IAAI,UAAW;AAG1C,MAAM,cAA2B;AAAA,EAC/B,QAAQ,CAAC,QAAQ,aAAa;AAE5B,QAAI,CAAC,OAAQ,QAAO,SAAS,MAAM,IAAI;AAEvC,QAAI,UAAU,SAAS,MAAM,GAAG;AAC9B,2BAAO,KAAK,sBAAsB,MAAM;AACxC,aAAO,SAAS,MAAM,IAAI;AAAA,IAC5B;AAEA,yBAAO,KAAK,0BAA0B,MAAM;AAE5C,aAAS,MAAM,MAAM;AAAA,EACvB;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,EAAE;AAAA,EACnB,mBAAmB;AAAA,EACnB,SAAS;AAAA,EACT,aAAa;AACf;AACA,IAAI,QAAI,YAAAK,SAAK,WAAW,CAAC;AAGzB,IAAI,IAAI,KAAK,CAAC,MAAM,QAAQ;AAC1B,MAAI;AAAA,QACF,2BAAE;AAAA,MACA,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IACN,CAAC;AAAA,EACH;AACF,CAAC;AAGD,IAAI,IAAI,QAAQ,4BAAS;AACzB,IAAI,IAAI,QAAQ,oCAAiB;AACjC,IAAI,IAAI,QAAQ,+BAAY;AAC5B,IAAI,IAAI,QAAQ,6BAAU;AAG1B,IAAI,OAAO;AACT,MAAI,IAAI,+BAAgB;AAC1B;AAGA,IAAI,IAAI,YAAY,yCAAqB;AACzC,IAAI,IAAI,aAAa,qCAAiB;AAGtC,IAAI,IAAI,eAAe,gCAAY;AAGnC,IAAI,IAAI,QAAQ,iCAAmB;AACnC,IAAI,KAAK,iBAAiB,6BAAc;AACxC,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS;AAElC,MAAI,CAAC,IAAI,OAAO,UAAU;AACxB,eAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,OAAK;AACP,CAAC;AAGD,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS;AAElC,MAAI,IAAI,OAAO,aAAa,WAAW;AACrC,eAAO,kCAAqB,KAAK,KAAK,IAAI;AAAA,EAC5C;AACA,OAAK;AACP,CAAC;AAGD,IAAI,IAAI,aAAa,sBAAU;AAC/B,IAAI,IAAI,qBAAqB,sCAAkB;AAC/C,IAAI,IAAI,gBAAgB,4BAAa;AACrC,IAAI,IAAI,YAAY,qBAAS;AAC7B,IAAI,IAAI,mBAAmB,kCAAgB;AAC3C,IAAI,IAAI,eAAe,0BAAY;AACnC,IAAI,IAAI,WAAW,kBAAQ;AAC3B,IAAI,IAAI,uBAAuB,wCAAmB;AAGlD,IAAI,OAAO,QAAQ,IAAI,MAAM,MAAM;AACjC,uBAAO,KAAK,qBAAqB,QAAQ,IAAI,IAAI,EAAE;AACrD,CAAC;AAGD,IAAO,gBAAQ;","names":["import_sessionAuth","import_stripe","import_oAuth2","express","helmet","dotenv","cookieParser","compression","cors"]}
|
|
@@ -16,13 +16,13 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var
|
|
20
|
-
__export(
|
|
19
|
+
var eventListener_routes_exports = {};
|
|
20
|
+
__export(eventListener_routes_exports, {
|
|
21
21
|
eventListenerRouter: () => eventListenerRouter,
|
|
22
22
|
eventListenerRoutes: () => eventListenerRoutes
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
25
|
-
var
|
|
24
|
+
module.exports = __toCommonJS(eventListener_routes_exports);
|
|
25
|
+
var import_eventListener = require('./../controllers/eventListener.controller.cjs');
|
|
26
26
|
var import_express = require("express");
|
|
27
27
|
const eventListenerRouter = (0, import_express.Router)();
|
|
28
28
|
const baseURL = () => `${process.env.BACKEND_URL}/api/event-listener`;
|
|
@@ -35,11 +35,11 @@ const eventListenerRoutes = () => ({
|
|
|
35
35
|
});
|
|
36
36
|
eventListenerRouter.get(
|
|
37
37
|
eventListenerRoutes().checkDictionaryChangeSSE.urlModel,
|
|
38
|
-
|
|
38
|
+
import_eventListener.listenChangeSSE
|
|
39
39
|
);
|
|
40
40
|
// Annotate the CommonJS export names for ESM import in node:
|
|
41
41
|
0 && (module.exports = {
|
|
42
42
|
eventListenerRouter,
|
|
43
43
|
eventListenerRoutes
|
|
44
44
|
});
|
|
45
|
-
//# sourceMappingURL=
|
|
45
|
+
//# sourceMappingURL=eventListener.routes.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/routes/eventListener.routes.ts"],"sourcesContent":["import { listenChangeSSE } from '@controllers/eventListener.controller';\nimport { Router } from 'express';\nimport type { Routes } from '@/types/Routes';\n\nexport const eventListenerRouter: Router = Router();\n\nconst baseURL = () => `${process.env.BACKEND_URL}/api/event-listener`;\n\nexport const eventListenerRoutes = () =>\n ({\n checkDictionaryChangeSSE: {\n urlModel: '/:accessToken',\n url: ({ accessToken }: { accessToken: string }) =>\n `${baseURL}/${accessToken}`,\n method: 'GET',\n },\n }) satisfies Routes;\n\neventListenerRouter.get(\n eventListenerRoutes().checkDictionaryChangeSSE.urlModel,\n listenChangeSSE\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAgC;AAChC,qBAAuB;AAGhB,MAAM,0BAA8B,uBAAO;AAElD,MAAM,UAAU,MAAM,GAAG,QAAQ,IAAI,WAAW;AAEzC,MAAM,sBAAsB,OAChC;AAAA,EACC,0BAA0B;AAAA,IACxB,UAAU;AAAA,IACV,KAAK,CAAC,EAAE,YAAY,MAClB,GAAG,OAAO,IAAI,WAAW;AAAA,IAC3B,QAAQ;AAAA,EACV;AACF;AAEF,oBAAoB;AAAA,EAClB,oBAAoB,EAAE,yBAAyB;AAAA,EAC/C;AACF;","names":[]}
|
|
@@ -46,26 +46,7 @@ const findDictionaries = async (filters, skip = 0, limit = 100) => {
|
|
|
46
46
|
// Stage 2: Skip for pagination
|
|
47
47
|
{ $skip: skip },
|
|
48
48
|
// Stage 3: Limit the number of documents
|
|
49
|
-
{ $limit: limit }
|
|
50
|
-
// Stage 4: Add the 'availableVersions' field
|
|
51
|
-
{
|
|
52
|
-
$addFields: {
|
|
53
|
-
availableVersions: {
|
|
54
|
-
$map: {
|
|
55
|
-
input: { $objectToArray: "$content" },
|
|
56
|
-
as: "version",
|
|
57
|
-
in: "$$version.k"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
// (Optional) Stage 5: Project the fields you want to include/exclude
|
|
63
|
-
// For example, to exclude the entire 'content' field and keep only 'availableVersions'
|
|
64
|
-
// {
|
|
65
|
-
// $project: {
|
|
66
|
-
// content: 0 // Exclude the 'content' field
|
|
67
|
-
// }
|
|
68
|
-
// }
|
|
49
|
+
{ $limit: limit }
|
|
69
50
|
]);
|
|
70
51
|
const formattedResults = dictionaries.map(
|
|
71
52
|
(result) => new import_dictionary.DictionaryModel(result)
|
|
@@ -248,18 +229,18 @@ const deleteDictionaryById = async (dictionaryId) => {
|
|
|
248
229
|
}
|
|
249
230
|
return dictionary;
|
|
250
231
|
};
|
|
232
|
+
const getVersionNumber = (version) => {
|
|
233
|
+
const match = version.match(/^v(\d+)$/);
|
|
234
|
+
if (!match) {
|
|
235
|
+
throw new Error(`Invalid version format: ${version}`);
|
|
236
|
+
}
|
|
237
|
+
return parseInt(match[1], 10);
|
|
238
|
+
};
|
|
251
239
|
const incrementVersion = (dictionary) => {
|
|
252
240
|
const VERSION_PREFIX = "v";
|
|
253
|
-
const availableVersions = dictionary.
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
const match = version.match(/^v(\d+)$/);
|
|
257
|
-
if (!match) {
|
|
258
|
-
throw new Error(`Invalid version format: ${version}`);
|
|
259
|
-
}
|
|
260
|
-
return parseInt(match[1], 10);
|
|
261
|
-
};
|
|
262
|
-
let newNumber = getVersionNumber(currentVersion) + 1;
|
|
241
|
+
const availableVersions = [...dictionary.content.keys() ?? []];
|
|
242
|
+
const lastVersion = availableVersions[availableVersions.length - 1];
|
|
243
|
+
let newNumber = getVersionNumber(lastVersion) + 1;
|
|
263
244
|
let newVersion = `${VERSION_PREFIX}${newNumber}`;
|
|
264
245
|
while (availableVersions.includes(newVersion)) {
|
|
265
246
|
newNumber += 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"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 type { ObjectId } 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): Promise<DictionaryDocument[]> => {\n try {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the filters\n { $match: filters },\n\n // Stage 2: Skip for pagination\n { $skip: skip },\n\n // Stage 3: Limit the number of documents\n { $limit: limit },\n\n // Stage 4: Add the 'availableVersions' field\n {\n $addFields: {\n availableVersions: {\n $map: {\n input: { $objectToArray: '$content' },\n as: 'version',\n in: '$$version.k',\n },\n },\n },\n },\n\n // (Optional) Stage 5: Project the fields you want to include/exclude\n // For example, to exclude the entire 'content' field and keep only 'availableVersions'\n // {\n // $project: {\n // content: 0 // Exclude the 'content' field\n // }\n // }\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 'availableVersions' 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 | ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by ID\n { $match: { _id: dictionaryId } },\n\n // Stage 2: Add the 'availableVersions' field\n {\n $addFields: {\n availableVersions: {\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 | 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 | 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 'availableVersions' field\n {\n $addFields: {\n availableVersions: {\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 getDictionariesKeys = async (\n projectId: string | ObjectId\n): Promise<string[]> => {\n const dictionaries = await DictionaryModel.find({\n projectIds: projectId,\n }).select('key');\n\n return dictionaries.map((dictionary) => dictionary.key);\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 'availableVersions' field\n {\n $addFields: {\n availableVersions: {\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 | 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 | ObjectId,\n dictionary: Partial<Dictionary>\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, ['_id']);\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 | ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, ['_id']);\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\nexport const incrementVersion = (dictionary: Dictionary): string => {\n const VERSION_PREFIX = 'v';\n const availableVersions = dictionary.availableVersions ?? [];\n\n // Get the current version from the version list, default to 'v1' if not present\n const currentVersion =\n availableVersions.length > 0\n ? availableVersions[availableVersions.length - 1]\n : 'v1';\n\n // Function to extract the numeric part of the version\n const 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\n // Start with the next version number\n let newNumber = getVersionNumber(currentVersion) + 1;\n let newVersion = `${VERSION_PREFIX}${newNumber}`;\n\n // Loop until a unique version is found\n while (availableVersions.includes(newVersion)) {\n newNumber += 1;\n newVersion = `${VERSION_PREFIX}${newNumber}`;\n }\n\n return newVersion;\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"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 type { ObjectId } 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): Promise<DictionaryDocument[]> => {\n try {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the filters\n { $match: filters },\n\n // Stage 2: Skip for pagination\n { $skip: skip },\n\n // Stage 3: 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 'availableVersions' 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 | ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaries = await DictionaryModel.aggregate<DictionaryDocument>([\n // Stage 1: Match the document by ID\n { $match: { _id: dictionaryId } },\n\n // Stage 2: Add the 'availableVersions' field\n {\n $addFields: {\n availableVersions: {\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 | 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 | 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 'availableVersions' field\n {\n $addFields: {\n availableVersions: {\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 getDictionariesKeys = async (\n projectId: string | ObjectId\n): Promise<string[]> => {\n const dictionaries = await DictionaryModel.find({\n projectIds: projectId,\n }).select('key');\n\n return dictionaries.map((dictionary) => dictionary.key);\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 'availableVersions' field\n {\n $addFields: {\n availableVersions: {\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 | 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 | ObjectId,\n dictionary: Partial<Dictionary>\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, ['_id']);\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 | ObjectId\n): Promise<DictionaryDocument> => {\n const dictionaryObject = ensureMongoDocumentToObject(dictionary);\n const dictionaryToUpdate = removeObjectKeys(dictionaryObject, ['_id']);\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 availableVersions = [...(dictionary.content.keys() ?? [])];\n const lastVersion = availableVersions[availableVersions.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 (availableVersions.includes(newVersion)) {\n newNumber += 1;\n newVersion = `${VERSION_PREFIX}${newNumber}`;\n }\n\n return newVersion;\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/types/dictionary.types.ts"],"sourcesContent":["import {\n type ContentNode,\n type Dictionary as DictionaryCore,\n} from '@intlayer/core';\nimport type { Model, ObjectId, Document } from 'mongoose';\nimport type { Project } from './project.types';\nimport type { User } from './user.types';\n\nexport type DictionaryCreationData = {\n projectIds: (Project['_id'] | string)[];\n key: string;\n content?: ContentNode;\n title?: string;\n description?: string;\n tags?: string[];\n filePath?: string;\n};\n\nexport type VersionedContentEl = {\n name?: string;\n description?: string;\n content: ContentNode;\n};\n\nexport type ContentVersion = string;\nexport type VersionedContent = Map<string, VersionedContentEl>;\n\nexport type DictionaryData = {\n key: string;\n content: VersionedContent;\n projectIds: (Project['_id'] | string)[];\n creatorId: User['_id'];\n title?: string;\n description?: string;\n tags?: string[];\n filePath?: Record<string, string>;\n};\n\nexport type Dictionary = DictionaryData & {\n _id: ObjectId;\n createdAt: number;\n updatedAt: number;\n
|
|
1
|
+
{"version":3,"sources":["../../../src/types/dictionary.types.ts"],"sourcesContent":["import {\n type ContentNode,\n type Dictionary as DictionaryCore,\n} from '@intlayer/core';\nimport type { Model, ObjectId, Document } from 'mongoose';\nimport type { Project } from './project.types';\nimport type { User } from './user.types';\n\nexport type DictionaryCreationData = {\n projectIds: (Project['_id'] | string)[];\n key: string;\n content?: ContentNode;\n title?: string;\n description?: string;\n tags?: string[];\n filePath?: string;\n};\n\nexport type VersionedContentEl = {\n name?: string;\n description?: string;\n content: ContentNode;\n};\n\nexport type ContentVersion = string;\nexport type VersionedContent = Map<string, VersionedContentEl>;\n\nexport type DictionaryData = {\n key: string;\n content: VersionedContent;\n projectIds: (Project['_id'] | string)[];\n creatorId: User['_id'];\n title?: string;\n description?: string;\n tags?: string[];\n filePath?: Record<string, string>;\n};\n\nexport type Dictionary = DictionaryData & {\n _id: ObjectId;\n createdAt: number;\n updatedAt: number;\n};\n\nexport type DictionaryAPI = DictionaryCore & {\n projectIds: (Project['_id'] | string)[];\n};\n\nexport type DictionaryDocument = Document<unknown, {}, Dictionary> & Dictionary;\nexport type DictionaryModelType = Model<Dictionary>;\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|