specweave 0.18.1 → 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/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-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 +7 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/epic-content-builder.js +42 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -1
- 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.js +1 -1
- 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 +8 -6
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +78 -117
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -1
- 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/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/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.map +1 -1
- package/dist/src/core/sync/enhanced-content-builder.js +2 -1
- 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/types/config.d.ts +94 -0
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js +16 -0
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +6 -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/package.json +1 -1
- package/plugins/specweave/COMMANDS.md +13 -4
- 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/hooks/hooks.json +4 -0
- package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -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-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 +10 -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 +38 -0
- package/plugins/specweave-github/lib/epic-content-builder.ts +59 -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.ts +1 -1
- 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,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced ksqlDB Patterns
|
|
3
|
+
*
|
|
4
|
+
* Complex joins, User-Defined Functions (UDFs), custom aggregations, and advanced SQL patterns
|
|
5
|
+
*
|
|
6
|
+
* @module advanced-ksqldb-patterns
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Join Pattern Types
|
|
11
|
+
*/
|
|
12
|
+
export enum JoinPattern {
|
|
13
|
+
/** Stream-Stream Join (time-windowed) */
|
|
14
|
+
STREAM_STREAM = 'stream-stream',
|
|
15
|
+
/** Stream-Table Join (enrichment) */
|
|
16
|
+
STREAM_TABLE = 'stream-table',
|
|
17
|
+
/** Table-Table Join (materialized view) */
|
|
18
|
+
TABLE_TABLE = 'table-table',
|
|
19
|
+
/** Multi-way Join (3+ sources) */
|
|
20
|
+
MULTI_WAY = 'multi-way',
|
|
21
|
+
/** Self-Join (correlation) */
|
|
22
|
+
SELF_JOIN = 'self-join',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Aggregation Pattern Types
|
|
27
|
+
*/
|
|
28
|
+
export enum AggregationPattern {
|
|
29
|
+
/** Simple aggregation (count, sum, avg) */
|
|
30
|
+
SIMPLE = 'simple',
|
|
31
|
+
/** Session-based aggregation */
|
|
32
|
+
SESSION = 'session',
|
|
33
|
+
/** Hopping window aggregation */
|
|
34
|
+
HOPPING = 'hopping',
|
|
35
|
+
/** Tumbling window aggregation */
|
|
36
|
+
TUMBLING = 'tumbling',
|
|
37
|
+
/** Custom UDF aggregation */
|
|
38
|
+
CUSTOM_UDF = 'custom-udf',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* ksqlDB Query Builder
|
|
43
|
+
*
|
|
44
|
+
* Generates optimized ksqlDB queries for complex patterns
|
|
45
|
+
*/
|
|
46
|
+
export class KsqlDBQueryBuilder {
|
|
47
|
+
/**
|
|
48
|
+
* Generate stream-stream join query
|
|
49
|
+
*
|
|
50
|
+
* Use case: Join two event streams within a time window (e.g., clicks + purchases)
|
|
51
|
+
*/
|
|
52
|
+
static generateStreamStreamJoin(options: {
|
|
53
|
+
leftStream: string;
|
|
54
|
+
rightStream: string;
|
|
55
|
+
joinKey: string;
|
|
56
|
+
windowSizeMinutes: number;
|
|
57
|
+
outputStream: string;
|
|
58
|
+
selectFields: string[];
|
|
59
|
+
}): string {
|
|
60
|
+
return `
|
|
61
|
+
-- Stream-Stream Join (time-windowed)
|
|
62
|
+
CREATE STREAM ${options.outputStream} AS
|
|
63
|
+
SELECT
|
|
64
|
+
${options.selectFields.join(',\n ')}
|
|
65
|
+
FROM ${options.leftStream} L
|
|
66
|
+
INNER JOIN ${options.rightStream} R
|
|
67
|
+
WITHIN ${options.windowSizeMinutes} MINUTES
|
|
68
|
+
ON L.${options.joinKey} = R.${options.joinKey}
|
|
69
|
+
EMIT CHANGES;
|
|
70
|
+
|
|
71
|
+
/* Example Output:
|
|
72
|
+
* Left stream: clicks (user_id, page, timestamp)
|
|
73
|
+
* Right stream: purchases (user_id, product, amount, timestamp)
|
|
74
|
+
* Join: Match clicks within 30 minutes of purchase
|
|
75
|
+
* Result: User journey (click → purchase conversion)
|
|
76
|
+
*/
|
|
77
|
+
`.trim();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Generate stream-table join query
|
|
82
|
+
*
|
|
83
|
+
* Use case: Enrich stream with reference data (e.g., user profile lookup)
|
|
84
|
+
*/
|
|
85
|
+
static generateStreamTableJoin(options: {
|
|
86
|
+
stream: string;
|
|
87
|
+
table: string;
|
|
88
|
+
joinKey: string;
|
|
89
|
+
outputStream: string;
|
|
90
|
+
selectFields: string[];
|
|
91
|
+
}): string {
|
|
92
|
+
return `
|
|
93
|
+
-- Stream-Table Join (enrichment)
|
|
94
|
+
CREATE STREAM ${options.outputStream} AS
|
|
95
|
+
SELECT
|
|
96
|
+
${options.selectFields.join(',\n ')}
|
|
97
|
+
FROM ${options.stream} S
|
|
98
|
+
LEFT JOIN ${options.table} T
|
|
99
|
+
ON S.${options.joinKey} = T.${options.joinKey}
|
|
100
|
+
EMIT CHANGES;
|
|
101
|
+
|
|
102
|
+
/* Example Output:
|
|
103
|
+
* Stream: orders (order_id, user_id, amount)
|
|
104
|
+
* Table: users (user_id, name, email, tier)
|
|
105
|
+
* Result: Enriched orders with user metadata
|
|
106
|
+
* Note: Table must be keyed on join key!
|
|
107
|
+
*/
|
|
108
|
+
`.trim();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Generate table-table join query
|
|
113
|
+
*
|
|
114
|
+
* Use case: Create materialized view of joined tables
|
|
115
|
+
*/
|
|
116
|
+
static generateTableTableJoin(options: {
|
|
117
|
+
leftTable: string;
|
|
118
|
+
rightTable: string;
|
|
119
|
+
joinKey: string;
|
|
120
|
+
outputTable: string;
|
|
121
|
+
selectFields: string[];
|
|
122
|
+
}): string {
|
|
123
|
+
return `
|
|
124
|
+
-- Table-Table Join (materialized view)
|
|
125
|
+
CREATE TABLE ${options.outputTable} AS
|
|
126
|
+
SELECT
|
|
127
|
+
${options.selectFields.join(',\n ')}
|
|
128
|
+
FROM ${options.leftTable} L
|
|
129
|
+
INNER JOIN ${options.rightTable} R
|
|
130
|
+
ON L.${options.joinKey} = R.${options.joinKey};
|
|
131
|
+
|
|
132
|
+
/* Example Output:
|
|
133
|
+
* Left table: customer_profiles (customer_id, name, email)
|
|
134
|
+
* Right table: customer_preferences (customer_id, category, value)
|
|
135
|
+
* Result: Unified customer view (profile + preferences)
|
|
136
|
+
* Note: Both tables must be keyed on join key!
|
|
137
|
+
*/
|
|
138
|
+
`.trim();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Generate multi-way join query
|
|
143
|
+
*
|
|
144
|
+
* Use case: Join 3+ streams/tables (e.g., clicks + cart + purchase)
|
|
145
|
+
*/
|
|
146
|
+
static generateMultiWayJoin(options: {
|
|
147
|
+
streams: Array<{ name: string; alias: string }>;
|
|
148
|
+
joinKey: string;
|
|
149
|
+
windowSizeMinutes?: number;
|
|
150
|
+
outputStream: string;
|
|
151
|
+
selectFields: string[];
|
|
152
|
+
}): string {
|
|
153
|
+
if (options.streams.length < 3) {
|
|
154
|
+
throw new Error('Multi-way join requires at least 3 streams');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const baseStream = options.streams[0];
|
|
158
|
+
const joinClauses = options.streams.slice(1).map((stream, index) => {
|
|
159
|
+
const within = options.windowSizeMinutes
|
|
160
|
+
? `WITHIN ${options.windowSizeMinutes} MINUTES`
|
|
161
|
+
: '';
|
|
162
|
+
return `INNER JOIN ${stream.name} ${stream.alias} ${within}
|
|
163
|
+
ON ${baseStream.alias}.${options.joinKey} = ${stream.alias}.${options.joinKey}`;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return `
|
|
167
|
+
-- Multi-Way Join (3+ streams)
|
|
168
|
+
CREATE STREAM ${options.outputStream} AS
|
|
169
|
+
SELECT
|
|
170
|
+
${options.selectFields.join(',\n ')}
|
|
171
|
+
FROM ${baseStream.name} ${baseStream.alias}
|
|
172
|
+
${joinClauses.join('\n')}
|
|
173
|
+
EMIT CHANGES;
|
|
174
|
+
|
|
175
|
+
/* Example Output:
|
|
176
|
+
* Stream 1: clicks (user_id, page)
|
|
177
|
+
* Stream 2: add_to_cart (user_id, product)
|
|
178
|
+
* Stream 3: purchases (user_id, order_id)
|
|
179
|
+
* Result: Full funnel (click → cart → purchase)
|
|
180
|
+
*/
|
|
181
|
+
`.trim();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Generate session window aggregation
|
|
186
|
+
*
|
|
187
|
+
* Use case: Group events by user session (e.g., website activity)
|
|
188
|
+
*/
|
|
189
|
+
static generateSessionAggregation(options: {
|
|
190
|
+
inputStream: string;
|
|
191
|
+
groupByKey: string;
|
|
192
|
+
sessionGapMinutes: number;
|
|
193
|
+
aggregations: Array<{ func: string; column: string; alias: string }>;
|
|
194
|
+
outputTable: string;
|
|
195
|
+
}): string {
|
|
196
|
+
const aggFields = options.aggregations
|
|
197
|
+
.map((agg) => `${agg.func}(${agg.column}) AS ${agg.alias}`)
|
|
198
|
+
.join(',\n ');
|
|
199
|
+
|
|
200
|
+
return `
|
|
201
|
+
-- Session Window Aggregation
|
|
202
|
+
CREATE TABLE ${options.outputTable} AS
|
|
203
|
+
SELECT
|
|
204
|
+
${options.groupByKey},
|
|
205
|
+
${aggFields}
|
|
206
|
+
FROM ${options.inputStream}
|
|
207
|
+
WINDOW SESSION (${options.sessionGapMinutes} MINUTES)
|
|
208
|
+
GROUP BY ${options.groupByKey}
|
|
209
|
+
EMIT CHANGES;
|
|
210
|
+
|
|
211
|
+
/* Example Output:
|
|
212
|
+
* Input: page_views (user_id, page, timestamp)
|
|
213
|
+
* Session gap: 30 minutes of inactivity
|
|
214
|
+
* Aggregations:
|
|
215
|
+
* - COUNT(*) AS page_count
|
|
216
|
+
* - COLLECT_LIST(page) AS pages_visited
|
|
217
|
+
* - EARLIEST_BY_OFFSET(timestamp) AS session_start
|
|
218
|
+
* - LATEST_BY_OFFSET(timestamp) AS session_end
|
|
219
|
+
* Result: User sessions with duration and page count
|
|
220
|
+
*/
|
|
221
|
+
`.trim();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Generate hopping window aggregation
|
|
226
|
+
*
|
|
227
|
+
* Use case: Overlapping time windows (e.g., 5-minute windows every 1 minute)
|
|
228
|
+
*/
|
|
229
|
+
static generateHoppingAggregation(options: {
|
|
230
|
+
inputStream: string;
|
|
231
|
+
groupByKey: string;
|
|
232
|
+
windowSizeMinutes: number;
|
|
233
|
+
advanceByMinutes: number;
|
|
234
|
+
aggregations: Array<{ func: string; column: string; alias: string }>;
|
|
235
|
+
outputTable: string;
|
|
236
|
+
}): string {
|
|
237
|
+
const aggFields = options.aggregations
|
|
238
|
+
.map((agg) => `${agg.func}(${agg.column}) AS ${agg.alias}`)
|
|
239
|
+
.join(',\n ');
|
|
240
|
+
|
|
241
|
+
return `
|
|
242
|
+
-- Hopping Window Aggregation
|
|
243
|
+
CREATE TABLE ${options.outputTable} AS
|
|
244
|
+
SELECT
|
|
245
|
+
${options.groupByKey},
|
|
246
|
+
WINDOWSTART AS window_start,
|
|
247
|
+
WINDOWEND AS window_end,
|
|
248
|
+
${aggFields}
|
|
249
|
+
FROM ${options.inputStream}
|
|
250
|
+
WINDOW HOPPING (SIZE ${options.windowSizeMinutes} MINUTES, ADVANCE BY ${options.advanceByMinutes} MINUTES)
|
|
251
|
+
GROUP BY ${options.groupByKey}
|
|
252
|
+
EMIT CHANGES;
|
|
253
|
+
|
|
254
|
+
/* Example Output:
|
|
255
|
+
* Input: sensor_data (sensor_id, temperature, timestamp)
|
|
256
|
+
* Window: 5 minutes, advance 1 minute (80% overlap)
|
|
257
|
+
* Aggregations:
|
|
258
|
+
* - AVG(temperature) AS avg_temp
|
|
259
|
+
* - MAX(temperature) AS max_temp
|
|
260
|
+
* - STDDEV(temperature) AS temp_stddev
|
|
261
|
+
* Use case: Sliding window anomaly detection
|
|
262
|
+
*/
|
|
263
|
+
`.trim();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Generate tumbling window aggregation
|
|
268
|
+
*
|
|
269
|
+
* Use case: Non-overlapping time windows (e.g., hourly totals)
|
|
270
|
+
*/
|
|
271
|
+
static generateTumblingAggregation(options: {
|
|
272
|
+
inputStream: string;
|
|
273
|
+
groupByKey: string;
|
|
274
|
+
windowSizeMinutes: number;
|
|
275
|
+
aggregations: Array<{ func: string; column: string; alias: string }>;
|
|
276
|
+
outputTable: string;
|
|
277
|
+
}): string {
|
|
278
|
+
const aggFields = options.aggregations
|
|
279
|
+
.map((agg) => `${agg.func}(${agg.column}) AS ${agg.alias}`)
|
|
280
|
+
.join(',\n ');
|
|
281
|
+
|
|
282
|
+
return `
|
|
283
|
+
-- Tumbling Window Aggregation
|
|
284
|
+
CREATE TABLE ${options.outputTable} AS
|
|
285
|
+
SELECT
|
|
286
|
+
${options.groupByKey},
|
|
287
|
+
WINDOWSTART AS window_start,
|
|
288
|
+
WINDOWEND AS window_end,
|
|
289
|
+
${aggFields}
|
|
290
|
+
FROM ${options.inputStream}
|
|
291
|
+
WINDOW TUMBLING (SIZE ${options.windowSizeMinutes} MINUTES)
|
|
292
|
+
GROUP BY ${options.groupByKey}
|
|
293
|
+
EMIT CHANGES;
|
|
294
|
+
|
|
295
|
+
/* Example Output:
|
|
296
|
+
* Input: transactions (merchant_id, amount, timestamp)
|
|
297
|
+
* Window: 60 minutes (non-overlapping hourly windows)
|
|
298
|
+
* Aggregations:
|
|
299
|
+
* - COUNT(*) AS transaction_count
|
|
300
|
+
* - SUM(amount) AS total_revenue
|
|
301
|
+
* - AVG(amount) AS avg_transaction_value
|
|
302
|
+
* Use case: Hourly sales reports
|
|
303
|
+
*/
|
|
304
|
+
`.trim();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Generate custom UDF aggregation
|
|
309
|
+
*
|
|
310
|
+
* Use case: Complex business logic (e.g., weighted average, percentiles)
|
|
311
|
+
*/
|
|
312
|
+
static generateCustomUDFQuery(options: {
|
|
313
|
+
inputStream: string;
|
|
314
|
+
udfName: string;
|
|
315
|
+
udfParameters: string[];
|
|
316
|
+
groupByKey?: string;
|
|
317
|
+
outputStream: string;
|
|
318
|
+
}): string {
|
|
319
|
+
const params = options.udfParameters.join(', ');
|
|
320
|
+
const groupBy = options.groupByKey ? `GROUP BY ${options.groupByKey}` : '';
|
|
321
|
+
|
|
322
|
+
return `
|
|
323
|
+
-- Custom UDF Query
|
|
324
|
+
CREATE STREAM ${options.outputStream} AS
|
|
325
|
+
SELECT
|
|
326
|
+
${options.groupByKey ? `${options.groupByKey},` : ''}
|
|
327
|
+
${options.udfName}(${params}) AS result
|
|
328
|
+
FROM ${options.inputStream}
|
|
329
|
+
${groupBy}
|
|
330
|
+
EMIT CHANGES;
|
|
331
|
+
|
|
332
|
+
/* Example UDF (Java):
|
|
333
|
+
* @UdfDescription(name = "weighted_avg", description = "Calculates weighted average")
|
|
334
|
+
* public class WeightedAvgUDF {
|
|
335
|
+
* @Udf(description = "weighted_avg(value, weight)")
|
|
336
|
+
* public double weightedAvg(double value, double weight) {
|
|
337
|
+
* // Custom aggregation logic
|
|
338
|
+
* }
|
|
339
|
+
* }
|
|
340
|
+
*
|
|
341
|
+
* Usage:
|
|
342
|
+
* SELECT weighted_avg(price, quantity) AS avg_price FROM orders;
|
|
343
|
+
*/
|
|
344
|
+
`.trim();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* ksqlDB UDF Generator
|
|
350
|
+
*
|
|
351
|
+
* Generates Java UDF code templates
|
|
352
|
+
*/
|
|
353
|
+
export class KsqlDBUDFGenerator {
|
|
354
|
+
/**
|
|
355
|
+
* Generate scalar UDF template
|
|
356
|
+
*/
|
|
357
|
+
static generateScalarUDF(options: {
|
|
358
|
+
udfName: string;
|
|
359
|
+
description: string;
|
|
360
|
+
parameters: Array<{ name: string; type: string }>;
|
|
361
|
+
returnType: string;
|
|
362
|
+
}): string {
|
|
363
|
+
const params = options.parameters
|
|
364
|
+
.map((p) => `final ${p.type} ${p.name}`)
|
|
365
|
+
.join(', ');
|
|
366
|
+
|
|
367
|
+
return `
|
|
368
|
+
package com.example.ksqldb.udf;
|
|
369
|
+
|
|
370
|
+
import io.confluent.ksql.function.udf.Udf;
|
|
371
|
+
import io.confluent.ksql.function.udf.UdfDescription;
|
|
372
|
+
|
|
373
|
+
@UdfDescription(
|
|
374
|
+
name = "${options.udfName}",
|
|
375
|
+
description = "${options.description}"
|
|
376
|
+
)
|
|
377
|
+
public class ${this.toPascalCase(options.udfName)}UDF {
|
|
378
|
+
|
|
379
|
+
@Udf(description = "${options.description}")
|
|
380
|
+
public ${options.returnType} ${options.udfName}(${params}) {
|
|
381
|
+
// TODO: Implement UDF logic
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/* Deployment:
|
|
387
|
+
* 1. Build JAR: mvn clean package
|
|
388
|
+
* 2. Copy to ksqlDB extensions: /usr/share/java/ksqldb-server/ext/
|
|
389
|
+
* 3. Restart ksqlDB server
|
|
390
|
+
* 4. Test: SHOW FUNCTIONS;
|
|
391
|
+
*/
|
|
392
|
+
`.trim();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Generate UDAF (User-Defined Aggregate Function) template
|
|
397
|
+
*/
|
|
398
|
+
static generateUDAF(options: {
|
|
399
|
+
udafName: string;
|
|
400
|
+
description: string;
|
|
401
|
+
inputType: string;
|
|
402
|
+
aggregateType: string;
|
|
403
|
+
returnType: string;
|
|
404
|
+
}): string {
|
|
405
|
+
return `
|
|
406
|
+
package com.example.ksqldb.udaf;
|
|
407
|
+
|
|
408
|
+
import io.confluent.ksql.function.udaf.Udaf;
|
|
409
|
+
import io.confluent.ksql.function.udaf.UdafDescription;
|
|
410
|
+
import io.confluent.ksql.function.udaf.UdafFactory;
|
|
411
|
+
|
|
412
|
+
@UdafDescription(
|
|
413
|
+
name = "${options.udafName}",
|
|
414
|
+
description = "${options.description}"
|
|
415
|
+
)
|
|
416
|
+
public class ${this.toPascalCase(options.udafName)}UDAF {
|
|
417
|
+
|
|
418
|
+
@UdafFactory(description = "${options.description}")
|
|
419
|
+
public static Udaf<${options.inputType}, ${options.aggregateType}, ${options.returnType}> create${this.toPascalCase(options.udafName)}() {
|
|
420
|
+
return new Udaf<${options.inputType}, ${options.aggregateType}, ${options.returnType}>() {
|
|
421
|
+
|
|
422
|
+
@Override
|
|
423
|
+
public ${options.aggregateType} initialize() {
|
|
424
|
+
// Initialize aggregate state
|
|
425
|
+
return null; // TODO
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
@Override
|
|
429
|
+
public ${options.aggregateType} aggregate(${options.inputType} newValue, ${options.aggregateType} aggregate) {
|
|
430
|
+
// Add new value to aggregate
|
|
431
|
+
return aggregate; // TODO
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
@Override
|
|
435
|
+
public ${options.aggregateType} merge(${options.aggregateType} agg1, ${options.aggregateType} agg2) {
|
|
436
|
+
// Merge two aggregates (for parallel processing)
|
|
437
|
+
return agg1; // TODO
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
@Override
|
|
441
|
+
public ${options.returnType} map(${options.aggregateType} aggregate) {
|
|
442
|
+
// Convert aggregate to return type
|
|
443
|
+
return null; // TODO
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* Example Usage (ksqlDB):
|
|
450
|
+
* CREATE TABLE aggregated AS
|
|
451
|
+
* SELECT
|
|
452
|
+
* key,
|
|
453
|
+
* ${options.udafName}(value) AS result
|
|
454
|
+
* FROM input_stream
|
|
455
|
+
* GROUP BY key;
|
|
456
|
+
*/
|
|
457
|
+
`.trim();
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private static toPascalCase(str: string): string {
|
|
461
|
+
return str
|
|
462
|
+
.split('_')
|
|
463
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
464
|
+
.join('');
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Example Usage: Stream-Stream Join
|
|
470
|
+
*
|
|
471
|
+
* ```typescript
|
|
472
|
+
* const joinQuery = KsqlDBQueryBuilder.generateStreamStreamJoin({
|
|
473
|
+
* leftStream: 'clicks',
|
|
474
|
+
* rightStream: 'purchases',
|
|
475
|
+
* joinKey: 'user_id',
|
|
476
|
+
* windowSizeMinutes: 30,
|
|
477
|
+
* outputStream: 'click_to_purchase',
|
|
478
|
+
* selectFields: [
|
|
479
|
+
* 'L.user_id',
|
|
480
|
+
* 'L.page AS clicked_page',
|
|
481
|
+
* 'R.product AS purchased_product',
|
|
482
|
+
* 'R.amount'
|
|
483
|
+
* ],
|
|
484
|
+
* });
|
|
485
|
+
* console.log(joinQuery);
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Example Usage: Session Window Aggregation
|
|
491
|
+
*
|
|
492
|
+
* ```typescript
|
|
493
|
+
* const sessionQuery = KsqlDBQueryBuilder.generateSessionAggregation({
|
|
494
|
+
* inputStream: 'page_views',
|
|
495
|
+
* groupByKey: 'user_id',
|
|
496
|
+
* sessionGapMinutes: 30,
|
|
497
|
+
* outputTable: 'user_sessions',
|
|
498
|
+
* aggregations: [
|
|
499
|
+
* { func: 'COUNT', column: '*', alias: 'page_count' },
|
|
500
|
+
* { func: 'COLLECT_LIST', column: 'page', alias: 'pages' },
|
|
501
|
+
* { func: 'EARLIEST_BY_OFFSET', column: 'timestamp', alias: 'session_start' },
|
|
502
|
+
* { func: 'LATEST_BY_OFFSET', column: 'timestamp', alias: 'session_end' },
|
|
503
|
+
* ],
|
|
504
|
+
* });
|
|
505
|
+
* console.log(sessionQuery);
|
|
506
|
+
* ```
|
|
507
|
+
*/
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Example Usage: Custom UDAF
|
|
511
|
+
*
|
|
512
|
+
* ```typescript
|
|
513
|
+
* const udafCode = KsqlDBUDFGenerator.generateUDAF({
|
|
514
|
+
* udafName: 'percentile',
|
|
515
|
+
* description: 'Calculate 95th percentile',
|
|
516
|
+
* inputType: 'Double',
|
|
517
|
+
* aggregateType: 'List<Double>',
|
|
518
|
+
* returnType: 'Double',
|
|
519
|
+
* });
|
|
520
|
+
* // Write to src/main/java/com/example/ksqldb/udaf/PercentileUDAF.java
|
|
521
|
+
* ```
|
|
522
|
+
*/
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Advanced ksqlDB Best Practices:
|
|
526
|
+
*
|
|
527
|
+
* **Join Performance**:
|
|
528
|
+
* - Use smallest window size possible (reduces state size)
|
|
529
|
+
* - Stream-table joins are faster than stream-stream joins
|
|
530
|
+
* - Ensure join keys have same partitioning (co-partitioning)
|
|
531
|
+
* - Use LEFT JOIN to avoid dropping unmatched records
|
|
532
|
+
*
|
|
533
|
+
* **Windowing**:
|
|
534
|
+
* - Session windows: User sessions, click streams (gap-based)
|
|
535
|
+
* - Tumbling windows: Hourly/daily totals (non-overlapping)
|
|
536
|
+
* - Hopping windows: Real-time anomaly detection (overlapping)
|
|
537
|
+
* - Choose window retention based on data volume
|
|
538
|
+
*
|
|
539
|
+
* **UDF Development**:
|
|
540
|
+
* - Package UDFs in separate JAR (easier deployment)
|
|
541
|
+
* - Use @SchemaProvider for complex types
|
|
542
|
+
* - Test UDFs with unit tests before deployment
|
|
543
|
+
* - Avoid heavy computation in UDFs (use preprocessing)
|
|
544
|
+
*
|
|
545
|
+
* **Query Optimization**:
|
|
546
|
+
* - Filter early in the query (before joins/aggregations)
|
|
547
|
+
* - Use EMIT CHANGES for continuous queries
|
|
548
|
+
* - Use EMIT FINAL for window close events only
|
|
549
|
+
* - Monitor query performance with EXPLAIN
|
|
550
|
+
*
|
|
551
|
+
* **State Management**:
|
|
552
|
+
* - Monitor state store size (du -sh /var/lib/kafka-streams/)
|
|
553
|
+
* - Use changelog compaction for key-value state
|
|
554
|
+
* - Consider state store TTL for large windows
|
|
555
|
+
* - Backup state stores for disaster recovery
|
|
556
|
+
*/
|
|
557
|
+
|
|
558
|
+
export default {
|
|
559
|
+
KsqlDBQueryBuilder,
|
|
560
|
+
KsqlDBUDFGenerator,
|
|
561
|
+
JoinPattern,
|
|
562
|
+
AggregationPattern,
|
|
563
|
+
};
|