javi-forge 0.1.0
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/.gitignore.template +105 -0
- package/.releaserc +44 -0
- package/README.md +45 -0
- package/ai-config/.skillignore +15 -0
- package/ai-config/AUTO_INVOKE.md +300 -0
- package/ai-config/agents/_TEMPLATE.md +93 -0
- package/ai-config/agents/business/api-designer.md +1657 -0
- package/ai-config/agents/business/business-analyst.md +1331 -0
- package/ai-config/agents/business/product-strategist.md +206 -0
- package/ai-config/agents/business/project-manager.md +178 -0
- package/ai-config/agents/business/requirements-analyst.md +1277 -0
- package/ai-config/agents/business/technical-writer.md +1679 -0
- package/ai-config/agents/creative/ux-designer.md +205 -0
- package/ai-config/agents/data-ai/ai-engineer.md +487 -0
- package/ai-config/agents/data-ai/analytics-engineer.md +953 -0
- package/ai-config/agents/data-ai/data-engineer.md +173 -0
- package/ai-config/agents/data-ai/data-scientist.md +672 -0
- package/ai-config/agents/data-ai/mlops-engineer.md +814 -0
- package/ai-config/agents/data-ai/prompt-engineer.md +772 -0
- package/ai-config/agents/development/angular-expert.md +620 -0
- package/ai-config/agents/development/backend-architect.md +795 -0
- package/ai-config/agents/development/database-specialist.md +212 -0
- package/ai-config/agents/development/frontend-specialist.md +686 -0
- package/ai-config/agents/development/fullstack-engineer.md +668 -0
- package/ai-config/agents/development/golang-pro.md +338 -0
- package/ai-config/agents/development/java-enterprise.md +400 -0
- package/ai-config/agents/development/javascript-pro.md +422 -0
- package/ai-config/agents/development/nextjs-pro.md +474 -0
- package/ai-config/agents/development/python-pro.md +570 -0
- package/ai-config/agents/development/react-pro.md +487 -0
- package/ai-config/agents/development/rust-pro.md +246 -0
- package/ai-config/agents/development/spring-boot-4-expert.md +326 -0
- package/ai-config/agents/development/typescript-pro.md +336 -0
- package/ai-config/agents/development/vue-specialist.md +605 -0
- package/ai-config/agents/infrastructure/cloud-architect.md +472 -0
- package/ai-config/agents/infrastructure/deployment-manager.md +358 -0
- package/ai-config/agents/infrastructure/devops-engineer.md +455 -0
- package/ai-config/agents/infrastructure/incident-responder.md +519 -0
- package/ai-config/agents/infrastructure/kubernetes-expert.md +705 -0
- package/ai-config/agents/infrastructure/monitoring-specialist.md +674 -0
- package/ai-config/agents/infrastructure/performance-engineer.md +658 -0
- package/ai-config/agents/orchestrator.md +241 -0
- package/ai-config/agents/quality/accessibility-auditor.md +1204 -0
- package/ai-config/agents/quality/code-reviewer-compact.md +123 -0
- package/ai-config/agents/quality/code-reviewer.md +363 -0
- package/ai-config/agents/quality/dependency-manager.md +743 -0
- package/ai-config/agents/quality/e2e-test-specialist.md +1005 -0
- package/ai-config/agents/quality/performance-tester.md +1086 -0
- package/ai-config/agents/quality/security-auditor.md +133 -0
- package/ai-config/agents/quality/test-engineer.md +453 -0
- package/ai-config/agents/specialists/api-designer.md +87 -0
- package/ai-config/agents/specialists/backend-architect.md +73 -0
- package/ai-config/agents/specialists/code-reviewer.md +77 -0
- package/ai-config/agents/specialists/db-optimizer.md +75 -0
- package/ai-config/agents/specialists/devops-engineer.md +83 -0
- package/ai-config/agents/specialists/documentation-writer.md +78 -0
- package/ai-config/agents/specialists/frontend-developer.md +75 -0
- package/ai-config/agents/specialists/performance-analyst.md +82 -0
- package/ai-config/agents/specialists/refactor-specialist.md +74 -0
- package/ai-config/agents/specialists/security-auditor.md +74 -0
- package/ai-config/agents/specialists/test-engineer.md +81 -0
- package/ai-config/agents/specialists/ux-consultant.md +76 -0
- package/ai-config/agents/specialized/agent-generator.md +1190 -0
- package/ai-config/agents/specialized/blockchain-developer.md +149 -0
- package/ai-config/agents/specialized/code-migrator.md +892 -0
- package/ai-config/agents/specialized/context-manager.md +978 -0
- package/ai-config/agents/specialized/documentation-writer.md +1078 -0
- package/ai-config/agents/specialized/ecommerce-expert.md +1756 -0
- package/ai-config/agents/specialized/embedded-engineer.md +1714 -0
- package/ai-config/agents/specialized/error-detective.md +1034 -0
- package/ai-config/agents/specialized/fintech-specialist.md +1659 -0
- package/ai-config/agents/specialized/freelance-project-planner-v2.md +1988 -0
- package/ai-config/agents/specialized/freelance-project-planner-v3.md +2136 -0
- package/ai-config/agents/specialized/freelance-project-planner-v4.md +4503 -0
- package/ai-config/agents/specialized/freelance-project-planner.md +722 -0
- package/ai-config/agents/specialized/game-developer.md +1963 -0
- package/ai-config/agents/specialized/healthcare-dev.md +1620 -0
- package/ai-config/agents/specialized/mobile-developer.md +188 -0
- package/ai-config/agents/specialized/parallel-plan-executor.md +506 -0
- package/ai-config/agents/specialized/plan-executor.md +485 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +485 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +3493 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +778 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +918 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +1537 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +2633 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +5610 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +335 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +215 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +260 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +379 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +355 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +279 -0
- package/ai-config/agents/specialized/template-writer.md +347 -0
- package/ai-config/agents/specialized/test-runner.md +99 -0
- package/ai-config/agents/specialized/vibekanban-smart-worker.md +244 -0
- package/ai-config/agents/specialized/wave-executor.md +138 -0
- package/ai-config/agents/specialized/workflow-optimizer.md +1114 -0
- package/ai-config/commands/git/changelog.md +32 -0
- package/ai-config/commands/git/ci-local.md +70 -0
- package/ai-config/commands/git/commit.md +35 -0
- package/ai-config/commands/git/fix-issue.md +23 -0
- package/ai-config/commands/git/pr-create.md +42 -0
- package/ai-config/commands/git/pr-review.md +50 -0
- package/ai-config/commands/git/worktree.md +39 -0
- package/ai-config/commands/refactoring/cleanup.md +24 -0
- package/ai-config/commands/refactoring/dead-code.md +40 -0
- package/ai-config/commands/refactoring/extract.md +31 -0
- package/ai-config/commands/testing/e2e.md +30 -0
- package/ai-config/commands/testing/tdd.md +36 -0
- package/ai-config/commands/testing/test-coverage.md +30 -0
- package/ai-config/commands/testing/test-fix.md +24 -0
- package/ai-config/commands/workflow/generate-agents-md.md +85 -0
- package/ai-config/commands/workflow/planning.md +47 -0
- package/ai-config/commands/workflows/compound.md +89 -0
- package/ai-config/commands/workflows/plan.md +77 -0
- package/ai-config/commands/workflows/review.md +78 -0
- package/ai-config/commands/workflows/work.md +75 -0
- package/ai-config/config.yaml +18 -0
- package/ai-config/hooks/_TEMPLATE.md +96 -0
- package/ai-config/hooks/block-dangerous-commands.md +75 -0
- package/ai-config/hooks/commit-guard.md +90 -0
- package/ai-config/hooks/context-loader.md +73 -0
- package/ai-config/hooks/improve-prompt.md +91 -0
- package/ai-config/hooks/learning-log.md +72 -0
- package/ai-config/hooks/model-router.md +86 -0
- package/ai-config/hooks/secret-scanner.md +64 -0
- package/ai-config/hooks/skill-validator.md +102 -0
- package/ai-config/hooks/task-artifact.md +114 -0
- package/ai-config/hooks/validate-workflow.md +100 -0
- package/ai-config/prompts/base.md +71 -0
- package/ai-config/prompts/modes/debug.md +34 -0
- package/ai-config/prompts/modes/deploy.md +40 -0
- package/ai-config/prompts/modes/research.md +32 -0
- package/ai-config/prompts/modes/review.md +33 -0
- package/ai-config/prompts/review-policy.md +79 -0
- package/ai-config/skills/_TEMPLATE.md +157 -0
- package/ai-config/skills/backend/api-gateway/SKILL.md +254 -0
- package/ai-config/skills/backend/bff-concepts/SKILL.md +239 -0
- package/ai-config/skills/backend/bff-spring/SKILL.md +364 -0
- package/ai-config/skills/backend/chi-router/SKILL.md +396 -0
- package/ai-config/skills/backend/error-handling/SKILL.md +255 -0
- package/ai-config/skills/backend/exceptions-spring/SKILL.md +323 -0
- package/ai-config/skills/backend/fastapi/SKILL.md +302 -0
- package/ai-config/skills/backend/gateway-spring/SKILL.md +390 -0
- package/ai-config/skills/backend/go-backend/SKILL.md +457 -0
- package/ai-config/skills/backend/gradle-multimodule/SKILL.md +274 -0
- package/ai-config/skills/backend/graphql-concepts/SKILL.md +352 -0
- package/ai-config/skills/backend/graphql-spring/SKILL.md +398 -0
- package/ai-config/skills/backend/grpc-concepts/SKILL.md +283 -0
- package/ai-config/skills/backend/grpc-spring/SKILL.md +445 -0
- package/ai-config/skills/backend/jwt-auth/SKILL.md +412 -0
- package/ai-config/skills/backend/notifications-concepts/SKILL.md +259 -0
- package/ai-config/skills/backend/recommendations-concepts/SKILL.md +261 -0
- package/ai-config/skills/backend/search-concepts/SKILL.md +263 -0
- package/ai-config/skills/backend/search-spring/SKILL.md +375 -0
- package/ai-config/skills/backend/spring-boot-4/SKILL.md +172 -0
- package/ai-config/skills/backend/websockets/SKILL.md +532 -0
- package/ai-config/skills/data-ai/ai-ml/SKILL.md +423 -0
- package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +195 -0
- package/ai-config/skills/data-ai/analytics-spring/SKILL.md +340 -0
- package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +440 -0
- package/ai-config/skills/data-ai/langchain/SKILL.md +238 -0
- package/ai-config/skills/data-ai/mlflow/SKILL.md +302 -0
- package/ai-config/skills/data-ai/onnx-inference/SKILL.md +290 -0
- package/ai-config/skills/data-ai/powerbi/SKILL.md +352 -0
- package/ai-config/skills/data-ai/pytorch/SKILL.md +274 -0
- package/ai-config/skills/data-ai/scikit-learn/SKILL.md +321 -0
- package/ai-config/skills/data-ai/vector-db/SKILL.md +301 -0
- package/ai-config/skills/database/graph-databases/SKILL.md +218 -0
- package/ai-config/skills/database/graph-spring/SKILL.md +361 -0
- package/ai-config/skills/database/pgx-postgres/SKILL.md +512 -0
- package/ai-config/skills/database/redis-cache/SKILL.md +343 -0
- package/ai-config/skills/database/sqlite-embedded/SKILL.md +388 -0
- package/ai-config/skills/database/timescaledb/SKILL.md +320 -0
- package/ai-config/skills/docs/api-documentation/SKILL.md +293 -0
- package/ai-config/skills/docs/docs-spring/SKILL.md +377 -0
- package/ai-config/skills/docs/mustache-templates/SKILL.md +190 -0
- package/ai-config/skills/docs/technical-docs/SKILL.md +447 -0
- package/ai-config/skills/frontend/astro-ssr/SKILL.md +441 -0
- package/ai-config/skills/frontend/frontend-design/SKILL.md +54 -0
- package/ai-config/skills/frontend/frontend-web/SKILL.md +368 -0
- package/ai-config/skills/frontend/mantine-ui/SKILL.md +396 -0
- package/ai-config/skills/frontend/tanstack-query/SKILL.md +439 -0
- package/ai-config/skills/frontend/zod-validation/SKILL.md +417 -0
- package/ai-config/skills/frontend/zustand-state/SKILL.md +350 -0
- package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +244 -0
- package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +378 -0
- package/ai-config/skills/infrastructure/devops-infra/SKILL.md +435 -0
- package/ai-config/skills/infrastructure/docker-containers/SKILL.md +420 -0
- package/ai-config/skills/infrastructure/kubernetes/SKILL.md +456 -0
- package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +546 -0
- package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +474 -0
- package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +315 -0
- package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +504 -0
- package/ai-config/skills/mobile/mobile-ionic/SKILL.md +448 -0
- package/ai-config/skills/prompt-improver/SKILL.md +125 -0
- package/ai-config/skills/quality/ghagga-review/SKILL.md +216 -0
- package/ai-config/skills/references/hooks-patterns/SKILL.md +238 -0
- package/ai-config/skills/references/mcp-servers/SKILL.md +275 -0
- package/ai-config/skills/references/plugins-reference/SKILL.md +110 -0
- package/ai-config/skills/references/skills-reference/SKILL.md +420 -0
- package/ai-config/skills/references/subagent-templates/SKILL.md +193 -0
- package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +410 -0
- package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +408 -0
- package/ai-config/skills/systems-iot/rust-systems/SKILL.md +386 -0
- package/ai-config/skills/systems-iot/tokio-async/SKILL.md +324 -0
- package/ai-config/skills/testing/playwright-e2e/SKILL.md +289 -0
- package/ai-config/skills/testing/testcontainers/SKILL.md +299 -0
- package/ai-config/skills/testing/vitest-testing/SKILL.md +381 -0
- package/ai-config/skills/workflow/ci-local-guide/SKILL.md +118 -0
- package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +299 -0
- package/ai-config/skills/workflow/claude-md-improver/SKILL.md +158 -0
- package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +117 -0
- package/ai-config/skills/workflow/git-github/SKILL.md +334 -0
- package/ai-config/skills/workflow/git-github/references/examples.md +160 -0
- package/ai-config/skills/workflow/git-workflow/SKILL.md +214 -0
- package/ai-config/skills/workflow/ide-plugins/SKILL.md +277 -0
- package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +401 -0
- package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +199 -0
- package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +100 -0
- package/ai-config/skills/workflow/verification-before-completion/SKILL.md +73 -0
- package/ai-config/skills/workflow/wave-workflow/SKILL.md +178 -0
- package/ci-local/README.md +170 -0
- package/ci-local/ci-local.sh +297 -0
- package/ci-local/hooks/commit-msg +74 -0
- package/ci-local/hooks/pre-commit +162 -0
- package/ci-local/hooks/pre-push +41 -0
- package/ci-local/install.sh +49 -0
- package/ci-local/semgrep.yml +214 -0
- package/dist/commands/analyze.d.ts +9 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +55 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/analyze.test.d.ts +2 -0
- package/dist/commands/analyze.test.d.ts.map +1 -0
- package/dist/commands/analyze.test.js +145 -0
- package/dist/commands/analyze.test.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +158 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/doctor.test.d.ts +2 -0
- package/dist/commands/doctor.test.d.ts.map +1 -0
- package/dist/commands/doctor.test.js +200 -0
- package/dist/commands/doctor.test.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +283 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.test.d.ts +2 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +271 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +201 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/constants.d.ts +21 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +57 -0
- package/dist/constants.js.map +1 -0
- package/dist/e2e/aggressive.e2e.test.d.ts +2 -0
- package/dist/e2e/aggressive.e2e.test.d.ts.map +1 -0
- package/dist/e2e/aggressive.e2e.test.js +350 -0
- package/dist/e2e/aggressive.e2e.test.js.map +1 -0
- package/dist/e2e/commands.e2e.test.d.ts +2 -0
- package/dist/e2e/commands.e2e.test.d.ts.map +1 -0
- package/dist/e2e/commands.e2e.test.js +213 -0
- package/dist/e2e/commands.e2e.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/common.d.ts +17 -0
- package/dist/lib/common.d.ts.map +1 -0
- package/dist/lib/common.js +111 -0
- package/dist/lib/common.js.map +1 -0
- package/dist/lib/common.test.d.ts +2 -0
- package/dist/lib/common.test.d.ts.map +1 -0
- package/dist/lib/common.test.js +316 -0
- package/dist/lib/common.test.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +18 -0
- package/dist/lib/frontmatter.d.ts.map +1 -0
- package/dist/lib/frontmatter.js +61 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/frontmatter.test.d.ts +2 -0
- package/dist/lib/frontmatter.test.d.ts.map +1 -0
- package/dist/lib/frontmatter.test.js +257 -0
- package/dist/lib/frontmatter.test.js.map +1 -0
- package/dist/lib/template.d.ts +24 -0
- package/dist/lib/template.d.ts.map +1 -0
- package/dist/lib/template.js +78 -0
- package/dist/lib/template.js.map +1 -0
- package/dist/lib/template.test.d.ts +2 -0
- package/dist/lib/template.test.d.ts.map +1 -0
- package/dist/lib/template.test.js +201 -0
- package/dist/lib/template.test.js.map +1 -0
- package/dist/types/index.d.ts +48 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/AnalyzeUI.d.ts +7 -0
- package/dist/ui/AnalyzeUI.d.ts.map +1 -0
- package/dist/ui/AnalyzeUI.js +100 -0
- package/dist/ui/AnalyzeUI.js.map +1 -0
- package/dist/ui/App.d.ts +13 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +100 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/CIContext.d.ts +9 -0
- package/dist/ui/CIContext.d.ts.map +1 -0
- package/dist/ui/CIContext.js +9 -0
- package/dist/ui/CIContext.js.map +1 -0
- package/dist/ui/CISelector.d.ts +8 -0
- package/dist/ui/CISelector.d.ts.map +1 -0
- package/dist/ui/CISelector.js +45 -0
- package/dist/ui/CISelector.js.map +1 -0
- package/dist/ui/Doctor.d.ts +3 -0
- package/dist/ui/Doctor.d.ts.map +1 -0
- package/dist/ui/Doctor.js +89 -0
- package/dist/ui/Doctor.js.map +1 -0
- package/dist/ui/Header.d.ts +8 -0
- package/dist/ui/Header.d.ts.map +1 -0
- package/dist/ui/Header.js +30 -0
- package/dist/ui/Header.js.map +1 -0
- package/dist/ui/MemorySelector.d.ts +8 -0
- package/dist/ui/MemorySelector.d.ts.map +1 -0
- package/dist/ui/MemorySelector.js +46 -0
- package/dist/ui/MemorySelector.js.map +1 -0
- package/dist/ui/NameInput.d.ts +8 -0
- package/dist/ui/NameInput.d.ts.map +1 -0
- package/dist/ui/NameInput.js +69 -0
- package/dist/ui/NameInput.js.map +1 -0
- package/dist/ui/OptionSelector.d.ts +12 -0
- package/dist/ui/OptionSelector.d.ts.map +1 -0
- package/dist/ui/OptionSelector.js +69 -0
- package/dist/ui/OptionSelector.js.map +1 -0
- package/dist/ui/Progress.d.ts +11 -0
- package/dist/ui/Progress.d.ts.map +1 -0
- package/dist/ui/Progress.js +58 -0
- package/dist/ui/Progress.js.map +1 -0
- package/dist/ui/StackSelector.d.ts +9 -0
- package/dist/ui/StackSelector.d.ts.map +1 -0
- package/dist/ui/StackSelector.js +65 -0
- package/dist/ui/StackSelector.js.map +1 -0
- package/dist/ui/Summary.d.ts +12 -0
- package/dist/ui/Summary.d.ts.map +1 -0
- package/dist/ui/Summary.js +114 -0
- package/dist/ui/Summary.js.map +1 -0
- package/dist/ui/SyncUI.d.ts +10 -0
- package/dist/ui/SyncUI.d.ts.map +1 -0
- package/dist/ui/SyncUI.js +64 -0
- package/dist/ui/SyncUI.js.map +1 -0
- package/dist/ui/Welcome.d.ts +7 -0
- package/dist/ui/Welcome.d.ts.map +1 -0
- package/dist/ui/Welcome.js +45 -0
- package/dist/ui/Welcome.js.map +1 -0
- package/dist/ui/theme.d.ts +10 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +9 -0
- package/dist/ui/theme.js.map +1 -0
- package/modules/engram/.gitignore-snippet.txt +6 -0
- package/modules/engram/.mcp-config-snippet.json +11 -0
- package/modules/engram/README.md +146 -0
- package/modules/engram/install-engram.sh +216 -0
- package/modules/ghagga/.env.example +43 -0
- package/modules/ghagga/README.md +153 -0
- package/modules/ghagga/docker-compose.yml +80 -0
- package/modules/ghagga/setup-ghagga.sh +139 -0
- package/modules/memory-simple/.project/NOTES.md +22 -0
- package/modules/memory-simple/README.md +23 -0
- package/modules/obsidian-brain/.obsidian/app.json +23 -0
- package/modules/obsidian-brain/.obsidian/appearance.json +5 -0
- package/modules/obsidian-brain/.obsidian/bookmarks.json +34 -0
- package/modules/obsidian-brain/.obsidian/community-plugins.json +1 -0
- package/modules/obsidian-brain/.obsidian/core-plugins-migration.json +21 -0
- package/modules/obsidian-brain/.obsidian/core-plugins.json +18 -0
- package/modules/obsidian-brain/.obsidian/daily-notes.json +5 -0
- package/modules/obsidian-brain/.obsidian/graph.json +37 -0
- package/modules/obsidian-brain/.obsidian/hotkeys.json +14 -0
- package/modules/obsidian-brain/.obsidian/plugins/dataview/data.json +25 -0
- package/modules/obsidian-brain/.obsidian/plugins/obsidian-kanban/data.json +29 -0
- package/modules/obsidian-brain/.obsidian/plugins/templater-obsidian/data.json +18 -0
- package/modules/obsidian-brain/.obsidian/snippets/project-memory.css +71 -0
- package/modules/obsidian-brain/.obsidian-gitignore-snippet.txt +8 -0
- package/modules/obsidian-brain/.project/Attachments/.gitkeep +0 -0
- package/modules/obsidian-brain/.project/Memory/BLOCKERS.md +78 -0
- package/modules/obsidian-brain/.project/Memory/CONTEXT.md +102 -0
- package/modules/obsidian-brain/.project/Memory/DASHBOARD.md +73 -0
- package/modules/obsidian-brain/.project/Memory/DECISIONS.md +87 -0
- package/modules/obsidian-brain/.project/Memory/KANBAN.md +15 -0
- package/modules/obsidian-brain/.project/Memory/README.md +61 -0
- package/modules/obsidian-brain/.project/Memory/WAVES.md +78 -0
- package/modules/obsidian-brain/.project/Sessions/TEMPLATE.md +99 -0
- package/modules/obsidian-brain/.project/Templates/ADR.md +33 -0
- package/modules/obsidian-brain/.project/Templates/Blocker.md +21 -0
- package/modules/obsidian-brain/.project/Templates/Session.md +88 -0
- package/modules/obsidian-brain/README.md +268 -0
- package/modules/obsidian-brain/new-wave.sh +182 -0
- package/package.json +51 -0
- package/schemas/agent.schema.json +34 -0
- package/schemas/ai-config.schema.json +28 -0
- package/schemas/skill.schema.json +44 -0
- package/src/commands/analyze.test.ts +145 -0
- package/src/commands/analyze.ts +69 -0
- package/src/commands/doctor.test.ts +208 -0
- package/src/commands/doctor.ts +163 -0
- package/src/commands/init.test.ts +298 -0
- package/src/commands/init.ts +285 -0
- package/src/constants.ts +69 -0
- package/src/e2e/aggressive.e2e.test.ts +557 -0
- package/src/e2e/commands.e2e.test.ts +298 -0
- package/src/index.tsx +106 -0
- package/src/lib/common.test.ts +318 -0
- package/src/lib/common.ts +127 -0
- package/src/lib/frontmatter.test.ts +291 -0
- package/src/lib/frontmatter.ts +77 -0
- package/src/lib/template.test.ts +226 -0
- package/src/lib/template.ts +99 -0
- package/src/types/index.ts +53 -0
- package/src/ui/AnalyzeUI.tsx +133 -0
- package/src/ui/App.tsx +175 -0
- package/src/ui/CIContext.tsx +25 -0
- package/src/ui/CISelector.tsx +72 -0
- package/src/ui/Doctor.tsx +122 -0
- package/src/ui/Header.tsx +48 -0
- package/src/ui/MemorySelector.tsx +73 -0
- package/src/ui/NameInput.tsx +82 -0
- package/src/ui/OptionSelector.tsx +100 -0
- package/src/ui/Progress.tsx +88 -0
- package/src/ui/StackSelector.tsx +101 -0
- package/src/ui/Summary.tsx +134 -0
- package/src/ui/Welcome.tsx +54 -0
- package/src/ui/theme.ts +10 -0
- package/stryker.config.json +19 -0
- package/tasks/_TEMPLATE/files-edited.md +3 -0
- package/tasks/_TEMPLATE/plan.md +3 -0
- package/tasks/_TEMPLATE/research.md +3 -0
- package/tasks/_TEMPLATE/verification.md +5 -0
- package/templates/common/dependabot/cargo.yml +11 -0
- package/templates/common/dependabot/github-actions.yml +16 -0
- package/templates/common/dependabot/gomod.yml +15 -0
- package/templates/common/dependabot/gradle.yml +15 -0
- package/templates/common/dependabot/header.yml +3 -0
- package/templates/common/dependabot/maven.yml +15 -0
- package/templates/common/dependabot/npm.yml +20 -0
- package/templates/common/dependabot/pip.yml +11 -0
- package/templates/dependabot.yml +162 -0
- package/templates/github/ci-go.yml +41 -0
- package/templates/github/ci-java.yml +45 -0
- package/templates/github/ci-monorepo.yml +150 -0
- package/templates/github/ci-node.yml +42 -0
- package/templates/github/ci-python.yml +42 -0
- package/templates/github/ci-rust.yml +42 -0
- package/templates/github/dependabot-automerge.yml +40 -0
- package/templates/gitlab/gitlab-ci-go.yml +88 -0
- package/templates/gitlab/gitlab-ci-java.yml +79 -0
- package/templates/gitlab/gitlab-ci-monorepo.yml +126 -0
- package/templates/gitlab/gitlab-ci-node.yml +63 -0
- package/templates/gitlab/gitlab-ci-python.yml +147 -0
- package/templates/gitlab/gitlab-ci-rust.yml +67 -0
- package/templates/global/claude-settings.json +98 -0
- package/templates/global/codex-config.toml +8 -0
- package/templates/global/copilot-instructions/base-rules.instructions.md +13 -0
- package/templates/global/copilot-instructions/sdd-orchestrator.instructions.md +37 -0
- package/templates/global/gemini-commands/cleanup.toml +20 -0
- package/templates/global/gemini-commands/commit.toml +15 -0
- package/templates/global/gemini-commands/dead-code.toml +22 -0
- package/templates/global/gemini-commands/plan.toml +30 -0
- package/templates/global/gemini-commands/review.toml +17 -0
- package/templates/global/gemini-commands/sdd-apply.toml +22 -0
- package/templates/global/gemini-commands/sdd-ff.toml +14 -0
- package/templates/global/gemini-commands/sdd-new.toml +21 -0
- package/templates/global/gemini-commands/sdd-verify.toml +21 -0
- package/templates/global/gemini-commands/tdd.toml +26 -0
- package/templates/global/gemini-settings.json +8 -0
- package/templates/global/opencode-config.json +44 -0
- package/templates/global/sdd-instructions.md +47 -0
- package/templates/global/sdd-orchestrator-claude.md +46 -0
- package/templates/global/sdd-orchestrator-copilot.md +34 -0
- package/templates/renovate.json +69 -0
- package/templates/woodpecker/monorepo/backend.yml +34 -0
- package/templates/woodpecker/monorepo/frontend.yml +34 -0
- package/templates/woodpecker/monorepo/summary.yml +25 -0
- package/templates/woodpecker/woodpecker-go.yml +51 -0
- package/templates/woodpecker/woodpecker-java.yml +67 -0
- package/templates/woodpecker/woodpecker-node.yml +47 -0
- package/templates/woodpecker/woodpecker-python.yml +108 -0
- package/templates/woodpecker/woodpecker-rust.yml +57 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +16 -0
- package/workflows/reusable-build-go.yml +111 -0
- package/workflows/reusable-build-java.yml +120 -0
- package/workflows/reusable-build-node.yml +145 -0
- package/workflows/reusable-build-python.yml +159 -0
- package/workflows/reusable-build-rust.yml +135 -0
- package/workflows/reusable-docker.yml +120 -0
- package/workflows/reusable-ghagga-review.yml +165 -0
- package/workflows/reusable-release.yml +91 -0
|
@@ -0,0 +1,1657 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-designer
|
|
3
|
+
description: API design expert specializing in REST, GraphQL, OpenAPI specifications, and API-first development
|
|
4
|
+
trigger: >
|
|
5
|
+
api design, rest api, graphql, openapi, swagger, api specification, api-first,
|
|
6
|
+
api versioning, api authentication, rate limiting, api documentation, endpoint design,
|
|
7
|
+
resource modeling, http methods, api gateway, microservices api
|
|
8
|
+
category: business
|
|
9
|
+
color: purple
|
|
10
|
+
tools: Write, Read, MultiEdit, Grep, Glob
|
|
11
|
+
model: sonnet
|
|
12
|
+
metadata:
|
|
13
|
+
version: "2.0"
|
|
14
|
+
updated: "2026-02"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
You are an API design specialist with expertise in RESTful services, GraphQL, OpenAPI/Swagger specifications, and API-first development methodologies.
|
|
18
|
+
|
|
19
|
+
## Core Expertise
|
|
20
|
+
- RESTful API design and best practices
|
|
21
|
+
- GraphQL schema design and optimization
|
|
22
|
+
- OpenAPI/Swagger specification
|
|
23
|
+
- API versioning and evolution
|
|
24
|
+
- Authentication and authorization patterns
|
|
25
|
+
- Rate limiting and throttling
|
|
26
|
+
- API documentation and testing
|
|
27
|
+
- Microservices architecture
|
|
28
|
+
|
|
29
|
+
## Technical Stack
|
|
30
|
+
- **Specification**: OpenAPI 3.1, Swagger 2.0, AsyncAPI, GraphQL SDL
|
|
31
|
+
- **Design Tools**: Stoplight Studio, Postman, Insomnia, SwaggerHub
|
|
32
|
+
- **Documentation**: Redoc, Swagger UI, GraphQL Playground, Slate
|
|
33
|
+
- **Testing**: Postman, Newman, Dredd, Pact, REST Assured
|
|
34
|
+
- **Gateways**: Kong, Apigee, AWS API Gateway, Azure API Management
|
|
35
|
+
- **Protocols**: REST, GraphQL, gRPC, WebSocket, Server-Sent Events
|
|
36
|
+
- **Standards**: JSON:API, HAL, JSON-LD, OData
|
|
37
|
+
|
|
38
|
+
## API Design Framework
|
|
39
|
+
```typescript
|
|
40
|
+
// api-designer.ts
|
|
41
|
+
import * as yaml from 'js-yaml';
|
|
42
|
+
import { OpenAPIV3 } from 'openapi-types';
|
|
43
|
+
import { GraphQLSchema, buildSchema } from 'graphql';
|
|
44
|
+
import { JSONSchema7 } from 'json-schema';
|
|
45
|
+
|
|
46
|
+
interface APIDesign {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
version: string;
|
|
50
|
+
type: APIType;
|
|
51
|
+
specification: APISpecification;
|
|
52
|
+
endpoints: Endpoint[];
|
|
53
|
+
dataModels: DataModel[];
|
|
54
|
+
authentication: AuthenticationScheme;
|
|
55
|
+
authorization: AuthorizationModel;
|
|
56
|
+
rateLimiting: RateLimitPolicy;
|
|
57
|
+
versioning: VersioningStrategy;
|
|
58
|
+
documentation: APIDocumentation;
|
|
59
|
+
testing: TestStrategy;
|
|
60
|
+
monitoring: MonitoringConfig;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface Endpoint {
|
|
64
|
+
id: string;
|
|
65
|
+
path: string;
|
|
66
|
+
method: HTTPMethod;
|
|
67
|
+
operation: OperationObject;
|
|
68
|
+
parameters: Parameter[];
|
|
69
|
+
requestBody?: RequestBody;
|
|
70
|
+
responses: ResponseObject[];
|
|
71
|
+
security?: SecurityRequirement[];
|
|
72
|
+
deprecated?: boolean;
|
|
73
|
+
version?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class APIDesigner {
|
|
77
|
+
private specifications: Map<string, APISpecification> = new Map();
|
|
78
|
+
private patterns: Map<string, DesignPattern> = new Map();
|
|
79
|
+
private validator: SpecificationValidator;
|
|
80
|
+
private generator: CodeGenerator;
|
|
81
|
+
|
|
82
|
+
constructor() {
|
|
83
|
+
this.validator = new SpecificationValidator();
|
|
84
|
+
this.generator = new CodeGenerator();
|
|
85
|
+
this.loadDesignPatterns();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async designRESTAPI(requirements: APIRequirements): Promise<OpenAPISpecification> {
|
|
89
|
+
// Analyze requirements
|
|
90
|
+
const analysis = await this.analyzeRequirements(requirements);
|
|
91
|
+
|
|
92
|
+
// Design resource model
|
|
93
|
+
const resources = this.designResources(analysis);
|
|
94
|
+
|
|
95
|
+
// Design endpoints
|
|
96
|
+
const endpoints = this.designEndpoints(resources, requirements);
|
|
97
|
+
|
|
98
|
+
// Design data models
|
|
99
|
+
const schemas = this.designSchemas(resources, requirements);
|
|
100
|
+
|
|
101
|
+
// Design authentication
|
|
102
|
+
const security = this.designSecurity(requirements);
|
|
103
|
+
|
|
104
|
+
// Generate OpenAPI specification
|
|
105
|
+
const spec = this.generateOpenAPISpec({
|
|
106
|
+
info: this.generateAPIInfo(requirements),
|
|
107
|
+
servers: this.generateServers(requirements),
|
|
108
|
+
paths: this.generatePaths(endpoints),
|
|
109
|
+
components: {
|
|
110
|
+
schemas: schemas,
|
|
111
|
+
securitySchemes: security,
|
|
112
|
+
parameters: this.generateCommonParameters(),
|
|
113
|
+
responses: this.generateCommonResponses(),
|
|
114
|
+
requestBodies: this.generateCommonRequestBodies(),
|
|
115
|
+
headers: this.generateCommonHeaders(),
|
|
116
|
+
examples: this.generateExamples(endpoints),
|
|
117
|
+
links: this.generateLinks(endpoints),
|
|
118
|
+
callbacks: this.generateCallbacks(endpoints),
|
|
119
|
+
},
|
|
120
|
+
security: this.generateSecurityRequirements(security),
|
|
121
|
+
tags: this.generateTags(resources),
|
|
122
|
+
externalDocs: requirements.documentation,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Validate specification
|
|
126
|
+
await this.validator.validateOpenAPI(spec);
|
|
127
|
+
|
|
128
|
+
// Apply best practices
|
|
129
|
+
const optimized = this.applyBestPractices(spec);
|
|
130
|
+
|
|
131
|
+
return optimized;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private designResources(analysis: RequirementAnalysis): Resource[] {
|
|
135
|
+
const resources: Resource[] = [];
|
|
136
|
+
|
|
137
|
+
for (const entity of analysis.entities) {
|
|
138
|
+
const resource: Resource = {
|
|
139
|
+
id: this.generateId('RES'),
|
|
140
|
+
name: entity.name,
|
|
141
|
+
plural: this.pluralize(entity.name),
|
|
142
|
+
description: entity.description,
|
|
143
|
+
attributes: this.mapAttributes(entity.properties),
|
|
144
|
+
relationships: this.mapRelationships(entity.relationships),
|
|
145
|
+
operations: this.determineOperations(entity),
|
|
146
|
+
uri: this.generateURI(entity),
|
|
147
|
+
subresources: [],
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Identify subresources
|
|
151
|
+
resource.subresources = this.identifySubresources(entity, analysis.entities);
|
|
152
|
+
|
|
153
|
+
resources.push(resource);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return resources;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private designEndpoints(resources: Resource[], requirements: APIRequirements): Endpoint[] {
|
|
160
|
+
const endpoints: Endpoint[] = [];
|
|
161
|
+
|
|
162
|
+
for (const resource of resources) {
|
|
163
|
+
// Collection endpoints
|
|
164
|
+
if (resource.operations.includes('list')) {
|
|
165
|
+
endpoints.push(this.createListEndpoint(resource));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (resource.operations.includes('create')) {
|
|
169
|
+
endpoints.push(this.createCreateEndpoint(resource));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Item endpoints
|
|
173
|
+
if (resource.operations.includes('read')) {
|
|
174
|
+
endpoints.push(this.createReadEndpoint(resource));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (resource.operations.includes('update')) {
|
|
178
|
+
endpoints.push(this.createUpdateEndpoint(resource));
|
|
179
|
+
|
|
180
|
+
if (requirements.supportPatch) {
|
|
181
|
+
endpoints.push(this.createPatchEndpoint(resource));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (resource.operations.includes('delete')) {
|
|
186
|
+
endpoints.push(this.createDeleteEndpoint(resource));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Custom actions
|
|
190
|
+
for (const action of resource.customActions || []) {
|
|
191
|
+
endpoints.push(this.createCustomActionEndpoint(resource, action));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Subresource endpoints
|
|
195
|
+
for (const subresource of resource.subresources) {
|
|
196
|
+
endpoints.push(...this.createSubresourceEndpoints(resource, subresource));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Add utility endpoints
|
|
201
|
+
endpoints.push(...this.createUtilityEndpoints(requirements));
|
|
202
|
+
|
|
203
|
+
return endpoints;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private createListEndpoint(resource: Resource): Endpoint {
|
|
207
|
+
return {
|
|
208
|
+
id: `list-${resource.plural}`,
|
|
209
|
+
path: `/${resource.plural}`,
|
|
210
|
+
method: HTTPMethod.GET,
|
|
211
|
+
operation: {
|
|
212
|
+
operationId: `list${this.capitalize(resource.plural)}`,
|
|
213
|
+
summary: `List ${resource.plural}`,
|
|
214
|
+
description: `Retrieve a paginated list of ${resource.plural}`,
|
|
215
|
+
tags: [resource.name],
|
|
216
|
+
parameters: [
|
|
217
|
+
this.createPaginationParameters(),
|
|
218
|
+
this.createFilterParameters(resource),
|
|
219
|
+
this.createSortParameters(resource),
|
|
220
|
+
this.createFieldsParameter(),
|
|
221
|
+
].flat(),
|
|
222
|
+
responses: [
|
|
223
|
+
{
|
|
224
|
+
status: '200',
|
|
225
|
+
description: `Successful response with ${resource.plural} list`,
|
|
226
|
+
content: {
|
|
227
|
+
'application/json': {
|
|
228
|
+
schema: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
properties: {
|
|
231
|
+
data: {
|
|
232
|
+
type: 'array',
|
|
233
|
+
items: { $ref: `#/components/schemas/${resource.name}` },
|
|
234
|
+
},
|
|
235
|
+
meta: { $ref: '#/components/schemas/PaginationMeta' },
|
|
236
|
+
links: { $ref: '#/components/schemas/PaginationLinks' },
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
examples: {
|
|
240
|
+
success: this.generateListExample(resource),
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{ $ref: '#/components/responses/400BadRequest' },
|
|
246
|
+
{ $ref: '#/components/responses/401Unauthorized' },
|
|
247
|
+
{ $ref: '#/components/responses/403Forbidden' },
|
|
248
|
+
{ $ref: '#/components/responses/500InternalServerError' },
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private createCreateEndpoint(resource: Resource): Endpoint {
|
|
255
|
+
return {
|
|
256
|
+
id: `create-${resource.name}`,
|
|
257
|
+
path: `/${resource.plural}`,
|
|
258
|
+
method: HTTPMethod.POST,
|
|
259
|
+
operation: {
|
|
260
|
+
operationId: `create${this.capitalize(resource.name)}`,
|
|
261
|
+
summary: `Create ${resource.name}`,
|
|
262
|
+
description: `Create a new ${resource.name}`,
|
|
263
|
+
tags: [resource.name],
|
|
264
|
+
requestBody: {
|
|
265
|
+
required: true,
|
|
266
|
+
content: {
|
|
267
|
+
'application/json': {
|
|
268
|
+
schema: { $ref: `#/components/schemas/${resource.name}Input` },
|
|
269
|
+
examples: {
|
|
270
|
+
complete: this.generateCreateExample(resource, 'complete'),
|
|
271
|
+
minimal: this.generateCreateExample(resource, 'minimal'),
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
responses: [
|
|
277
|
+
{
|
|
278
|
+
status: '201',
|
|
279
|
+
description: `${resource.name} created successfully`,
|
|
280
|
+
headers: {
|
|
281
|
+
Location: {
|
|
282
|
+
description: 'URL of the created resource',
|
|
283
|
+
schema: { type: 'string' },
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
content: {
|
|
287
|
+
'application/json': {
|
|
288
|
+
schema: { $ref: `#/components/schemas/${resource.name}` },
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
{ $ref: '#/components/responses/400BadRequest' },
|
|
293
|
+
{ $ref: '#/components/responses/401Unauthorized' },
|
|
294
|
+
{ $ref: '#/components/responses/403Forbidden' },
|
|
295
|
+
{ $ref: '#/components/responses/409Conflict' },
|
|
296
|
+
{ $ref: '#/components/responses/422UnprocessableEntity' },
|
|
297
|
+
],
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private createReadEndpoint(resource: Resource): Endpoint {
|
|
303
|
+
return {
|
|
304
|
+
id: `get-${resource.name}`,
|
|
305
|
+
path: `/${resource.plural}/{id}`,
|
|
306
|
+
method: HTTPMethod.GET,
|
|
307
|
+
operation: {
|
|
308
|
+
operationId: `get${this.capitalize(resource.name)}`,
|
|
309
|
+
summary: `Get ${resource.name}`,
|
|
310
|
+
description: `Retrieve a specific ${resource.name} by ID`,
|
|
311
|
+
tags: [resource.name],
|
|
312
|
+
parameters: [
|
|
313
|
+
{
|
|
314
|
+
name: 'id',
|
|
315
|
+
in: 'path',
|
|
316
|
+
required: true,
|
|
317
|
+
description: `${resource.name} identifier`,
|
|
318
|
+
schema: { type: 'string', format: 'uuid' },
|
|
319
|
+
},
|
|
320
|
+
this.createFieldsParameter(),
|
|
321
|
+
this.createExpandParameter(resource),
|
|
322
|
+
],
|
|
323
|
+
responses: [
|
|
324
|
+
{
|
|
325
|
+
status: '200',
|
|
326
|
+
description: `${resource.name} retrieved successfully`,
|
|
327
|
+
content: {
|
|
328
|
+
'application/json': {
|
|
329
|
+
schema: { $ref: `#/components/schemas/${resource.name}` },
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
{ $ref: '#/components/responses/401Unauthorized' },
|
|
334
|
+
{ $ref: '#/components/responses/403Forbidden' },
|
|
335
|
+
{ $ref: '#/components/responses/404NotFound' },
|
|
336
|
+
],
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private createUpdateEndpoint(resource: Resource): Endpoint {
|
|
342
|
+
return {
|
|
343
|
+
id: `update-${resource.name}`,
|
|
344
|
+
path: `/${resource.plural}/{id}`,
|
|
345
|
+
method: HTTPMethod.PUT,
|
|
346
|
+
operation: {
|
|
347
|
+
operationId: `update${this.capitalize(resource.name)}`,
|
|
348
|
+
summary: `Update ${resource.name}`,
|
|
349
|
+
description: `Replace an entire ${resource.name}`,
|
|
350
|
+
tags: [resource.name],
|
|
351
|
+
parameters: [
|
|
352
|
+
{
|
|
353
|
+
name: 'id',
|
|
354
|
+
in: 'path',
|
|
355
|
+
required: true,
|
|
356
|
+
description: `${resource.name} identifier`,
|
|
357
|
+
schema: { type: 'string', format: 'uuid' },
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
requestBody: {
|
|
361
|
+
required: true,
|
|
362
|
+
content: {
|
|
363
|
+
'application/json': {
|
|
364
|
+
schema: { $ref: `#/components/schemas/${resource.name}Input` },
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
responses: [
|
|
369
|
+
{
|
|
370
|
+
status: '200',
|
|
371
|
+
description: `${resource.name} updated successfully`,
|
|
372
|
+
content: {
|
|
373
|
+
'application/json': {
|
|
374
|
+
schema: { $ref: `#/components/schemas/${resource.name}` },
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
{ $ref: '#/components/responses/400BadRequest' },
|
|
379
|
+
{ $ref: '#/components/responses/401Unauthorized' },
|
|
380
|
+
{ $ref: '#/components/responses/403Forbidden' },
|
|
381
|
+
{ $ref: '#/components/responses/404NotFound' },
|
|
382
|
+
{ $ref: '#/components/responses/409Conflict' },
|
|
383
|
+
{ $ref: '#/components/responses/422UnprocessableEntity' },
|
|
384
|
+
],
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private createPatchEndpoint(resource: Resource): Endpoint {
|
|
390
|
+
return {
|
|
391
|
+
id: `patch-${resource.name}`,
|
|
392
|
+
path: `/${resource.plural}/{id}`,
|
|
393
|
+
method: HTTPMethod.PATCH,
|
|
394
|
+
operation: {
|
|
395
|
+
operationId: `patch${this.capitalize(resource.name)}`,
|
|
396
|
+
summary: `Partially update ${resource.name}`,
|
|
397
|
+
description: `Update specific fields of a ${resource.name}`,
|
|
398
|
+
tags: [resource.name],
|
|
399
|
+
parameters: [
|
|
400
|
+
{
|
|
401
|
+
name: 'id',
|
|
402
|
+
in: 'path',
|
|
403
|
+
required: true,
|
|
404
|
+
description: `${resource.name} identifier`,
|
|
405
|
+
schema: { type: 'string', format: 'uuid' },
|
|
406
|
+
},
|
|
407
|
+
],
|
|
408
|
+
requestBody: {
|
|
409
|
+
required: true,
|
|
410
|
+
content: {
|
|
411
|
+
'application/json-patch+json': {
|
|
412
|
+
schema: { $ref: '#/components/schemas/JSONPatch' },
|
|
413
|
+
examples: {
|
|
414
|
+
updateField: {
|
|
415
|
+
value: [
|
|
416
|
+
{ op: 'replace', path: '/status', value: 'active' },
|
|
417
|
+
],
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
'application/merge-patch+json': {
|
|
422
|
+
schema: { $ref: `#/components/schemas/${resource.name}Patch` },
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
responses: [
|
|
427
|
+
{
|
|
428
|
+
status: '200',
|
|
429
|
+
description: `${resource.name} patched successfully`,
|
|
430
|
+
content: {
|
|
431
|
+
'application/json': {
|
|
432
|
+
schema: { $ref: `#/components/schemas/${resource.name}` },
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
{ $ref: '#/components/responses/400BadRequest' },
|
|
437
|
+
{ $ref: '#/components/responses/401Unauthorized' },
|
|
438
|
+
{ $ref: '#/components/responses/403Forbidden' },
|
|
439
|
+
{ $ref: '#/components/responses/404NotFound' },
|
|
440
|
+
{ $ref: '#/components/responses/409Conflict' },
|
|
441
|
+
{ $ref: '#/components/responses/422UnprocessableEntity' },
|
|
442
|
+
],
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async designGraphQLAPI(requirements: APIRequirements): Promise<GraphQLDesign> {
|
|
448
|
+
// Design type system
|
|
449
|
+
const types = this.designGraphQLTypes(requirements);
|
|
450
|
+
|
|
451
|
+
// Design queries
|
|
452
|
+
const queries = this.designQueries(types, requirements);
|
|
453
|
+
|
|
454
|
+
// Design mutations
|
|
455
|
+
const mutations = this.designMutations(types, requirements);
|
|
456
|
+
|
|
457
|
+
// Design subscriptions
|
|
458
|
+
const subscriptions = this.designSubscriptions(types, requirements);
|
|
459
|
+
|
|
460
|
+
// Generate SDL
|
|
461
|
+
const sdl = this.generateGraphQLSDL({
|
|
462
|
+
types,
|
|
463
|
+
queries,
|
|
464
|
+
mutations,
|
|
465
|
+
subscriptions,
|
|
466
|
+
directives: this.designDirectives(requirements),
|
|
467
|
+
scalars: this.designScalars(requirements),
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// Build schema
|
|
471
|
+
const schema = buildSchema(sdl);
|
|
472
|
+
|
|
473
|
+
// Generate resolvers template
|
|
474
|
+
const resolvers = this.generateResolvers(schema);
|
|
475
|
+
|
|
476
|
+
// Validate schema
|
|
477
|
+
await this.validator.validateGraphQLSchema(schema);
|
|
478
|
+
|
|
479
|
+
return {
|
|
480
|
+
schema,
|
|
481
|
+
sdl,
|
|
482
|
+
resolvers,
|
|
483
|
+
documentation: this.generateGraphQLDocumentation(schema),
|
|
484
|
+
examples: this.generateGraphQLExamples(schema),
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
private designGraphQLTypes(requirements: APIRequirements): GraphQLType[] {
|
|
489
|
+
const types: GraphQLType[] = [];
|
|
490
|
+
|
|
491
|
+
for (const entity of requirements.entities) {
|
|
492
|
+
// Object type
|
|
493
|
+
types.push({
|
|
494
|
+
kind: 'ObjectType',
|
|
495
|
+
name: entity.name,
|
|
496
|
+
description: entity.description,
|
|
497
|
+
fields: this.mapGraphQLFields(entity.properties),
|
|
498
|
+
interfaces: this.identifyInterfaces(entity),
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// Input type
|
|
502
|
+
types.push({
|
|
503
|
+
kind: 'InputType',
|
|
504
|
+
name: `${entity.name}Input`,
|
|
505
|
+
description: `Input for creating/updating ${entity.name}`,
|
|
506
|
+
fields: this.mapGraphQLInputFields(entity.properties),
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// Filter type
|
|
510
|
+
types.push({
|
|
511
|
+
kind: 'InputType',
|
|
512
|
+
name: `${entity.name}Filter`,
|
|
513
|
+
description: `Filter for querying ${entity.name}`,
|
|
514
|
+
fields: this.generateFilterFields(entity.properties),
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Connection type for pagination
|
|
518
|
+
if (requirements.usePagination) {
|
|
519
|
+
types.push(this.generateConnectionType(entity));
|
|
520
|
+
types.push(this.generateEdgeType(entity));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Add common types
|
|
525
|
+
types.push(...this.generateCommonGraphQLTypes());
|
|
526
|
+
|
|
527
|
+
return types;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
private designQueries(types: GraphQLType[], requirements: APIRequirements): Query[] {
|
|
531
|
+
const queries: Query[] = [];
|
|
532
|
+
|
|
533
|
+
for (const type of types.filter(t => t.kind === 'ObjectType' && !t.name.includes('Connection'))) {
|
|
534
|
+
// Single item query
|
|
535
|
+
queries.push({
|
|
536
|
+
name: this.uncapitalize(type.name),
|
|
537
|
+
description: `Get a single ${type.name}`,
|
|
538
|
+
args: [
|
|
539
|
+
{ name: 'id', type: 'ID!', description: `${type.name} ID` },
|
|
540
|
+
],
|
|
541
|
+
returnType: type.name,
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
// List query
|
|
545
|
+
const listQuery: Query = {
|
|
546
|
+
name: this.pluralize(this.uncapitalize(type.name)),
|
|
547
|
+
description: `List ${type.name} items`,
|
|
548
|
+
args: [
|
|
549
|
+
{ name: 'filter', type: `${type.name}Filter`, description: 'Filter criteria' },
|
|
550
|
+
{ name: 'sort', type: 'SortInput', description: 'Sort options' },
|
|
551
|
+
],
|
|
552
|
+
returnType: `[${type.name}!]!`,
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
// Add pagination args if needed
|
|
556
|
+
if (requirements.usePagination) {
|
|
557
|
+
listQuery.args.push(
|
|
558
|
+
{ name: 'first', type: 'Int', description: 'Number of items to return' },
|
|
559
|
+
{ name: 'after', type: 'String', description: 'Cursor for pagination' },
|
|
560
|
+
);
|
|
561
|
+
listQuery.returnType = `${type.name}Connection!`;
|
|
562
|
+
} else {
|
|
563
|
+
listQuery.args.push(
|
|
564
|
+
{ name: 'limit', type: 'Int', description: 'Maximum number of items' },
|
|
565
|
+
{ name: 'offset', type: 'Int', description: 'Number of items to skip' },
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
queries.push(listQuery);
|
|
570
|
+
|
|
571
|
+
// Search query
|
|
572
|
+
if (requirements.includeSearch) {
|
|
573
|
+
queries.push({
|
|
574
|
+
name: `search${type.name}`,
|
|
575
|
+
description: `Search ${type.name} items`,
|
|
576
|
+
args: [
|
|
577
|
+
{ name: 'query', type: 'String!', description: 'Search query' },
|
|
578
|
+
{ name: 'limit', type: 'Int', description: 'Maximum results' },
|
|
579
|
+
],
|
|
580
|
+
returnType: `[${type.name}!]!`,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return queries;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
private designMutations(types: GraphQLType[], requirements: APIRequirements): Mutation[] {
|
|
589
|
+
const mutations: Mutation[] = [];
|
|
590
|
+
|
|
591
|
+
for (const type of types.filter(t => t.kind === 'ObjectType' && !t.name.includes('Connection'))) {
|
|
592
|
+
// Create mutation
|
|
593
|
+
mutations.push({
|
|
594
|
+
name: `create${type.name}`,
|
|
595
|
+
description: `Create a new ${type.name}`,
|
|
596
|
+
args: [
|
|
597
|
+
{ name: 'input', type: `${type.name}Input!`, description: 'Input data' },
|
|
598
|
+
],
|
|
599
|
+
returnType: `${type.name}!`,
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
// Update mutation
|
|
603
|
+
mutations.push({
|
|
604
|
+
name: `update${type.name}`,
|
|
605
|
+
description: `Update an existing ${type.name}`,
|
|
606
|
+
args: [
|
|
607
|
+
{ name: 'id', type: 'ID!', description: `${type.name} ID` },
|
|
608
|
+
{ name: 'input', type: `${type.name}Input!`, description: 'Updated data' },
|
|
609
|
+
],
|
|
610
|
+
returnType: `${type.name}!`,
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
// Delete mutation
|
|
614
|
+
mutations.push({
|
|
615
|
+
name: `delete${type.name}`,
|
|
616
|
+
description: `Delete a ${type.name}`,
|
|
617
|
+
args: [
|
|
618
|
+
{ name: 'id', type: 'ID!', description: `${type.name} ID` },
|
|
619
|
+
],
|
|
620
|
+
returnType: 'Boolean!',
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
// Batch operations
|
|
624
|
+
if (requirements.includeBatchOperations) {
|
|
625
|
+
mutations.push({
|
|
626
|
+
name: `batchCreate${type.name}`,
|
|
627
|
+
description: `Create multiple ${type.name} items`,
|
|
628
|
+
args: [
|
|
629
|
+
{ name: 'inputs', type: `[${type.name}Input!]!`, description: 'Input data array' },
|
|
630
|
+
],
|
|
631
|
+
returnType: `[${type.name}!]!`,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
mutations.push({
|
|
635
|
+
name: `batchDelete${type.name}`,
|
|
636
|
+
description: `Delete multiple ${type.name} items`,
|
|
637
|
+
args: [
|
|
638
|
+
{ name: 'ids', type: '[ID!]!', description: 'IDs to delete' },
|
|
639
|
+
],
|
|
640
|
+
returnType: 'Int!', // Number of deleted items
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return mutations;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
async generateAPIClient(specification: APISpecification): Promise<ClientSDK> {
|
|
649
|
+
const sdk: ClientSDK = {
|
|
650
|
+
language: specification.targetLanguage || 'typescript',
|
|
651
|
+
name: `${specification.name}Client`,
|
|
652
|
+
version: specification.version,
|
|
653
|
+
files: [],
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
switch (sdk.language) {
|
|
657
|
+
case 'typescript':
|
|
658
|
+
sdk.files = await this.generateTypeScriptClient(specification);
|
|
659
|
+
break;
|
|
660
|
+
case 'python':
|
|
661
|
+
sdk.files = await this.generatePythonClient(specification);
|
|
662
|
+
break;
|
|
663
|
+
case 'go':
|
|
664
|
+
sdk.files = await this.generateGoClient(specification);
|
|
665
|
+
break;
|
|
666
|
+
case 'java':
|
|
667
|
+
sdk.files = await this.generateJavaClient(specification);
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return sdk;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
private async generateTypeScriptClient(spec: APISpecification): Promise<ClientFile[]> {
|
|
675
|
+
const files: ClientFile[] = [];
|
|
676
|
+
|
|
677
|
+
// Types file
|
|
678
|
+
files.push({
|
|
679
|
+
name: 'types.ts',
|
|
680
|
+
content: this.generateTypeScriptTypes(spec),
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
// API client class
|
|
684
|
+
files.push({
|
|
685
|
+
name: 'client.ts',
|
|
686
|
+
content: this.generateTypeScriptClientClass(spec),
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
// Individual service classes
|
|
690
|
+
for (const tag of spec.tags || []) {
|
|
691
|
+
files.push({
|
|
692
|
+
name: `${tag.name.toLowerCase()}.service.ts`,
|
|
693
|
+
content: this.generateTypeScriptService(spec, tag),
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Utils
|
|
698
|
+
files.push({
|
|
699
|
+
name: 'utils.ts',
|
|
700
|
+
content: this.generateTypeScriptUtils(),
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// Index file
|
|
704
|
+
files.push({
|
|
705
|
+
name: 'index.ts',
|
|
706
|
+
content: this.generateTypeScriptIndex(spec),
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
return files;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
private generateTypeScriptTypes(spec: APISpecification): string {
|
|
713
|
+
let types = `// Auto-generated types from ${spec.name} v${spec.version}\n\n`;
|
|
714
|
+
|
|
715
|
+
// Generate interfaces from schemas
|
|
716
|
+
for (const [name, schema] of Object.entries(spec.components?.schemas || {})) {
|
|
717
|
+
types += this.schemaToTypeScript(name, schema);
|
|
718
|
+
types += '\n\n';
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Generate enums
|
|
722
|
+
for (const [name, schema] of Object.entries(spec.components?.schemas || {})) {
|
|
723
|
+
if (schema.enum) {
|
|
724
|
+
types += `export enum ${name} {\n`;
|
|
725
|
+
for (const value of schema.enum) {
|
|
726
|
+
types += ` ${this.toEnumKey(value)} = '${value}',\n`;
|
|
727
|
+
}
|
|
728
|
+
types += '}\n\n';
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return types;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
private schemaToTypeScript(name: string, schema: any): string {
|
|
736
|
+
let ts = `export interface ${name} {\n`;
|
|
737
|
+
|
|
738
|
+
if (schema.properties) {
|
|
739
|
+
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
740
|
+
const required = schema.required?.includes(propName) || false;
|
|
741
|
+
const optional = required ? '' : '?';
|
|
742
|
+
const type = this.jsonSchemaToTypeScript(propSchema);
|
|
743
|
+
|
|
744
|
+
ts += ` ${propName}${optional}: ${type};\n`;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
ts += '}';
|
|
749
|
+
return ts;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
private generateTypeScriptClientClass(spec: APISpecification): string {
|
|
753
|
+
return `
|
|
754
|
+
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
755
|
+
import { ${this.getTypeImports(spec).join(', ')} } from './types';
|
|
756
|
+
|
|
757
|
+
export interface ClientConfig {
|
|
758
|
+
baseURL: string;
|
|
759
|
+
apiKey?: string;
|
|
760
|
+
accessToken?: string;
|
|
761
|
+
timeout?: number;
|
|
762
|
+
headers?: Record<string, string>;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
export class ${spec.name}Client {
|
|
766
|
+
private client: AxiosInstance;
|
|
767
|
+
${this.generateServiceProperties(spec)}
|
|
768
|
+
|
|
769
|
+
constructor(config: ClientConfig) {
|
|
770
|
+
this.client = axios.create({
|
|
771
|
+
baseURL: config.baseURL,
|
|
772
|
+
timeout: config.timeout || 30000,
|
|
773
|
+
headers: {
|
|
774
|
+
'Content-Type': 'application/json',
|
|
775
|
+
...config.headers,
|
|
776
|
+
},
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
// Add authentication
|
|
780
|
+
if (config.apiKey) {
|
|
781
|
+
this.client.defaults.headers.common['X-API-Key'] = config.apiKey;
|
|
782
|
+
}
|
|
783
|
+
if (config.accessToken) {
|
|
784
|
+
this.client.defaults.headers.common['Authorization'] = \`Bearer \${config.accessToken}\`;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// Add interceptors
|
|
788
|
+
this.setupInterceptors();
|
|
789
|
+
|
|
790
|
+
// Initialize services
|
|
791
|
+
${this.generateServiceInitialization(spec)}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
private setupInterceptors(): void {
|
|
795
|
+
// Request interceptor
|
|
796
|
+
this.client.interceptors.request.use(
|
|
797
|
+
(config) => {
|
|
798
|
+
// Add request ID
|
|
799
|
+
config.headers['X-Request-Id'] = this.generateRequestId();
|
|
800
|
+
return config;
|
|
801
|
+
},
|
|
802
|
+
(error) => Promise.reject(error)
|
|
803
|
+
);
|
|
804
|
+
|
|
805
|
+
// Response interceptor
|
|
806
|
+
this.client.interceptors.response.use(
|
|
807
|
+
(response) => response,
|
|
808
|
+
async (error) => {
|
|
809
|
+
if (error.response?.status === 401) {
|
|
810
|
+
// Handle token refresh
|
|
811
|
+
await this.refreshToken();
|
|
812
|
+
return this.client.request(error.config);
|
|
813
|
+
}
|
|
814
|
+
return Promise.reject(error);
|
|
815
|
+
}
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
private generateRequestId(): string {
|
|
820
|
+
return \`\${Date.now()}-\${Math.random().toString(36).substr(2, 9)}\`;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
private async refreshToken(): Promise<void> {
|
|
824
|
+
// Implement token refresh logic
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
async setAccessToken(token: string): Promise<void> {
|
|
828
|
+
this.client.defaults.headers.common['Authorization'] = \`Bearer \${token}\`;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
`;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
async validateAPIDesign(design: APIDesign): Promise<ValidationResult> {
|
|
835
|
+
const issues: ValidationIssue[] = [];
|
|
836
|
+
|
|
837
|
+
// Validate naming conventions
|
|
838
|
+
issues.push(...this.validateNaming(design));
|
|
839
|
+
|
|
840
|
+
// Validate HTTP methods usage
|
|
841
|
+
issues.push(...this.validateHTTPMethods(design));
|
|
842
|
+
|
|
843
|
+
// Validate status codes
|
|
844
|
+
issues.push(...this.validateStatusCodes(design));
|
|
845
|
+
|
|
846
|
+
// Validate pagination
|
|
847
|
+
issues.push(...this.validatePagination(design));
|
|
848
|
+
|
|
849
|
+
// Validate error handling
|
|
850
|
+
issues.push(...this.validateErrorHandling(design));
|
|
851
|
+
|
|
852
|
+
// Validate security
|
|
853
|
+
issues.push(...this.validateSecurity(design));
|
|
854
|
+
|
|
855
|
+
// Validate versioning
|
|
856
|
+
issues.push(...this.validateVersioning(design));
|
|
857
|
+
|
|
858
|
+
// Check for breaking changes
|
|
859
|
+
if (design.previousVersion) {
|
|
860
|
+
issues.push(...await this.checkBreakingChanges(design));
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
return {
|
|
864
|
+
valid: issues.filter(i => i.severity === 'error').length === 0,
|
|
865
|
+
issues,
|
|
866
|
+
score: this.calculateDesignScore(issues),
|
|
867
|
+
recommendations: this.generateRecommendations(issues),
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
private validateNaming(design: APIDesign): ValidationIssue[] {
|
|
872
|
+
const issues: ValidationIssue[] = [];
|
|
873
|
+
|
|
874
|
+
for (const endpoint of design.endpoints) {
|
|
875
|
+
// Check path naming
|
|
876
|
+
if (!this.isValidPath(endpoint.path)) {
|
|
877
|
+
issues.push({
|
|
878
|
+
type: 'naming',
|
|
879
|
+
severity: 'warning',
|
|
880
|
+
message: `Path '${endpoint.path}' does not follow REST naming conventions`,
|
|
881
|
+
location: endpoint.path,
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Check for verbs in URIs
|
|
886
|
+
if (this.containsVerb(endpoint.path)) {
|
|
887
|
+
issues.push({
|
|
888
|
+
type: 'naming',
|
|
889
|
+
severity: 'error',
|
|
890
|
+
message: `Path '${endpoint.path}' contains a verb, use HTTP methods instead`,
|
|
891
|
+
location: endpoint.path,
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
return issues;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
private validateHTTPMethods(design: APIDesign): ValidationIssue[] {
|
|
900
|
+
const issues: ValidationIssue[] = [];
|
|
901
|
+
|
|
902
|
+
for (const endpoint of design.endpoints) {
|
|
903
|
+
// Check idempotency
|
|
904
|
+
if (['PUT', 'DELETE'].includes(endpoint.method) && !endpoint.idempotent) {
|
|
905
|
+
issues.push({
|
|
906
|
+
type: 'http-method',
|
|
907
|
+
severity: 'warning',
|
|
908
|
+
message: `${endpoint.method} ${endpoint.path} should be idempotent`,
|
|
909
|
+
location: endpoint.path,
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// Check safe methods
|
|
914
|
+
if (endpoint.method === 'GET' && endpoint.hasSideEffects) {
|
|
915
|
+
issues.push({
|
|
916
|
+
type: 'http-method',
|
|
917
|
+
severity: 'error',
|
|
918
|
+
message: `GET ${endpoint.path} should not have side effects`,
|
|
919
|
+
location: endpoint.path,
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return issues;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
private applyBestPractices(spec: OpenAPISpecification): OpenAPISpecification {
|
|
928
|
+
// Add common responses
|
|
929
|
+
spec.components.responses = {
|
|
930
|
+
...spec.components.responses,
|
|
931
|
+
...this.getCommonResponses(),
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
// Add common parameters
|
|
935
|
+
spec.components.parameters = {
|
|
936
|
+
...spec.components.parameters,
|
|
937
|
+
...this.getCommonParameters(),
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
// Add security schemes
|
|
941
|
+
if (!spec.components.securitySchemes) {
|
|
942
|
+
spec.components.securitySchemes = this.getDefaultSecuritySchemes();
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Add rate limiting headers
|
|
946
|
+
for (const path of Object.values(spec.paths)) {
|
|
947
|
+
for (const operation of Object.values(path)) {
|
|
948
|
+
if (operation.responses) {
|
|
949
|
+
this.addRateLimitHeaders(operation.responses);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
return spec;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
private getCommonResponses(): Record<string, any> {
|
|
958
|
+
return {
|
|
959
|
+
'400BadRequest': {
|
|
960
|
+
description: 'Bad request',
|
|
961
|
+
content: {
|
|
962
|
+
'application/json': {
|
|
963
|
+
schema: { $ref: '#/components/schemas/Error' },
|
|
964
|
+
example: {
|
|
965
|
+
error: {
|
|
966
|
+
code: 'BAD_REQUEST',
|
|
967
|
+
message: 'Invalid request parameters',
|
|
968
|
+
},
|
|
969
|
+
},
|
|
970
|
+
},
|
|
971
|
+
},
|
|
972
|
+
},
|
|
973
|
+
'401Unauthorized': {
|
|
974
|
+
description: 'Authentication required',
|
|
975
|
+
content: {
|
|
976
|
+
'application/json': {
|
|
977
|
+
schema: { $ref: '#/components/schemas/Error' },
|
|
978
|
+
example: {
|
|
979
|
+
error: {
|
|
980
|
+
code: 'UNAUTHORIZED',
|
|
981
|
+
message: 'Authentication required',
|
|
982
|
+
},
|
|
983
|
+
},
|
|
984
|
+
},
|
|
985
|
+
},
|
|
986
|
+
},
|
|
987
|
+
'403Forbidden': {
|
|
988
|
+
description: 'Insufficient permissions',
|
|
989
|
+
content: {
|
|
990
|
+
'application/json': {
|
|
991
|
+
schema: { $ref: '#/components/schemas/Error' },
|
|
992
|
+
},
|
|
993
|
+
},
|
|
994
|
+
},
|
|
995
|
+
'404NotFound': {
|
|
996
|
+
description: 'Resource not found',
|
|
997
|
+
content: {
|
|
998
|
+
'application/json': {
|
|
999
|
+
schema: { $ref: '#/components/schemas/Error' },
|
|
1000
|
+
},
|
|
1001
|
+
},
|
|
1002
|
+
},
|
|
1003
|
+
'409Conflict': {
|
|
1004
|
+
description: 'Resource conflict',
|
|
1005
|
+
content: {
|
|
1006
|
+
'application/json': {
|
|
1007
|
+
schema: { $ref: '#/components/schemas/Error' },
|
|
1008
|
+
},
|
|
1009
|
+
},
|
|
1010
|
+
},
|
|
1011
|
+
'422UnprocessableEntity': {
|
|
1012
|
+
description: 'Validation error',
|
|
1013
|
+
content: {
|
|
1014
|
+
'application/json': {
|
|
1015
|
+
schema: { $ref: '#/components/schemas/ValidationError' },
|
|
1016
|
+
},
|
|
1017
|
+
},
|
|
1018
|
+
},
|
|
1019
|
+
'429TooManyRequests': {
|
|
1020
|
+
description: 'Rate limit exceeded',
|
|
1021
|
+
headers: {
|
|
1022
|
+
'X-RateLimit-Limit': {
|
|
1023
|
+
schema: { type: 'integer' },
|
|
1024
|
+
description: 'Request limit per hour',
|
|
1025
|
+
},
|
|
1026
|
+
'X-RateLimit-Remaining': {
|
|
1027
|
+
schema: { type: 'integer' },
|
|
1028
|
+
description: 'Remaining requests',
|
|
1029
|
+
},
|
|
1030
|
+
'X-RateLimit-Reset': {
|
|
1031
|
+
schema: { type: 'integer' },
|
|
1032
|
+
description: 'Unix timestamp when limit resets',
|
|
1033
|
+
},
|
|
1034
|
+
},
|
|
1035
|
+
content: {
|
|
1036
|
+
'application/json': {
|
|
1037
|
+
schema: { $ref: '#/components/schemas/Error' },
|
|
1038
|
+
},
|
|
1039
|
+
},
|
|
1040
|
+
},
|
|
1041
|
+
'500InternalServerError': {
|
|
1042
|
+
description: 'Internal server error',
|
|
1043
|
+
content: {
|
|
1044
|
+
'application/json': {
|
|
1045
|
+
schema: { $ref: '#/components/schemas/Error' },
|
|
1046
|
+
},
|
|
1047
|
+
},
|
|
1048
|
+
},
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
private generateId(prefix: string): string {
|
|
1053
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
private pluralize(word: string): string {
|
|
1057
|
+
// Simple pluralization
|
|
1058
|
+
if (word.endsWith('y')) {
|
|
1059
|
+
return word.slice(0, -1) + 'ies';
|
|
1060
|
+
}
|
|
1061
|
+
if (word.endsWith('s')) {
|
|
1062
|
+
return word + 'es';
|
|
1063
|
+
}
|
|
1064
|
+
return word + 's';
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
private capitalize(word: string): string {
|
|
1068
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
private uncapitalize(word: string): string {
|
|
1072
|
+
return word.charAt(0).toLowerCase() + word.slice(1);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
private toEnumKey(value: string): string {
|
|
1076
|
+
return value.toUpperCase().replace(/[^A-Z0-9]/g, '_');
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// Supporting classes
|
|
1081
|
+
class SpecificationValidator {
|
|
1082
|
+
async validateOpenAPI(spec: OpenAPISpecification): Promise<void> {
|
|
1083
|
+
// Validate against OpenAPI schema
|
|
1084
|
+
// Check for required fields
|
|
1085
|
+
// Validate references
|
|
1086
|
+
// Check for circular references
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
async validateGraphQLSchema(schema: GraphQLSchema): Promise<void> {
|
|
1090
|
+
// Validate schema
|
|
1091
|
+
// Check for orphaned types
|
|
1092
|
+
// Validate directives
|
|
1093
|
+
// Check query complexity
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
class CodeGenerator {
|
|
1098
|
+
generateTypeScript(spec: APISpecification): string {
|
|
1099
|
+
// Generate TypeScript code
|
|
1100
|
+
return '';
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
generatePython(spec: APISpecification): string {
|
|
1104
|
+
// Generate Python code
|
|
1105
|
+
return '';
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
generateGo(spec: APISpecification): string {
|
|
1109
|
+
// Generate Go code
|
|
1110
|
+
return '';
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// Type definitions
|
|
1115
|
+
enum APIType {
|
|
1116
|
+
REST = 'rest',
|
|
1117
|
+
GRAPHQL = 'graphql',
|
|
1118
|
+
GRPC = 'grpc',
|
|
1119
|
+
WEBSOCKET = 'websocket',
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
enum HTTPMethod {
|
|
1123
|
+
GET = 'GET',
|
|
1124
|
+
POST = 'POST',
|
|
1125
|
+
PUT = 'PUT',
|
|
1126
|
+
PATCH = 'PATCH',
|
|
1127
|
+
DELETE = 'DELETE',
|
|
1128
|
+
HEAD = 'HEAD',
|
|
1129
|
+
OPTIONS = 'OPTIONS',
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
interface APISpecification {
|
|
1133
|
+
name: string;
|
|
1134
|
+
version: string;
|
|
1135
|
+
type: APIType;
|
|
1136
|
+
baseUrl?: string;
|
|
1137
|
+
paths?: any;
|
|
1138
|
+
components?: any;
|
|
1139
|
+
tags?: Tag[];
|
|
1140
|
+
servers?: Server[];
|
|
1141
|
+
security?: SecurityRequirement[];
|
|
1142
|
+
targetLanguage?: string;
|
|
1143
|
+
previousVersion?: APISpecification;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
interface OpenAPISpecification extends APISpecification {
|
|
1147
|
+
openapi: string;
|
|
1148
|
+
info: Info;
|
|
1149
|
+
paths: Paths;
|
|
1150
|
+
components: Components;
|
|
1151
|
+
security?: SecurityRequirement[];
|
|
1152
|
+
tags?: Tag[];
|
|
1153
|
+
servers?: Server[];
|
|
1154
|
+
externalDocs?: ExternalDocumentation;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
interface GraphQLDesign {
|
|
1158
|
+
schema: GraphQLSchema;
|
|
1159
|
+
sdl: string;
|
|
1160
|
+
resolvers: any;
|
|
1161
|
+
documentation: any;
|
|
1162
|
+
examples: any[];
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
interface APIRequirements {
|
|
1166
|
+
name: string;
|
|
1167
|
+
description: string;
|
|
1168
|
+
version: string;
|
|
1169
|
+
entities: Entity[];
|
|
1170
|
+
useCases: UseCase[];
|
|
1171
|
+
authentication?: AuthRequirement;
|
|
1172
|
+
authorization?: AuthzRequirement;
|
|
1173
|
+
rateLimiting?: RateLimitRequirement;
|
|
1174
|
+
pagination?: PaginationRequirement;
|
|
1175
|
+
supportPatch?: boolean;
|
|
1176
|
+
usePagination?: boolean;
|
|
1177
|
+
includeSearch?: boolean;
|
|
1178
|
+
includeBatchOperations?: boolean;
|
|
1179
|
+
documentation?: any;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
interface Entity {
|
|
1183
|
+
name: string;
|
|
1184
|
+
description: string;
|
|
1185
|
+
properties: Property[];
|
|
1186
|
+
relationships: Relationship[];
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
interface Property {
|
|
1190
|
+
name: string;
|
|
1191
|
+
type: string;
|
|
1192
|
+
required: boolean;
|
|
1193
|
+
description: string;
|
|
1194
|
+
constraints?: Constraint[];
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
interface Relationship {
|
|
1198
|
+
type: string;
|
|
1199
|
+
target: string;
|
|
1200
|
+
cardinality: string;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
interface Constraint {
|
|
1204
|
+
type: string;
|
|
1205
|
+
value: any;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
interface UseCase {
|
|
1209
|
+
name: string;
|
|
1210
|
+
description: string;
|
|
1211
|
+
actors: string[];
|
|
1212
|
+
preconditions: string[];
|
|
1213
|
+
steps: string[];
|
|
1214
|
+
postconditions: string[];
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
interface AuthRequirement {
|
|
1218
|
+
type: string;
|
|
1219
|
+
flows: string[];
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
interface AuthzRequirement {
|
|
1223
|
+
model: string;
|
|
1224
|
+
roles: string[];
|
|
1225
|
+
permissions: string[];
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
interface RateLimitRequirement {
|
|
1229
|
+
default: number;
|
|
1230
|
+
endpoints: Record<string, number>;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
interface PaginationRequirement {
|
|
1234
|
+
defaultLimit: number;
|
|
1235
|
+
maxLimit: number;
|
|
1236
|
+
style: 'offset' | 'cursor' | 'page';
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
interface RequirementAnalysis {
|
|
1240
|
+
entities: Entity[];
|
|
1241
|
+
operations: Operation[];
|
|
1242
|
+
constraints: Constraint[];
|
|
1243
|
+
nonFunctional: NonFunctionalRequirement[];
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
interface Resource {
|
|
1247
|
+
id: string;
|
|
1248
|
+
name: string;
|
|
1249
|
+
plural: string;
|
|
1250
|
+
description: string;
|
|
1251
|
+
attributes: Attribute[];
|
|
1252
|
+
relationships: ResourceRelationship[];
|
|
1253
|
+
operations: string[];
|
|
1254
|
+
uri: string;
|
|
1255
|
+
subresources: Resource[];
|
|
1256
|
+
customActions?: CustomAction[];
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
interface Attribute {
|
|
1260
|
+
name: string;
|
|
1261
|
+
type: string;
|
|
1262
|
+
required: boolean;
|
|
1263
|
+
description: string;
|
|
1264
|
+
validation?: any;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
interface ResourceRelationship {
|
|
1268
|
+
name: string;
|
|
1269
|
+
type: string;
|
|
1270
|
+
target: string;
|
|
1271
|
+
cardinality: string;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
interface CustomAction {
|
|
1275
|
+
name: string;
|
|
1276
|
+
method: HTTPMethod;
|
|
1277
|
+
path: string;
|
|
1278
|
+
description: string;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
interface Operation {
|
|
1282
|
+
type: string;
|
|
1283
|
+
resource: string;
|
|
1284
|
+
description: string;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
interface NonFunctionalRequirement {
|
|
1288
|
+
type: string;
|
|
1289
|
+
requirement: string;
|
|
1290
|
+
metric: string;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
interface OperationObject {
|
|
1294
|
+
operationId: string;
|
|
1295
|
+
summary: string;
|
|
1296
|
+
description: string;
|
|
1297
|
+
tags: string[];
|
|
1298
|
+
parameters?: Parameter[];
|
|
1299
|
+
requestBody?: RequestBody;
|
|
1300
|
+
responses: ResponseObject[];
|
|
1301
|
+
security?: SecurityRequirement[];
|
|
1302
|
+
deprecated?: boolean;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
interface Parameter {
|
|
1306
|
+
name: string;
|
|
1307
|
+
in: string;
|
|
1308
|
+
required: boolean;
|
|
1309
|
+
description: string;
|
|
1310
|
+
schema: any;
|
|
1311
|
+
style?: string;
|
|
1312
|
+
explode?: boolean;
|
|
1313
|
+
example?: any;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
interface RequestBody {
|
|
1317
|
+
required: boolean;
|
|
1318
|
+
description?: string;
|
|
1319
|
+
content: Record<string, MediaType>;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
interface MediaType {
|
|
1323
|
+
schema: any;
|
|
1324
|
+
examples?: Record<string, any>;
|
|
1325
|
+
example?: any;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
interface ResponseObject {
|
|
1329
|
+
status: string;
|
|
1330
|
+
description: string;
|
|
1331
|
+
headers?: Record<string, any>;
|
|
1332
|
+
content?: Record<string, MediaType>;
|
|
1333
|
+
links?: Record<string, any>;
|
|
1334
|
+
$ref?: string;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
interface SecurityRequirement {
|
|
1338
|
+
[key: string]: string[];
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
interface AuthenticationScheme {
|
|
1342
|
+
type: string;
|
|
1343
|
+
scheme?: string;
|
|
1344
|
+
bearerFormat?: string;
|
|
1345
|
+
flows?: any;
|
|
1346
|
+
openIdConnectUrl?: string;
|
|
1347
|
+
description?: string;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
interface AuthorizationModel {
|
|
1351
|
+
type: string;
|
|
1352
|
+
roles: Role[];
|
|
1353
|
+
permissions: Permission[];
|
|
1354
|
+
policies: Policy[];
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
interface Role {
|
|
1358
|
+
name: string;
|
|
1359
|
+
description: string;
|
|
1360
|
+
permissions: string[];
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
interface Permission {
|
|
1364
|
+
name: string;
|
|
1365
|
+
resource: string;
|
|
1366
|
+
action: string;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
interface Policy {
|
|
1370
|
+
name: string;
|
|
1371
|
+
effect: string;
|
|
1372
|
+
conditions: any[];
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
interface RateLimitPolicy {
|
|
1376
|
+
default: RateLimit;
|
|
1377
|
+
endpoints: Map<string, RateLimit>;
|
|
1378
|
+
tiers: RateLimitTier[];
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
interface RateLimit {
|
|
1382
|
+
requests: number;
|
|
1383
|
+
window: string;
|
|
1384
|
+
strategy: string;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
interface RateLimitTier {
|
|
1388
|
+
name: string;
|
|
1389
|
+
limits: RateLimit;
|
|
1390
|
+
price?: number;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
interface VersioningStrategy {
|
|
1394
|
+
type: 'uri' | 'header' | 'query' | 'media-type';
|
|
1395
|
+
format: string;
|
|
1396
|
+
default: string;
|
|
1397
|
+
supported: string[];
|
|
1398
|
+
deprecation: DeprecationPolicy;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
interface DeprecationPolicy {
|
|
1402
|
+
notice: string;
|
|
1403
|
+
sunset: string;
|
|
1404
|
+
migration: string;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
interface APIDocumentation {
|
|
1408
|
+
format: string;
|
|
1409
|
+
sections: DocumentationSection[];
|
|
1410
|
+
examples: Example[];
|
|
1411
|
+
tutorials: Tutorial[];
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
interface DocumentationSection {
|
|
1415
|
+
title: string;
|
|
1416
|
+
content: string;
|
|
1417
|
+
subsections?: DocumentationSection[];
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
interface Example {
|
|
1421
|
+
title: string;
|
|
1422
|
+
description: string;
|
|
1423
|
+
request: any;
|
|
1424
|
+
response: any;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
interface Tutorial {
|
|
1428
|
+
title: string;
|
|
1429
|
+
steps: TutorialStep[];
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
interface TutorialStep {
|
|
1433
|
+
title: string;
|
|
1434
|
+
description: string;
|
|
1435
|
+
code: string;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
interface TestStrategy {
|
|
1439
|
+
unit: boolean;
|
|
1440
|
+
integration: boolean;
|
|
1441
|
+
contract: boolean;
|
|
1442
|
+
performance: boolean;
|
|
1443
|
+
security: boolean;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
interface MonitoringConfig {
|
|
1447
|
+
metrics: string[];
|
|
1448
|
+
logging: LoggingConfig;
|
|
1449
|
+
tracing: TracingConfig;
|
|
1450
|
+
alerts: Alert[];
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
interface LoggingConfig {
|
|
1454
|
+
level: string;
|
|
1455
|
+
format: string;
|
|
1456
|
+
destination: string;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
interface TracingConfig {
|
|
1460
|
+
enabled: boolean;
|
|
1461
|
+
sampling: number;
|
|
1462
|
+
backend: string;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
interface Alert {
|
|
1466
|
+
name: string;
|
|
1467
|
+
condition: string;
|
|
1468
|
+
threshold: number;
|
|
1469
|
+
action: string;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
interface DesignPattern {
|
|
1473
|
+
name: string;
|
|
1474
|
+
description: string;
|
|
1475
|
+
context: string;
|
|
1476
|
+
solution: any;
|
|
1477
|
+
examples: any[];
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
interface GraphQLType {
|
|
1481
|
+
kind: string;
|
|
1482
|
+
name: string;
|
|
1483
|
+
description: string;
|
|
1484
|
+
fields: Field[];
|
|
1485
|
+
interfaces?: string[];
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
interface Field {
|
|
1489
|
+
name: string;
|
|
1490
|
+
type: string;
|
|
1491
|
+
description: string;
|
|
1492
|
+
args?: Argument[];
|
|
1493
|
+
deprecated?: boolean;
|
|
1494
|
+
deprecationReason?: string;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
interface Argument {
|
|
1498
|
+
name: string;
|
|
1499
|
+
type: string;
|
|
1500
|
+
description: string;
|
|
1501
|
+
defaultValue?: any;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
interface Query {
|
|
1505
|
+
name: string;
|
|
1506
|
+
description: string;
|
|
1507
|
+
args: Argument[];
|
|
1508
|
+
returnType: string;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
interface Mutation {
|
|
1512
|
+
name: string;
|
|
1513
|
+
description: string;
|
|
1514
|
+
args: Argument[];
|
|
1515
|
+
returnType: string;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
interface Subscription {
|
|
1519
|
+
name: string;
|
|
1520
|
+
description: string;
|
|
1521
|
+
args: Argument[];
|
|
1522
|
+
returnType: string;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
interface ClientSDK {
|
|
1526
|
+
language: string;
|
|
1527
|
+
name: string;
|
|
1528
|
+
version: string;
|
|
1529
|
+
files: ClientFile[];
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
interface ClientFile {
|
|
1533
|
+
name: string;
|
|
1534
|
+
content: string;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
interface ValidationResult {
|
|
1538
|
+
valid: boolean;
|
|
1539
|
+
issues: ValidationIssue[];
|
|
1540
|
+
score: number;
|
|
1541
|
+
recommendations: string[];
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
interface ValidationIssue {
|
|
1545
|
+
type: string;
|
|
1546
|
+
severity: string;
|
|
1547
|
+
message: string;
|
|
1548
|
+
location?: string;
|
|
1549
|
+
suggestion?: string;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
interface Info {
|
|
1553
|
+
title: string;
|
|
1554
|
+
version: string;
|
|
1555
|
+
description?: string;
|
|
1556
|
+
termsOfService?: string;
|
|
1557
|
+
contact?: Contact;
|
|
1558
|
+
license?: License;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
interface Contact {
|
|
1562
|
+
name?: string;
|
|
1563
|
+
url?: string;
|
|
1564
|
+
email?: string;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
interface License {
|
|
1568
|
+
name: string;
|
|
1569
|
+
url?: string;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
interface Server {
|
|
1573
|
+
url: string;
|
|
1574
|
+
description?: string;
|
|
1575
|
+
variables?: Record<string, ServerVariable>;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
interface ServerVariable {
|
|
1579
|
+
enum?: string[];
|
|
1580
|
+
default: string;
|
|
1581
|
+
description?: string;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
interface Tag {
|
|
1585
|
+
name: string;
|
|
1586
|
+
description?: string;
|
|
1587
|
+
externalDocs?: ExternalDocumentation;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
interface ExternalDocumentation {
|
|
1591
|
+
description?: string;
|
|
1592
|
+
url: string;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
interface Paths {
|
|
1596
|
+
[path: string]: PathItem;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
interface PathItem {
|
|
1600
|
+
[method: string]: Operation;
|
|
1601
|
+
$ref?: string;
|
|
1602
|
+
summary?: string;
|
|
1603
|
+
description?: string;
|
|
1604
|
+
servers?: Server[];
|
|
1605
|
+
parameters?: Parameter[];
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
interface Components {
|
|
1609
|
+
schemas?: Record<string, any>;
|
|
1610
|
+
responses?: Record<string, any>;
|
|
1611
|
+
parameters?: Record<string, any>;
|
|
1612
|
+
examples?: Record<string, any>;
|
|
1613
|
+
requestBodies?: Record<string, any>;
|
|
1614
|
+
headers?: Record<string, any>;
|
|
1615
|
+
securitySchemes?: Record<string, any>;
|
|
1616
|
+
links?: Record<string, any>;
|
|
1617
|
+
callbacks?: Record<string, any>;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// Export the designer
|
|
1621
|
+
export { APIDesigner, APIDesign, OpenAPISpecification };
|
|
1622
|
+
```
|
|
1623
|
+
|
|
1624
|
+
## Best Practices
|
|
1625
|
+
1. **RESTful Principles**: Follow REST architectural constraints
|
|
1626
|
+
2. **Consistent Naming**: Use consistent naming conventions
|
|
1627
|
+
3. **Versioning Strategy**: Plan for API evolution
|
|
1628
|
+
4. **Error Handling**: Provide clear, actionable error messages
|
|
1629
|
+
5. **Documentation**: Comprehensive, up-to-date documentation
|
|
1630
|
+
6. **Security First**: Design with security in mind
|
|
1631
|
+
7. **Performance**: Consider caching and pagination
|
|
1632
|
+
|
|
1633
|
+
## API Design Principles
|
|
1634
|
+
- Resource-based URLs (nouns, not verbs)
|
|
1635
|
+
- Use HTTP methods appropriately
|
|
1636
|
+
- Stateless communication
|
|
1637
|
+
- HATEOAS when applicable
|
|
1638
|
+
- Standard status codes
|
|
1639
|
+
- Content negotiation
|
|
1640
|
+
- Idempotent operations
|
|
1641
|
+
|
|
1642
|
+
## Approach
|
|
1643
|
+
- Understand business requirements
|
|
1644
|
+
- Design resource model
|
|
1645
|
+
- Define operations and endpoints
|
|
1646
|
+
- Create data schemas
|
|
1647
|
+
- Design authentication/authorization
|
|
1648
|
+
- Document comprehensively
|
|
1649
|
+
- Generate client SDKs
|
|
1650
|
+
|
|
1651
|
+
## Output Format
|
|
1652
|
+
- Provide complete API specifications
|
|
1653
|
+
- Include OpenAPI/Swagger documentation
|
|
1654
|
+
- Generate client SDK code
|
|
1655
|
+
- Add testing strategies
|
|
1656
|
+
- Include security considerations
|
|
1657
|
+
- Provide migration guides
|