UNPKG

@channel.io/be-user-chat-mcp

Version:

Backend UserChat Model Context Protocol server for Channel.io

77 lines 4 kB
import { executeRawRedashQuery } from "../services/redash.service.js"; // --- Type Definitions --- export var Action; (function (Action) { Action["CREATE"] = "create"; Action["UPDATE"] = "update"; Action["DELETE"] = "delete"; })(Action = Action || (Action = {})); // --- Constants --- // Use hard-coded default values instead of environment variables const REDASH_DATA_SOURCE_ID_CHANNEL_PROD_PSQL = "1"; const TABLE_CHANGE_LOGS = "change_logs"; // --- Utility Functions --- /** * 엔티티 타입과 ID 문자열의 유효성을 검사합니다. (간단한 예시) * 실제 환경에서는 더 엄격한 검증이 필요할 수 있습니다. */ function validateEntityParameters(entityType, entityId, context) { if (!entityType || typeof entityType !== "string" || entityType.length === 0 || entityType.length > 255) { console.error(`Invalid entityType format detected in ${context}: ${entityType}`); throw new Error(`Invalid entityType format provided for ${context}.`); } if (!entityId || typeof entityId !== "string" || entityId.length === 0 || entityId.length > 255) { console.error(`Invalid entityId format detected in ${context}: ${entityId}`); throw new Error(`Invalid entityId format provided for ${context}.`); } // SQL 인젝션 방지를 위해 매우 기본적인 필터링 (실제로는 부족할 수 있음) // 실제로는 ORM이나 매개변수화된 쿼리를 사용하는 것이 훨씬 안전합니다. if (/[^a-zA-Z0-9_:-]/.test(entityType) || /[^a-zA-Z0-9_:-]/.test(entityId)) { console.error(`Potentially unsafe characters in entityType or entityId in ${context}. entityType: ${entityType}, entityId: ${entityId}`); throw new Error(`Unsafe characters detected in entityType or entityId for ${context}.`); } } // --- Data Fetching Functions --- /** * 주어진 entityType과 entityId에 해당하는 변경 로그들을 Redash를 통해 조회합니다. * 생성 날짜(createdAt) 기준 내림차순으로 정렬되며, 페이지네이션을 지원합니다. * 쿼리 실패 시 에러를 발생시킵니다. * @param entityType 엔티티 유형 * @param entityId 엔티티 ID * @param since 페이지 번호 (1부터 시작, 기본값 1) * @param context Optional RequestContext for HTTP transport. * @returns 로그 목록과 다음 페이지 번호 */ export async function getChangeLogsByEntity(entityType, entityId, since = 1, // 기본 페이지 1 context) { const operationContext = `getChangeLogsByEntity (entityType: ${entityType}, entityId: ${entityId}, since: ${since})`; validateEntityParameters(entityType, entityId, operationContext); // 입력값 검증 const pageSize = 10; const offset = (since - 1) * pageSize; // SQL 쿼리: SQL 인젝션에 매우 취약합니다. // 프로덕션 환경에서는 반드시 매개변수화된 쿼리나 ORM을 사용해야 합니다. const sql = `SELECT created_at, diff FROM ${TABLE_CHANGE_LOGS} WHERE entity_type = '${entityType}' AND entity_id = '${entityId}' ORDER BY created_at DESC LIMIT ${pageSize} OFFSET ${offset};`; const dataSourceId = parseInt(REDASH_DATA_SOURCE_ID_CHANNEL_PROD_PSQL, 10); if (isNaN(dataSourceId)) { throw new Error(`Invalid REDASH_DATA_SOURCE_ID_PSQL: ${REDASH_DATA_SOURCE_ID_CHANNEL_PROD_PSQL}`); } try { const results = await executeRawRedashQuery(dataSourceId, sql, operationContext, context); let nextSince = undefined; if (results.length === pageSize) { nextSince = since + 1; } return { nextSince, changeLogs: results }; // 결과가 없으면 빈 배열과 undefined nextSince 반환 } catch (error) { console.error(`[ChangeLog Feature] Error in ${operationContext}:`, error); throw error; // redash.service.ts에서 처리된 에러를 다시 throw } } //# sourceMappingURL=change-log.repository.js.map