blockmine 1.21.0 → 1.22.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/agents/README.md +469 -0
- package/.claude/agents/auth-route-debugger.md +118 -0
- package/.claude/agents/auth-route-tester.md +93 -0
- package/.claude/agents/auto-error-resolver.md +97 -0
- package/.claude/agents/build-optimizer.md +236 -0
- package/.claude/agents/code-architecture-reviewer.md +83 -0
- package/.claude/agents/code-refactor-master.md +94 -0
- package/.claude/agents/cost-optimizer.md +134 -0
- package/.claude/agents/deployment-orchestrator.md +113 -0
- package/.claude/agents/documentation-architect.md +82 -0
- package/.claude/agents/frontend-error-fixer.md +77 -0
- package/.claude/agents/iac-code-generator.md +71 -0
- package/.claude/agents/incident-responder.md +346 -0
- package/.claude/agents/infrastructure-architect.md +31 -0
- package/.claude/agents/kubernetes-specialist.md +56 -0
- package/.claude/agents/migration-planner.md +181 -0
- package/.claude/agents/network-architect.md +196 -0
- package/.claude/agents/plan-reviewer.md +52 -0
- package/.claude/agents/refactor-planner.md +63 -0
- package/.claude/agents/security-scanner.md +102 -0
- package/.claude/agents/web-research-specialist.md +78 -0
- package/.claude/commands/cost-analysis.md +315 -0
- package/.claude/commands/dev-docs-update.md +55 -0
- package/.claude/commands/dev-docs.md +51 -0
- package/.claude/commands/incident-debug.md +247 -0
- package/.claude/commands/infra-plan.md +81 -0
- package/.claude/commands/migration-plan.md +478 -0
- package/.claude/commands/route-research-for-testing.md +37 -0
- package/.claude/commands/security-review.md +66 -0
- package/.claude/hooks/CONFIG.md +448 -0
- package/.claude/hooks/README.md +163 -0
- package/.claude/hooks/SKILL_ACTIVATION_COMPLETE.md +226 -0
- package/.claude/hooks/WINDOWS_HOOKS_README.md +151 -0
- package/.claude/hooks/add-skill-activation-banners.ts +132 -0
- package/.claude/hooks/comprehensive-skill-test.ts +1315 -0
- package/.claude/hooks/error-handling-reminder.sh +12 -0
- package/.claude/hooks/error-handling-reminder.ts +222 -0
- package/.claude/hooks/k8s-manifest-validator.sh +56 -0
- package/.claude/hooks/package-lock.json +556 -0
- package/.claude/hooks/package.json +16 -0
- package/.claude/hooks/post-tool-use-tracker.ps1 +174 -0
- package/.claude/hooks/post-tool-use-tracker.sh +183 -0
- package/.claude/hooks/security-policy-check.sh +247 -0
- package/.claude/hooks/skill-activation-prompt.ps1 +10 -0
- package/.claude/hooks/skill-activation-prompt.sh +10 -0
- package/.claude/hooks/skill-activation-prompt.ts +141 -0
- package/.claude/hooks/stop-build-check-enhanced.sh +130 -0
- package/.claude/hooks/terraform-validator.sh +53 -0
- package/.claude/hooks/test-input.json +7 -0
- package/.claude/hooks/test-skill-activation.ts +427 -0
- package/.claude/hooks/trigger-build-resolver.sh +79 -0
- package/.claude/hooks/tsc-check.sh +173 -0
- package/.claude/hooks/tsconfig.json +19 -0
- package/.claude/settings.json +55 -0
- package/.claude/settings.local.json +27 -14
- package/.claude/skills/README.md +507 -0
- package/.claude/skills/api-engineering/SKILL.md +63 -0
- package/.claude/skills/api-engineering/resources/api-versioning.md +88 -0
- package/.claude/skills/api-engineering/resources/graphql-patterns.md +106 -0
- package/.claude/skills/api-engineering/resources/rate-limiting.md +118 -0
- package/.claude/skills/api-engineering/resources/rest-api-design.md +105 -0
- package/.claude/skills/backend-dev-guidelines/SKILL.md +306 -0
- package/.claude/skills/backend-dev-guidelines/resources/architecture-overview.md +451 -0
- package/.claude/skills/backend-dev-guidelines/resources/async-and-errors.md +307 -0
- package/.claude/skills/backend-dev-guidelines/resources/complete-examples.md +638 -0
- package/.claude/skills/backend-dev-guidelines/resources/configuration.md +275 -0
- package/.claude/skills/backend-dev-guidelines/resources/database-patterns.md +224 -0
- package/.claude/skills/backend-dev-guidelines/resources/middleware-guide.md +213 -0
- package/.claude/skills/backend-dev-guidelines/resources/routing-and-controllers.md +756 -0
- package/.claude/skills/backend-dev-guidelines/resources/sentry-and-monitoring.md +336 -0
- package/.claude/skills/backend-dev-guidelines/resources/services-and-repositories.md +789 -0
- package/.claude/skills/backend-dev-guidelines/resources/testing-guide.md +235 -0
- package/.claude/skills/backend-dev-guidelines/resources/validation-patterns.md +754 -0
- package/.claude/skills/budget-and-cost-management/SKILL.md +850 -0
- package/.claude/skills/build-engineering/SKILL.md +431 -0
- package/.claude/skills/build-engineering/resources/artifact-repositories.md +72 -0
- package/.claude/skills/build-engineering/resources/build-caching.md +96 -0
- package/.claude/skills/build-engineering/resources/build-pipelines.md +105 -0
- package/.claude/skills/build-engineering/resources/build-security.md +95 -0
- package/.claude/skills/build-engineering/resources/build-systems.md +389 -0
- package/.claude/skills/build-engineering/resources/compilation-optimization.md +201 -0
- package/.claude/skills/build-engineering/resources/dependency-management.md +73 -0
- package/.claude/skills/build-engineering/resources/monorepo-builds.md +110 -0
- package/.claude/skills/build-engineering/resources/performance-optimization.md +113 -0
- package/.claude/skills/build-engineering/resources/reproducible-builds.md +82 -0
- package/.claude/skills/cloud-engineering/SKILL.md +675 -0
- package/.claude/skills/cloud-engineering/resources/aws-patterns.md +742 -0
- package/.claude/skills/cloud-engineering/resources/azure-patterns.md +714 -0
- package/.claude/skills/cloud-engineering/resources/cleared-cloud-environments.md +987 -0
- package/.claude/skills/cloud-engineering/resources/cloud-cost-optimization.md +757 -0
- package/.claude/skills/cloud-engineering/resources/cloud-networking.md +1058 -0
- package/.claude/skills/cloud-engineering/resources/cloud-security-tools.md +1530 -0
- package/.claude/skills/cloud-engineering/resources/cloud-security.md +990 -0
- package/.claude/skills/cloud-engineering/resources/gcp-patterns.md +758 -0
- package/.claude/skills/cloud-engineering/resources/migration-strategies.md +820 -0
- package/.claude/skills/cloud-engineering/resources/multi-cloud-strategies.md +670 -0
- package/.claude/skills/cloud-engineering/resources/oci-patterns.md +1198 -0
- package/.claude/skills/cloud-engineering/resources/serverless-patterns.md +795 -0
- package/.claude/skills/cloud-engineering/resources/well-architected-frameworks.md +966 -0
- package/.claude/skills/cybersecurity/SKILL.md +409 -0
- package/.claude/skills/cybersecurity/resources/security-architecture.md +266 -0
- package/.claude/skills/database-engineering/SKILL.md +61 -0
- package/.claude/skills/database-engineering/resources/backup-and-recovery.md +72 -0
- package/.claude/skills/database-engineering/resources/database-replication.md +63 -0
- package/.claude/skills/database-engineering/resources/postgresql-fundamentals.md +70 -0
- package/.claude/skills/database-engineering/resources/query-optimization.md +68 -0
- package/.claude/skills/devsecops/SKILL.md +374 -0
- package/.claude/skills/devsecops/resources/ci-cd-security.md +204 -0
- package/.claude/skills/devsecops/resources/compliance-automation.md +530 -0
- package/.claude/skills/devsecops/resources/compliance-frameworks.md +2322 -0
- package/.claude/skills/devsecops/resources/container-security.md +915 -0
- package/.claude/skills/devsecops/resources/cspm-integration.md +1440 -0
- package/.claude/skills/devsecops/resources/policy-enforcement.md +619 -0
- package/.claude/skills/devsecops/resources/secrets-management.md +755 -0
- package/.claude/skills/devsecops/resources/security-monitoring.md +146 -0
- package/.claude/skills/devsecops/resources/security-scanning.md +887 -0
- package/.claude/skills/devsecops/resources/security-testing.md +203 -0
- package/.claude/skills/devsecops/resources/supply-chain-security.md +518 -0
- package/.claude/skills/devsecops/resources/vulnerability-management.md +481 -0
- package/.claude/skills/devsecops/resources/zero-trust-architecture.md +177 -0
- package/.claude/skills/documentation-as-code/SKILL.md +323 -0
- package/.claude/skills/documentation-as-code/resources/api-documentation.md +90 -0
- package/.claude/skills/documentation-as-code/resources/changelog-management.md +79 -0
- package/.claude/skills/documentation-as-code/resources/diagram-generation.md +44 -0
- package/.claude/skills/documentation-as-code/resources/docs-as-code-workflow.md +99 -0
- package/.claude/skills/documentation-as-code/resources/documentation-automation.md +68 -0
- package/.claude/skills/documentation-as-code/resources/documentation-sites.md +79 -0
- package/.claude/skills/documentation-as-code/resources/markdown-best-practices.md +162 -0
- package/.claude/skills/documentation-as-code/resources/openapi-specification.md +77 -0
- package/.claude/skills/documentation-as-code/resources/readme-engineering.md +60 -0
- package/.claude/skills/documentation-as-code/resources/technical-writing-guide.md +202 -0
- package/.claude/skills/engineering-management/SKILL.md +356 -0
- package/.claude/skills/engineering-management/resources/career-ladders.md +609 -0
- package/.claude/skills/engineering-management/resources/hiring-and-assessment.md +555 -0
- package/.claude/skills/engineering-management/resources/one-on-one-guides.md +609 -0
- package/.claude/skills/engineering-management/resources/resource-planning.md +557 -0
- package/.claude/skills/engineering-management/resources/team-organization-patterns.md +491 -0
- package/.claude/skills/engineering-management/resources/technical-interviews.md +474 -0
- package/.claude/skills/engineering-operations-management/SKILL.md +817 -0
- package/.claude/skills/error-tracking/SKILL.md +379 -0
- package/.claude/skills/frontend-dev-guidelines/SKILL.md +403 -0
- package/.claude/skills/frontend-dev-guidelines/resources/common-patterns.md +331 -0
- package/.claude/skills/frontend-dev-guidelines/resources/complete-examples.md +872 -0
- package/.claude/skills/frontend-dev-guidelines/resources/component-patterns.md +502 -0
- package/.claude/skills/frontend-dev-guidelines/resources/data-fetching.md +767 -0
- package/.claude/skills/frontend-dev-guidelines/resources/file-organization.md +502 -0
- package/.claude/skills/frontend-dev-guidelines/resources/loading-and-error-states.md +501 -0
- package/.claude/skills/frontend-dev-guidelines/resources/performance.md +406 -0
- package/.claude/skills/frontend-dev-guidelines/resources/routing-guide.md +364 -0
- package/.claude/skills/frontend-dev-guidelines/resources/styling-guide.md +428 -0
- package/.claude/skills/frontend-dev-guidelines/resources/typescript-standards.md +418 -0
- package/.claude/skills/general-it-engineering/SKILL.md +393 -0
- package/.claude/skills/general-it-engineering/resources/asset-management.md +712 -0
- package/.claude/skills/general-it-engineering/resources/automation-orchestration.md +817 -0
- package/.claude/skills/general-it-engineering/resources/business-continuity.md +786 -0
- package/.claude/skills/general-it-engineering/resources/change-management.md +715 -0
- package/.claude/skills/general-it-engineering/resources/enterprise-monitoring.md +729 -0
- package/.claude/skills/general-it-engineering/resources/help-desk-operations.md +738 -0
- package/.claude/skills/general-it-engineering/resources/incident-service-management.md +834 -0
- package/.claude/skills/general-it-engineering/resources/it-governance.md +753 -0
- package/.claude/skills/general-it-engineering/resources/itil-framework.md +503 -0
- package/.claude/skills/general-it-engineering/resources/service-management.md +669 -0
- package/.claude/skills/infrastructure-architecture/SKILL.md +328 -0
- package/.claude/skills/infrastructure-architecture/resources/architecture-decision-records.md +505 -0
- package/.claude/skills/infrastructure-architecture/resources/architecture-patterns.md +528 -0
- package/.claude/skills/infrastructure-architecture/resources/capacity-planning.md +453 -0
- package/.claude/skills/infrastructure-architecture/resources/cleared-environment-architecture.md +773 -0
- package/.claude/skills/infrastructure-architecture/resources/cost-architecture.md +499 -0
- package/.claude/skills/infrastructure-architecture/resources/data-architecture.md +501 -0
- package/.claude/skills/infrastructure-architecture/resources/disaster-recovery.md +535 -0
- package/.claude/skills/infrastructure-architecture/resources/migration-architecture.md +512 -0
- package/.claude/skills/infrastructure-architecture/resources/multi-region-design.md +608 -0
- package/.claude/skills/infrastructure-architecture/resources/reference-architectures.md +562 -0
- package/.claude/skills/infrastructure-architecture/resources/security-architecture.md +538 -0
- package/.claude/skills/infrastructure-architecture/resources/system-design-principles.md +489 -0
- package/.claude/skills/infrastructure-architecture/resources/workload-classification.md +1000 -0
- package/.claude/skills/infrastructure-strategy/SKILL.md +924 -0
- package/.claude/skills/network-engineering/SKILL.md +385 -0
- package/.claude/skills/network-engineering/resources/dns-management.md +738 -0
- package/.claude/skills/network-engineering/resources/load-balancing.md +820 -0
- package/.claude/skills/network-engineering/resources/network-architecture.md +546 -0
- package/.claude/skills/network-engineering/resources/network-security.md +921 -0
- package/.claude/skills/network-engineering/resources/network-troubleshooting.md +749 -0
- package/.claude/skills/network-engineering/resources/routing-switching.md +373 -0
- package/.claude/skills/network-engineering/resources/sdn-networking.md +695 -0
- package/.claude/skills/network-engineering/resources/service-mesh-networking.md +777 -0
- package/.claude/skills/network-engineering/resources/tcp-ip-protocols.md +444 -0
- package/.claude/skills/network-engineering/resources/vpn-connectivity.md +672 -0
- package/.claude/skills/observability-engineering/SKILL.md +101 -0
- package/.claude/skills/observability-engineering/resources/apm-tools.md +97 -0
- package/.claude/skills/observability-engineering/resources/correlation-strategies.md +87 -0
- package/.claude/skills/observability-engineering/resources/distributed-tracing.md +98 -0
- package/.claude/skills/observability-engineering/resources/logs-aggregation.md +118 -0
- package/.claude/skills/observability-engineering/resources/observability-cost-optimization.md +141 -0
- package/.claude/skills/observability-engineering/resources/opentelemetry.md +110 -0
- package/.claude/skills/platform-engineering/SKILL.md +555 -0
- package/.claude/skills/platform-engineering/resources/architecture-overview.md +600 -0
- package/.claude/skills/platform-engineering/resources/container-orchestration.md +916 -0
- package/.claude/skills/platform-engineering/resources/cost-optimization.md +634 -0
- package/.claude/skills/platform-engineering/resources/developer-platforms.md +670 -0
- package/.claude/skills/platform-engineering/resources/gitops-automation.md +650 -0
- package/.claude/skills/platform-engineering/resources/infrastructure-as-code.md +778 -0
- package/.claude/skills/platform-engineering/resources/infrastructure-standards.md +708 -0
- package/.claude/skills/platform-engineering/resources/multi-tenancy.md +602 -0
- package/.claude/skills/platform-engineering/resources/platform-security.md +711 -0
- package/.claude/skills/platform-engineering/resources/resource-management.md +592 -0
- package/.claude/skills/platform-engineering/resources/service-mesh.md +628 -0
- package/.claude/skills/release-engineering/SKILL.md +393 -0
- package/.claude/skills/release-engineering/resources/artifact-management.md +108 -0
- package/.claude/skills/release-engineering/resources/build-optimization.md +84 -0
- package/.claude/skills/release-engineering/resources/ci-cd-pipelines.md +411 -0
- package/.claude/skills/release-engineering/resources/deployment-strategies.md +197 -0
- package/.claude/skills/release-engineering/resources/pipeline-security.md +62 -0
- package/.claude/skills/release-engineering/resources/progressive-delivery.md +83 -0
- package/.claude/skills/release-engineering/resources/release-automation.md +68 -0
- package/.claude/skills/release-engineering/resources/release-orchestration.md +77 -0
- package/.claude/skills/release-engineering/resources/rollback-strategies.md +66 -0
- package/.claude/skills/release-engineering/resources/versioning-strategies.md +59 -0
- package/.claude/skills/route-tester/SKILL.md +392 -0
- package/.claude/skills/skill-developer/ADVANCED.md +197 -0
- package/.claude/skills/skill-developer/HOOK_MECHANISMS.md +306 -0
- package/.claude/skills/skill-developer/PATTERNS_LIBRARY.md +152 -0
- package/.claude/skills/skill-developer/SKILL.md +430 -0
- package/.claude/skills/skill-developer/SKILL_RULES_REFERENCE.md +315 -0
- package/.claude/skills/skill-developer/TRIGGER_TYPES.md +305 -0
- package/.claude/skills/skill-developer/TROUBLESHOOTING.md +514 -0
- package/.claude/skills/skill-rules.json +2940 -0
- package/.claude/skills/sre/SKILL.md +464 -0
- package/.claude/skills/sre/resources/alerting-best-practices.md +282 -0
- package/.claude/skills/sre/resources/capacity-planning.md +226 -0
- package/.claude/skills/sre/resources/chaos-engineering.md +193 -0
- package/.claude/skills/sre/resources/disaster-recovery.md +232 -0
- package/.claude/skills/sre/resources/incident-management.md +436 -0
- package/.claude/skills/sre/resources/observability-stack.md +240 -0
- package/.claude/skills/sre/resources/on-call-runbooks.md +167 -0
- package/.claude/skills/sre/resources/performance-optimization.md +108 -0
- package/.claude/skills/sre/resources/reliability-patterns.md +183 -0
- package/.claude/skills/sre/resources/slo-sli-sla.md +464 -0
- package/.claude/skills/sre/resources/toil-reduction.md +145 -0
- package/.claude/skills/systems-engineering/SKILL.md +648 -0
- package/.claude/skills/systems-engineering/resources/automation-patterns.md +771 -0
- package/.claude/skills/systems-engineering/resources/configuration-management.md +998 -0
- package/.claude/skills/systems-engineering/resources/linux-administration.md +672 -0
- package/.claude/skills/systems-engineering/resources/networking-fundamentals.md +982 -0
- package/.claude/skills/systems-engineering/resources/performance-tuning.md +871 -0
- package/.claude/skills/systems-engineering/resources/powershell-scripting.md +482 -0
- package/.claude/skills/systems-engineering/resources/security-hardening.md +739 -0
- package/.claude/skills/systems-engineering/resources/shell-scripting.md +915 -0
- package/.claude/skills/systems-engineering/resources/storage-management.md +628 -0
- package/.claude/skills/systems-engineering/resources/system-monitoring.md +787 -0
- package/.claude/skills/systems-engineering/resources/troubleshooting-guide.md +753 -0
- package/.claude/skills/systems-engineering/resources/windows-administration.md +738 -0
- package/.claude/skills/technical-leadership/SKILL.md +728 -0
- package/CHANGELOG.md +90 -54
- package/README.md +94 -0
- package/backend/docs/SECRETS_DOCUMENTATION.md +327 -0
- package/backend/jest.config.js +59 -0
- package/backend/package-lock.json +6129 -0
- package/backend/package.json +16 -4
- package/backend/prisma/migrations/20251026104609_add_websocket_api/migration.sql +33 -0
- package/backend/prisma/schema.prisma +33 -0
- package/backend/src/__tests__/core/DependencyService.test.js +336 -0
- package/backend/src/__tests__/core/UserService.test.js +875 -0
- package/backend/src/__tests__/repositories/BaseRepository.test.js +146 -0
- package/backend/src/__tests__/repositories/BotRepository.test.js +118 -0
- package/backend/src/__tests__/repositories/CommandRepository.test.js +132 -0
- package/backend/src/__tests__/repositories/EventGraphRepository.test.js +93 -0
- package/backend/src/__tests__/repositories/GroupRepository.test.js +155 -0
- package/backend/src/__tests__/repositories/PermissionRepository.test.js +130 -0
- package/backend/src/__tests__/repositories/PluginRepository.test.js +107 -0
- package/backend/src/__tests__/repositories/ServerRepository.test.js +80 -0
- package/backend/src/__tests__/repositories/UserRepository.test.js +128 -0
- package/backend/src/__tests__/secretsFilter.test.js +425 -0
- package/backend/src/__tests__/services/BotLifecycleService.test.js +411 -0
- package/backend/src/__tests__/services/BotProcessManager.test.js +285 -0
- package/backend/src/__tests__/services/CacheManager.test.js +125 -0
- package/backend/src/__tests__/services/CommandExecutionService.test.js +460 -0
- package/backend/src/__tests__/services/ResourceMonitorService.test.js +207 -0
- package/backend/src/__tests__/services/TelemetryService.test.js +291 -0
- package/backend/src/__tests__/setup.js +25 -0
- package/backend/src/api/routes/apiKeys.js +181 -0
- package/backend/src/api/routes/bots.js +49 -7
- package/backend/src/api/routes/plugins.js +2 -1
- package/backend/src/api/routes/system.js +174 -0
- package/backend/src/container.js +82 -0
- package/backend/src/core/BotManager.js +142 -871
- package/backend/src/core/BotManager.old.js +1093 -0
- package/backend/src/core/BotProcess.js +1092 -858
- package/backend/src/core/EventGraphManager.js +280 -198
- package/backend/src/core/GraphExecutionEngine.js +321 -325
- package/backend/src/core/MessageQueue.js +27 -6
- package/backend/src/core/NodeRegistry.js +37 -1134
- package/backend/src/core/PluginManager.js +62 -12
- package/backend/src/core/PrismaService.js +32 -0
- package/backend/src/core/UserService.js +3 -3
- package/backend/src/core/__tests__/PrismaService.test.js +24 -0
- package/backend/src/core/commands/README.md +305 -0
- package/backend/src/core/commands/dev.js +13 -7
- package/backend/src/core/commands/ping.js +10 -4
- package/backend/src/core/commands/whois.js +63 -0
- package/backend/src/core/config/validation.js +27 -0
- package/backend/src/core/constants/graphTypes.js +21 -0
- package/backend/src/core/node-registries/actions.js +132 -0
- package/backend/src/core/node-registries/arrays.js +137 -0
- package/backend/src/core/node-registries/bot.js +23 -0
- package/backend/src/core/node-registries/data.js +290 -0
- package/backend/src/core/node-registries/debug.js +26 -0
- package/backend/src/core/node-registries/events.js +187 -0
- package/backend/src/core/node-registries/flow.js +139 -0
- package/backend/src/core/node-registries/logic.js +45 -0
- package/backend/src/core/node-registries/math.js +42 -0
- package/backend/src/core/node-registries/objects.js +98 -0
- package/backend/src/core/node-registries/strings.js +153 -0
- package/backend/src/core/node-registries/time.js +113 -0
- package/backend/src/core/node-registries/users.js +79 -0
- package/backend/src/core/nodes/{action_bot_look_at.js → actions/bot_look_at.js} +36 -36
- package/backend/src/core/nodes/{action_bot_set_variable.js → actions/bot_set_variable.js} +32 -32
- package/backend/src/core/nodes/{action_send_log.js → actions/send_log.js} +28 -23
- package/backend/src/core/nodes/{action_send_message.js → actions/send_message.js} +32 -32
- package/backend/src/core/nodes/actions/send_websocket_response.js +33 -0
- package/backend/src/core/nodes/arrays/get_next.js +35 -0
- package/backend/src/core/nodes/{data_cast.js → data/cast.js} +8 -0
- package/backend/src/core/nodes/data/datetime_literal.js +27 -0
- package/backend/src/core/nodes/data/entity_info.js +69 -0
- package/backend/src/core/nodes/data/get_nearby_entities.js +32 -0
- package/backend/src/core/nodes/data/get_nearby_players.js +64 -0
- package/backend/src/core/nodes/{data_get_user_field.js → data/get_user_field.js} +1 -1
- package/backend/src/core/nodes/data/type_check.js +53 -0
- package/backend/src/core/nodes/{debug_log.js → debug/log.js} +16 -16
- package/backend/src/core/nodes/{flow_branch.js → flow/branch.js} +15 -15
- package/backend/src/core/nodes/{flow_break.js → flow/break.js} +14 -14
- package/backend/src/core/nodes/flow/delay.js +43 -0
- package/backend/src/core/nodes/{flow_for_each.js → flow/for_each.js} +39 -39
- package/backend/src/core/nodes/{flow_sequence.js → flow/sequence.js} +16 -16
- package/backend/src/core/nodes/{flow_switch.js → flow/switch.js} +47 -47
- package/backend/src/core/nodes/{flow_while.js → flow/while.js} +1 -1
- package/backend/src/core/nodes/logic/__tests__/compare.test.js +83 -0
- package/backend/src/core/nodes/math/__tests__/operation.test.js +65 -0
- package/backend/src/core/nodes/strings/__tests__/concat.test.js +89 -0
- package/backend/src/core/nodes/time/__tests__/now.test.js +24 -0
- package/backend/src/core/nodes/time/add.js +33 -0
- package/backend/src/core/nodes/time/compare.js +35 -0
- package/backend/src/core/nodes/time/diff.js +29 -0
- package/backend/src/core/nodes/time/format.js +32 -0
- package/backend/src/core/nodes/time/now.js +18 -0
- package/backend/src/core/nodes/{user_check_blacklist.js → users/check_blacklist.js} +37 -37
- package/backend/src/core/nodes/{user_get_groups.js → users/get_groups.js} +36 -36
- package/backend/src/core/nodes/{user_get_permissions.js → users/get_permissions.js} +36 -36
- package/backend/src/core/nodes/{user_set_blacklist.js → users/set_blacklist.js} +37 -37
- package/backend/src/core/services/BotLifecycleService.js +596 -0
- package/backend/src/core/services/BotProcessManager.js +163 -0
- package/backend/src/core/services/CacheManager.js +111 -0
- package/backend/src/core/services/CommandExecutionService.js +351 -0
- package/backend/src/core/services/ResourceMonitorService.js +90 -0
- package/backend/src/core/services/TelemetryService.js +124 -0
- package/backend/src/core/services/ValidationService.js +132 -0
- package/backend/src/core/services/__tests__/ValidationService.test.js +148 -0
- package/backend/src/core/services.js +20 -5
- package/backend/src/core/system/CommandContext.js +84 -0
- package/backend/src/core/system/Transport.js +78 -0
- package/backend/src/core/utils/__tests__/jsonParser.test.js +44 -0
- package/backend/src/core/utils/jsonParser.js +18 -0
- package/backend/src/core/utils/secretsFilter.js +262 -0
- package/backend/src/core/utils/variableParser.js +89 -0
- package/backend/src/core/validation/__tests__/nodeSchemas.test.js +175 -0
- package/backend/src/core/validation/nodeSchemas.js +112 -0
- package/backend/src/lib/prisma.js +2 -4
- package/backend/src/real-time/botApi/handlers/commandHandlers.js +28 -0
- package/backend/src/real-time/botApi/handlers/graphHandlers.js +99 -0
- package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +147 -0
- package/backend/src/real-time/botApi/handlers/index.js +43 -0
- package/backend/src/real-time/botApi/handlers/messageHandlers.js +66 -0
- package/backend/src/real-time/botApi/handlers/statusHandlers.js +17 -0
- package/backend/src/real-time/botApi/handlers/userHandlers.js +141 -0
- package/backend/src/real-time/botApi/index.js +40 -0
- package/backend/src/real-time/botApi/middleware.js +79 -0
- package/backend/src/real-time/botApi/utils.js +54 -0
- package/backend/src/real-time/socketHandler.js +6 -2
- package/backend/src/repositories/BaseRepository.js +43 -0
- package/backend/src/repositories/BotRepository.js +42 -0
- package/backend/src/repositories/CommandRepository.js +53 -0
- package/backend/src/repositories/EventGraphRepository.js +40 -0
- package/backend/src/repositories/GroupRepository.js +69 -0
- package/backend/src/repositories/PermissionRepository.js +48 -0
- package/backend/src/repositories/PluginRepository.js +42 -0
- package/backend/src/repositories/ServerRepository.js +27 -0
- package/backend/src/repositories/UserRepository.js +48 -0
- package/backend/src/server.js +3 -0
- package/backend/src/test-refactor.js +85 -0
- package/frontend/dist/assets/index-CfTo92bP.css +1 -0
- package/frontend/dist/assets/index-CiFD5X9Z.js +8344 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +0 -5
- package/package.json +2 -1
- package/frontend/dist/assets/index-B9GedHEa.js +0 -8352
- package/frontend/dist/assets/index-zLiy9MDx.css +0 -1
- package/nul +0 -0
- /package/backend/src/core/nodes/{action_http_request.js → actions/http_request.js} +0 -0
- /package/backend/src/core/nodes/{array_add_element.js → arrays/add_element.js} +0 -0
- /package/backend/src/core/nodes/{array_contains.js → arrays/contains.js} +0 -0
- /package/backend/src/core/nodes/{array_find_index.js → arrays/find_index.js} +0 -0
- /package/backend/src/core/nodes/{array_get_by_index.js → arrays/get_by_index.js} +0 -0
- /package/backend/src/core/nodes/{array_get_random_element.js → arrays/get_random_element.js} +0 -0
- /package/backend/src/core/nodes/{array_remove_by_index.js → arrays/remove_by_index.js} +0 -0
- /package/backend/src/core/nodes/{bot_get_position.js → bot/get_position.js} +0 -0
- /package/backend/src/core/nodes/{data_array_literal.js → data/array_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_boolean_literal.js → data/boolean_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_get_argument.js → data/get_argument.js} +0 -0
- /package/backend/src/core/nodes/{data_get_bot_look.js → data/get_bot_look.js} +0 -0
- /package/backend/src/core/nodes/{data_get_entity_field.js → data/get_entity_field.js} +0 -0
- /package/backend/src/core/nodes/{data_get_server_players.js → data/get_server_players.js} +0 -0
- /package/backend/src/core/nodes/{data_get_variable.js → data/get_variable.js} +0 -0
- /package/backend/src/core/nodes/{data_length.js → data/length.js} +0 -0
- /package/backend/src/core/nodes/{data_make_object.js → data/make_object.js} +0 -0
- /package/backend/src/core/nodes/{data_number_literal.js → data/number_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_string_literal.js → data/string_literal.js} +0 -0
- /package/backend/src/core/nodes/{logic_compare.js → logic/compare.js} +0 -0
- /package/backend/src/core/nodes/{logic_operation.js → logic/operation.js} +0 -0
- /package/backend/src/core/nodes/{math_operation.js → math/operation.js} +0 -0
- /package/backend/src/core/nodes/{math_random_number.js → math/random_number.js} +0 -0
- /package/backend/src/core/nodes/{object_create.js → objects/create.js} +0 -0
- /package/backend/src/core/nodes/{object_delete.js → objects/delete.js} +0 -0
- /package/backend/src/core/nodes/{object_get.js → objects/get.js} +0 -0
- /package/backend/src/core/nodes/{object_has_key.js → objects/has_key.js} +0 -0
- /package/backend/src/core/nodes/{object_set.js → objects/set.js} +0 -0
- /package/backend/src/core/nodes/{string_concat.js → strings/concat.js} +0 -0
- /package/backend/src/core/nodes/{string_contains.js → strings/contains.js} +0 -0
- /package/backend/src/core/nodes/{string_ends_with.js → strings/ends_with.js} +0 -0
- /package/backend/src/core/nodes/{string_equals.js → strings/equals.js} +0 -0
- /package/backend/src/core/nodes/{string_length.js → strings/length.js} +0 -0
- /package/backend/src/core/nodes/{string_matches.js → strings/matches.js} +0 -0
- /package/backend/src/core/nodes/{string_split.js → strings/split.js} +0 -0
- /package/backend/src/core/nodes/{string_starts_with.js → strings/starts_with.js} +0 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Configuration Management - UnifiedConfig Pattern
|
|
2
|
+
|
|
3
|
+
Complete guide to managing configuration in backend microservices.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [UnifiedConfig Overview](#unifiedconfig-overview)
|
|
8
|
+
- [NEVER Use process.env Directly](#never-use-processenv-directly)
|
|
9
|
+
- [Configuration Structure](#configuration-structure)
|
|
10
|
+
- [Environment-Specific Configs](#environment-specific-configs)
|
|
11
|
+
- [Secrets Management](#secrets-management)
|
|
12
|
+
- [Migration Guide](#migration-guide)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## UnifiedConfig Overview
|
|
17
|
+
|
|
18
|
+
### Why UnifiedConfig?
|
|
19
|
+
|
|
20
|
+
**Problems with process.env:**
|
|
21
|
+
- ❌ No type safety
|
|
22
|
+
- ❌ No validation
|
|
23
|
+
- ❌ Hard to test
|
|
24
|
+
- ❌ Scattered throughout code
|
|
25
|
+
- ❌ No default values
|
|
26
|
+
- ❌ Runtime errors for typos
|
|
27
|
+
|
|
28
|
+
**Benefits of unifiedConfig:**
|
|
29
|
+
- ✅ Type-safe configuration
|
|
30
|
+
- ✅ Single source of truth
|
|
31
|
+
- ✅ Validated at startup
|
|
32
|
+
- ✅ Easy to test with mocks
|
|
33
|
+
- ✅ Clear structure
|
|
34
|
+
- ✅ Fallback to environment variables
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## NEVER Use process.env Directly
|
|
39
|
+
|
|
40
|
+
### The Rule
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// ❌ NEVER DO THIS
|
|
44
|
+
const timeout = parseInt(process.env.TIMEOUT_MS || '5000');
|
|
45
|
+
const dbHost = process.env.DB_HOST || 'localhost';
|
|
46
|
+
|
|
47
|
+
// ✅ ALWAYS DO THIS
|
|
48
|
+
import { config } from './config/unifiedConfig';
|
|
49
|
+
const timeout = config.timeouts.default;
|
|
50
|
+
const dbHost = config.database.host;
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Why This Matters
|
|
54
|
+
|
|
55
|
+
**Example of problems:**
|
|
56
|
+
```typescript
|
|
57
|
+
// Typo in environment variable name
|
|
58
|
+
const host = process.env.DB_HSOT; // undefined! No error!
|
|
59
|
+
|
|
60
|
+
// Type safety
|
|
61
|
+
const port = process.env.PORT; // string! Need parseInt
|
|
62
|
+
const timeout = parseInt(process.env.TIMEOUT); // NaN if not set!
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**With unifiedConfig:**
|
|
66
|
+
```typescript
|
|
67
|
+
const port = config.server.port; // number, guaranteed
|
|
68
|
+
const timeout = config.timeouts.default; // number, with fallback
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Configuration Structure
|
|
74
|
+
|
|
75
|
+
### UnifiedConfig Interface
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
export interface UnifiedConfig {
|
|
79
|
+
database: {
|
|
80
|
+
host: string;
|
|
81
|
+
port: number;
|
|
82
|
+
username: string;
|
|
83
|
+
password: string;
|
|
84
|
+
database: string;
|
|
85
|
+
};
|
|
86
|
+
server: {
|
|
87
|
+
port: number;
|
|
88
|
+
sessionSecret: string;
|
|
89
|
+
};
|
|
90
|
+
tokens: {
|
|
91
|
+
jwt: string;
|
|
92
|
+
inactivity: string;
|
|
93
|
+
internal: string;
|
|
94
|
+
};
|
|
95
|
+
keycloak: {
|
|
96
|
+
realm: string;
|
|
97
|
+
client: string;
|
|
98
|
+
baseUrl: string;
|
|
99
|
+
secret: string;
|
|
100
|
+
};
|
|
101
|
+
aws: {
|
|
102
|
+
region: string;
|
|
103
|
+
emailQueueUrl: string;
|
|
104
|
+
accessKeyId: string;
|
|
105
|
+
secretAccessKey: string;
|
|
106
|
+
};
|
|
107
|
+
sentry: {
|
|
108
|
+
dsn: string;
|
|
109
|
+
environment: string;
|
|
110
|
+
tracesSampleRate: number;
|
|
111
|
+
};
|
|
112
|
+
// ... more sections
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Implementation Pattern
|
|
117
|
+
|
|
118
|
+
**File:** `/blog-api/src/config/unifiedConfig.ts`
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import * as fs from 'fs';
|
|
122
|
+
import * as path from 'path';
|
|
123
|
+
import * as ini from 'ini';
|
|
124
|
+
|
|
125
|
+
const configPath = path.join(__dirname, '../../config.ini');
|
|
126
|
+
const iniConfig = ini.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
127
|
+
|
|
128
|
+
export const config: UnifiedConfig = {
|
|
129
|
+
database: {
|
|
130
|
+
host: iniConfig.database?.host || process.env.DB_HOST || 'localhost',
|
|
131
|
+
port: parseInt(iniConfig.database?.port || process.env.DB_PORT || '3306'),
|
|
132
|
+
username: iniConfig.database?.username || process.env.DB_USER || 'root',
|
|
133
|
+
password: iniConfig.database?.password || process.env.DB_PASSWORD || '',
|
|
134
|
+
database: iniConfig.database?.database || process.env.DB_NAME || 'blog_dev',
|
|
135
|
+
},
|
|
136
|
+
server: {
|
|
137
|
+
port: parseInt(iniConfig.server?.port || process.env.PORT || '3002'),
|
|
138
|
+
sessionSecret: iniConfig.server?.sessionSecret || process.env.SESSION_SECRET || 'dev-secret',
|
|
139
|
+
},
|
|
140
|
+
// ... more configuration
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Validate critical config
|
|
144
|
+
if (!config.tokens.jwt) {
|
|
145
|
+
throw new Error('JWT secret not configured!');
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Key Points:**
|
|
150
|
+
- Read from config.ini first
|
|
151
|
+
- Fallback to process.env
|
|
152
|
+
- Default values for development
|
|
153
|
+
- Validation at startup
|
|
154
|
+
- Type-safe access
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Environment-Specific Configs
|
|
159
|
+
|
|
160
|
+
### config.ini Structure
|
|
161
|
+
|
|
162
|
+
```ini
|
|
163
|
+
[database]
|
|
164
|
+
host = localhost
|
|
165
|
+
port = 3306
|
|
166
|
+
username = root
|
|
167
|
+
password = password1
|
|
168
|
+
database = blog_dev
|
|
169
|
+
|
|
170
|
+
[server]
|
|
171
|
+
port = 3002
|
|
172
|
+
sessionSecret = your-secret-here
|
|
173
|
+
|
|
174
|
+
[tokens]
|
|
175
|
+
jwt = your-jwt-secret
|
|
176
|
+
inactivity = 30m
|
|
177
|
+
internal = internal-api-token
|
|
178
|
+
|
|
179
|
+
[keycloak]
|
|
180
|
+
realm = myapp
|
|
181
|
+
client = myapp-client
|
|
182
|
+
baseUrl = http://localhost:8080
|
|
183
|
+
secret = keycloak-client-secret
|
|
184
|
+
|
|
185
|
+
[sentry]
|
|
186
|
+
dsn = https://your-sentry-dsn
|
|
187
|
+
environment = development
|
|
188
|
+
tracesSampleRate = 0.1
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Environment Overrides
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# .env file (optional overrides)
|
|
195
|
+
DB_HOST=production-db.example.com
|
|
196
|
+
DB_PASSWORD=secure-password
|
|
197
|
+
PORT=80
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Precedence:**
|
|
201
|
+
1. config.ini (highest priority)
|
|
202
|
+
2. process.env variables
|
|
203
|
+
3. Hard-coded defaults (lowest priority)
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Secrets Management
|
|
208
|
+
|
|
209
|
+
### DO NOT Commit Secrets
|
|
210
|
+
|
|
211
|
+
```gitignore
|
|
212
|
+
# .gitignore
|
|
213
|
+
config.ini
|
|
214
|
+
.env
|
|
215
|
+
sentry.ini
|
|
216
|
+
*.pem
|
|
217
|
+
*.key
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Use Environment Variables in Production
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// Development: config.ini
|
|
224
|
+
// Production: Environment variables
|
|
225
|
+
|
|
226
|
+
export const config: UnifiedConfig = {
|
|
227
|
+
database: {
|
|
228
|
+
password: process.env.DB_PASSWORD || iniConfig.database?.password || '',
|
|
229
|
+
},
|
|
230
|
+
tokens: {
|
|
231
|
+
jwt: process.env.JWT_SECRET || iniConfig.tokens?.jwt || '',
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Migration Guide
|
|
239
|
+
|
|
240
|
+
### Find All process.env Usage
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
grep -r "process.env" blog-api/src/ --include="*.ts" | wc -l
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Migration Example
|
|
247
|
+
|
|
248
|
+
**Before:**
|
|
249
|
+
```typescript
|
|
250
|
+
// Scattered throughout code
|
|
251
|
+
const timeout = parseInt(process.env.OPENID_HTTP_TIMEOUT_MS || '15000');
|
|
252
|
+
const keycloakUrl = process.env.KEYCLOAK_BASE_URL;
|
|
253
|
+
const jwtSecret = process.env.JWT_SECRET;
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**After:**
|
|
257
|
+
```typescript
|
|
258
|
+
import { config } from './config/unifiedConfig';
|
|
259
|
+
|
|
260
|
+
const timeout = config.keycloak.timeout;
|
|
261
|
+
const keycloakUrl = config.keycloak.baseUrl;
|
|
262
|
+
const jwtSecret = config.tokens.jwt;
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Benefits:**
|
|
266
|
+
- Type-safe
|
|
267
|
+
- Centralized
|
|
268
|
+
- Easy to test
|
|
269
|
+
- Validated at startup
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
**Related Files:**
|
|
274
|
+
- [SKILL.md](SKILL.md)
|
|
275
|
+
- [testing-guide.md](testing-guide.md)
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Database Patterns - Prisma Best Practices
|
|
2
|
+
|
|
3
|
+
Complete guide to database access patterns using Prisma in backend microservices.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [PrismaService Usage](#prismaservice-usage)
|
|
8
|
+
- [Repository Pattern](#repository-pattern)
|
|
9
|
+
- [Transaction Patterns](#transaction-patterns)
|
|
10
|
+
- [Query Optimization](#query-optimization)
|
|
11
|
+
- [N+1 Query Prevention](#n1-query-prevention)
|
|
12
|
+
- [Error Handling](#error-handling)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## PrismaService Usage
|
|
17
|
+
|
|
18
|
+
### Basic Pattern
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { PrismaService } from '@project-lifecycle-portal/database';
|
|
22
|
+
|
|
23
|
+
// Always use PrismaService.main
|
|
24
|
+
const users = await PrismaService.main.user.findMany();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Check Availability
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
if (!PrismaService.isAvailable) {
|
|
31
|
+
throw new Error('Prisma client not initialized');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const user = await PrismaService.main.user.findUnique({ where: { id } });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Repository Pattern
|
|
40
|
+
|
|
41
|
+
### Why Use Repositories
|
|
42
|
+
|
|
43
|
+
✅ **Use repositories when:**
|
|
44
|
+
- Complex queries with joins/includes
|
|
45
|
+
- Query used in multiple places
|
|
46
|
+
- Need caching layer
|
|
47
|
+
- Want to mock for testing
|
|
48
|
+
|
|
49
|
+
❌ **Skip repositories for:**
|
|
50
|
+
- Simple one-off queries
|
|
51
|
+
- Prototyping (can refactor later)
|
|
52
|
+
|
|
53
|
+
### Repository Template
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
export class UserRepository {
|
|
57
|
+
async findById(id: string): Promise<User | null> {
|
|
58
|
+
return PrismaService.main.user.findUnique({
|
|
59
|
+
where: { id },
|
|
60
|
+
include: { profile: true },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async findActive(): Promise<User[]> {
|
|
65
|
+
return PrismaService.main.user.findMany({
|
|
66
|
+
where: { isActive: true },
|
|
67
|
+
orderBy: { createdAt: 'desc' },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async create(data: Prisma.UserCreateInput): Promise<User> {
|
|
72
|
+
return PrismaService.main.user.create({ data });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Transaction Patterns
|
|
80
|
+
|
|
81
|
+
### Simple Transaction
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const result = await PrismaService.main.$transaction(async (tx) => {
|
|
85
|
+
const user = await tx.user.create({ data: userData });
|
|
86
|
+
const profile = await tx.userProfile.create({ data: { userId: user.id } });
|
|
87
|
+
return { user, profile };
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Interactive Transaction
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const result = await PrismaService.main.$transaction(
|
|
95
|
+
async (tx) => {
|
|
96
|
+
const user = await tx.user.findUnique({ where: { id } });
|
|
97
|
+
if (!user) throw new Error('User not found');
|
|
98
|
+
|
|
99
|
+
return await tx.user.update({
|
|
100
|
+
where: { id },
|
|
101
|
+
data: { lastLogin: new Date() },
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
maxWait: 5000,
|
|
106
|
+
timeout: 10000,
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Query Optimization
|
|
114
|
+
|
|
115
|
+
### Use select to Limit Fields
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// ❌ Fetches all fields
|
|
119
|
+
const users = await PrismaService.main.user.findMany();
|
|
120
|
+
|
|
121
|
+
// ✅ Only fetch needed fields
|
|
122
|
+
const users = await PrismaService.main.user.findMany({
|
|
123
|
+
select: {
|
|
124
|
+
id: true,
|
|
125
|
+
email: true,
|
|
126
|
+
profile: { select: { firstName: true, lastName: true } },
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Use include Carefully
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// ❌ Excessive includes
|
|
135
|
+
const user = await PrismaService.main.user.findUnique({
|
|
136
|
+
where: { id },
|
|
137
|
+
include: {
|
|
138
|
+
profile: true,
|
|
139
|
+
posts: { include: { comments: true } },
|
|
140
|
+
workflows: { include: { steps: { include: { actions: true } } } },
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// ✅ Only include what you need
|
|
145
|
+
const user = await PrismaService.main.user.findUnique({
|
|
146
|
+
where: { id },
|
|
147
|
+
include: { profile: true },
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## N+1 Query Prevention
|
|
154
|
+
|
|
155
|
+
### Problem: N+1 Queries
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// ❌ N+1 Query Problem
|
|
159
|
+
const users = await PrismaService.main.user.findMany(); // 1 query
|
|
160
|
+
|
|
161
|
+
for (const user of users) {
|
|
162
|
+
// N queries (one per user)
|
|
163
|
+
const profile = await PrismaService.main.userProfile.findUnique({
|
|
164
|
+
where: { userId: user.id },
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Solution: Use include or Batching
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// ✅ Single query with include
|
|
173
|
+
const users = await PrismaService.main.user.findMany({
|
|
174
|
+
include: { profile: true },
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// ✅ Or batch query
|
|
178
|
+
const userIds = users.map(u => u.id);
|
|
179
|
+
const profiles = await PrismaService.main.userProfile.findMany({
|
|
180
|
+
where: { userId: { in: userIds } },
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Error Handling
|
|
187
|
+
|
|
188
|
+
### Prisma Error Types
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { Prisma } from '@prisma/client';
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
await PrismaService.main.user.create({ data });
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
|
197
|
+
// Unique constraint violation
|
|
198
|
+
if (error.code === 'P2002') {
|
|
199
|
+
throw new ConflictError('Email already exists');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Foreign key constraint
|
|
203
|
+
if (error.code === 'P2003') {
|
|
204
|
+
throw new ValidationError('Invalid reference');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Record not found
|
|
208
|
+
if (error.code === 'P2025') {
|
|
209
|
+
throw new NotFoundError('Record not found');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Unknown error
|
|
214
|
+
Sentry.captureException(error);
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
**Related Files:**
|
|
222
|
+
- [SKILL.md](SKILL.md)
|
|
223
|
+
- [services-and-repositories.md](services-and-repositories.md)
|
|
224
|
+
- [async-and-errors.md](async-and-errors.md)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Middleware Guide - Express Middleware Patterns
|
|
2
|
+
|
|
3
|
+
Complete guide to creating and using middleware in backend microservices.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Authentication Middleware](#authentication-middleware)
|
|
8
|
+
- [Audit Middleware with AsyncLocalStorage](#audit-middleware-with-asynclocalstorage)
|
|
9
|
+
- [Error Boundary Middleware](#error-boundary-middleware)
|
|
10
|
+
- [Validation Middleware](#validation-middleware)
|
|
11
|
+
- [Composable Middleware](#composable-middleware)
|
|
12
|
+
- [Middleware Ordering](#middleware-ordering)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Authentication Middleware
|
|
17
|
+
|
|
18
|
+
### SSOMiddleware Pattern
|
|
19
|
+
|
|
20
|
+
**File:** `/form/src/middleware/SSOMiddleware.ts`
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
export class SSOMiddlewareClient {
|
|
24
|
+
static verifyLoginStatus(req: Request, res: Response, next: NextFunction): void {
|
|
25
|
+
const token = req.cookies.refresh_token;
|
|
26
|
+
|
|
27
|
+
if (!token) {
|
|
28
|
+
return res.status(401).json({ error: 'Not authenticated' });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const decoded = jwt.verify(token, config.tokens.jwt);
|
|
33
|
+
res.locals.claims = decoded;
|
|
34
|
+
res.locals.effectiveUserId = decoded.sub;
|
|
35
|
+
next();
|
|
36
|
+
} catch (error) {
|
|
37
|
+
res.status(401).json({ error: 'Invalid token' });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Audit Middleware with AsyncLocalStorage
|
|
46
|
+
|
|
47
|
+
### Excellent Pattern from Blog API
|
|
48
|
+
|
|
49
|
+
**File:** `/form/src/middleware/auditMiddleware.ts`
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
53
|
+
|
|
54
|
+
export interface AuditContext {
|
|
55
|
+
userId: string;
|
|
56
|
+
userName?: string;
|
|
57
|
+
impersonatedBy?: string;
|
|
58
|
+
sessionId?: string;
|
|
59
|
+
timestamp: Date;
|
|
60
|
+
requestId: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const auditContextStorage = new AsyncLocalStorage<AuditContext>();
|
|
64
|
+
|
|
65
|
+
export function auditMiddleware(req: Request, res: Response, next: NextFunction): void {
|
|
66
|
+
const context: AuditContext = {
|
|
67
|
+
userId: res.locals.effectiveUserId || 'anonymous',
|
|
68
|
+
userName: res.locals.claims?.preferred_username,
|
|
69
|
+
impersonatedBy: res.locals.isImpersonating ? res.locals.originalUserId : undefined,
|
|
70
|
+
timestamp: new Date(),
|
|
71
|
+
requestId: req.id || uuidv4(),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
auditContextStorage.run(context, () => {
|
|
75
|
+
next();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Getter for current context
|
|
80
|
+
export function getAuditContext(): AuditContext | null {
|
|
81
|
+
return auditContextStorage.getStore() || null;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Benefits:**
|
|
86
|
+
- Context propagates through entire request
|
|
87
|
+
- No need to pass context through every function
|
|
88
|
+
- Automatically available in services, repositories
|
|
89
|
+
- Type-safe context access
|
|
90
|
+
|
|
91
|
+
**Usage in Services:**
|
|
92
|
+
```typescript
|
|
93
|
+
import { getAuditContext } from '../middleware/auditMiddleware';
|
|
94
|
+
|
|
95
|
+
async function someOperation() {
|
|
96
|
+
const context = getAuditContext();
|
|
97
|
+
console.log('Operation by:', context?.userId);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Error Boundary Middleware
|
|
104
|
+
|
|
105
|
+
### Comprehensive Error Handler
|
|
106
|
+
|
|
107
|
+
**File:** `/form/src/middleware/errorBoundary.ts`
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
export function errorBoundary(
|
|
111
|
+
error: Error,
|
|
112
|
+
req: Request,
|
|
113
|
+
res: Response,
|
|
114
|
+
next: NextFunction
|
|
115
|
+
): void {
|
|
116
|
+
// Determine status code
|
|
117
|
+
const statusCode = getStatusCodeForError(error);
|
|
118
|
+
|
|
119
|
+
// Capture to Sentry
|
|
120
|
+
Sentry.withScope((scope) => {
|
|
121
|
+
scope.setLevel(statusCode >= 500 ? 'error' : 'warning');
|
|
122
|
+
scope.setTag('error_type', error.name);
|
|
123
|
+
scope.setContext('error_details', {
|
|
124
|
+
message: error.message,
|
|
125
|
+
stack: error.stack,
|
|
126
|
+
});
|
|
127
|
+
Sentry.captureException(error);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// User-friendly response
|
|
131
|
+
res.status(statusCode).json({
|
|
132
|
+
success: false,
|
|
133
|
+
error: {
|
|
134
|
+
message: getUserFriendlyMessage(error),
|
|
135
|
+
code: error.name,
|
|
136
|
+
},
|
|
137
|
+
requestId: Sentry.getCurrentScope().getPropagationContext().traceId,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Async wrapper
|
|
142
|
+
export function asyncErrorWrapper(
|
|
143
|
+
handler: (req: Request, res: Response, next: NextFunction) => Promise<any>
|
|
144
|
+
) {
|
|
145
|
+
return async (req: Request, res: Response, next: NextFunction) => {
|
|
146
|
+
try {
|
|
147
|
+
await handler(req, res, next);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
next(error);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Composable Middleware
|
|
158
|
+
|
|
159
|
+
### withAuthAndAudit Pattern
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
export function withAuthAndAudit(...authMiddleware: any[]) {
|
|
163
|
+
return [
|
|
164
|
+
...authMiddleware,
|
|
165
|
+
auditMiddleware,
|
|
166
|
+
];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Usage
|
|
170
|
+
router.post('/:formID/submit',
|
|
171
|
+
...withAuthAndAudit(SSOMiddlewareClient.verifyLoginStatus),
|
|
172
|
+
async (req, res) => controller.submit(req, res)
|
|
173
|
+
);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Middleware Ordering
|
|
179
|
+
|
|
180
|
+
### Critical Order (Must Follow)
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// 1. Sentry request handler (FIRST)
|
|
184
|
+
app.use(Sentry.Handlers.requestHandler());
|
|
185
|
+
|
|
186
|
+
// 2. Body parsing
|
|
187
|
+
app.use(express.json());
|
|
188
|
+
app.use(express.urlencoded({ extended: true }));
|
|
189
|
+
|
|
190
|
+
// 3. Cookie parsing
|
|
191
|
+
app.use(cookieParser());
|
|
192
|
+
|
|
193
|
+
// 4. Auth initialization
|
|
194
|
+
app.use(SSOMiddleware.initialize());
|
|
195
|
+
|
|
196
|
+
// 5. Routes registered here
|
|
197
|
+
app.use('/api/users', userRoutes);
|
|
198
|
+
|
|
199
|
+
// 6. Error handler (AFTER routes)
|
|
200
|
+
app.use(errorBoundary);
|
|
201
|
+
|
|
202
|
+
// 7. Sentry error handler (LAST)
|
|
203
|
+
app.use(Sentry.Handlers.errorHandler());
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Rule:** Error handlers MUST be registered AFTER all routes!
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
**Related Files:**
|
|
211
|
+
- [SKILL.md](SKILL.md)
|
|
212
|
+
- [routing-and-controllers.md](routing-and-controllers.md)
|
|
213
|
+
- [async-and-errors.md](async-and-errors.md)
|