@caddis/cli 0.2.6 → 0.4.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/bundles/antigravity-plugin/agents/claude-md-curator.md +1 -1
- package/bundles/antigravity-plugin/agents/knowledge-transfer.md +17 -32
- package/bundles/antigravity-plugin/caddis_statusline.py +825 -0
- package/bundles/antigravity-plugin/claude-md/folder-agents.md.tmpl +21 -0
- package/bundles/antigravity-plugin/guard_agy.py +60 -9
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/scripts/caddis_gate.py +524 -0
- package/bundles/antigravity-plugin/scripts/caddis_inventory.py +439 -0
- package/bundles/antigravity-plugin/scripts/caddis_migrate_dir.py +270 -0
- package/bundles/antigravity-plugin/scripts/caddis_spawn.py +300 -0
- package/bundles/antigravity-plugin/scripts/caddis_statusline.py +825 -0
- package/bundles/antigravity-plugin/scripts/caddis_tidy.py +366 -0
- package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +924 -0
- package/bundles/antigravity-plugin/scripts/claude-deepseek.ps1 +4 -0
- package/bundles/antigravity-plugin/scripts/claude-deepseek.sh +3 -0
- package/bundles/antigravity-plugin/scripts/claude-glm.ps1 +4 -0
- package/bundles/antigravity-plugin/scripts/claude-glm.sh +3 -0
- package/bundles/antigravity-plugin/scripts/claude-oss.ps1 +64 -0
- package/bundles/antigravity-plugin/scripts/claude-oss.sh +60 -0
- package/bundles/antigravity-plugin/scripts/claudster_config.py +121 -0
- package/bundles/antigravity-plugin/scripts/claudster_doctor.py +356 -0
- package/bundles/antigravity-plugin/scripts/claudster_init.py +400 -0
- package/bundles/antigravity-plugin/scripts/claudster_migrate_rules.py +300 -0
- package/bundles/antigravity-plugin/scripts/enforcement_inventory.py +261 -0
- package/bundles/antigravity-plugin/scripts/hook_log.py +156 -0
- package/bundles/antigravity-plugin/scripts/new-machine.ps1 +170 -0
- package/bundles/antigravity-plugin/scripts/oss_ask.py +98 -0
- package/bundles/antigravity-plugin/scripts/oss_model.py +174 -0
- package/bundles/antigravity-plugin/scripts/oss_review.py +718 -0
- package/bundles/antigravity-plugin/scripts/setup_project_ai.py +1432 -0
- package/bundles/antigravity-plugin/scripts/usage_review.py +1323 -0
- package/bundles/antigravity-plugin/session_end_agy.py +52 -8
- package/bundles/antigravity-plugin/skills/_registry.md +1 -0
- package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +44 -0
- package/bundles/antigravity-plugin/skills/code-review/SKILL.md +11 -0
- package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +21 -0
- package/bundles/antigravity-plugin/skills/gate-review/SKILL.md +11 -0
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +36 -0
- package/bundles/antigravity-plugin/skills/security-review/SKILL.md +9 -0
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/statusline/SKILL.md +105 -0
- package/bundles/antigravity-plugin/skills/use-model/SKILL.md +15 -3
- package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +31 -0
- package/bundles/antigravity-plugin/warm_start_agy.py +117 -11
- package/bundles/antigravity-plugin-extras/plugin.json +1 -1
- package/bundles/antigravity-plugin-extras/skills/architecture-design/SKILL.md +1 -1
- package/bundles/antigravity-plugin-extras/skills/caching-patterns/SKILL.md +1 -1
- package/bundles/antigravity-plugin-extras/skills/webapp-development/SKILL.md +1 -1
- package/bundles/codex/.codex/config.toml.example +36 -0
- package/bundles/codex/.codex/skills/coding/api-design/SKILL.md +249 -0
- package/bundles/codex/.codex/skills/coding/backend-development/SKILL.md +305 -0
- package/bundles/codex/.codex/skills/coding/code-review/SKILL.md +140 -0
- package/bundles/codex/.codex/skills/coding/codebase-audit/SKILL.md +204 -0
- package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/SKILL.md +132 -0
- package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/scripts/perf_sweep.py +249 -0
- package/bundles/codex/.codex/skills/coding/error-handling/SKILL.md +260 -0
- package/bundles/codex/.codex/skills/coding/fastapi-dev/SKILL.md +300 -0
- package/bundles/codex/.codex/skills/coding/javascript-typescript/SKILL.md +142 -0
- package/bundles/codex/.codex/skills/coding/python/SKILL.md +388 -0
- package/bundles/codex/.codex/skills/coding/refactoring/SKILL.md +486 -0
- package/bundles/codex/.codex/skills/coding/security-review/SKILL.md +205 -0
- package/bundles/codex/.codex/skills/coding/sql/SKILL.md +321 -0
- package/bundles/codex/.codex/skills/data/database-design/SKILL.md +177 -0
- package/bundles/codex/.codex/skills/data/db-diagram/SKILL.md +148 -0
- package/bundles/codex/.codex/skills/data/db-diagram/scripts/sql_to_graph.py +1212 -0
- package/bundles/codex/.codex/skills/devops/ci-cd-pipeline/SKILL.md +315 -0
- package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +195 -0
- package/bundles/codex/.codex/skills/devops/git-commit/SKILL.md +285 -0
- package/bundles/codex/.codex/skills/devops/using-git-worktrees/SKILL.md +217 -0
- package/bundles/codex/.codex/skills/devops/windows-deployment/SKILL.md +880 -0
- package/bundles/codex/.codex/skills/docs/code-documentation/SKILL.md +271 -0
- package/bundles/codex/.codex/skills/docs/explainer-doc/SKILL.md +97 -0
- package/bundles/codex/.codex/skills/docs/technical-writing/SKILL.md +286 -0
- package/bundles/codex/.codex/skills/docs/writing-plans/SKILL.md +387 -0
- package/bundles/codex/.codex/skills/frontend/css-architecture/SKILL.md +305 -0
- package/bundles/codex/.codex/skills/frontend/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
- package/bundles/codex/.codex/skills/frontend/frontend-design/SKILL.md +193 -0
- package/bundles/codex/.codex/skills/frontend/frontend-design/references/my-tech-stack.md +127 -0
- package/bundles/codex/.codex/skills/frontend/mockup/SKILL.md +242 -0
- package/bundles/codex/.codex/skills/frontend/react-best-practices/SKILL.md +269 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/README.md +404 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/SKILL.md +459 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/examples/generic-components.md +579 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/examples/server-components.md +579 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/event-handlers.md +574 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/hooks.md +456 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/react-19-patterns.md +638 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/react-router.md +1002 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/tanstack-router.md +587 -0
- package/bundles/codex/.codex/skills/frontend/ui-review/SKILL.md +176 -0
- package/bundles/codex/.codex/skills/frontend/ui-review/references/framework-fixes.md +471 -0
- package/bundles/codex/.codex/skills/frontend/ui-review/references/visual-checklist.md +236 -0
- package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
- package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
- package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/SKILL.md +732 -0
- package/bundles/codex/.codex/skills/media/draw-io/SKILL.md +162 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/aws-icons.md +677 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/layout-guidelines.md +142 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/troubleshooting.md +118 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/workflows.md +103 -0
- package/bundles/codex/.codex/skills/media/draw-io/scripts/convert-drawio-to-png.sh +25 -0
- package/bundles/codex/.codex/skills/media/draw-io/scripts/find_aws_icon.py +79 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/SKILL.md +292 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/advanced-features.md +556 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/architecture-diagrams.md +192 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/c4-diagrams.md +410 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/class-diagrams.md +361 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/erd-diagrams.md +510 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/flowcharts.md +450 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/sequence-diagrams.md +394 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/troubleshooting.md +335 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/workflows.md +418 -0
- package/bundles/codex/.codex/skills/media/particle-art/SKILL.md +243 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/canvas-utils.ts +171 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/dot-field.template.tsx +203 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/flow-field.template.tsx +263 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/node-shape.template.tsx +261 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/shape-sampler.ts +281 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/stipple-morph.template.tsx +167 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/stipple.template.tsx +175 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/trail-ghost.template.tsx +266 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/usage-examples.md +320 -0
- package/bundles/codex/.codex/skills/testing/playwright/API_REFERENCE.md +653 -0
- package/bundles/codex/.codex/skills/testing/playwright/SKILL.md +454 -0
- package/bundles/codex/.codex/skills/testing/playwright/lib/helpers.js +441 -0
- package/bundles/codex/.codex/skills/testing/playwright/package.json +26 -0
- package/bundles/codex/.codex/skills/testing/playwright/run.js +228 -0
- package/bundles/codex/.codex/skills/testing/tdd-workflow/SKILL.md +188 -0
- package/bundles/codex/.codex/skills/testing/test-strategy/SKILL.md +155 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/LICENSE.txt +202 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/SKILL.md +97 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/examples/console_logging.py +35 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/examples/element_discovery.py +40 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/examples/static_html_automation.py +33 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/scripts/with_server.py +106 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +227 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +214 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +233 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +94 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +118 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/SKILL.md +500 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +263 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +326 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +245 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/anti-patterns.md +571 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/before-after-examples.md +1114 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/best-practices-guide.md +513 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/common-workflows.md +692 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/prompt-patterns.md +547 -0
- package/bundles/codex/.codex/skills/workflow/brainstorming/SKILL.md +57 -0
- package/bundles/codex/.codex/skills/workflow/context-curator/SKILL.md +157 -0
- package/bundles/codex/.codex/skills/workflow/golden-plan/SKILL.md +586 -0
- package/bundles/codex/.codex/skills/workflow/preflight/SKILL.md +440 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/LICENSE.txt +202 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/SKILL.md +491 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/agents/analyzer.md +274 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/agents/comparator.md +202 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/agents/grader.md +223 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/assets/eval_review.html +146 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/generate_review.py +471 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/viewer.html +1325 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/references/schemas.md +430 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/__init__.py +0 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/generate_report.py +326 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/improve_description.py +247 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/package_skill.py +136 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/quick_validate.py +103 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_eval.py +310 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_loop.py +328 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/utils.py +47 -0
- package/bundles/codex/AGENTS.md +146 -0
- package/bundles/manifest.json +4 -3
- package/dist/claude-deepseek.js +544 -0
- package/dist/claude-glm.js +544 -0
- package/dist/claude-oss.js +544 -0
- package/dist/cli.js +542 -90
- package/package.json +5 -2
- package/bundles/antigravity-plugin/statusline-command-agy.sh +0 -91
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
|
@@ -283,6 +283,6 @@ st.plotly_chart(create_trend_chart(filter_type), use_container_width=True)
|
|
|
283
283
|
|----------|------|
|
|
284
284
|
| Streamlit dev skill | `skills/frontend/streamlit-dev/SKILL.md` |
|
|
285
285
|
| FastAPI dev skill | `skills/coding/fastapi-dev/SKILL.md` |
|
|
286
|
-
| SQL expert skill | `
|
|
286
|
+
| SQL expert skill | the `sql` skill |
|
|
287
287
|
| Caching patterns | `skills/coding/caching-patterns/SKILL.md` |
|
|
288
288
|
| UX design skill | `skills/frontend/ux-design/SKILL.md` |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Codex CLI configuration example
|
|
2
|
+
# Copy to ~/.codex/config.toml (user-level, all projects)
|
|
3
|
+
# or <project>/.codex/config.toml (project-level; project must be trusted)
|
|
4
|
+
#
|
|
5
|
+
# Add a server interactively: codex mcp add <name> -- <command> [args...]
|
|
6
|
+
# Verify loaded servers: codex mcp list
|
|
7
|
+
|
|
8
|
+
# ── Model (adjust to your OpenAI tier) ───────────────────────────────────────
|
|
9
|
+
# model = "codex-mini-latest"
|
|
10
|
+
|
|
11
|
+
# ── Skills ────────────────────────────────────────────────────────────────────
|
|
12
|
+
# Project skills: <project>/.codex/skills/<category>/<name>/SKILL.md
|
|
13
|
+
# User skills: ~/.codex/skills/<name>/SKILL.md (no category subdir)
|
|
14
|
+
# (Paths probed from codex 0.137 — see docs/analysis/codex-cli-contract.md.
|
|
15
|
+
# .agents/ is codex's PLUGINS root, not a skills root.)
|
|
16
|
+
#
|
|
17
|
+
# Disable a skill without deleting it:
|
|
18
|
+
# [[skills.config]]
|
|
19
|
+
# path = ".codex/skills/devops/windows-deployment"
|
|
20
|
+
# enabled = false
|
|
21
|
+
|
|
22
|
+
# ── junai MCP (pipeline state + project context) ─────────────────────────────
|
|
23
|
+
# OFF by default. The junai MCP server tracks pipeline stage and project state
|
|
24
|
+
# across sessions. Enable when the server is available locally.
|
|
25
|
+
#
|
|
26
|
+
# Prerequisites:
|
|
27
|
+
# pip install junai-mcp (or: uv tool install junai-mcp)
|
|
28
|
+
# codex mcp add junai -- python -m junai_mcp --project-root .
|
|
29
|
+
#
|
|
30
|
+
# Or add the block below manually and run `codex mcp list` to confirm:
|
|
31
|
+
#
|
|
32
|
+
# [[mcp_servers]]
|
|
33
|
+
# name = "junai"
|
|
34
|
+
# command = "python"
|
|
35
|
+
# args = ["-m", "junai_mcp", "--project-root", "."]
|
|
36
|
+
# env = {}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-design
|
|
3
|
+
description: REST and GraphQL API design patterns. Use when designing new API endpoints, defining resource schemas, planning versioning strategies, or reviewing API contracts. Covers naming conventions, pagination, filtering, error responses, and OpenAPI documentation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# API Design Skill
|
|
7
|
+
|
|
8
|
+
Design APIs that are consistent, discoverable, and hard to misuse. Conventions over configuration.
|
|
9
|
+
|
|
10
|
+
## 1. When to Apply This Skill
|
|
11
|
+
|
|
12
|
+
**Trigger conditions:**
|
|
13
|
+
- Designing new API endpoints or a full API surface
|
|
14
|
+
- "What should this endpoint look like?"
|
|
15
|
+
- Planning API versioning or migration
|
|
16
|
+
- Reviewing API contracts for consistency
|
|
17
|
+
- Building an API spec or OpenAPI document
|
|
18
|
+
|
|
19
|
+
## 2. REST Resource Naming
|
|
20
|
+
|
|
21
|
+
### URL Convention
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
# Resources are nouns, plural, lowercase, kebab-case
|
|
25
|
+
GET /api/v1/customers # List
|
|
26
|
+
GET /api/v1/customers/{id} # Get one
|
|
27
|
+
POST /api/v1/customers # Create
|
|
28
|
+
PUT /api/v1/customers/{id} # Full update
|
|
29
|
+
PATCH /api/v1/customers/{id} # Partial update
|
|
30
|
+
DELETE /api/v1/customers/{id} # Delete
|
|
31
|
+
|
|
32
|
+
# Nested resources for strong ownership
|
|
33
|
+
GET /api/v1/customers/{id}/orders # Customer's orders
|
|
34
|
+
POST /api/v1/customers/{id}/orders # Create order for customer
|
|
35
|
+
|
|
36
|
+
# Actions (when CRUD doesn't fit) — verb suffix
|
|
37
|
+
POST /api/v1/orders/{id}/cancel # Action on resource
|
|
38
|
+
POST /api/v1/reports/generate # Trigger async operation
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Naming Rules
|
|
42
|
+
|
|
43
|
+
| Rule | Good | Bad |
|
|
44
|
+
|------|------|-----|
|
|
45
|
+
| Plural nouns | `/customers` | `/customer`, `/getCustomers` |
|
|
46
|
+
| Kebab-case | `/order-items` | `/orderItems`, `/order_items` |
|
|
47
|
+
| No verbs in path | `/customers` (POST = create) | `/createCustomer` |
|
|
48
|
+
| Consistent nesting depth | Max 2 levels: `/customers/{id}/orders` | `/customers/{id}/orders/{id}/items/{id}/details` |
|
|
49
|
+
| No trailing slash | `/customers` | `/customers/` |
|
|
50
|
+
|
|
51
|
+
## 3. Request & Response Envelope
|
|
52
|
+
|
|
53
|
+
### Success Response
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"data": { ... },
|
|
58
|
+
"meta": {
|
|
59
|
+
"request_id": "req_abc123",
|
|
60
|
+
"timestamp": "2025-01-15T10:30:00Z"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### List Response (with pagination)
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"data": [ ... ],
|
|
70
|
+
"pagination": {
|
|
71
|
+
"page": 1,
|
|
72
|
+
"per_page": 25,
|
|
73
|
+
"total": 142,
|
|
74
|
+
"total_pages": 6
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Error Response
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"error": {
|
|
84
|
+
"code": "VALIDATION_ERROR",
|
|
85
|
+
"message": "Request validation failed",
|
|
86
|
+
"details": [
|
|
87
|
+
{ "field": "email", "message": "Invalid email format" },
|
|
88
|
+
{ "field": "age", "message": "Must be at least 18" }
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 4. HTTP Status Codes
|
|
95
|
+
|
|
96
|
+
Use the right code. Clients depend on these for control flow.
|
|
97
|
+
|
|
98
|
+
| Code | When to Use |
|
|
99
|
+
|------|-------------|
|
|
100
|
+
| `200 OK` | Successful GET, PUT, PATCH |
|
|
101
|
+
| `201 Created` | Successful POST that creates a resource |
|
|
102
|
+
| `204 No Content` | Successful DELETE |
|
|
103
|
+
| `400 Bad Request` | Malformed request body or parameters |
|
|
104
|
+
| `401 Unauthorized` | Missing or invalid authentication |
|
|
105
|
+
| `403 Forbidden` | Authenticated but not authorized |
|
|
106
|
+
| `404 Not Found` | Resource doesn't exist |
|
|
107
|
+
| `409 Conflict` | Duplicate resource, version conflict |
|
|
108
|
+
| `422 Unprocessable Entity` | Valid syntax but semantic validation failed |
|
|
109
|
+
| `429 Too Many Requests` | Rate limit exceeded (include `Retry-After` header) |
|
|
110
|
+
| `500 Internal Server Error` | Unhandled server error |
|
|
111
|
+
|
|
112
|
+
## 5. Pagination
|
|
113
|
+
|
|
114
|
+
### Offset-based (simple, good for most cases)
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
GET /api/v1/customers?page=2&per_page=25
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Cursor-based (better for real-time data, large datasets)
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
GET /api/v1/events?cursor=eyJpZCI6MTAwfQ&limit=25
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
| Strategy | Pros | Cons |
|
|
127
|
+
|----------|------|------|
|
|
128
|
+
| Offset | Simple, supports jumping to page N | Skips/duplicates on mutations, slow at high offsets |
|
|
129
|
+
| Cursor | Consistent with mutations, performant | No "jump to page 5", harder to implement |
|
|
130
|
+
|
|
131
|
+
**Rule:** Use offset for admin/dashboard UIs. Use cursor for feeds, events, and public APIs.
|
|
132
|
+
|
|
133
|
+
## 6. Filtering, Sorting, and Search
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
# Filtering — field-level with operators
|
|
137
|
+
GET /api/v1/orders?status=open&created_after=2025-01-01
|
|
138
|
+
|
|
139
|
+
# Sorting — field with direction prefix
|
|
140
|
+
GET /api/v1/orders?sort=-created_at # descending
|
|
141
|
+
GET /api/v1/orders?sort=status,created_at # multi-field
|
|
142
|
+
|
|
143
|
+
# Search — dedicated parameter
|
|
144
|
+
GET /api/v1/customers?q=acme+corp
|
|
145
|
+
|
|
146
|
+
# Field selection — sparse fieldsets
|
|
147
|
+
GET /api/v1/customers?fields=id,name,email
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 7. Versioning
|
|
151
|
+
|
|
152
|
+
### URL Path versioning (recommended)
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
/api/v1/customers
|
|
156
|
+
/api/v2/customers
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Version lifecycle
|
|
160
|
+
|
|
161
|
+
| Phase | Duration | Behaviour |
|
|
162
|
+
|-------|----------|-----------|
|
|
163
|
+
| **Current** | Indefinite | Actively maintained |
|
|
164
|
+
| **Deprecated** | 6-12 months | Returns `Deprecation` header, still works |
|
|
165
|
+
| **Sunset** | After deprecation | Returns `410 Gone` |
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
# FastAPI deprecation header
|
|
169
|
+
@app.get("/api/v1/old-endpoint", deprecated=True)
|
|
170
|
+
async def old_endpoint(response: Response):
|
|
171
|
+
response.headers["Deprecation"] = "true"
|
|
172
|
+
response.headers["Sunset"] = "2026-06-01"
|
|
173
|
+
response.headers["Link"] = '</api/v2/new-endpoint>; rel="successor-version"'
|
|
174
|
+
return {"data": ...}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 8. Authentication & Security
|
|
178
|
+
|
|
179
|
+
- Use `Authorization: Bearer <token>` for API auth
|
|
180
|
+
- Never put tokens in URL query parameters (they appear in logs)
|
|
181
|
+
- Return `401` for missing/invalid auth, `403` for insufficient permissions
|
|
182
|
+
- Include `X-Request-Id` header for tracing
|
|
183
|
+
- Rate limit all public endpoints
|
|
184
|
+
|
|
185
|
+
## 9. FastAPI Implementation Pattern
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from fastapi import APIRouter, Depends, Query, HTTPException, status
|
|
189
|
+
from pydantic import BaseModel, Field
|
|
190
|
+
|
|
191
|
+
router = APIRouter(prefix="/api/v1/customers", tags=["customers"])
|
|
192
|
+
|
|
193
|
+
class CustomerCreate(BaseModel):
|
|
194
|
+
name: str = Field(..., min_length=1, max_length=200)
|
|
195
|
+
email: str = Field(..., pattern=r"^[\w.-]+@[\w.-]+\.\w+$")
|
|
196
|
+
|
|
197
|
+
class CustomerResponse(BaseModel):
|
|
198
|
+
id: str
|
|
199
|
+
name: str
|
|
200
|
+
email: str
|
|
201
|
+
|
|
202
|
+
class PaginatedResponse(BaseModel):
|
|
203
|
+
data: list[CustomerResponse]
|
|
204
|
+
pagination: dict
|
|
205
|
+
|
|
206
|
+
@router.get("", response_model=PaginatedResponse)
|
|
207
|
+
async def list_customers(
|
|
208
|
+
page: int = Query(1, ge=1),
|
|
209
|
+
per_page: int = Query(25, ge=1, le=100),
|
|
210
|
+
):
|
|
211
|
+
...
|
|
212
|
+
|
|
213
|
+
@router.post("", response_model=CustomerResponse, status_code=status.HTTP_201_CREATED)
|
|
214
|
+
async def create_customer(body: CustomerCreate):
|
|
215
|
+
...
|
|
216
|
+
|
|
217
|
+
@router.get("/{customer_id}", response_model=CustomerResponse)
|
|
218
|
+
async def get_customer(customer_id: str):
|
|
219
|
+
customer = await repo.find(customer_id)
|
|
220
|
+
if not customer:
|
|
221
|
+
raise HTTPException(status_code=404, detail="Customer not found")
|
|
222
|
+
return customer
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 10. API Design Checklist
|
|
226
|
+
|
|
227
|
+
Before shipping an API endpoint:
|
|
228
|
+
|
|
229
|
+
- [ ] Resource names are plural nouns in kebab-case
|
|
230
|
+
- [ ] Correct HTTP methods (GET reads, POST creates, etc.)
|
|
231
|
+
- [ ] Correct status codes (201 for create, 204 for delete)
|
|
232
|
+
- [ ] Request body validated with Pydantic/Zod
|
|
233
|
+
- [ ] Error responses use consistent envelope with error code
|
|
234
|
+
- [ ] Pagination implemented for list endpoints
|
|
235
|
+
- [ ] Authentication required (unless intentionally public)
|
|
236
|
+
- [ ] Rate limiting configured
|
|
237
|
+
- [ ] OpenAPI spec generated and reviewed
|
|
238
|
+
- [ ] No sensitive data in URLs or logs
|
|
239
|
+
|
|
240
|
+
## 11. Anti-Patterns
|
|
241
|
+
|
|
242
|
+
| Anti-Pattern | Problem | Fix |
|
|
243
|
+
|---|---|---|
|
|
244
|
+
| Verbs in URLs | `/getUser`, `/deleteOrder` | Use HTTP methods + nouns |
|
|
245
|
+
| Inconsistent pluralisation | `/user` vs `/orders` | Always plural |
|
|
246
|
+
| Returning 200 for errors | Client can't distinguish success/failure | Use proper status codes |
|
|
247
|
+
| Nested resources > 2 levels | Hard to discover, fragile URLs | Flatten with query params |
|
|
248
|
+
| No pagination on lists | Unbounded response size, OOM | Always paginate |
|
|
249
|
+
| Exposing internal IDs/schemas | Coupling clients to implementation | Use public-facing schemas |
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-development
|
|
3
|
+
description: Backend API design, database architecture, microservices patterns, and test-driven development. Use for designing APIs, database schemas, or backend system architecture.
|
|
4
|
+
source: wshobson/agents
|
|
5
|
+
license: MIT
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Backend Development
|
|
9
|
+
|
|
10
|
+
## API Design
|
|
11
|
+
|
|
12
|
+
### RESTful Conventions
|
|
13
|
+
```
|
|
14
|
+
GET /users # List users
|
|
15
|
+
POST /users # Create user
|
|
16
|
+
GET /users/:id # Get user
|
|
17
|
+
PUT /users/:id # Update user (full)
|
|
18
|
+
PATCH /users/:id # Update user (partial)
|
|
19
|
+
DELETE /users/:id # Delete user
|
|
20
|
+
|
|
21
|
+
GET /users/:id/posts # List user's posts
|
|
22
|
+
POST /users/:id/posts # Create post for user
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Response Format
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"data": { ... },
|
|
29
|
+
"meta": {
|
|
30
|
+
"page": 1,
|
|
31
|
+
"per_page": 20,
|
|
32
|
+
"total": 100
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Error Format
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"error": {
|
|
41
|
+
"code": "VALIDATION_ERROR",
|
|
42
|
+
"message": "Invalid input",
|
|
43
|
+
"details": [
|
|
44
|
+
{ "field": "email", "message": "Invalid format" }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Database Patterns
|
|
51
|
+
|
|
52
|
+
### Schema Design
|
|
53
|
+
```sql
|
|
54
|
+
-- Use UUIDs for public IDs
|
|
55
|
+
CREATE TABLE users (
|
|
56
|
+
id SERIAL PRIMARY KEY,
|
|
57
|
+
public_id UUID DEFAULT gen_random_uuid() UNIQUE,
|
|
58
|
+
email VARCHAR(255) UNIQUE NOT NULL,
|
|
59
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
60
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
-- Soft deletes
|
|
64
|
+
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMPTZ;
|
|
65
|
+
|
|
66
|
+
-- Indexes
|
|
67
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
68
|
+
CREATE INDEX idx_users_created ON users(created_at DESC);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Query Patterns
|
|
72
|
+
```sql
|
|
73
|
+
-- Pagination with cursor
|
|
74
|
+
SELECT * FROM posts
|
|
75
|
+
WHERE created_at < $cursor
|
|
76
|
+
ORDER BY created_at DESC
|
|
77
|
+
LIMIT 20;
|
|
78
|
+
|
|
79
|
+
-- Efficient counting
|
|
80
|
+
SELECT reltuples::bigint AS estimate
|
|
81
|
+
FROM pg_class WHERE relname = 'users';
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Authentication
|
|
85
|
+
|
|
86
|
+
### JWT Pattern
|
|
87
|
+
```typescript
|
|
88
|
+
interface TokenPayload {
|
|
89
|
+
sub: string; // User ID
|
|
90
|
+
iat: number; // Issued at
|
|
91
|
+
exp: number; // Expiration
|
|
92
|
+
scope: string[]; // Permissions
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function verifyToken(token: string): TokenPayload {
|
|
96
|
+
return jwt.verify(token, SECRET) as TokenPayload;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Middleware
|
|
101
|
+
```typescript
|
|
102
|
+
async function authenticate(req: Request, res: Response, next: Next) {
|
|
103
|
+
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
104
|
+
if (!token) {
|
|
105
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
req.user = verifyToken(token);
|
|
110
|
+
next();
|
|
111
|
+
} catch {
|
|
112
|
+
res.status(401).json({ error: 'Invalid token' });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Caching Strategy
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Cache-aside pattern
|
|
121
|
+
async function getUser(id: string): Promise<User> {
|
|
122
|
+
const cached = await redis.get(`user:${id}`);
|
|
123
|
+
if (cached) return JSON.parse(cached);
|
|
124
|
+
|
|
125
|
+
const user = await db.users.findById(id);
|
|
126
|
+
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
|
|
127
|
+
return user;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Cache invalidation
|
|
131
|
+
async function updateUser(id: string, data: Partial<User>) {
|
|
132
|
+
await db.users.update(id, data);
|
|
133
|
+
await redis.del(`user:${id}`);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Architecture Patterns
|
|
138
|
+
|
|
139
|
+
### Repository Pattern
|
|
140
|
+
Abstract data access from business logic for testability and swappable backends.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
interface UserRepository {
|
|
144
|
+
findAll(filters?: UserFilters): Promise<User[]>
|
|
145
|
+
findById(id: string): Promise<User | null>
|
|
146
|
+
create(data: CreateUserDto): Promise<User>
|
|
147
|
+
update(id: string, data: UpdateUserDto): Promise<User>
|
|
148
|
+
delete(id: string): Promise<void>
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Service Layer Pattern
|
|
153
|
+
Separate business logic from data access and HTTP concerns.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
class UserService {
|
|
157
|
+
constructor(private userRepo: UserRepository) {}
|
|
158
|
+
|
|
159
|
+
async createUser(data: CreateUserDto): Promise<User> {
|
|
160
|
+
// Business logic: validation, enrichment, side effects
|
|
161
|
+
const existing = await this.userRepo.findByEmail(data.email);
|
|
162
|
+
if (existing) throw new ConflictError('Email already registered');
|
|
163
|
+
return this.userRepo.create(data);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### N+1 Query Prevention
|
|
169
|
+
```typescript
|
|
170
|
+
// Bad: N+1 queries
|
|
171
|
+
const posts = await getPosts();
|
|
172
|
+
for (const post of posts) {
|
|
173
|
+
post.author = await getUser(post.author_id); // N queries
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Good: Batch fetch
|
|
177
|
+
const posts = await getPosts();
|
|
178
|
+
const authorIds = posts.map(p => p.author_id);
|
|
179
|
+
const authors = await getUsers(authorIds); // 1 query
|
|
180
|
+
const authorMap = new Map(authors.map(a => [a.id, a]));
|
|
181
|
+
posts.forEach(post => { post.author = authorMap.get(post.author_id); });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Rate Limiting
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// Library-based approach
|
|
188
|
+
const limiter = rateLimit({
|
|
189
|
+
windowMs: 60 * 1000, // 1 minute
|
|
190
|
+
max: 100, // 100 requests per window
|
|
191
|
+
keyGenerator: (req) => req.ip,
|
|
192
|
+
handler: (req, res) => {
|
|
193
|
+
res.status(429).json({ error: 'Too many requests' });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Error Handling
|
|
199
|
+
|
|
200
|
+
### Retry with Exponential Backoff
|
|
201
|
+
```typescript
|
|
202
|
+
async function fetchWithRetry<T>(
|
|
203
|
+
fn: () => Promise<T>,
|
|
204
|
+
maxRetries = 3
|
|
205
|
+
): Promise<T> {
|
|
206
|
+
let lastError: Error;
|
|
207
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
208
|
+
try {
|
|
209
|
+
return await fn();
|
|
210
|
+
} catch (error) {
|
|
211
|
+
lastError = error as Error;
|
|
212
|
+
if (i < maxRetries - 1) {
|
|
213
|
+
const delay = Math.pow(2, i) * 1000;
|
|
214
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
throw lastError!;
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Centralized Error Handler
|
|
223
|
+
```typescript
|
|
224
|
+
class ApiError extends Error {
|
|
225
|
+
constructor(public statusCode: number, message: string, public isOperational = true) {
|
|
226
|
+
super(message);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function errorHandler(error: unknown, req: Request): Response {
|
|
231
|
+
if (error instanceof ApiError) {
|
|
232
|
+
return json({ error: error.message }, { status: error.statusCode });
|
|
233
|
+
}
|
|
234
|
+
if (error instanceof z.ZodError) {
|
|
235
|
+
return json({ error: 'Validation failed', details: error.errors }, { status: 400 });
|
|
236
|
+
}
|
|
237
|
+
console.error('Unexpected error:', error);
|
|
238
|
+
return json({ error: 'Internal server error' }, { status: 500 });
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Role-Based Access Control
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
type Permission = 'read' | 'write' | 'delete' | 'admin';
|
|
246
|
+
|
|
247
|
+
const rolePermissions: Record<string, Permission[]> = {
|
|
248
|
+
admin: ['read', 'write', 'delete', 'admin'],
|
|
249
|
+
moderator: ['read', 'write', 'delete'],
|
|
250
|
+
user: ['read', 'write']
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
function hasPermission(user: { role: string }, permission: Permission): boolean {
|
|
254
|
+
return (rolePermissions[user.role] || []).includes(permission);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Background Jobs and Queues
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
class JobQueue<T> {
|
|
262
|
+
private queue: T[] = [];
|
|
263
|
+
private processing = false;
|
|
264
|
+
|
|
265
|
+
async add(job: T): Promise<void> {
|
|
266
|
+
this.queue.push(job);
|
|
267
|
+
if (!this.processing) this.process();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private async process(): Promise<void> {
|
|
271
|
+
this.processing = true;
|
|
272
|
+
while (this.queue.length > 0) {
|
|
273
|
+
const job = this.queue.shift()!;
|
|
274
|
+
try { await this.execute(job); }
|
|
275
|
+
catch (error) { console.error('Job failed:', error); }
|
|
276
|
+
}
|
|
277
|
+
this.processing = false;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private async execute(job: T): Promise<void> { /* implementation */ }
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Observability
|
|
285
|
+
|
|
286
|
+
### Structured Logging
|
|
287
|
+
```typescript
|
|
288
|
+
class Logger {
|
|
289
|
+
log(level: 'info' | 'warn' | 'error', message: string, context?: Record<string, unknown>) {
|
|
290
|
+
console.log(JSON.stringify({
|
|
291
|
+
timestamp: new Date().toISOString(), level, message, ...context
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
294
|
+
info(msg: string, ctx?: Record<string, unknown>) { this.log('info', msg, ctx); }
|
|
295
|
+
warn(msg: string, ctx?: Record<string, unknown>) { this.log('warn', msg, ctx); }
|
|
296
|
+
error(msg: string, err: Error, ctx?: Record<string, unknown>) {
|
|
297
|
+
this.log('error', msg, { ...ctx, error: err.message, stack: err.stack });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Health and Monitoring
|
|
303
|
+
- **Metrics**: Request latency, error rates, queue depths
|
|
304
|
+
- **Tracing**: Distributed tracing with correlation IDs
|
|
305
|
+
- **Health checks**: `/health` and `/ready` endpoints
|