UNPKG

@iyulab/oops

Version:

Core SDK for Oops - Safe text file editing with automatic backup

205 lines 7.43 kB
"use strict"; /** * Atomic transaction system for file operations */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.FileOperations = exports.Transaction = void 0; const fs = __importStar(require("fs/promises")); const file_system_1 = require("./file-system"); const errors_1 = require("./errors"); class Transaction { operations = []; rollbackActions = []; isCommitted = false; isRolledBack = false; addOperation(operation) { if (this.isCommitted || this.isRolledBack) { throw new errors_1.OopsError('Cannot add operation to completed transaction', 'TRANSACTION_COMPLETED'); } this.operations.push(operation); } async execute() { if (this.isCommitted || this.isRolledBack) { throw new errors_1.OopsError('Transaction already completed', 'TRANSACTION_COMPLETED'); } try { // Execute all operations and collect rollback actions for (const operation of this.operations) { const rollbackAction = await operation.execute(); // Create rollback function const rollback = this.createRollbackFunction(operation, rollbackAction); this.rollbackActions.unshift(rollback); // Add to beginning for reverse order } this.isCommitted = true; } catch (error) { // Rollback on any failure await this.rollback(); throw error; } } async rollback() { if (this.isRolledBack) { return; // Already rolled back } try { // Execute rollback actions in reverse order for (const rollbackAction of this.rollbackActions) { await rollbackAction(); } } catch (error) { // Log rollback errors but don't throw console.error('Error during transaction rollback:', error); } finally { this.isRolledBack = true; } } createRollbackFunction(operation, rollbackAction) { return async () => { switch (operation.type) { case 'create': // Delete created file if (await file_system_1.FileSystem.exists(operation.target)) { await fs.unlink(operation.target); } break; case 'copy': // Delete copied file if (await file_system_1.FileSystem.exists(operation.target)) { await fs.unlink(operation.target); } break; case 'move': // Move back to original location if (rollbackAction && (await file_system_1.FileSystem.exists(operation.target))) { await fs.rename(operation.target, rollbackAction); } break; case 'delete': // Restore from backup if available if (rollbackAction && (await file_system_1.FileSystem.exists(rollbackAction))) { await fs.rename(rollbackAction, operation.target); } break; case 'write': // Restore original content if (rollbackAction) { await fs.writeFile(operation.target, rollbackAction, 'utf8'); } break; } }; } } exports.Transaction = Transaction; class FileOperations { static createFile(filePath, content) { return { type: 'create', target: filePath, content, async execute() { await file_system_1.FileSystem.writeFile(filePath, content); return ''; // No rollback data needed }, }; } static copyFile(source, target) { return { type: 'copy', source, target, async execute() { await file_system_1.FileSystem.copyFile(source, target); return ''; // No rollback data needed }, }; } static moveFile(source, target) { return { type: 'move', source, target, async execute() { await fs.rename(source, target); return source; // Return original path for rollback }, }; } static deleteFile(filePath) { return { type: 'delete', target: filePath, async execute() { // Create backup before deletion const backupPath = `${filePath}.backup.${Date.now()}`; await fs.rename(filePath, backupPath); return backupPath; // Return backup path for rollback }, }; } static writeFile(filePath, content) { return { type: 'write', target: filePath, content, async execute() { let originalContent = ''; // Read original content if file exists if (await file_system_1.FileSystem.exists(filePath)) { originalContent = await file_system_1.FileSystem.readFile(filePath); } // Write new content await file_system_1.FileSystem.writeFile(filePath, content); return originalContent; // Return original content for rollback }, }; } static createDirectory(dirPath) { return { type: 'create', target: dirPath, async execute() { await file_system_1.FileSystem.mkdir(dirPath); return ''; // No rollback data needed }, }; } } exports.FileOperations = FileOperations; //# sourceMappingURL=transaction.js.map