import { AIProcessor } from "@helpers/ai_processor";
import { generateInvestigation as generateInvestigationImpl, generateInvestigationObjects as generateInvestigationObjectsImpl, generateInvestigationSteps as generateInvestigationStepsImpl, generateInvestigationWithoutStepsAndObjects as generateInvestigationWithoutStepsAndObjectsImpl, } from "./investigation/ai-generate";
import { regenerateOtherFields as regenerateOtherFieldsImpl, regenerateOtherFieldsObjects as regenerateOtherFieldsObjectsImpl, regenerateOtherFieldsSteps as regenerateOtherFieldsStepsImpl, regenerateOtherFieldsWithoutStepsAndObjects as regenerateOtherFieldsWithoutStepsAndObjectsImpl, } from "./investigation/ai-regenerate";
import { ensureInvestigationAuthor as ensureInvestigationAuthorImpl } from "./investigation/author";
import { cloneInvestigation as cloneInvestigationImpl } from "./investigation/clone";
import { addContradictionInPlace as addContradictionInPlaceImpl } from "./investigation/contradictions";
import { createInvestigation as createInvestigationImpl, getInvestigationById as getInvestigationByIdImpl, updateInvestigation as updateInvestigationImpl, } from "./investigation/crud";
import { deleteInvestigationById as deleteInvestigationByIdImpl, deleteInvestigationData as deleteInvestigationDataImpl, } from "./investigation/delete";
import { getFilterMetadata as getFilterMetadataImpl, getInvestigations as getInvestigationsImpl, } from "./investigation/listing";
import { checkAndUnlockStaleLocks as checkAndUnlockStaleLocksImpl, lockInvestigation as lockInvestigationImpl, toggleInvestigationDevelopment as toggleInvestigationDevelopmentImpl, unlockInvestigation as unlockInvestigationImpl, } from "./investigation/locks";
import { getFieldHistory as getFieldHistoryImpl, getInvestigationVersions as getInvestigationVersionsImpl, redoInvestigation as redoInvestigationImpl, undoInvestigation as undoInvestigationImpl, updateInvestigationByVersion as updateInvestigationByVersionImpl, } from "./investigation/versions";
/**
* Investigation Service (facade)
* @category Services
*/
export class InvestigationService {
aiProcessor;
/**
* Constructor
* @category Services
*/
constructor() {
this.aiProcessor = new AIProcessor();
}
/**
* Creates a new investigation.
* @param {ICreateInvestigationDto} createDto - DTO used to create the investigation.
* @returns {Promise<IInvestigation>} The created investigation.
*/
async createInvestigation(createDto) {
return await createInvestigationImpl(createDto);
}
/**
* Retrieves a single investigation by id (version-aware).
* @param {string} investigationId - Investigation id.
* @returns {Promise<IInvestigation>} The investigation document.
*/
async getInvestigationById(investigationId) {
return await getInvestigationByIdImpl(investigationId);
}
/**
* Updates an investigation with the new API format.
* @param {string} investigationId - Investigation id.
* @param {IUpdateInvestigationDto} updateData - Update payload.
* @param {object} [obj] - Optional update options.
* @param {boolean} [obj.needsBuildUpdate] - Whether to rebuild update fields with the builder.
* @param {(Types.ObjectId | null)} [obj.updatedBy] - User id performing the update.
* @param {boolean} [obj.isAiGenerated] - Whether the update is AI-generated.
* @param {boolean} [obj.skipVersioning] - Whether to skip versioning for this update.
* @returns {Promise<IUpdateInvestigationResponse>} Update result.
*/
async updateInvestigation(investigationId, updateData, obj) {
return await updateInvestigationImpl(investigationId, updateData, obj);
}
/**
* Gets history entries for a specific field.
* @param {string} investigationId - Investigation id.
* @param {string} fieldPath - Field path (e.g. "title", "steps.0.title").
* @param {number} [limit] - Max number of entries (defaults to 50).
* @returns {Promise<{ fieldPath: string, history: Array<*>, totalCount: number }>} Field history data.
*/
async getFieldHistory(investigationId, fieldPath, limit = 50) {
return await getFieldHistoryImpl(investigationId, fieldPath, limit);
}
/**
* Lists versions for an investigation.
* @param {string} investigationId - Investigation id.
* @param {number} [limit] - Max number of versions (defaults to 20).
* @returns {Promise<IInvestigationVersionListResponse>} Versions list response.
*/
async getInvestigationVersions(investigationId, limit = 20) {
return await getInvestigationVersionsImpl(investigationId, limit);
}
/**
* Moves currentVersionIndex back (undo).
* @param {string} investigationId - Investigation id.
* @returns {Promise<IInvestigation>} Investigation restored to the previous version.
*/
async undoInvestigation(investigationId) {
return await undoInvestigationImpl(investigationId);
}
/**
* Moves currentVersionIndex forward (redo).
* @param {string} investigationId - Investigation id.
* @returns {Promise<IInvestigation>} Investigation restored to the next version.
*/
async redoInvestigation(investigationId) {
return await redoInvestigationImpl(investigationId);
}
/**
* Ensures author is set for an investigation.
* @param {string} investigationId - Investigation id.
* @param {Types.ObjectId} authorId - Author id to set when missing.
* @returns {Promise<IInvestigation | null>} Updated investigation or null if no change.
*/
async ensureInvestigationAuthor(investigationId, authorId) {
return await ensureInvestigationAuthorImpl(investigationId, authorId);
}
/**
* Adds contradiction metadata to a field on the investigation object (mutates in place).
* @param {Partial<IInvestigation>} investigation - Investigation (partial) to mutate.
* @param {IContradictionInput} contradiction - Contradiction descriptor.
* @returns {Partial<IInvestigation>} The same investigation object, mutated in place.
*/
addContradictionInPlace(investigation, contradiction) {
return addContradictionInPlaceImpl(investigation, contradiction);
}
/**
* Retrieves investigations with filtering/sorting/sectioning.
* @param {IInvestigationSearchDto} searchDto - Search and pagination parameters.
* @param {AuthGrpcService} [grpcClient] - Optional gRPC client for profile enrichment.
* @returns {Promise<IInvestigationListResponseDto>} Investigation list response.
*/
async getInvestigations(searchDto, grpcClient) {
return await getInvestigationsImpl(searchDto, grpcClient);
}
/**
* Retrieves available filter metadata for investigations list.
* @returns {Promise<IInvestigationFilterMetadataDto>} Filter metadata response.
*/
async getFilterMetadata() {
return await getFilterMetadataImpl();
}
/**
* AI: Generates investigation text fields without steps/objects.
* @param {string} message - User message.
* @param {string} history - Chat history.
* @param {string} investigationMetadata - Guide/metadata YAML.
* @returns {Promise<IAssistantInvestigationFormat | null>} AI response.
*/
async generateInvestigationWithoutStepsAndObjects(message, history, investigationMetadata) {
return await generateInvestigationWithoutStepsAndObjectsImpl(this.aiProcessor, message, history, investigationMetadata);
}
/**
* AI: Generates objects for an investigation.
* @param {string} message - User message.
* @param {string} history - Chat history.
* @param {string} investigationMetadata - Guide/metadata YAML.
* @param {string} investigation - Investigation YAML.
* @returns {Promise<IAssistantInvestigationFormat | null>} AI response.
*/
async generateInvestigationObjects(message, history, investigationMetadata, investigation) {
return await generateInvestigationObjectsImpl(this.aiProcessor, message, history, investigationMetadata, investigation);
}
/**
* AI: Generates steps for an investigation.
* @param {string} message - User message.
* @param {string} history - Chat history.
* @param {string} investigationMetadata - Guide/metadata YAML.
* @param {string} investigation - Investigation YAML.
* @returns {Promise<IAssistantInvestigationFormat | null>} AI response.
*/
async generateInvestigationSteps(message, history, investigationMetadata, investigation) {
return await generateInvestigationStepsImpl(this.aiProcessor, message, history, investigationMetadata, investigation);
}
/**
* AI: Generates a full investigation (text + objects + steps).
* @param {string} message - User message.
* @param {FormattedHistory} history - Structured chat history.
* @param {IMetadataDocument} investigationMetadata - Metadata document used as guide.
* @returns {Promise<IAssistantInvestigationFormat | null>} AI response.
*/
async generateInvestigation(message, history, investigationMetadata) {
return await generateInvestigationImpl(this.aiProcessor, message, history, investigationMetadata);
}
/**
* Creates a clone of an investigation.
* @param {string} investigationId - Investigation id.
* @param {string} [userId] - The ID of the user cloning the investigation (will be set as the new author).
* @returns {Promise<IInvestigation>} The cloned investigation.
*/
async cloneInvestigation(investigationId, userId) {
return await cloneInvestigationImpl(investigationId, userId);
}
/**
* Clears investigation content and marks it as empty (mutates in place).
* @param {IInvestigation} investigation - Investigation to clear.
* @returns {IInvestigation} The same investigation instance after mutation.
*/
deleteInvestigationData(investigation) {
return deleteInvestigationDataImpl(investigation);
}
/**
* Permanently deletes an investigation and related chat history.
* @param {string} investigationId - Investigation id.
* @returns {Promise<IDeleteInvestigationByIdResponse>} Delete result.
*/
async deleteInvestigationById(investigationId) {
return await deleteInvestigationByIdImpl(investigationId);
}
/**
* Adds a new version entry and updates currentVersionIndex (legacy flow).
* @param {IInvestigation} oldInvestigation - Previous investigation state.
* @param {IInvestigation} investigation - Current investigation document to update.
* @param {(ObjectId | null)} [userId] - User id who made the change.
* @param {boolean} [isUserChangeExist] - Whether the change was made by user (defaults to false).
* @returns {Promise<IInvestigation>} Updated investigation document.
*/
async updateInvestigationByVersion(oldInvestigation, investigation, userId, isUserChangeExist = false) {
return await updateInvestigationByVersionImpl(oldInvestigation, investigation, userId, isUserChangeExist);
}
/**
* AI regeneration step 1: text fields (no steps/objects).
* @param {string} fieldName - Field name used as regeneration source.
* @param {string} fieldValue - Source field value.
* @param {string} investigation - Current investigation YAML.
* @param {string} investigationMetadata - Guide/metadata YAML.
* @param {string} [history] - Chat history YAML (defaults to "-").
* @param {object} [contradictionInfo] - Optional contradiction info.
* @param {(string | null)} [contradictionInfo.contradictionReason] - Contradiction reason (if any).
* @param {(string | null)} [contradictionInfo.targetFieldName] - Target field name related to contradiction.
* @param {boolean} [contradictionInfo.isContradicting] - Whether the source field is contradicting.
* @returns {Promise<IAssistantInvestigationFormat | null>} AI response.
*/
async regenerateOtherFieldsWithoutStepsAndObjects(fieldName, fieldValue, investigation, investigationMetadata, history = "-", contradictionInfo) {
return await regenerateOtherFieldsWithoutStepsAndObjectsImpl(this.aiProcessor, fieldName, fieldValue, investigation, investigationMetadata, history, contradictionInfo);
}
/**
* AI regeneration step 2: objects.
* @param {string} fieldName - Field name used as regeneration source.
* @param {string} fieldValue - Source field value.
* @param {string} investigation - Current investigation YAML.
* @param {string} investigationMetadata - Guide/metadata YAML.
* @param {string} [history] - Chat history YAML (defaults to "-").
* @param {object} [contradictionInfo] - Optional contradiction info.
* @param {(string | null)} [contradictionInfo.contradictionReason] - Contradiction reason (if any).
* @param {(string | null)} [contradictionInfo.targetFieldName] - Target field name related to contradiction.
* @param {boolean} [contradictionInfo.isContradicting] - Whether the source field is contradicting.
* @returns {Promise<IAssistantInvestigationFormat | null>} AI response.
*/
async regenerateOtherFieldsObjects(fieldName, fieldValue, investigation, investigationMetadata, history = "-", contradictionInfo) {
return await regenerateOtherFieldsObjectsImpl(this.aiProcessor, fieldName, fieldValue, investigation, investigationMetadata, history, contradictionInfo);
}
/**
* AI regeneration step 3: steps.
* @param {string} fieldName - Field name used as regeneration source.
* @param {string} fieldValue - Source field value.
* @param {string} investigation - Current investigation YAML.
* @param {string} investigationMetadata - Guide/metadata YAML.
* @param {string} [history] - Chat history YAML (defaults to "-").
* @param {object} [contradictionInfo] - Optional contradiction info.
* @param {(string | null)} [contradictionInfo.contradictionReason] - Contradiction reason (if any).
* @param {(string | null)} [contradictionInfo.targetFieldName] - Target field name related to contradiction.
* @param {boolean} [contradictionInfo.isContradicting] - Whether the source field is contradicting.
* @returns {Promise<IAssistantInvestigationFormat | null>} AI response.
*/
async regenerateOtherFieldsSteps(fieldName, fieldValue, investigation, investigationMetadata, history = "-", contradictionInfo) {
return await regenerateOtherFieldsStepsImpl(this.aiProcessor, fieldName, fieldValue, investigation, investigationMetadata, history, contradictionInfo);
}
/**
* Orchestrates 3-step regeneration and writes results back to DB.
* @param {string} investigationId - Investigation id.
* @param {string} fieldName - Field name used as regeneration source.
* @param {(Types.ObjectId | null)} [updatedBy] - User id who triggered regeneration.
* @param {string} [history] - Chat history YAML (defaults to "-").
* @returns {Promise<IInvestigation>} Updated investigation.
*/
async regenerateOtherFields(investigationId, fieldName, updatedBy = null, history = "-") {
return await regenerateOtherFieldsImpl(this.aiProcessor, investigationId, fieldName, updatedBy, history);
}
/**
* Toggles investigation status to/from IN_DEVELOPMENT.
* @param {string} investigationId - Investigation id.
* @returns {Promise<IInvestigation>} Updated investigation.
*/
async toggleInvestigationDevelopment(investigationId) {
return await toggleInvestigationDevelopmentImpl(investigationId);
}
/**
* Locks investigation for editing.
* @param {string} investigationId - Investigation id.
* @param {string} userId - User id acquiring the lock.
* @returns {Promise<IInvestigation>} Updated investigation.
*/
async lockInvestigation(investigationId, userId) {
return await lockInvestigationImpl(investigationId, userId);
}
/**
* Unlocks investigation.
* @param {string} investigationId - Investigation id.
* @param {string} userId - User id releasing the lock.
* @returns {Promise<IInvestigation>} Updated investigation.
*/
async unlockInvestigation(investigationId, userId) {
return await unlockInvestigationImpl(investigationId, userId);
}
/**
* Unlocks stale locks (older than configured threshold).
* @returns {Promise<number>} Count of unlocked investigations.
*/
async checkAndUnlockStaleLocks() {
return await checkAndUnlockStaleLocksImpl();
}
}
Source