UNPKG

@allma/core-cdk

Version:

Core AWS CDK constructs for deploying the Allma serverless AI orchestration platform.

110 lines 5 kB
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; import { AllmaImporterService } from '../services/allma-importer.service.js'; import { sendCloudFormationResponse } from '@allma/core-sdk'; import fs from 'fs'; import path from 'path'; import AdmZip from 'adm-zip'; import { Readable } from 'stream'; const s3Client = new S3Client({}); /** * Downloads an asset from S3 to a local temporary file. * @param bucket The S3 bucket name. * @param key The S3 object key. * @returns The local file path where the asset was saved. */ async function downloadAsset(bucket, key) { const command = new GetObjectCommand({ Bucket: bucket, Key: key }); const response = await s3Client.send(command); const localPath = path.join('/tmp', path.basename(key)); if (response.Body instanceof Readable) { const writer = fs.createWriteStream(localPath); response.Body.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', () => resolve(localPath)); writer.on('error', reject); }); } throw new Error('Failed to download asset from S3.'); } /** * Validates and aggregates config data from a single file. * This now uses the centralized validation service. * @param data The parsed JSON data from a file. * @param allStepDefinitions Accumulator for step definitions. * @param allFlows Accumulator for flows. * @param sourceFileName The name of the file for error reporting. */ function aggregateConfigData(data, allStepDefinitions, allFlows, sourceFileName) { const importer = new AllmaImporterService(); const validationResult = importer.validateImportData(data, sourceFileName); if (!validationResult.success) { // Format the structured error for clear logging in CloudFormation/CDK output. const errorMessages = []; validationResult.error.formErrors.forEach(err => errorMessages.push(err)); for (const [field, errors] of Object.entries(validationResult.error.fieldErrors)) { if (errors) { errorMessages.push(`Field '${field}': ${errors.join(', ')}`); } } throw new Error(`Validation failed for ${sourceFileName}:\n- ${errorMessages.join('\n- ')}`); } const config = validationResult.data; if (config.stepDefinitions) { allStepDefinitions.push(...config.stepDefinitions); } if (config.flows) { allFlows.push(...config.flows); } } export async function handler(event) { const { RequestType, ResourceProperties } = event; const { S3Bucket, S3Key } = ResourceProperties; try { if (RequestType === 'Delete') { await sendCloudFormationResponse(event, 'SUCCESS'); return; } if (RequestType === 'Create' || RequestType === 'Update') { const localAssetPath = await downloadAsset(S3Bucket, S3Key); const allStepDefinitions = []; const allFlows = []; if (S3Key.endsWith('.zip')) { const zip = new AdmZip(localAssetPath); const zipEntries = zip.getEntries(); for (const entry of zipEntries) { if (!entry.isDirectory && entry.entryName.endsWith('.json')) { const fileContent = entry.getData().toString('utf8'); const jsonData = JSON.parse(fileContent); aggregateConfigData(jsonData, allStepDefinitions, allFlows, entry.entryName); } } } else { const fileContent = fs.readFileSync(localAssetPath, 'utf8'); const jsonData = JSON.parse(fileContent); aggregateConfigData(jsonData, allStepDefinitions, allFlows, path.basename(S3Key)); } const finalConfig = { formatVersion: '1.0', exportedAt: new Date().toISOString(), stepDefinitions: allStepDefinitions, flows: allFlows, }; const importer = new AllmaImporterService(); const result = await importer.import(finalConfig, { overwrite: true }); console.log('Import summary:', JSON.stringify(result, null, 2)); if (result.errors.length > 0) { const errorSummary = result.errors.map(e => `[${e.type}:${e.id}] ${e.message}`).join('; '); throw new Error(`Import failed with ${result.errors.length} errors: ${errorSummary}`); } await sendCloudFormationResponse(event, 'SUCCESS', { ImportedItems: result.created.flows + result.created.steps }); return; } await sendCloudFormationResponse(event, 'SUCCESS'); } catch (error) { console.error('Failed to process CDK configuration import:', error); await sendCloudFormationResponse(event, 'FAILED', { Error: error.message }); } } //# sourceMappingURL=config-importer.js.map