specweave 0.18.0 → 0.20.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/CLAUDE.md +229 -1817
- package/README.md +68 -0
- package/bin/specweave.js +62 -6
- package/dist/locales/de/.gitkeep +0 -0
- package/dist/locales/de/cli.json +108 -0
- package/dist/locales/en/cli.json +287 -0
- package/dist/locales/en/errors.json +7 -0
- package/dist/locales/en/templates.json +6 -0
- package/dist/locales/es/.gitkeep +0 -0
- package/dist/locales/es/cli.json +41 -0
- package/dist/locales/fr/.gitkeep +0 -0
- package/dist/locales/fr/cli.json +108 -0
- package/dist/locales/ja/.gitkeep +0 -0
- package/dist/locales/ja/cli.json +108 -0
- package/dist/locales/ko/.gitkeep +0 -0
- package/dist/locales/ko/cli.json +108 -0
- package/dist/locales/pt/.gitkeep +0 -0
- package/dist/locales/pt/cli.json +108 -0
- package/dist/locales/ru/.gitkeep +0 -0
- package/dist/locales/ru/cli.json +269 -0
- package/dist/locales/zh/.gitkeep +0 -0
- package/dist/locales/zh/cli.json +108 -0
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.d.ts.map +1 -1
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.js +3 -0
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.js.map +1 -1
- package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts +21 -0
- package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts.map +1 -0
- package/dist/plugins/specweave/lib/hooks/update-ac-status.js +162 -0
- package/dist/plugins/specweave/lib/hooks/update-ac-status.js.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js +65 -6
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts +25 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js +191 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.d.ts +112 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.js +301 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.js.map +1 -0
- package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts +3 -3
- package/dist/plugins/specweave-github/lib/duplicate-detector.js +3 -3
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +70 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js +258 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +14 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +51 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +2 -2
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.js +20 -5
- package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +87 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync.js +412 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.js +64 -13
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts +78 -0
- package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/progress-comment-builder.js +237 -0
- package/dist/plugins/specweave-github/lib/progress-comment-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts +97 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.js +301 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts +83 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +386 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts +28 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +156 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.d.ts +57 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.js +248 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.d.ts +82 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.js +13 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.d.ts +49 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.js +316 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.d.ts +70 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.js +23 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.d.ts +85 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.js +281 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.d.ts +75 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.js +238 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.js.map +1 -0
- package/dist/spec-parser.js +629 -0
- package/dist/src/cli/commands/import-docs.js +4 -4
- package/dist/src/cli/commands/import-docs.js.map +1 -1
- package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
- package/dist/src/cli/commands/init-multiproject.js +17 -18
- package/dist/src/cli/commands/init-multiproject.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +107 -3
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.js +8 -4
- package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
- package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
- package/dist/src/cli/commands/switch-project.js +9 -26
- package/dist/src/cli/commands/switch-project.js.map +1 -1
- package/dist/src/cli/commands/sync-spec-content.js +3 -0
- package/dist/src/cli/commands/sync-spec-content.js.map +1 -1
- package/dist/src/core/deduplication/command-deduplicator.d.ts +166 -0
- package/dist/src/core/deduplication/command-deduplicator.d.ts.map +1 -0
- package/dist/src/core/deduplication/command-deduplicator.js +254 -0
- package/dist/src/core/deduplication/command-deduplicator.js.map +1 -0
- package/dist/src/core/increment/active-increment-manager.d.ts +42 -15
- package/dist/src/core/increment/active-increment-manager.d.ts.map +1 -1
- package/dist/src/core/increment/active-increment-manager.js +113 -46
- package/dist/src/core/increment/active-increment-manager.js.map +1 -1
- package/dist/src/core/increment/conflict-resolver.d.ts +40 -0
- package/dist/src/core/increment/conflict-resolver.d.ts.map +1 -0
- package/dist/src/core/increment/conflict-resolver.js +219 -0
- package/dist/src/core/increment/conflict-resolver.js.map +1 -0
- package/dist/src/core/increment/discipline-checker.d.ts.map +1 -1
- package/dist/src/core/increment/discipline-checker.js +7 -1
- package/dist/src/core/increment/discipline-checker.js.map +1 -1
- package/dist/src/core/increment/duplicate-detector.d.ts +52 -0
- package/dist/src/core/increment/duplicate-detector.d.ts.map +1 -0
- package/dist/src/core/increment/duplicate-detector.js +276 -0
- package/dist/src/core/increment/duplicate-detector.js.map +1 -0
- package/dist/src/core/increment/increment-archiver.d.ts +90 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -0
- package/dist/src/core/increment/increment-archiver.js +368 -0
- package/dist/src/core/increment/increment-archiver.js.map +1 -0
- package/dist/src/core/increment/increment-reopener.d.ts +165 -0
- package/dist/src/core/increment/increment-reopener.d.ts.map +1 -0
- package/dist/src/core/increment/increment-reopener.js +390 -0
- package/dist/src/core/increment/increment-reopener.js.map +1 -0
- package/dist/src/core/increment/metadata-manager.d.ts +26 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +143 -5
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/recent-work-scanner.d.ts +121 -0
- package/dist/src/core/increment/recent-work-scanner.d.ts.map +1 -0
- package/dist/src/core/increment/recent-work-scanner.js +303 -0
- package/dist/src/core/increment/recent-work-scanner.js.map +1 -0
- package/dist/src/core/increment/types.d.ts +1 -0
- package/dist/src/core/increment/types.d.ts.map +1 -1
- package/dist/src/core/increment-utils.d.ts +112 -0
- package/dist/src/core/increment-utils.d.ts.map +1 -0
- package/dist/src/core/increment-utils.js +210 -0
- package/dist/src/core/increment-utils.js.map +1 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.d.ts +65 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.js +175 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.js.map +1 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts +130 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -0
- package/dist/src/core/living-docs/feature-archiver.js +549 -0
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts +81 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -0
- package/dist/src/core/living-docs/feature-id-manager.js +339 -0
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -0
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts +144 -83
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.js +488 -270
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
- package/dist/src/core/living-docs/index.d.ts +6 -0
- package/dist/src/core/living-docs/index.d.ts.map +1 -1
- package/dist/src/core/living-docs/index.js +6 -0
- package/dist/src/core/living-docs/index.js.map +1 -1
- package/dist/src/core/living-docs/project-detector.d.ts +6 -0
- package/dist/src/core/living-docs/project-detector.d.ts.map +1 -1
- package/dist/src/core/living-docs/project-detector.js +35 -1
- package/dist/src/core/living-docs/project-detector.js.map +1 -1
- package/dist/src/core/living-docs/spec-distributor.d.ts +100 -26
- package/dist/src/core/living-docs/spec-distributor.d.ts.map +1 -1
- package/dist/src/core/living-docs/spec-distributor.js +1275 -258
- package/dist/src/core/living-docs/spec-distributor.js.map +1 -1
- package/dist/src/core/living-docs/task-project-specific-generator.d.ts +109 -0
- package/dist/src/core/living-docs/task-project-specific-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/task-project-specific-generator.js +221 -0
- package/dist/src/core/living-docs/task-project-specific-generator.js.map +1 -0
- package/dist/src/core/living-docs/types.d.ts +143 -0
- package/dist/src/core/living-docs/types.d.ts.map +1 -1
- package/dist/src/core/project-manager.d.ts +2 -17
- package/dist/src/core/project-manager.d.ts.map +1 -1
- package/dist/src/core/project-manager.js +68 -48
- package/dist/src/core/project-manager.js.map +1 -1
- package/dist/src/core/spec-content-sync.d.ts +1 -1
- package/dist/src/core/spec-content-sync.d.ts.map +1 -1
- package/dist/src/core/sync/enhanced-content-builder.d.ts +32 -54
- package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -1
- package/dist/src/core/sync/enhanced-content-builder.js +142 -138
- package/dist/src/core/sync/enhanced-content-builder.js.map +1 -1
- package/dist/src/core/sync/performance-optimizer.d.ts +153 -0
- package/dist/src/core/sync/performance-optimizer.d.ts.map +1 -0
- package/dist/src/core/sync/performance-optimizer.js +220 -0
- package/dist/src/core/sync/performance-optimizer.js.map +1 -0
- package/dist/src/core/sync/retry-handler.d.ts +98 -0
- package/dist/src/core/sync/retry-handler.d.ts.map +1 -0
- package/dist/src/core/sync/retry-handler.js +196 -0
- package/dist/src/core/sync/retry-handler.js.map +1 -0
- package/dist/src/core/sync/spec-content-sync.d.ts +88 -0
- package/dist/src/core/sync/spec-content-sync.d.ts.map +1 -0
- package/dist/src/core/sync/spec-content-sync.js +5 -0
- package/dist/src/core/sync/spec-content-sync.js.map +1 -0
- package/dist/src/core/sync/types.d.ts +52 -0
- package/dist/src/core/sync/types.d.ts.map +1 -0
- package/dist/src/core/sync/types.js +5 -0
- package/dist/src/core/sync/types.js.map +1 -0
- package/dist/src/core/types/config.d.ts +125 -0
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js +25 -0
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +10 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/core/types/increment-metadata.js +10 -1
- package/dist/src/core/types/increment-metadata.js.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.js +4 -8
- package/dist/src/integrations/jira/jira-incremental-mapper.js.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.js +4 -8
- package/dist/src/integrations/jira/jira-mapper.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
- package/plugins/specweave/COMMANDS.md +13 -4
- package/plugins/specweave/agents/pm/AGENT.md +159 -12
- package/plugins/specweave/commands/specweave-abandon.md +22 -20
- package/plugins/specweave/commands/specweave-archive-features.md +121 -0
- package/plugins/specweave/commands/specweave-archive-increments.md +82 -0
- package/plugins/specweave/commands/specweave-archive.md +363 -0
- package/plugins/specweave/commands/specweave-backlog.md +211 -0
- package/plugins/specweave/commands/specweave-fix-duplicates.md +517 -0
- package/plugins/specweave/commands/specweave-increment.md +4 -3
- package/plugins/specweave/commands/specweave-progress.md +176 -27
- package/plugins/specweave/commands/specweave-reopen.md +391 -0
- package/plugins/specweave/commands/specweave-restore-feature.md +90 -0
- package/plugins/specweave/commands/specweave-restore.md +309 -0
- package/plugins/specweave/commands/specweave-resume.md +51 -23
- package/plugins/specweave/commands/specweave-status.md +41 -7
- package/plugins/specweave/commands/specweave-sync-specs.md +425 -0
- package/plugins/specweave/commands/specweave.md +70 -405
- package/plugins/specweave/hooks/hooks.json +4 -0
- package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -2
- package/plugins/specweave/hooks/post-increment-planning.sh +26 -2
- package/plugins/specweave/hooks/post-task-completion.sh +39 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh +83 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +1 -1
- package/plugins/specweave/lib/hooks/sync-living-docs.js +2 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.ts +4 -0
- package/plugins/specweave/lib/hooks/update-ac-status.js +102 -0
- package/plugins/specweave/lib/hooks/update-ac-status.ts +192 -0
- package/plugins/specweave/skills/archive-increments/SKILL.md +198 -0
- package/plugins/specweave/skills/increment-planner/scripts/feature-utils.js +14 -0
- package/plugins/specweave/skills/smart-reopen-detector/SKILL.md +244 -0
- package/plugins/specweave-ado/lib/ado-spec-content-sync.js +49 -5
- package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +72 -6
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-confluent/.claude-plugin/plugin.json +23 -0
- package/plugins/specweave-confluent/README.md +375 -0
- package/plugins/specweave-confluent/agents/confluent-architect/AGENT.md +306 -0
- package/plugins/specweave-confluent/skills/confluent-kafka-connect/SKILL.md +453 -0
- package/plugins/specweave-confluent/skills/confluent-ksqldb/SKILL.md +470 -0
- package/plugins/specweave-confluent/skills/confluent-schema-registry/SKILL.md +316 -0
- package/plugins/specweave-github/agents/github-task-splitter/AGENT.md +2 -2
- package/plugins/specweave-github/agents/user-story-updater/AGENT.md +148 -0
- package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +1 -1
- package/plugins/specweave-github/commands/specweave-github-update-user-story.md +156 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh +42 -9
- package/plugins/specweave-github/lib/completion-calculator.js +262 -0
- package/plugins/specweave-github/lib/completion-calculator.ts +434 -0
- package/plugins/specweave-github/lib/duplicate-detector.js +3 -3
- package/plugins/specweave-github/lib/duplicate-detector.ts +4 -4
- package/plugins/specweave-github/lib/epic-content-builder.js +265 -0
- package/plugins/specweave-github/lib/epic-content-builder.ts +376 -0
- package/plugins/specweave-github/lib/github-client-v2.js +49 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +59 -0
- package/plugins/specweave-github/lib/github-epic-sync.js +23 -24
- package/plugins/specweave-github/lib/github-epic-sync.ts +30 -5
- package/plugins/specweave-github/lib/github-feature-sync.js +381 -0
- package/plugins/specweave-github/lib/github-feature-sync.ts +568 -0
- package/plugins/specweave-github/lib/github-spec-content-sync.js +40 -10
- package/plugins/specweave-github/lib/github-spec-content-sync.ts +82 -14
- package/plugins/specweave-github/lib/progress-comment-builder.js +229 -0
- package/plugins/specweave-github/lib/progress-comment-builder.ts +324 -0
- package/plugins/specweave-github/lib/user-story-content-builder.js +299 -0
- package/plugins/specweave-github/lib/user-story-content-builder.ts +413 -0
- package/plugins/specweave-github/lib/user-story-issue-builder.js +344 -0
- package/plugins/specweave-github/lib/user-story-issue-builder.ts +543 -0
- package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +189 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
- package/plugins/specweave-jira/lib/{enhanced-jira-sync.ts.disabled → enhanced-jira-sync.ts} +26 -52
- package/plugins/specweave-kafka/.claude-plugin/plugin.json +26 -0
- package/plugins/specweave-kafka/IMPLEMENTATION-COMPLETE.md +483 -0
- package/plugins/specweave-kafka/README.md +242 -0
- package/plugins/specweave-kafka/agents/kafka-architect/AGENT.md +235 -0
- package/plugins/specweave-kafka/agents/kafka-devops/AGENT.md +209 -0
- package/plugins/specweave-kafka/agents/kafka-observability/AGENT.md +266 -0
- package/plugins/specweave-kafka/commands/deploy.md +99 -0
- package/plugins/specweave-kafka/commands/dev-env.md +176 -0
- package/plugins/specweave-kafka/commands/mcp-configure.md +101 -0
- package/plugins/specweave-kafka/commands/monitor-setup.md +96 -0
- package/plugins/specweave-kafka/docker/kafka-local/docker-compose.yml +187 -0
- package/plugins/specweave-kafka/docker/redpanda/docker-compose.yml +199 -0
- package/plugins/specweave-kafka/docker/templates/consumer-nodejs.js +225 -0
- package/plugins/specweave-kafka/docker/templates/consumer-python.py +220 -0
- package/plugins/specweave-kafka/docker/templates/producer-nodejs.js +168 -0
- package/plugins/specweave-kafka/docker/templates/producer-python.py +167 -0
- package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.js +438 -0
- package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.ts +541 -0
- package/plugins/specweave-kafka/lib/adapters/platform-adapter.js +47 -0
- package/plugins/specweave-kafka/lib/adapters/platform-adapter.ts +343 -0
- package/plugins/specweave-kafka/lib/cli/kcat-wrapper.js +258 -0
- package/plugins/specweave-kafka/lib/cli/kcat-wrapper.ts +298 -0
- package/plugins/specweave-kafka/lib/cli/types.js +10 -0
- package/plugins/specweave-kafka/lib/cli/types.ts +92 -0
- package/plugins/specweave-kafka/lib/connectors/connector-catalog.js +305 -0
- package/plugins/specweave-kafka/lib/connectors/connector-catalog.ts +528 -0
- package/plugins/specweave-kafka/lib/documentation/diagram-generator.js +114 -0
- package/plugins/specweave-kafka/lib/documentation/diagram-generator.ts +195 -0
- package/plugins/specweave-kafka/lib/documentation/exporter.js +210 -0
- package/plugins/specweave-kafka/lib/documentation/exporter.ts +338 -0
- package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.js +60 -0
- package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.ts +130 -0
- package/plugins/specweave-kafka/lib/documentation/topology-generator.js +143 -0
- package/plugins/specweave-kafka/lib/documentation/topology-generator.ts +290 -0
- package/plugins/specweave-kafka/lib/mcp/detector.js +298 -0
- package/plugins/specweave-kafka/lib/mcp/detector.ts +352 -0
- package/plugins/specweave-kafka/lib/mcp/types.js +21 -0
- package/plugins/specweave-kafka/lib/mcp/types.ts +77 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.js +193 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.ts +362 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.js +188 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.ts +359 -0
- package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.js +195 -0
- package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.ts +380 -0
- package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.js +209 -0
- package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.ts +358 -0
- package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.js +354 -0
- package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.ts +563 -0
- package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.js +259 -0
- package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.ts +516 -0
- package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.js +233 -0
- package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.ts +423 -0
- package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.js +266 -0
- package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.ts +445 -0
- package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.js +312 -0
- package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.ts +561 -0
- package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.js +289 -0
- package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.ts +607 -0
- package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.js +264 -0
- package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.ts +498 -0
- package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.js +263 -0
- package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.ts +549 -0
- package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.js +205 -0
- package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.ts +399 -0
- package/plugins/specweave-kafka/lib/performance/performance-optimizer.js +249 -0
- package/plugins/specweave-kafka/lib/performance/performance-optimizer.ts +427 -0
- package/plugins/specweave-kafka/lib/security/kafka-security.js +252 -0
- package/plugins/specweave-kafka/lib/security/kafka-security.ts +494 -0
- package/plugins/specweave-kafka/lib/utils/capacity-planner.js +203 -0
- package/plugins/specweave-kafka/lib/utils/capacity-planner.ts +469 -0
- package/plugins/specweave-kafka/lib/utils/config-validator.js +419 -0
- package/plugins/specweave-kafka/lib/utils/config-validator.ts +564 -0
- package/plugins/specweave-kafka/lib/utils/partitioning.js +329 -0
- package/plugins/specweave-kafka/lib/utils/partitioning.ts +473 -0
- package/plugins/specweave-kafka/lib/utils/sizing.js +221 -0
- package/plugins/specweave-kafka/lib/utils/sizing.ts +374 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-broker-metrics.json +628 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-cluster-overview.json +564 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-consumer-lag.json +509 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-jvm-metrics.json +674 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-topic-metrics.json +578 -0
- package/plugins/specweave-kafka/monitoring/grafana/provisioning/dashboards/kafka.yml +17 -0
- package/plugins/specweave-kafka/monitoring/grafana/provisioning/datasources/prometheus.yml +17 -0
- package/plugins/specweave-kafka/monitoring/prometheus/kafka-alerts.yml +415 -0
- package/plugins/specweave-kafka/monitoring/prometheus/kafka-jmx-exporter.yml +256 -0
- package/plugins/specweave-kafka/package.json +41 -0
- package/plugins/specweave-kafka/skills/kafka-architecture/SKILL.md +647 -0
- package/plugins/specweave-kafka/skills/kafka-cli-tools/SKILL.md +433 -0
- package/plugins/specweave-kafka/skills/kafka-iac-deployment/SKILL.md +449 -0
- package/plugins/specweave-kafka/skills/kafka-kubernetes/SKILL.md +667 -0
- package/plugins/specweave-kafka/skills/kafka-mcp-integration/SKILL.md +273 -0
- package/plugins/specweave-kafka/skills/kafka-observability/SKILL.md +576 -0
- package/plugins/specweave-kafka/templates/config/broker-production.properties +254 -0
- package/plugins/specweave-kafka/templates/config/consumer-low-latency.properties +112 -0
- package/plugins/specweave-kafka/templates/config/producer-high-throughput.properties +120 -0
- package/plugins/specweave-kafka/templates/migration/mirrormaker2-config.properties +234 -0
- package/plugins/specweave-kafka/templates/monitoring/grafana/multi-cluster-dashboard.json +686 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/main.tf +347 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/outputs.tf +107 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/templates/kafka-broker-init.sh.tpl +216 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/variables.tf +156 -0
- package/plugins/specweave-kafka/terraform/aws-msk/main.tf +362 -0
- package/plugins/specweave-kafka/terraform/aws-msk/outputs.tf +93 -0
- package/plugins/specweave-kafka/terraform/aws-msk/templates/server.properties.tpl +32 -0
- package/plugins/specweave-kafka/terraform/aws-msk/variables.tf +235 -0
- package/plugins/specweave-kafka/terraform/azure-event-hubs/main.tf +281 -0
- package/plugins/specweave-kafka/terraform/azure-event-hubs/outputs.tf +118 -0
- package/plugins/specweave-kafka/terraform/azure-event-hubs/variables.tf +148 -0
- package/plugins/specweave-kafka/tsconfig.json +21 -0
- package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +23 -0
- package/plugins/specweave-kafka-streams/README.md +310 -0
- package/plugins/specweave-kafka-streams/skills/kafka-streams-topology/SKILL.md +539 -0
- package/plugins/specweave-n8n/.claude-plugin/plugin.json +22 -0
- package/plugins/specweave-n8n/README.md +354 -0
- package/plugins/specweave-n8n/skills/n8n-kafka-workflows/SKILL.md +504 -0
- package/plugins/specweave-release/commands/specweave-release-platform.md +1 -1
- package/plugins/specweave-release/hooks/post-task-completion.sh +2 -2
- package/src/templates/AGENTS.md.template +601 -7
- package/src/templates/CLAUDE.md.template +188 -88
- package/plugins/specweave-ado/commands/specweave-ado-sync-spec.md +0 -255
- package/plugins/specweave-github/commands/specweave-github-sync-epic.md +0 -248
- package/plugins/specweave-github/commands/specweave-github-sync-from.md +0 -147
- package/plugins/specweave-github/commands/specweave-github-sync-spec.md +0 -208
- package/plugins/specweave-github/commands/specweave-github-sync-tasks.md +0 -530
- package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +0 -267
- package/plugins/specweave-jira/commands/specweave-jira-sync-spec.md +0 -240
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiting and Backpressure Handling
|
|
3
|
+
*
|
|
4
|
+
* Producer rate limiting, consumer backpressure, quota management, and flow control
|
|
5
|
+
*
|
|
6
|
+
* @module rate-limiting-backpressure
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Producer, Consumer } from 'kafkajs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Rate Limiter Configuration
|
|
13
|
+
*/
|
|
14
|
+
export interface RateLimiterConfig {
|
|
15
|
+
/** Max messages per second */
|
|
16
|
+
maxMessagesPerSecond: number;
|
|
17
|
+
/** Max bytes per second */
|
|
18
|
+
maxBytesPerSecond?: number;
|
|
19
|
+
/** Burst capacity (tokens) */
|
|
20
|
+
burstCapacity?: number;
|
|
21
|
+
/** Refill rate (messages/sec) */
|
|
22
|
+
refillRate?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Backpressure Strategy
|
|
27
|
+
*/
|
|
28
|
+
export enum BackpressureStrategy {
|
|
29
|
+
/** Drop messages when overwhelmed */
|
|
30
|
+
DROP = 'drop',
|
|
31
|
+
/** Buffer messages up to limit */
|
|
32
|
+
BUFFER = 'buffer',
|
|
33
|
+
/** Throttle producer */
|
|
34
|
+
THROTTLE = 'throttle',
|
|
35
|
+
/** Dynamic (adaptive) */
|
|
36
|
+
DYNAMIC = 'dynamic',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Quota Configuration (Kafka Broker-Level)
|
|
41
|
+
*/
|
|
42
|
+
export interface QuotaConfig {
|
|
43
|
+
/** Client ID */
|
|
44
|
+
clientId: string;
|
|
45
|
+
/** Producer quota (bytes/sec) */
|
|
46
|
+
producerQuota?: number;
|
|
47
|
+
/** Consumer quota (bytes/sec) */
|
|
48
|
+
consumerQuota?: number;
|
|
49
|
+
/** Request quota (% of network/IO thread time) */
|
|
50
|
+
requestQuota?: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Token Bucket Rate Limiter
|
|
55
|
+
*
|
|
56
|
+
* Classic rate limiting algorithm with burst capacity
|
|
57
|
+
*/
|
|
58
|
+
export class TokenBucketRateLimiter {
|
|
59
|
+
private tokens: number;
|
|
60
|
+
private lastRefill: number;
|
|
61
|
+
private readonly maxTokens: number;
|
|
62
|
+
private readonly refillRate: number; // tokens per millisecond
|
|
63
|
+
|
|
64
|
+
constructor(config: RateLimiterConfig) {
|
|
65
|
+
this.maxTokens = config.burstCapacity || config.maxMessagesPerSecond;
|
|
66
|
+
this.refillRate = (config.refillRate || config.maxMessagesPerSecond) / 1000; // per ms
|
|
67
|
+
this.tokens = this.maxTokens;
|
|
68
|
+
this.lastRefill = Date.now();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Try to consume tokens (non-blocking)
|
|
73
|
+
*/
|
|
74
|
+
tryConsume(count: number = 1): boolean {
|
|
75
|
+
this.refill();
|
|
76
|
+
|
|
77
|
+
if (this.tokens >= count) {
|
|
78
|
+
this.tokens -= count;
|
|
79
|
+
return true; // Allowed
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return false; // Rate limit exceeded
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Wait until tokens available (blocking)
|
|
87
|
+
*/
|
|
88
|
+
async consume(count: number = 1): Promise<void> {
|
|
89
|
+
while (!this.tryConsume(count)) {
|
|
90
|
+
const waitMs = (count - this.tokens) / this.refillRate;
|
|
91
|
+
await this.sleep(Math.ceil(waitMs));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Refill tokens based on elapsed time
|
|
97
|
+
*/
|
|
98
|
+
private refill(): void {
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const elapsed = now - this.lastRefill;
|
|
101
|
+
const newTokens = elapsed * this.refillRate;
|
|
102
|
+
|
|
103
|
+
this.tokens = Math.min(this.maxTokens, this.tokens + newTokens);
|
|
104
|
+
this.lastRefill = now;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get current tokens available
|
|
109
|
+
*/
|
|
110
|
+
getAvailableTokens(): number {
|
|
111
|
+
this.refill();
|
|
112
|
+
return Math.floor(this.tokens);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private sleep(ms: number): Promise<void> {
|
|
116
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Rate-Limited Producer
|
|
122
|
+
*
|
|
123
|
+
* Wraps kafkajs Producer with rate limiting
|
|
124
|
+
*/
|
|
125
|
+
export class RateLimitedProducer {
|
|
126
|
+
private producer: Producer;
|
|
127
|
+
private rateLimiter: TokenBucketRateLimiter;
|
|
128
|
+
private byteRateLimiter?: TokenBucketRateLimiter;
|
|
129
|
+
|
|
130
|
+
constructor(producer: Producer, config: RateLimiterConfig) {
|
|
131
|
+
this.producer = producer;
|
|
132
|
+
this.rateLimiter = new TokenBucketRateLimiter(config);
|
|
133
|
+
|
|
134
|
+
if (config.maxBytesPerSecond) {
|
|
135
|
+
this.byteRateLimiter = new TokenBucketRateLimiter({
|
|
136
|
+
maxMessagesPerSecond: config.maxBytesPerSecond,
|
|
137
|
+
burstCapacity: config.maxBytesPerSecond * 2, // 2x burst
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Send message with rate limiting
|
|
144
|
+
*/
|
|
145
|
+
async send(params: {
|
|
146
|
+
topic: string;
|
|
147
|
+
messages: Array<{ key?: string; value: string }>;
|
|
148
|
+
}): Promise<void> {
|
|
149
|
+
const messageCount = params.messages.length;
|
|
150
|
+
|
|
151
|
+
// Rate limit by message count
|
|
152
|
+
await this.rateLimiter.consume(messageCount);
|
|
153
|
+
|
|
154
|
+
// Rate limit by bytes (if configured)
|
|
155
|
+
if (this.byteRateLimiter) {
|
|
156
|
+
const totalBytes = params.messages.reduce(
|
|
157
|
+
(sum, msg) => sum + (msg.value?.length || 0),
|
|
158
|
+
0
|
|
159
|
+
);
|
|
160
|
+
await this.byteRateLimiter.consume(totalBytes);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Send to Kafka
|
|
164
|
+
await this.producer.send(params);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Try send (non-blocking, returns false if rate limited)
|
|
169
|
+
*/
|
|
170
|
+
trySend(params: {
|
|
171
|
+
topic: string;
|
|
172
|
+
messages: Array<{ key?: string; value: string }>;
|
|
173
|
+
}): boolean {
|
|
174
|
+
const messageCount = params.messages.length;
|
|
175
|
+
|
|
176
|
+
if (!this.rateLimiter.tryConsume(messageCount)) {
|
|
177
|
+
return false; // Rate limited
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Async send (fire-and-forget)
|
|
181
|
+
this.producer.send(params).catch((err) => {
|
|
182
|
+
console.error('Send failed:', err);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return true; // Accepted
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get current rate limit status
|
|
190
|
+
*/
|
|
191
|
+
getStatus(): {
|
|
192
|
+
availableMessages: number;
|
|
193
|
+
availableBytes?: number;
|
|
194
|
+
} {
|
|
195
|
+
return {
|
|
196
|
+
availableMessages: this.rateLimiter.getAvailableTokens(),
|
|
197
|
+
availableBytes: this.byteRateLimiter?.getAvailableTokens(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Backpressure Handler
|
|
204
|
+
*
|
|
205
|
+
* Handles consumer backpressure with different strategies
|
|
206
|
+
*/
|
|
207
|
+
export class BackpressureHandler {
|
|
208
|
+
private strategy: BackpressureStrategy;
|
|
209
|
+
private buffer: Array<any> = [];
|
|
210
|
+
private maxBufferSize: number;
|
|
211
|
+
private droppedCount: number = 0;
|
|
212
|
+
|
|
213
|
+
constructor(strategy: BackpressureStrategy, maxBufferSize: number = 10000) {
|
|
214
|
+
this.strategy = strategy;
|
|
215
|
+
this.maxBufferSize = maxBufferSize;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Handle incoming message with backpressure
|
|
220
|
+
*/
|
|
221
|
+
async handleMessage(
|
|
222
|
+
message: any,
|
|
223
|
+
processor: (msg: any) => Promise<void>
|
|
224
|
+
): Promise<boolean> {
|
|
225
|
+
switch (this.strategy) {
|
|
226
|
+
case BackpressureStrategy.DROP:
|
|
227
|
+
return this.handleDrop(message, processor);
|
|
228
|
+
|
|
229
|
+
case BackpressureStrategy.BUFFER:
|
|
230
|
+
return this.handleBuffer(message, processor);
|
|
231
|
+
|
|
232
|
+
case BackpressureStrategy.THROTTLE:
|
|
233
|
+
return this.handleThrottle(message, processor);
|
|
234
|
+
|
|
235
|
+
case BackpressureStrategy.DYNAMIC:
|
|
236
|
+
return this.handleDynamic(message, processor);
|
|
237
|
+
|
|
238
|
+
default:
|
|
239
|
+
throw new Error(`Unknown backpressure strategy: ${this.strategy}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Drop strategy: Drop messages when buffer full
|
|
245
|
+
*/
|
|
246
|
+
private async handleDrop(message: any, processor: (msg: any) => Promise<void>): Promise<boolean> {
|
|
247
|
+
if (this.buffer.length < this.maxBufferSize) {
|
|
248
|
+
this.buffer.push(message);
|
|
249
|
+
this.processBuffer(processor);
|
|
250
|
+
return true; // Accepted
|
|
251
|
+
} else {
|
|
252
|
+
this.droppedCount++;
|
|
253
|
+
console.warn(`Message dropped (backpressure). Total dropped: ${this.droppedCount}`);
|
|
254
|
+
return false; // Dropped
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Buffer strategy: Buffer up to max size, then block
|
|
260
|
+
*/
|
|
261
|
+
private async handleBuffer(message: any, processor: (msg: any) => Promise<void>): Promise<boolean> {
|
|
262
|
+
// Wait until buffer has space
|
|
263
|
+
while (this.buffer.length >= this.maxBufferSize) {
|
|
264
|
+
await this.sleep(100); // Wait 100ms
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
this.buffer.push(message);
|
|
268
|
+
this.processBuffer(processor);
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Throttle strategy: Slow down producer by blocking
|
|
274
|
+
*/
|
|
275
|
+
private async handleThrottle(message: any, processor: (msg: any) => Promise<void>): Promise<boolean> {
|
|
276
|
+
// Calculate delay based on buffer utilization
|
|
277
|
+
const utilizationPercent = (this.buffer.length / this.maxBufferSize) * 100;
|
|
278
|
+
const delayMs = utilizationPercent > 80 ? 1000 : utilizationPercent > 50 ? 100 : 0;
|
|
279
|
+
|
|
280
|
+
if (delayMs > 0) {
|
|
281
|
+
await this.sleep(delayMs);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
this.buffer.push(message);
|
|
285
|
+
this.processBuffer(processor);
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Dynamic strategy: Adapt based on buffer state
|
|
291
|
+
*/
|
|
292
|
+
private async handleDynamic(message: any, processor: (msg: any) => Promise<void>): Promise<boolean> {
|
|
293
|
+
const utilization = this.buffer.length / this.maxBufferSize;
|
|
294
|
+
|
|
295
|
+
if (utilization < 0.5) {
|
|
296
|
+
// Low utilization: Accept immediately
|
|
297
|
+
this.buffer.push(message);
|
|
298
|
+
this.processBuffer(processor);
|
|
299
|
+
return true;
|
|
300
|
+
} else if (utilization < 0.9) {
|
|
301
|
+
// Medium utilization: Throttle
|
|
302
|
+
return this.handleThrottle(message, processor);
|
|
303
|
+
} else {
|
|
304
|
+
// High utilization: Drop
|
|
305
|
+
return this.handleDrop(message, processor);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Process buffered messages
|
|
311
|
+
*/
|
|
312
|
+
private async processBuffer(processor: (msg: any) => Promise<void>): Promise<void> {
|
|
313
|
+
while (this.buffer.length > 0) {
|
|
314
|
+
const message = this.buffer.shift();
|
|
315
|
+
if (message) {
|
|
316
|
+
try {
|
|
317
|
+
await processor(message);
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error('Processing failed:', error);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Get backpressure metrics
|
|
327
|
+
*/
|
|
328
|
+
getMetrics(): {
|
|
329
|
+
bufferSize: number;
|
|
330
|
+
bufferUtilization: number;
|
|
331
|
+
droppedCount: number;
|
|
332
|
+
} {
|
|
333
|
+
return {
|
|
334
|
+
bufferSize: this.buffer.length,
|
|
335
|
+
bufferUtilization: (this.buffer.length / this.maxBufferSize) * 100,
|
|
336
|
+
droppedCount: this.droppedCount,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private sleep(ms: number): Promise<void> {
|
|
341
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Kafka Quota Manager
|
|
347
|
+
*
|
|
348
|
+
* Manages broker-level quotas via Admin API
|
|
349
|
+
*/
|
|
350
|
+
export class KafkaQuotaManager {
|
|
351
|
+
/**
|
|
352
|
+
* Generate quota configuration script
|
|
353
|
+
*/
|
|
354
|
+
static generateQuotaScript(quota: QuotaConfig): string {
|
|
355
|
+
const commands: string[] = [];
|
|
356
|
+
|
|
357
|
+
if (quota.producerQuota) {
|
|
358
|
+
commands.push(
|
|
359
|
+
`kafka-configs.sh --alter --add-config 'producer_byte_rate=${quota.producerQuota}' --entity-type clients --entity-name ${quota.clientId}`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (quota.consumerQuota) {
|
|
364
|
+
commands.push(
|
|
365
|
+
`kafka-configs.sh --alter --add-config 'consumer_byte_rate=${quota.consumerQuota}' --entity-type clients --entity-name ${quota.clientId}`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (quota.requestQuota) {
|
|
370
|
+
commands.push(
|
|
371
|
+
`kafka-configs.sh --alter --add-config 'request_percentage=${quota.requestQuota}' --entity-type clients --entity-name ${quota.clientId}`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return commands.join('\n');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Calculate recommended quotas
|
|
380
|
+
*/
|
|
381
|
+
static calculateRecommendedQuotas(
|
|
382
|
+
expectedThroughputMBps: number,
|
|
383
|
+
clientCount: number,
|
|
384
|
+
headroomPercent: number = 20
|
|
385
|
+
): {
|
|
386
|
+
producerQuota: number;
|
|
387
|
+
consumerQuota: number;
|
|
388
|
+
} {
|
|
389
|
+
// Add headroom
|
|
390
|
+
const targetThroughputMBps = expectedThroughputMBps * (1 + headroomPercent / 100);
|
|
391
|
+
|
|
392
|
+
// Convert to bytes/sec
|
|
393
|
+
const targetBytesPerSec = targetThroughputMBps * 1024 * 1024;
|
|
394
|
+
|
|
395
|
+
// Distribute across clients
|
|
396
|
+
const quotaPerClient = Math.ceil(targetBytesPerSec / clientCount);
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
producerQuota: quotaPerClient,
|
|
400
|
+
consumerQuota: quotaPerClient * 2, // Consumers need 2x (read + fanout)
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Example Usage: Rate-Limited Producer
|
|
407
|
+
*
|
|
408
|
+
* ```typescript
|
|
409
|
+
* const kafka = new Kafka({ brokers: ['localhost:9092'] });
|
|
410
|
+
* const producer = kafka.producer();
|
|
411
|
+
* await producer.connect();
|
|
412
|
+
*
|
|
413
|
+
* const rateLimitedProducer = new RateLimitedProducer(producer, {
|
|
414
|
+
* maxMessagesPerSecond: 1000,
|
|
415
|
+
* maxBytesPerSecond: 10 * 1024 * 1024, // 10 MB/s
|
|
416
|
+
* burstCapacity: 2000, // Allow bursts up to 2000 messages
|
|
417
|
+
* });
|
|
418
|
+
*
|
|
419
|
+
* // Rate-limited send
|
|
420
|
+
* await rateLimitedProducer.send({
|
|
421
|
+
* topic: 'high-volume-topic',
|
|
422
|
+
* messages: [{ value: 'message1' }, { value: 'message2' }],
|
|
423
|
+
* });
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Example Usage: Backpressure Handler
|
|
429
|
+
*
|
|
430
|
+
* ```typescript
|
|
431
|
+
* const backpressure = new BackpressureHandler(
|
|
432
|
+
* BackpressureStrategy.DYNAMIC,
|
|
433
|
+
* 10000 // Max 10K buffered messages
|
|
434
|
+
* );
|
|
435
|
+
*
|
|
436
|
+
* await consumer.run({
|
|
437
|
+
* eachMessage: async ({ message }) => {
|
|
438
|
+
* await backpressure.handleMessage(message, async (msg) => {
|
|
439
|
+
* // Your processing logic
|
|
440
|
+
* await processMessage(msg);
|
|
441
|
+
* });
|
|
442
|
+
* },
|
|
443
|
+
* });
|
|
444
|
+
*
|
|
445
|
+
* // Monitor backpressure
|
|
446
|
+
* setInterval(() => {
|
|
447
|
+
* const metrics = backpressure.getMetrics();
|
|
448
|
+
* console.log(`Buffer: ${metrics.bufferUtilization.toFixed(1)}%`);
|
|
449
|
+
* }, 5000);
|
|
450
|
+
* ```
|
|
451
|
+
*/
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Rate Limiting & Backpressure Best Practices:
|
|
455
|
+
*
|
|
456
|
+
* **When to Use Rate Limiting**:
|
|
457
|
+
* - Protect downstream systems from overload
|
|
458
|
+
* - Comply with SLA/quotas
|
|
459
|
+
* - Prevent "thundering herd" problems
|
|
460
|
+
* - Smooth out traffic spikes
|
|
461
|
+
*
|
|
462
|
+
* **Rate Limiter Configuration**:
|
|
463
|
+
* - maxMessagesPerSecond: Set to 80% of target (20% headroom)
|
|
464
|
+
* - burstCapacity: 2x rate (handle short bursts)
|
|
465
|
+
* - Use token bucket (better than leaky bucket for bursts)
|
|
466
|
+
*
|
|
467
|
+
* **Backpressure Strategies**:
|
|
468
|
+
* - DROP: Real-time analytics (some loss OK)
|
|
469
|
+
* - BUFFER: Important data (no loss, accept latency)
|
|
470
|
+
* - THROTTLE: Flow control (slow down producer)
|
|
471
|
+
* - DYNAMIC: Adaptive (combine strategies)
|
|
472
|
+
*
|
|
473
|
+
* **Kafka Broker Quotas**:
|
|
474
|
+
* - producer_byte_rate: Limit producer throughput (bytes/sec)
|
|
475
|
+
* - consumer_byte_rate: Limit consumer throughput (bytes/sec)
|
|
476
|
+
* - request_percentage: Limit CPU/network time (%)
|
|
477
|
+
* - Apply per client-id or user
|
|
478
|
+
*
|
|
479
|
+
* **Monitoring**:
|
|
480
|
+
* - Rate limiter: Available tokens, wait time
|
|
481
|
+
* - Backpressure: Buffer utilization, dropped count
|
|
482
|
+
* - Broker quotas: Throttle time, quota violations
|
|
483
|
+
* - Consumer lag: Detect backpressure issues
|
|
484
|
+
*
|
|
485
|
+
* **Tuning**:
|
|
486
|
+
* - Start conservative (low limits)
|
|
487
|
+
* - Monitor throttle metrics
|
|
488
|
+
* - Gradually increase limits
|
|
489
|
+
* - Set alerts for quota violations
|
|
490
|
+
*/
|
|
491
|
+
|
|
492
|
+
export default {
|
|
493
|
+
TokenBucketRateLimiter,
|
|
494
|
+
RateLimitedProducer,
|
|
495
|
+
BackpressureHandler,
|
|
496
|
+
KafkaQuotaManager,
|
|
497
|
+
BackpressureStrategy,
|
|
498
|
+
};
|