@allma/core-cdk
Version:
Core AWS CDK constructs for deploying the Allma serverless AI orchestration platform.
198 lines • 10.3 kB
JavaScript
import { AllmaExportFormatSchema, StepDefinitionSchema, FlowDefinitionSchema, PromptTemplateSchema } from '@allma/core-types';
import { FlowDefinitionService } from '../allma-admin/services/flow-definition.service.js';
import { StepDefinitionService } from '../allma-admin/services/step-definition.service.js';
import { PromptTemplateService } from '../allma-admin/services/prompt-template.service.js';
export class AllmaImporterService {
/**
* Validates the raw data for an import operation with detailed, item-by-item checks.
* @param rawData The raw, unparsed data from the import request.
* @param sourceFileName Optional name of the source file for more descriptive error messages.
* @returns A discriminated union indicating success with parsed data, or failure with structured errors.
*/
validateImportData(rawData, sourceFileName) {
const filePrefix = sourceFileName ? `[${sourceFileName}] ` : '';
const topLevelSchema = AllmaExportFormatSchema.omit({ flows: true, stepDefinitions: true, promptTemplates: true });
const topLevelValidation = topLevelSchema.safeParse(rawData);
if (!topLevelValidation.success) {
return { success: false, error: topLevelValidation.error.flatten() };
}
const data = rawData;
const fieldErrors = {};
const formErrors = [];
// Manually iterate through Zod issues to build precise error paths.
const processIssues = (issues, arrayName, itemIndex, itemIdentifier) => {
for (const issue of issues) {
if (issue.path.length === 0) {
formErrors.push(`${filePrefix}${itemIdentifier}: ${issue.message}`);
}
else {
const key = `${arrayName}[${itemIndex}].${issue.path.join('.')}`;
fieldErrors[key] = (fieldErrors[key] || []).concat(`${filePrefix}${issue.message}`);
}
}
};
// Validate each flow individually
if (data.flows && Array.isArray(data.flows)) {
data.flows.forEach((flow, index) => {
const flowValidation = FlowDefinitionSchema.safeParse(flow);
if (!flowValidation.success) {
const flowIdentifier = flow?.id ? `Flow '${flow.id}' (v${flow.version})` : `Flow at index ${index}`;
processIssues(flowValidation.error.issues, 'flows', index, flowIdentifier);
}
});
}
// Validate each step definition individually
if (data.stepDefinitions && Array.isArray(data.stepDefinitions)) {
data.stepDefinitions.forEach((step, index) => {
const stepValidation = StepDefinitionSchema.safeParse(step);
if (!stepValidation.success) {
const stepIdentifier = step?.id ? `Step Definition '${step.id}'` : `Step Definition at index ${index}`;
processIssues(stepValidation.error.issues, 'stepDefinitions', index, stepIdentifier);
}
});
}
// Validate each prompt template individually
if (data.promptTemplates && Array.isArray(data.promptTemplates)) {
data.promptTemplates.forEach((prompt, index) => {
const promptValidation = PromptTemplateSchema.safeParse(prompt);
if (!promptValidation.success) {
const promptIdentifier = prompt?.id ? `Prompt '${prompt.id}' (v${prompt.version})` : `Prompt at index ${index}`;
processIssues(promptValidation.error.issues, 'promptTemplates', index, promptIdentifier);
}
});
}
if (formErrors.length > 0 || Object.keys(fieldErrors).length > 0) {
return { success: false, error: { formErrors, fieldErrors } };
}
// Final parse of the whole object to get a fully typed result
const finalValidation = AllmaExportFormatSchema.safeParse(data);
if (finalValidation.success) {
return { success: true, data: finalValidation.data };
}
else {
// This should be unreachable if the above logic is correct, but serves as a safeguard.
return { success: false, error: finalValidation.error.flatten() };
}
}
async import(data, options) {
const result = {
created: { flows: 0, steps: 0, prompts: 0 },
updated: { flows: 0, steps: 0, prompts: 0 },
skipped: { flows: 0, steps: 0, prompts: 0 },
errors: [],
};
// Step 1: Import Step Definitions
if (data.stepDefinitions) {
for (const step of data.stepDefinitions) {
try {
const existing = await StepDefinitionService.get(step.id);
if (existing) {
if (options.overwrite) {
await StepDefinitionService.update(step.id, step);
result.updated.steps++;
}
else {
result.skipped.steps++;
}
}
else {
// The create method in the service handles the full creation logic.
// We assume the imported `step` object fits the `CreateStepDefinitionInput` shape.
await StepDefinitionService.create(step);
result.created.steps++;
}
}
catch (error) {
result.errors.push({
id: step.id,
type: 'step',
message: error.message || 'An unknown error occurred',
});
}
}
}
// Step 2: Import Prompt Templates
if (data.promptTemplates) {
for (const prompt of data.promptTemplates) {
try {
const existingMaster = await PromptTemplateService.getMaster(prompt.id);
if (existingMaster) {
if (options.overwrite) {
const existingVersion = await PromptTemplateService.getVersion(prompt.id, prompt.version);
if (existingVersion) {
if (existingVersion.isPublished) {
result.errors.push({ id: prompt.id, type: 'prompt', message: `Version ${prompt.version} is published and cannot be overwritten.` });
continue;
}
await PromptTemplateService.updateVersion(prompt.id, prompt.version, prompt);
result.updated.prompts++;
}
else {
result.errors.push({ id: prompt.id, type: 'prompt', message: `Cannot overwrite prompt: version ${prompt.version} does not exist. Creating new versions for existing prompts on import is not supported.` });
}
}
else {
result.skipped.prompts++;
}
}
else {
// This prompt does not exist. Create it from the imported definition.
await PromptTemplateService.createPromptFromImport(prompt);
result.created.prompts++;
}
}
catch (error) {
result.errors.push({
id: prompt.id,
type: 'prompt',
message: error.message || 'An unknown error occurred',
});
}
}
}
// Step 3: Import Flow Definitions
if (data.flows) {
for (const flow of data.flows) {
try {
const existingMaster = await FlowDefinitionService.getMaster(flow.id);
if (existingMaster) {
if (options.overwrite) {
const existingVersion = await FlowDefinitionService.getVersion(flow.id, flow.version);
if (existingVersion) {
// This version exists, so update it.
if (existingVersion.isPublished) {
result.errors.push({ id: flow.id, type: 'flow', message: `Version ${flow.version} is published and cannot be overwritten.` });
continue;
}
await FlowDefinitionService.updateVersion(flow.id, flow.version, flow);
result.updated.flows++;
}
else {
// This version doesn't exist for a flow that is already in the system.
// Creating new versions on an existing flow during import is not supported yet.
result.errors.push({ id: flow.id, type: 'flow', message: `Cannot overwrite flow: version ${flow.version} does not exist. Creating new versions for existing flows on import is not supported.` });
}
}
else {
result.skipped.flows++;
}
}
else {
// This flow does not exist. Create it from the imported definition.
await FlowDefinitionService.createFlowFromImport(flow);
result.created.flows++;
}
}
catch (error) {
result.errors.push({
id: flow.id,
type: 'flow',
message: error.message || 'An unknown error occurred',
});
}
}
}
return result;
}
}
//# sourceMappingURL=allma-importer.service.js.map