claude-flow-novice 2.15.3 → 2.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/.claude/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/.claude/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/.claude/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/.claude/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/.claude/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/.claude/commands/cfn-loop-cli.md +16 -2
- package/.claude/commands/switch-api.md +31 -10
- package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
- package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- package/.claude/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
- package/.claude/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/.claude/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
- package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/.claude/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
- package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/.claude/skills/cfn-redis-coordination/redis-functions.sh +33 -0
- package/.claude/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/.claude/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/.claude/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/.claude/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- package/README.md +116 -475
- package/claude-assets/agents/cfn-dev-team/README.md +103 -0
- package/claude-assets/agents/cfn-dev-team/architecture/goal-planner.md +1 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +355 -6
- package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +99 -12
- package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +1 -1
- package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +20 -1
- package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +110 -13
- package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +106 -15
- package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +115 -11
- package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +94 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +87 -9
- package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +85 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +160 -28
- package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +101 -19
- package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +108 -14
- package/claude-assets/agents/cfn-dev-team/reviewers/{reviewer.md → code-reviewer.md} +95 -8
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +107 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +98 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +95 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +136 -9
- package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +108 -1
- package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +107 -13
- package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +737 -0
- package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
- package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +828 -0
- package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +106 -7
- package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +77 -0
- package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +684 -0
- package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +110 -1
- package/claude-assets/agents/cfn-dev-team/testers/tester.md +94 -7
- package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +87 -13
- package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +103 -7
- package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +94 -7
- package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +46 -0
- package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
- package/claude-assets/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/claude-assets/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/claude-assets/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/claude-assets/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/claude-assets/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/claude-assets/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/claude-assets/commands/cfn-loop-cli.md +16 -2
- package/claude-assets/commands/switch-api.md +31 -10
- package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
- package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/claude-assets/hooks/detect-hardcoded-credentials.sh +212 -0
- package/claude-assets/skills/SKILL_TEMPLATE.md +774 -0
- package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +84 -113
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +33 -6
- package/claude-assets/skills/agent-template-generator/SKILL.md +440 -0
- package/claude-assets/skills/agent-template-generator/generate-agent.sh +405 -0
- package/claude-assets/skills/agent-validation-linter/SKILL.md +589 -0
- package/claude-assets/skills/agent-validation-linter/lint-agents.sh +271 -0
- package/claude-assets/skills/bootstrap/bash-fundamentals.md +786 -0
- package/claude-assets/skills/bootstrap/database-connection.md +464 -0
- package/claude-assets/skills/bootstrap/error-handling.md +580 -0
- package/claude-assets/skills/bootstrap/file-operations.md +699 -0
- package/claude-assets/skills/bootstrap/skill-loader.md +616 -0
- package/claude-assets/skills/bootstrap/sqlite-params.sh +287 -0
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/claude-assets/skills/cfn-automatic-memory-persistence/test-memory-persistence.sh +17 -16
- package/claude-assets/skills/cfn-deployment/SKILL.md +293 -0
- package/claude-assets/skills/cfn-deployment/execute.sh +21 -0
- package/claude-assets/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/claude-assets/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +38 -0
- package/claude-assets/skills/cfn-error-batching-strategy/lib/core-functions.sh +47 -47
- package/claude-assets/skills/cfn-file-operations/SKILL.md +290 -0
- package/claude-assets/skills/cfn-file-operations/execute.sh +129 -0
- package/claude-assets/skills/cfn-file-operations/lib/atomic-write.sh +294 -0
- package/claude-assets/skills/cfn-file-operations/lib/lock.sh +361 -0
- package/claude-assets/skills/cfn-file-operations/test.sh +369 -0
- package/claude-assets/skills/cfn-log-operations/SKILL.md +308 -0
- package/claude-assets/skills/cfn-log-operations/execute.sh +420 -0
- package/claude-assets/skills/cfn-log-operations/lib/rotate.sh +406 -0
- package/claude-assets/skills/cfn-log-operations/lib/search.sh +448 -0
- package/claude-assets/skills/cfn-log-operations/test.sh +394 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
- package/claude-assets/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/claude-assets/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/claude-assets/skills/cfn-parameterized-queries/SKILL.md +339 -0
- package/claude-assets/skills/cfn-playbook/query-playbook.sh +19 -15
- package/claude-assets/skills/cfn-playbook/update-playbook.sh +25 -14
- package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +44 -0
- package/claude-assets/skills/cfn-promotion/SKILL.md +305 -0
- package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
- package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
- package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +33 -0
- package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/claude-assets/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/claude-assets/skills/cfn-skill-loader/SKILL.md +466 -0
- package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
- package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/claude-assets/skills/cfn-task-audit/get-audit-data.sh +42 -21
- package/claude-assets/skills/cfn-task-audit/store-task-audit.sh +17 -10
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh +17 -14
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh.backup-1763392821 +55 -0
- package/claude-assets/skills/cfn-test-runner/store-benchmarks.sh +17 -19
- package/claude-assets/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- package/claude-assets/skills/cfn-utilities/SKILL.md +237 -0
- package/claude-assets/skills/cfn-utilities/execute.sh +32 -0
- package/claude-assets/skills/cfn-utilities/lib/errors.sh +56 -0
- package/claude-assets/skills/cfn-utilities/lib/file-ops.sh +164 -0
- package/claude-assets/skills/cfn-utilities/lib/logging.sh +77 -0
- package/claude-assets/skills/cfn-utilities/lib/retry.sh +127 -0
- package/claude-assets/skills/cfn-utilities/test.sh +317 -0
- package/claude-assets/skills/integration/agent-handoff.sh +62 -64
- package/claude-assets/skills/json-validation/SKILL.md +431 -0
- package/claude-assets/skills/json-validation/test-validate-success-criteria.sh +421 -0
- package/claude-assets/skills/json-validation/validate-success-criteria.sh +197 -0
- package/claude-assets/skills/redis-coordination/validate-parameters.sh +34 -0
- package/claude-assets/skills/workflow-codification/DEPLOY_QUICK_REFERENCE.md +106 -0
- package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh +481 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh.backup-1763392820 +512 -0
- package/claude-assets/skills/workflow-codification/lib/security-utils.sh +204 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh +648 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh.backup-1763392820 +664 -0
- package/claude-assets/skills/workflow-codification/test-integration.sh +15 -0
- package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh +55 -14
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
- package/claude-assets/skills/workflow-codification/track-edge-case.sh +27 -60
- package/claude-assets/skills/workflow-codification/workflow-codification.db +0 -0
- package/dist/ace/ace-curator.js +10 -2
- package/dist/ace/ace-curator.js.map +1 -1
- package/dist/ace/ace-generator.js +4 -0
- package/dist/ace/ace-generator.js.map +1 -1
- package/dist/ace/ace-reflector.js +1 -1
- package/dist/ace/ace-reflector.js.map +1 -1
- package/dist/ace/context-injection.js +24 -2
- package/dist/ace/context-injection.js.map +1 -1
- package/dist/agents/agent-loader.js +146 -165
- package/dist/agents/agent-loader.js.map +1 -1
- package/dist/agents/task-agent-integration.js +1 -1
- package/dist/agents/task-agent-integration.js.map +1 -1
- package/dist/api/health-endpoints.js +390 -0
- package/dist/api/health-endpoints.js.map +1 -0
- package/dist/cli/agent-executor.js +4 -1
- package/dist/cli/agent-executor.js.map +1 -1
- package/dist/cli/agent-prompt-builder.js +89 -1
- package/dist/cli/agent-prompt-builder.js.map +1 -1
- package/dist/cli/agent-spawn.js +130 -37
- package/dist/cli/agent-spawn.js.map +1 -1
- package/dist/cli/skill-cache-validator.js +412 -0
- package/dist/cli/skill-cache-validator.js.map +1 -0
- package/dist/cli/skill-cli.js +991 -0
- package/dist/cli/skill-cli.js.map +1 -0
- package/dist/cli/skill-execution-logger.js +284 -0
- package/dist/cli/skill-execution-logger.js.map +1 -0
- package/dist/cli/skill-loader.js +457 -0
- package/dist/cli/skill-loader.js.map +1 -0
- package/dist/coordination/event-bus.js +2 -2
- package/dist/coordination/event-bus.js.map +1 -1
- package/dist/coordination/fleet-manager.js +1 -1
- package/dist/coordination/fleet-manager.js.map +1 -1
- package/dist/coordination/index.js +23 -9
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/types/fleet-manager.types.js.map +1 -1
- package/dist/db/migration-manager.js +483 -0
- package/dist/db/migration-manager.js.map +1 -0
- package/dist/db/skills-query.js +535 -0
- package/dist/db/skills-query.js.map +1 -0
- package/dist/integration/DatabaseHandoff.js +1 -1
- package/dist/integration/DatabaseHandoff.js.map +1 -1
- package/dist/jobs/edge-case-analyzer.js +367 -0
- package/dist/jobs/edge-case-analyzer.js.map +1 -0
- package/dist/jobs/promotion-sla-enforcer.js +288 -0
- package/dist/jobs/promotion-sla-enforcer.js.map +1 -0
- package/dist/lib/agent-output-parser.js.map +1 -1
- package/dist/lib/agent-output-validator.js.map +1 -1
- package/dist/lib/agent-workspace.js +281 -0
- package/dist/lib/agent-workspace.js.map +1 -0
- package/dist/lib/atomic-file-writer.js +377 -0
- package/dist/lib/atomic-file-writer.js.map +1 -0
- package/dist/lib/backup-manager.js +779 -0
- package/dist/lib/backup-manager.js.map +1 -0
- package/dist/lib/checkpoint-manager.js +837 -0
- package/dist/lib/checkpoint-manager.js.map +1 -0
- package/dist/lib/circuit-breaker.js +340 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/completion-signal-handler.js +243 -0
- package/dist/lib/completion-signal-handler.js.map +1 -0
- package/dist/lib/config-manager.js +312 -0
- package/dist/lib/config-manager.js.map +1 -0
- package/dist/lib/config-migrator.js +386 -0
- package/dist/lib/config-migrator.js.map +1 -0
- package/dist/lib/config-validator.js.map +1 -1
- package/dist/lib/correlation-cache.js +311 -0
- package/dist/lib/correlation-cache.js.map +1 -0
- package/dist/lib/correlation.js +263 -0
- package/dist/lib/correlation.js.map +1 -0
- package/dist/lib/database-service/connection-pool-manager.js +520 -0
- package/dist/lib/database-service/connection-pool-manager.js.map +1 -0
- package/dist/lib/database-service/correlation.js +329 -0
- package/dist/lib/database-service/correlation.js.map +1 -0
- package/dist/lib/database-service/errors.js +120 -0
- package/dist/lib/database-service/errors.js.map +1 -0
- package/dist/lib/database-service/index.js +168 -0
- package/dist/lib/database-service/index.js.map +1 -0
- package/dist/lib/database-service/postgres-adapter.js +526 -0
- package/dist/lib/database-service/postgres-adapter.js.map +1 -0
- package/dist/lib/database-service/redis-adapter.js +360 -0
- package/dist/lib/database-service/redis-adapter.js.map +1 -0
- package/dist/lib/database-service/sqlite-adapter.js +544 -0
- package/dist/lib/database-service/sqlite-adapter.js.map +1 -0
- package/dist/lib/database-service/transaction-manager.js +773 -0
- package/dist/lib/database-service/transaction-manager.js.map +1 -0
- package/dist/lib/database-service/types.js +23 -0
- package/dist/lib/database-service/types.js.map +1 -0
- package/dist/lib/deadlock-resolver.js +292 -0
- package/dist/lib/deadlock-resolver.js.map +1 -0
- package/dist/lib/distributed-lock.js +451 -0
- package/dist/lib/distributed-lock.js.map +1 -0
- package/dist/lib/edge-case-deduplicator.js +227 -0
- package/dist/lib/edge-case-deduplicator.js.map +1 -0
- package/dist/lib/encryption-manager.js +322 -0
- package/dist/lib/encryption-manager.js.map +1 -0
- package/dist/lib/error-aggregator.js +234 -0
- package/dist/lib/error-aggregator.js.map +1 -0
- package/dist/lib/errors.js +287 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-lock-manager.js +578 -0
- package/dist/lib/file-lock-manager.js.map +1 -0
- package/dist/lib/file-operations.js +367 -0
- package/dist/lib/file-operations.js.map +1 -0
- package/dist/lib/idempotent-write.js +237 -0
- package/dist/lib/idempotent-write.js.map +1 -0
- package/dist/lib/integration-schema-validator.js +522 -0
- package/dist/lib/integration-schema-validator.js.map +1 -0
- package/dist/lib/lock-health-monitor.js +298 -0
- package/dist/lib/lock-health-monitor.js.map +1 -0
- package/dist/lib/log-shipper.js +422 -0
- package/dist/lib/log-shipper.js.map +1 -0
- package/dist/lib/logging.js +146 -0
- package/dist/lib/logging.js.map +1 -0
- package/dist/lib/message-deduplicator.js +439 -0
- package/dist/lib/message-deduplicator.js.map +1 -0
- package/dist/lib/multi-system-query.js +604 -0
- package/dist/lib/multi-system-query.js.map +1 -0
- package/dist/lib/orphan-detector.js +332 -0
- package/dist/lib/orphan-detector.js.map +1 -0
- package/dist/lib/password-generator.js +166 -0
- package/dist/lib/password-generator.js.map +1 -0
- package/dist/lib/path-validator.js +429 -0
- package/dist/lib/path-validator.js.map +1 -0
- package/dist/lib/query-translator.js +905 -0
- package/dist/lib/query-translator.js.map +1 -0
- package/dist/lib/queue-recovery.js +469 -0
- package/dist/lib/queue-recovery.js.map +1 -0
- package/dist/lib/redis-queue-manager.js +512 -0
- package/dist/lib/redis-queue-manager.js.map +1 -0
- package/dist/lib/reflection-archiver.js +272 -0
- package/dist/lib/reflection-archiver.js.map +1 -0
- package/dist/lib/retry-manager.js +453 -0
- package/dist/lib/retry-manager.js.map +1 -0
- package/dist/lib/retry.js +262 -0
- package/dist/lib/retry.js.map +1 -0
- package/dist/lib/schema-transform.js +695 -0
- package/dist/lib/schema-transform.js.map +1 -0
- package/dist/lib/schema-validator.js +491 -0
- package/dist/lib/schema-validator.js.map +1 -0
- package/dist/lib/skill-cache.js +297 -0
- package/dist/lib/skill-cache.js.map +1 -0
- package/dist/lib/skill-content-manager.js +337 -0
- package/dist/lib/skill-content-manager.js.map +1 -0
- package/dist/lib/skill-frontmatter-parser.js +237 -0
- package/dist/lib/skill-frontmatter-parser.js.map +1 -0
- package/dist/lib/skill-git-integration.js +275 -0
- package/dist/lib/skill-git-integration.js.map +1 -0
- package/dist/lib/skill-markdown-validator.js +396 -0
- package/dist/lib/skill-markdown-validator.js.map +1 -0
- package/dist/lib/skill-output-parser.js +312 -0
- package/dist/lib/skill-output-parser.js.map +1 -0
- package/dist/lib/unified-query-api.js +467 -0
- package/dist/lib/unified-query-api.js.map +1 -0
- package/dist/middleware/auth-middleware.js +350 -0
- package/dist/middleware/auth-middleware.js.map +1 -0
- package/dist/middleware/schema-validation.js +347 -0
- package/dist/middleware/schema-validation.js.map +1 -0
- package/dist/providers/anthropic-provider.js +1 -1
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/provider-factory.js +2 -2
- package/dist/providers/provider-factory.js.map +1 -1
- package/dist/services/edge-case-analyzer.js +321 -0
- package/dist/services/edge-case-analyzer.js.map +1 -0
- package/dist/services/edge-case-deduplicator.js +266 -0
- package/dist/services/edge-case-deduplicator.js.map +1 -0
- package/dist/services/edge-case-detector.js +337 -0
- package/dist/services/edge-case-detector.js.map +1 -0
- package/dist/services/edge-case-tracker.js +547 -0
- package/dist/services/edge-case-tracker.js.map +1 -0
- package/dist/services/health-check-system.js +586 -0
- package/dist/services/health-check-system.js.map +1 -0
- package/dist/services/metrics-logger.js +412 -0
- package/dist/services/metrics-logger.js.map +1 -0
- package/dist/services/patch-generator.js +378 -0
- package/dist/services/patch-generator.js.map +1 -0
- package/dist/services/patch-validator.js +337 -0
- package/dist/services/patch-validator.js.map +1 -0
- package/dist/services/performance-monitor.js +811 -0
- package/dist/services/performance-monitor.js.map +1 -0
- package/dist/services/promotion-pipeline.js +918 -0
- package/dist/services/promotion-pipeline.js.map +1 -0
- package/dist/services/promotion-validator.js +394 -0
- package/dist/services/promotion-validator.js.map +1 -0
- package/dist/services/reflection-logger.js +388 -0
- package/dist/services/reflection-logger.js.map +1 -0
- package/dist/services/skill-deployment.js +472 -0
- package/dist/services/skill-deployment.js.map +1 -0
- package/dist/services/skill-loader.js +427 -0
- package/dist/services/skill-loader.js.map +1 -0
- package/dist/services/skill-promotion.js +372 -0
- package/dist/services/skill-promotion.js.map +1 -0
- package/dist/services/skill-validator.js +454 -0
- package/dist/services/skill-validator.js.map +1 -0
- package/dist/services/skill-versioning.js +244 -0
- package/dist/services/skill-versioning.js.map +1 -0
- package/dist/services/workspace-supervisor.js +597 -0
- package/dist/services/workspace-supervisor.js.map +1 -0
- package/dist/types/edge-case.js +45 -0
- package/dist/types/edge-case.js.map +1 -0
- package/package.json +201 -177
- package/readme/README.md +19 -4
- package/scripts/backup-cleanup.sh +627 -0
- package/scripts/cleanup-workspaces.sh +412 -0
- package/scripts/cleanup-yaml-configs.sh +141 -0
- package/scripts/deploy-approved-skills.sh +263 -0
- package/scripts/health-check.sh +447 -0
- package/scripts/log-aggregator.sh +554 -0
- package/scripts/log-monitor.sh +629 -0
- package/scripts/manage-agent-workspaces.sh +434 -0
- package/scripts/migrate-schema.sh +533 -0
- package/scripts/promote-staged-skills.sh +423 -0
- package/scripts/verify-no-secrets.sh +88 -35
- package/.claude/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/.claude/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/.claude/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/.claude/skills/agent-lifecycle/SKILL.md +0 -60
- package/.claude/skills/agent-lifecycle/execute-lifecycle-hook.sh +0 -573
- package/.claude/skills/agent-lifecycle/simple-audit.sh +0 -31
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
- package/README.md.backup_before_replace +0 -781
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Database Transaction Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages atomic transactions across Redis, SQLite, and PostgreSQL with:
|
|
5
|
+
* - Savepoint support for nested transactions
|
|
6
|
+
* - Distributed locking integration
|
|
7
|
+
* - Transaction timeout handling
|
|
8
|
+
* - Isolation level support
|
|
9
|
+
*
|
|
10
|
+
* Part of Task 3.1: Cross-Database Transaction Framework
|
|
11
|
+
*/ import { randomUUID } from 'crypto';
|
|
12
|
+
import { DatabaseErrorCode, createDatabaseError } from './errors.js';
|
|
13
|
+
import { createLogger } from '../logging.js';
|
|
14
|
+
import { generateCorrelationId } from '../correlation.js';
|
|
15
|
+
const logger = createLogger('transaction-manager');
|
|
16
|
+
/**
|
|
17
|
+
* Transaction isolation levels
|
|
18
|
+
*/ export var IsolationLevel = /*#__PURE__*/ function(IsolationLevel) {
|
|
19
|
+
IsolationLevel["READ_UNCOMMITTED"] = "READ UNCOMMITTED";
|
|
20
|
+
IsolationLevel["READ_COMMITTED"] = "READ COMMITTED";
|
|
21
|
+
IsolationLevel["REPEATABLE_READ"] = "REPEATABLE READ";
|
|
22
|
+
IsolationLevel["SERIALIZABLE"] = "SERIALIZABLE";
|
|
23
|
+
return IsolationLevel;
|
|
24
|
+
}({});
|
|
25
|
+
/**
|
|
26
|
+
* Transaction state for two-phase commit
|
|
27
|
+
*/ export var TransactionState = /*#__PURE__*/ function(TransactionState) {
|
|
28
|
+
TransactionState["ACTIVE"] = "ACTIVE";
|
|
29
|
+
TransactionState["PREPARING"] = "PREPARING";
|
|
30
|
+
TransactionState["PREPARED"] = "PREPARED";
|
|
31
|
+
TransactionState["COMMITTING"] = "COMMITTING";
|
|
32
|
+
TransactionState["COMMITTED"] = "COMMITTED";
|
|
33
|
+
TransactionState["ABORTING"] = "ABORTING";
|
|
34
|
+
TransactionState["ABORTED"] = "ABORTED";
|
|
35
|
+
TransactionState["ROLLED_BACK"] = "ROLLED_BACK";
|
|
36
|
+
return TransactionState;
|
|
37
|
+
}({});
|
|
38
|
+
/**
|
|
39
|
+
* Transaction class providing fluent API for cross-database transactions
|
|
40
|
+
*/ export class Transaction {
|
|
41
|
+
id;
|
|
42
|
+
startedAt;
|
|
43
|
+
databases;
|
|
44
|
+
correlationId;
|
|
45
|
+
options;
|
|
46
|
+
contexts = new Map();
|
|
47
|
+
adapters = new Map();
|
|
48
|
+
savepoints = new Map();
|
|
49
|
+
state = "ACTIVE";
|
|
50
|
+
isCommitted = false;
|
|
51
|
+
isRolledBack = false;
|
|
52
|
+
timeoutHandle;
|
|
53
|
+
prepareTimeoutHandle;
|
|
54
|
+
lockReleaser;
|
|
55
|
+
preparedDatabases = new Set();
|
|
56
|
+
twoPhaseCommitLog = [];
|
|
57
|
+
constructor(id, databases, adapters, options = {}){
|
|
58
|
+
this.id = id;
|
|
59
|
+
this.startedAt = new Date();
|
|
60
|
+
this.databases = databases;
|
|
61
|
+
this.adapters = adapters;
|
|
62
|
+
this.correlationId = options.correlationId || generateCorrelationId();
|
|
63
|
+
this.options = {
|
|
64
|
+
timeout: options.timeout ?? 30000,
|
|
65
|
+
isolationLevel: options.isolationLevel ?? "READ COMMITTED",
|
|
66
|
+
acquireLock: options.acquireLock ?? false,
|
|
67
|
+
lockTimeout: options.lockTimeout ?? 10000,
|
|
68
|
+
prepareTimeout: options.prepareTimeout ?? 5000,
|
|
69
|
+
useTwoPhaseCommit: options.useTwoPhaseCommit ?? databases.length > 1
|
|
70
|
+
};
|
|
71
|
+
logger.info('Transaction created', {
|
|
72
|
+
transactionId: this.id,
|
|
73
|
+
databases: this.databases,
|
|
74
|
+
correlationId: this.correlationId,
|
|
75
|
+
options: this.options,
|
|
76
|
+
useTwoPhaseCommit: this.options.useTwoPhaseCommit
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Start the transaction on all databases
|
|
81
|
+
*/ async begin() {
|
|
82
|
+
if (this.isCommitted || this.isRolledBack) {
|
|
83
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Cannot begin transaction that has already completed', undefined, {
|
|
84
|
+
transactionId: this.id,
|
|
85
|
+
status: this.isCommitted ? 'committed' : 'rolled_back'
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
// Set transaction timeout
|
|
90
|
+
this.timeoutHandle = setTimeout(()=>{
|
|
91
|
+
this.handleTimeout();
|
|
92
|
+
}, this.options.timeout);
|
|
93
|
+
// Begin transaction on each database
|
|
94
|
+
for (const dbType of this.databases){
|
|
95
|
+
const adapter = this.adapters.get(dbType);
|
|
96
|
+
if (!adapter) {
|
|
97
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, `Database adapter not found: ${dbType}`, undefined, {
|
|
98
|
+
database: dbType
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const context = await adapter.beginTransaction();
|
|
102
|
+
this.contexts.set(dbType, context);
|
|
103
|
+
logger.debug('Transaction started on database', {
|
|
104
|
+
transactionId: this.id,
|
|
105
|
+
database: dbType,
|
|
106
|
+
contextId: context.id
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
logger.info('Transaction began successfully', {
|
|
110
|
+
transactionId: this.id,
|
|
111
|
+
databases: this.databases
|
|
112
|
+
});
|
|
113
|
+
} catch (err) {
|
|
114
|
+
// Rollback any successful transaction starts
|
|
115
|
+
await this.rollback();
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Execute an operation on a specific database within this transaction
|
|
121
|
+
*/ async execute(database, operation) {
|
|
122
|
+
if (this.isCommitted) {
|
|
123
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Cannot execute operation on committed transaction', undefined, {
|
|
124
|
+
transactionId: this.id
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (this.isRolledBack) {
|
|
128
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Cannot execute operation on rolled back transaction', undefined, {
|
|
129
|
+
transactionId: this.id
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const adapter = this.adapters.get(database);
|
|
133
|
+
if (!adapter) {
|
|
134
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, `Database not part of this transaction: ${database}`, undefined, {
|
|
135
|
+
database,
|
|
136
|
+
transactionDatabases: this.databases
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
logger.debug('Executing operation', {
|
|
141
|
+
transactionId: this.id,
|
|
142
|
+
database
|
|
143
|
+
});
|
|
144
|
+
const result = await operation(adapter);
|
|
145
|
+
logger.debug('Operation completed', {
|
|
146
|
+
transactionId: this.id,
|
|
147
|
+
database
|
|
148
|
+
});
|
|
149
|
+
return result;
|
|
150
|
+
} catch (err) {
|
|
151
|
+
logger.error('Operation failed', err, {
|
|
152
|
+
transactionId: this.id,
|
|
153
|
+
database
|
|
154
|
+
});
|
|
155
|
+
// Auto-rollback on error
|
|
156
|
+
await this.rollback();
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Create a savepoint for nested transaction control
|
|
162
|
+
*/ async savepoint(name) {
|
|
163
|
+
if (!name || !/^[a-zA-Z0-9_]+$/.test(name)) {
|
|
164
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, 'Savepoint name must be alphanumeric with underscores', undefined, {
|
|
165
|
+
name
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (this.savepoints.has(name)) {
|
|
169
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, `Savepoint already exists: ${name}`, undefined, {
|
|
170
|
+
name
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Create savepoint on all databases
|
|
174
|
+
for (const dbType of this.databases){
|
|
175
|
+
const adapter = this.adapters.get(dbType);
|
|
176
|
+
if (!adapter) continue;
|
|
177
|
+
try {
|
|
178
|
+
// Execute savepoint SQL (PostgreSQL and SQLite support this)
|
|
179
|
+
if (dbType === 'postgres' || dbType === 'sqlite') {
|
|
180
|
+
await adapter.raw(`SAVEPOINT ${name}`);
|
|
181
|
+
}
|
|
182
|
+
// Redis doesn't support savepoints, skip
|
|
183
|
+
} catch (err) {
|
|
184
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, `Failed to create savepoint: ${name}`, err, {
|
|
185
|
+
database: dbType,
|
|
186
|
+
savepoint: name
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
this.savepoints.set(name, {
|
|
191
|
+
name,
|
|
192
|
+
createdAt: new Date(),
|
|
193
|
+
database: this.databases.join(',')
|
|
194
|
+
});
|
|
195
|
+
logger.info('Savepoint created', {
|
|
196
|
+
transactionId: this.id,
|
|
197
|
+
savepoint: name
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Rollback to a specific savepoint
|
|
202
|
+
*/ async rollbackToSavepoint(name) {
|
|
203
|
+
if (!this.savepoints.has(name)) {
|
|
204
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, `Savepoint not found: ${name}`, undefined, {
|
|
205
|
+
name,
|
|
206
|
+
availableSavepoints: Array.from(this.savepoints.keys())
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// Rollback to savepoint on all databases
|
|
210
|
+
for (const dbType of this.databases){
|
|
211
|
+
const adapter = this.adapters.get(dbType);
|
|
212
|
+
if (!adapter) continue;
|
|
213
|
+
try {
|
|
214
|
+
if (dbType === 'postgres' || dbType === 'sqlite') {
|
|
215
|
+
await adapter.raw(`ROLLBACK TO SAVEPOINT ${name}`);
|
|
216
|
+
}
|
|
217
|
+
} catch (err) {
|
|
218
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, `Failed to rollback to savepoint: ${name}`, err, {
|
|
219
|
+
database: dbType,
|
|
220
|
+
savepoint: name
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Remove this savepoint and all later ones
|
|
225
|
+
const savepoints = Array.from(this.savepoints.entries());
|
|
226
|
+
const targetIndex = savepoints.findIndex(([n])=>n === name);
|
|
227
|
+
for(let i = targetIndex; i < savepoints.length; i++){
|
|
228
|
+
this.savepoints.delete(savepoints[i][0]);
|
|
229
|
+
}
|
|
230
|
+
logger.info('Rolled back to savepoint', {
|
|
231
|
+
transactionId: this.id,
|
|
232
|
+
savepoint: name
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Release a savepoint (no longer needed)
|
|
237
|
+
*/ async releaseSavepoint(name) {
|
|
238
|
+
if (!this.savepoints.has(name)) {
|
|
239
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, `Savepoint not found: ${name}`, undefined, {
|
|
240
|
+
name
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
// Release savepoint on all databases
|
|
244
|
+
for (const dbType of this.databases){
|
|
245
|
+
const adapter = this.adapters.get(dbType);
|
|
246
|
+
if (!adapter) continue;
|
|
247
|
+
try {
|
|
248
|
+
if (dbType === 'postgres' || dbType === 'sqlite') {
|
|
249
|
+
await adapter.raw(`RELEASE SAVEPOINT ${name}`);
|
|
250
|
+
}
|
|
251
|
+
} catch (err) {
|
|
252
|
+
logger.warn('Failed to release savepoint (non-fatal)', {
|
|
253
|
+
transactionId: this.id,
|
|
254
|
+
database: dbType,
|
|
255
|
+
savepoint: name,
|
|
256
|
+
error: err.message
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
this.savepoints.delete(name);
|
|
261
|
+
logger.debug('Savepoint released', {
|
|
262
|
+
transactionId: this.id,
|
|
263
|
+
savepoint: name
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Log 2PC state transition
|
|
268
|
+
* @private
|
|
269
|
+
*/ log2PCState(state, preparedDatabases = [], failedDatabases = [], error) {
|
|
270
|
+
const logEntry = {
|
|
271
|
+
transactionId: this.id,
|
|
272
|
+
state,
|
|
273
|
+
timestamp: new Date(),
|
|
274
|
+
databases: this.databases,
|
|
275
|
+
preparedDatabases,
|
|
276
|
+
failedDatabases,
|
|
277
|
+
error
|
|
278
|
+
};
|
|
279
|
+
this.twoPhaseCommitLog.push(logEntry);
|
|
280
|
+
logger.info('2PC state transition', {
|
|
281
|
+
transactionId: this.id,
|
|
282
|
+
from: this.state,
|
|
283
|
+
to: state,
|
|
284
|
+
preparedDatabases,
|
|
285
|
+
failedDatabases,
|
|
286
|
+
error
|
|
287
|
+
});
|
|
288
|
+
this.state = state;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get 2PC transaction log
|
|
292
|
+
*/ get2PCLog() {
|
|
293
|
+
return [
|
|
294
|
+
...this.twoPhaseCommitLog
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Get current transaction state
|
|
299
|
+
*/ getTransactionState() {
|
|
300
|
+
return this.state;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Phase 1: PREPARE - Validate all databases can commit
|
|
304
|
+
* @private
|
|
305
|
+
*/ async preparePhase() {
|
|
306
|
+
this.log2PCState("PREPARING");
|
|
307
|
+
const preparedDbs = [];
|
|
308
|
+
const failedDbs = [];
|
|
309
|
+
let prepareError;
|
|
310
|
+
// Set prepare timeout
|
|
311
|
+
const preparePromise = new Promise(async (resolve, reject)=>{
|
|
312
|
+
this.prepareTimeoutHandle = setTimeout(()=>{
|
|
313
|
+
reject(createDatabaseError(DatabaseErrorCode.TIMEOUT, `Prepare phase timeout after ${this.options.prepareTimeout}ms`, undefined, {
|
|
314
|
+
transactionId: this.id,
|
|
315
|
+
timeout: this.options.prepareTimeout
|
|
316
|
+
}));
|
|
317
|
+
}, this.options.prepareTimeout);
|
|
318
|
+
try {
|
|
319
|
+
// Attempt to prepare all databases
|
|
320
|
+
for (const [dbType, context] of Array.from(this.contexts.entries())){
|
|
321
|
+
const adapter = this.adapters.get(dbType);
|
|
322
|
+
if (!adapter) {
|
|
323
|
+
failedDbs.push(dbType);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const prepared = await adapter.prepareTransaction(context);
|
|
328
|
+
if (prepared) {
|
|
329
|
+
preparedDbs.push(dbType);
|
|
330
|
+
this.preparedDatabases.add(dbType);
|
|
331
|
+
logger.debug('Database prepared successfully', {
|
|
332
|
+
transactionId: this.id,
|
|
333
|
+
database: dbType
|
|
334
|
+
});
|
|
335
|
+
} else {
|
|
336
|
+
failedDbs.push(dbType);
|
|
337
|
+
logger.warn('Database failed to prepare', {
|
|
338
|
+
transactionId: this.id,
|
|
339
|
+
database: dbType
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
} catch (err) {
|
|
343
|
+
failedDbs.push(dbType);
|
|
344
|
+
prepareError = err.message;
|
|
345
|
+
logger.error('Database prepare error', err, {
|
|
346
|
+
transactionId: this.id,
|
|
347
|
+
database: dbType
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Clear prepare timeout
|
|
352
|
+
if (this.prepareTimeoutHandle) {
|
|
353
|
+
clearTimeout(this.prepareTimeoutHandle);
|
|
354
|
+
}
|
|
355
|
+
const allPrepared = failedDbs.length === 0;
|
|
356
|
+
if (allPrepared) {
|
|
357
|
+
this.log2PCState("PREPARED", preparedDbs);
|
|
358
|
+
resolve(true);
|
|
359
|
+
} else {
|
|
360
|
+
this.log2PCState("ABORTING", preparedDbs, failedDbs, prepareError || 'One or more databases failed to prepare');
|
|
361
|
+
resolve(false);
|
|
362
|
+
}
|
|
363
|
+
} catch (err) {
|
|
364
|
+
reject(err);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
try {
|
|
368
|
+
return await preparePromise;
|
|
369
|
+
} catch (err) {
|
|
370
|
+
// Timeout or other error
|
|
371
|
+
this.log2PCState("ABORTING", preparedDbs, failedDbs, err.message);
|
|
372
|
+
throw err;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Phase 2: COMMIT - Commit all prepared databases
|
|
377
|
+
* @private
|
|
378
|
+
*/ async commitPhase() {
|
|
379
|
+
this.log2PCState("COMMITTING", Array.from(this.preparedDatabases));
|
|
380
|
+
const errors = [];
|
|
381
|
+
const failedDbs = [];
|
|
382
|
+
// Commit all prepared databases
|
|
383
|
+
for (const [dbType, context] of Array.from(this.contexts.entries())){
|
|
384
|
+
const adapter = this.adapters.get(dbType);
|
|
385
|
+
if (!adapter) continue;
|
|
386
|
+
try {
|
|
387
|
+
await adapter.commitTransaction(context);
|
|
388
|
+
logger.debug('Transaction committed on database', {
|
|
389
|
+
transactionId: this.id,
|
|
390
|
+
database: dbType
|
|
391
|
+
});
|
|
392
|
+
} catch (err) {
|
|
393
|
+
errors.push(err);
|
|
394
|
+
failedDbs.push(dbType);
|
|
395
|
+
logger.error('Failed to commit on database', err, {
|
|
396
|
+
transactionId: this.id,
|
|
397
|
+
database: dbType
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// If any commits failed after PREPARE succeeded, this is critical
|
|
402
|
+
if (errors.length > 0) {
|
|
403
|
+
this.log2PCState("COMMITTED", Array.from(this.preparedDatabases).filter((db)=>!failedDbs.includes(db)), failedDbs, `Partial commit: ${errors.length} databases failed`);
|
|
404
|
+
logger.error('CRITICAL: Partial commit occurred after PREPARE', new Error('Partial commit'), {
|
|
405
|
+
transactionId: this.id,
|
|
406
|
+
failedDatabases: failedDbs,
|
|
407
|
+
totalDatabases: this.contexts.size,
|
|
408
|
+
preparedDatabases: Array.from(this.preparedDatabases)
|
|
409
|
+
});
|
|
410
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Transaction partially committed - data may be inconsistent', undefined, {
|
|
411
|
+
transactionId: this.id,
|
|
412
|
+
preparedDatabases: Array.from(this.preparedDatabases),
|
|
413
|
+
failedDatabases: failedDbs,
|
|
414
|
+
errors: errors.map((e)=>e.message)
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
this.log2PCState("COMMITTED", Array.from(this.preparedDatabases));
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Abort transaction (rollback all prepared databases)
|
|
421
|
+
* @private
|
|
422
|
+
*/ async abortPhase() {
|
|
423
|
+
this.log2PCState("ABORTING", Array.from(this.preparedDatabases));
|
|
424
|
+
// Rollback all databases (both prepared and not prepared)
|
|
425
|
+
for (const [dbType, context] of Array.from(this.contexts.entries())){
|
|
426
|
+
const adapter = this.adapters.get(dbType);
|
|
427
|
+
if (!adapter) continue;
|
|
428
|
+
try {
|
|
429
|
+
await adapter.rollbackTransaction(context);
|
|
430
|
+
logger.debug('Transaction rolled back on database', {
|
|
431
|
+
transactionId: this.id,
|
|
432
|
+
database: dbType
|
|
433
|
+
});
|
|
434
|
+
} catch (err) {
|
|
435
|
+
logger.error('Failed to rollback on database (non-fatal)', err, {
|
|
436
|
+
transactionId: this.id,
|
|
437
|
+
database: dbType
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
this.log2PCState("ABORTED", [], Array.from(this.preparedDatabases));
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Commit the transaction using two-phase commit protocol
|
|
445
|
+
*/ async commit() {
|
|
446
|
+
if (this.isCommitted) {
|
|
447
|
+
logger.warn('Transaction already committed', {
|
|
448
|
+
transactionId: this.id
|
|
449
|
+
});
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (this.isRolledBack) {
|
|
453
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Cannot commit rolled back transaction', undefined, {
|
|
454
|
+
transactionId: this.id
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
// Clear timeout
|
|
458
|
+
if (this.timeoutHandle) {
|
|
459
|
+
clearTimeout(this.timeoutHandle);
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
// Use two-phase commit for multi-database transactions
|
|
463
|
+
if (this.options.useTwoPhaseCommit && this.databases.length > 1) {
|
|
464
|
+
logger.info('Starting two-phase commit', {
|
|
465
|
+
transactionId: this.id,
|
|
466
|
+
databases: this.databases
|
|
467
|
+
});
|
|
468
|
+
// Phase 1: PREPARE
|
|
469
|
+
const prepared = await this.preparePhase();
|
|
470
|
+
if (!prepared) {
|
|
471
|
+
// At least one database failed to prepare, abort all
|
|
472
|
+
logger.warn('Prepare phase failed, aborting transaction', {
|
|
473
|
+
transactionId: this.id,
|
|
474
|
+
preparedDatabases: Array.from(this.preparedDatabases)
|
|
475
|
+
});
|
|
476
|
+
await this.abortPhase();
|
|
477
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Transaction prepare phase failed - all databases rolled back', undefined, {
|
|
478
|
+
transactionId: this.id,
|
|
479
|
+
preparedDatabases: Array.from(this.preparedDatabases),
|
|
480
|
+
log: this.get2PCLog()
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
// Phase 2: COMMIT
|
|
484
|
+
await this.commitPhase();
|
|
485
|
+
this.isCommitted = true;
|
|
486
|
+
logger.info('Two-phase commit completed successfully', {
|
|
487
|
+
transactionId: this.id,
|
|
488
|
+
duration: Date.now() - this.startedAt.getTime(),
|
|
489
|
+
databases: this.databases,
|
|
490
|
+
log: this.get2PCLog()
|
|
491
|
+
});
|
|
492
|
+
} else {
|
|
493
|
+
// Single database or 2PC disabled - use legacy commit
|
|
494
|
+
logger.info('Using legacy commit (single database or 2PC disabled)', {
|
|
495
|
+
transactionId: this.id,
|
|
496
|
+
databases: this.databases,
|
|
497
|
+
use2PC: this.options.useTwoPhaseCommit
|
|
498
|
+
});
|
|
499
|
+
const errors = [];
|
|
500
|
+
// Commit all database transactions
|
|
501
|
+
for (const [dbType, context] of Array.from(this.contexts.entries())){
|
|
502
|
+
const adapter = this.adapters.get(dbType);
|
|
503
|
+
if (!adapter) continue;
|
|
504
|
+
try {
|
|
505
|
+
await adapter.commitTransaction(context);
|
|
506
|
+
logger.debug('Transaction committed on database', {
|
|
507
|
+
transactionId: this.id,
|
|
508
|
+
database: dbType
|
|
509
|
+
});
|
|
510
|
+
} catch (err) {
|
|
511
|
+
errors.push(err);
|
|
512
|
+
logger.error('Failed to commit on database', err, {
|
|
513
|
+
transactionId: this.id,
|
|
514
|
+
database: dbType
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// If any commits failed, this is a partial commit - log critical error
|
|
519
|
+
if (errors.length > 0) {
|
|
520
|
+
logger.error('CRITICAL: Partial commit occurred', new Error('Partial commit'), {
|
|
521
|
+
transactionId: this.id,
|
|
522
|
+
failedDatabases: errors.length,
|
|
523
|
+
totalDatabases: this.contexts.size
|
|
524
|
+
});
|
|
525
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Transaction partially committed - data may be inconsistent', undefined, {
|
|
526
|
+
transactionId: this.id,
|
|
527
|
+
errors: errors.map((e)=>e.message)
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
this.isCommitted = true;
|
|
531
|
+
logger.info('Transaction committed successfully', {
|
|
532
|
+
transactionId: this.id,
|
|
533
|
+
duration: Date.now() - this.startedAt.getTime()
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
// Release distributed lock if acquired
|
|
537
|
+
await this.releaseLock();
|
|
538
|
+
} catch (err) {
|
|
539
|
+
// On any error, attempt to rollback
|
|
540
|
+
try {
|
|
541
|
+
if (this.state === "PREPARED" || this.state === "PREPARING") {
|
|
542
|
+
await this.abortPhase();
|
|
543
|
+
}
|
|
544
|
+
} catch (rollbackErr) {
|
|
545
|
+
logger.error('Failed to rollback after commit error', rollbackErr, {
|
|
546
|
+
transactionId: this.id
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
throw err;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Rollback the transaction
|
|
554
|
+
*/ async rollback() {
|
|
555
|
+
if (this.isRolledBack) {
|
|
556
|
+
logger.debug('Transaction already rolled back', {
|
|
557
|
+
transactionId: this.id
|
|
558
|
+
});
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (this.isCommitted) {
|
|
562
|
+
throw createDatabaseError(DatabaseErrorCode.TRANSACTION_FAILED, 'Cannot rollback committed transaction', undefined, {
|
|
563
|
+
transactionId: this.id
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
// Clear timeouts
|
|
567
|
+
if (this.timeoutHandle) {
|
|
568
|
+
clearTimeout(this.timeoutHandle);
|
|
569
|
+
}
|
|
570
|
+
if (this.prepareTimeoutHandle) {
|
|
571
|
+
clearTimeout(this.prepareTimeoutHandle);
|
|
572
|
+
}
|
|
573
|
+
// Update state
|
|
574
|
+
this.state = "ROLLED_BACK";
|
|
575
|
+
// Rollback all database transactions
|
|
576
|
+
for (const [dbType, context] of Array.from(this.contexts.entries())){
|
|
577
|
+
const adapter = this.adapters.get(dbType);
|
|
578
|
+
if (!adapter) continue;
|
|
579
|
+
try {
|
|
580
|
+
await adapter.rollbackTransaction(context);
|
|
581
|
+
logger.debug('Transaction rolled back on database', {
|
|
582
|
+
transactionId: this.id,
|
|
583
|
+
database: dbType
|
|
584
|
+
});
|
|
585
|
+
} catch (err) {
|
|
586
|
+
logger.error('Failed to rollback on database (non-fatal)', err, {
|
|
587
|
+
transactionId: this.id,
|
|
588
|
+
database: dbType
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
this.isRolledBack = true;
|
|
593
|
+
logger.info('Transaction rolled back', {
|
|
594
|
+
transactionId: this.id,
|
|
595
|
+
duration: Date.now() - this.startedAt.getTime(),
|
|
596
|
+
state: this.state
|
|
597
|
+
});
|
|
598
|
+
// Release distributed lock if acquired
|
|
599
|
+
await this.releaseLock();
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Set lock releaser callback
|
|
603
|
+
* @internal Used by TransactionManager to integrate with distributed lock
|
|
604
|
+
*/ setLockReleaser(releaser) {
|
|
605
|
+
this.lockReleaser = releaser;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Release distributed lock
|
|
609
|
+
*/ async releaseLock() {
|
|
610
|
+
if (this.lockReleaser) {
|
|
611
|
+
try {
|
|
612
|
+
await this.lockReleaser();
|
|
613
|
+
logger.debug('Distributed lock released', {
|
|
614
|
+
transactionId: this.id
|
|
615
|
+
});
|
|
616
|
+
} catch (err) {
|
|
617
|
+
logger.error('Failed to release distributed lock', err, {
|
|
618
|
+
transactionId: this.id
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Handle transaction timeout
|
|
625
|
+
*/ async handleTimeout() {
|
|
626
|
+
logger.warn('Transaction timeout exceeded', {
|
|
627
|
+
transactionId: this.id,
|
|
628
|
+
timeout: this.options.timeout,
|
|
629
|
+
duration: Date.now() - this.startedAt.getTime()
|
|
630
|
+
});
|
|
631
|
+
// Auto-rollback on timeout
|
|
632
|
+
await this.rollback();
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Get transaction status
|
|
636
|
+
*/ getStatus() {
|
|
637
|
+
if (this.isCommitted) return 'committed';
|
|
638
|
+
if (this.isRolledBack) return 'rolled_back';
|
|
639
|
+
return 'active';
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Get transaction duration in milliseconds
|
|
643
|
+
*/ getDuration() {
|
|
644
|
+
return Date.now() - this.startedAt.getTime();
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Transaction Manager - manages transaction lifecycle and coordination
|
|
649
|
+
*/ export class TransactionManager {
|
|
650
|
+
activeTransactions = new Map();
|
|
651
|
+
adapters = new Map();
|
|
652
|
+
constructor(adapters){
|
|
653
|
+
if (adapters) {
|
|
654
|
+
this.adapters = adapters;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Register a database adapter
|
|
659
|
+
*/ registerAdapter(type, adapter) {
|
|
660
|
+
this.adapters.set(type, adapter);
|
|
661
|
+
logger.debug('Database adapter registered', {
|
|
662
|
+
type
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Begin a new cross-database transaction
|
|
667
|
+
*/ async begin(databases, options) {
|
|
668
|
+
if (!databases || databases.length === 0) {
|
|
669
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, 'At least one database must be specified', undefined, {
|
|
670
|
+
databases
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
// Validate all databases have adapters
|
|
674
|
+
for (const dbType of databases){
|
|
675
|
+
if (!this.adapters.has(dbType)) {
|
|
676
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, `No adapter registered for database: ${dbType}`, undefined, {
|
|
677
|
+
database: dbType,
|
|
678
|
+
registered: Array.from(this.adapters.keys())
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
const txId = randomUUID();
|
|
683
|
+
const transaction = new Transaction(txId, databases, this.adapters, options);
|
|
684
|
+
// Begin the transaction
|
|
685
|
+
await transaction.begin();
|
|
686
|
+
this.activeTransactions.set(txId, transaction);
|
|
687
|
+
return transaction;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Get active transaction by ID
|
|
691
|
+
*/ getTransaction(id) {
|
|
692
|
+
return this.activeTransactions.get(id);
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Get all active transactions
|
|
696
|
+
*/ getActiveTransactions() {
|
|
697
|
+
return Array.from(this.activeTransactions.values()).filter((tx)=>tx.getStatus() === 'active');
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Get active transaction count
|
|
701
|
+
*/ getActiveCount() {
|
|
702
|
+
return this.getActiveTransactions().length;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Cleanup completed transactions from memory
|
|
706
|
+
*/ cleanupCompleted() {
|
|
707
|
+
let cleaned = 0;
|
|
708
|
+
for (const [id, tx] of Array.from(this.activeTransactions.entries())){
|
|
709
|
+
if (tx.getStatus() !== 'active') {
|
|
710
|
+
this.activeTransactions.delete(id);
|
|
711
|
+
cleaned++;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (cleaned > 0) {
|
|
715
|
+
logger.debug('Cleaned up completed transactions', {
|
|
716
|
+
count: cleaned
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
return cleaned;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Force rollback of stale transactions (timeout cleanup)
|
|
723
|
+
*/ async cleanupStaleTransactions(maxAge = 60000) {
|
|
724
|
+
const now = Date.now();
|
|
725
|
+
const stale = [];
|
|
726
|
+
for (const tx of Array.from(this.activeTransactions.values())){
|
|
727
|
+
if (tx.getStatus() === 'active' && tx.getDuration() > maxAge) {
|
|
728
|
+
stale.push(tx);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
for (const tx of stale){
|
|
732
|
+
try {
|
|
733
|
+
await tx.rollback();
|
|
734
|
+
logger.warn('Rolled back stale transaction', {
|
|
735
|
+
transactionId: tx.id,
|
|
736
|
+
age: tx.getDuration()
|
|
737
|
+
});
|
|
738
|
+
} catch (err) {
|
|
739
|
+
logger.error('Failed to rollback stale transaction', err, {
|
|
740
|
+
transactionId: tx.id
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return stale.length;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Legacy: Execute operations across multiple databases atomically
|
|
748
|
+
* @deprecated Use begin() for new code
|
|
749
|
+
*/ async executeTransaction(adapters, operations) {
|
|
750
|
+
if (adapters.length !== operations.length) {
|
|
751
|
+
throw createDatabaseError(DatabaseErrorCode.VALIDATION_FAILED, `Adapters and operations arrays must be the same length`, undefined, {
|
|
752
|
+
adaptersLength: adapters.length,
|
|
753
|
+
operationsLength: operations.length
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
const databases = adapters.map((a)=>a.getType());
|
|
757
|
+
const tx = await this.begin(databases);
|
|
758
|
+
try {
|
|
759
|
+
const results = [];
|
|
760
|
+
for(let i = 0; i < operations.length; i++){
|
|
761
|
+
const result = await tx.execute(databases[i], operations[i]);
|
|
762
|
+
results.push(result);
|
|
763
|
+
}
|
|
764
|
+
await tx.commit();
|
|
765
|
+
return results;
|
|
766
|
+
} catch (err) {
|
|
767
|
+
await tx.rollback();
|
|
768
|
+
throw err;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
//# sourceMappingURL=transaction-manager.js.map
|