@wazir-dev/cli 1.0.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/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
# WebSockets and Real-Time — Architecture Expertise Module
|
|
2
|
+
|
|
3
|
+
> WebSockets provide full-duplex, persistent connections between client and server, enabling real-time bidirectional communication. They solve the fundamental limitation of HTTP's request-response model but introduce significant complexity in scaling, connection management, and state handling. Every open WebSocket is a piece of server state — and stateful services are inherently harder to scale, deploy, and reason about.
|
|
4
|
+
|
|
5
|
+
> **Category:** Integration
|
|
6
|
+
> **Complexity:** Complex
|
|
7
|
+
> **Applies when:** Applications requiring real-time bidirectional communication — chat, collaborative editing, live dashboards, gaming, trading platforms
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What This Is (and What It Isn't)
|
|
12
|
+
|
|
13
|
+
### The WebSocket Protocol
|
|
14
|
+
|
|
15
|
+
WebSocket (RFC 6455) is a communication protocol that provides full-duplex communication channels over a single TCP connection. It is **not HTTP**. It begins life as an HTTP request — the client sends an `Upgrade: websocket` header — but after the server accepts the handshake, the protocol switches entirely. From that point forward, both sides can send messages at any time without waiting for a request. The connection stays open until one side closes it.
|
|
16
|
+
|
|
17
|
+
The handshake looks like HTTP:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
GET /chat HTTP/1.1
|
|
21
|
+
Host: server.example.com
|
|
22
|
+
Upgrade: websocket
|
|
23
|
+
Connection: Upgrade
|
|
24
|
+
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
|
25
|
+
Sec-WebSocket-Version: 13
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The server responds with `101 Switching Protocols`, and from that moment on, the connection speaks WebSocket framing — not HTTP. This distinction matters: HTTP middleware, caching proxies, and CDNs that do not understand WebSocket will break the connection. Load balancers must be configured for WebSocket-aware routing.
|
|
29
|
+
|
|
30
|
+
### Full-Duplex vs Half-Duplex
|
|
31
|
+
|
|
32
|
+
**Full-duplex** means both client and server can send data simultaneously and independently. Neither side waits for the other. This is fundamentally different from HTTP's request-response model (half-duplex), where the client sends a request and waits for a response before sending another.
|
|
33
|
+
|
|
34
|
+
This matters for interactive applications. In a collaborative editor, User A types a character, and User B types a character at the same time. Both changes must reach the server and propagate to the other client without either waiting. HTTP cannot do this without hacks — you would need two separate connections or multiplex over HTTP/2 streams.
|
|
35
|
+
|
|
36
|
+
### What WebSocket Is Not
|
|
37
|
+
|
|
38
|
+
WebSocket is not a message broker. It does not provide pub/sub, rooms, presence, message persistence, delivery guarantees, or ordering guarantees across multiple connections. It is a raw bidirectional pipe. Everything else — reconnection, authentication, rooms, fan-out — must be built on top or provided by a library like Socket.IO.
|
|
39
|
+
|
|
40
|
+
WebSocket is not a replacement for REST. Request-response APIs that fetch data on demand are perfectly served by HTTP. Adding WebSocket to an application that makes ten API calls per page load and updates once a minute is overengineering.
|
|
41
|
+
|
|
42
|
+
WebSocket is not fire-and-forget. Every open connection consumes server memory (typically 20-50 KB per connection with application-level buffers). Ten thousand connections means 200-500 MB of memory just for connection state, before any application logic. A million connections means 20-50 GB. You pay for every connection whether or not it is actively sending data.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## The Alternatives Landscape
|
|
47
|
+
|
|
48
|
+
WebSocket is one of several real-time communication technologies. Choosing the wrong one is a common and expensive mistake.
|
|
49
|
+
|
|
50
|
+
### Server-Sent Events (SSE)
|
|
51
|
+
|
|
52
|
+
SSE is a simple, HTTP-based protocol where the server pushes events to the client over a single long-lived HTTP connection. The client opens a standard HTTP request; the server keeps the response stream open and writes events as they occur.
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
GET /events HTTP/1.1
|
|
56
|
+
Accept: text/event-stream
|
|
57
|
+
|
|
58
|
+
HTTP/1.1 200 OK
|
|
59
|
+
Content-Type: text/event-stream
|
|
60
|
+
|
|
61
|
+
data: {"type": "price", "value": 142.50}
|
|
62
|
+
|
|
63
|
+
data: {"type": "price", "value": 143.10}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Key properties:**
|
|
67
|
+
- Server-to-client only (unidirectional). The client cannot send data back over the same connection.
|
|
68
|
+
- Built on standard HTTP — works with all existing infrastructure: CDNs, proxies, load balancers, HTTP/2 multiplexing.
|
|
69
|
+
- Automatic reconnection built into the browser API with `Last-Event-ID` for resumption.
|
|
70
|
+
- Text-only (no binary frames), though you can Base64-encode binary data.
|
|
71
|
+
- Limited to ~6 concurrent connections per domain in HTTP/1.1 (browser limit). HTTP/2 removes this limit via multiplexing.
|
|
72
|
+
|
|
73
|
+
**When SSE wins over WebSocket:** Notification feeds, live dashboards, stock tickers, news feeds, server log streaming — any scenario where data flows in one direction (server to client) and the client sends requests via normal HTTP endpoints. SSE is dramatically simpler to operate because the connection is standard HTTP.
|
|
74
|
+
|
|
75
|
+
### Long Polling
|
|
76
|
+
|
|
77
|
+
The client sends an HTTP request. The server holds the request open until it has new data (or a timeout expires), then responds. The client immediately sends another request. This simulates server push using standard HTTP.
|
|
78
|
+
|
|
79
|
+
**Key properties:**
|
|
80
|
+
- Works everywhere — no special protocol support required.
|
|
81
|
+
- High overhead: full HTTP headers on every exchange (hundreds of bytes per round trip).
|
|
82
|
+
- Latency floor equals one round trip — the client must receive the response and send a new request before it can receive the next update.
|
|
83
|
+
- Simple to implement, simple to debug, simple to scale (stateless servers).
|
|
84
|
+
|
|
85
|
+
**When long polling wins:** Legacy environments, very low update frequency (once per 5-30 seconds), situations where simplicity and debuggability outweigh latency, or when WebSocket/SSE are blocked by corporate proxies.
|
|
86
|
+
|
|
87
|
+
### HTTP/2 Server Push and Streams
|
|
88
|
+
|
|
89
|
+
HTTP/2 server push allows the server to proactively send resources to the client before the client requests them. However, this was designed for preloading assets (CSS, JS), not for real-time data streams. Major browsers have deprecated or removed HTTP/2 push support. It is not a viable real-time solution.
|
|
90
|
+
|
|
91
|
+
HTTP/2 streams, combined with SSE, are more relevant. HTTP/2 multiplexes multiple streams over a single TCP connection, eliminating the 6-connection limit that hampered SSE over HTTP/1.1. This makes SSE + HTTP/2 a strong combination for many real-time use cases.
|
|
92
|
+
|
|
93
|
+
### WebTransport
|
|
94
|
+
|
|
95
|
+
WebTransport is an emerging protocol built on HTTP/3 (QUIC). It provides bidirectional streams and unreliable datagrams over a single connection, avoiding TCP's head-of-line blocking.
|
|
96
|
+
|
|
97
|
+
**Current state (2025-2026):** Available in Chrome, Edge, and partially Firefox. Safari support is in development. Server infrastructure is limited. The specification is still evolving. WebTransport is the likely long-term successor to WebSocket for latency-sensitive applications (gaming, video), but it is not production-ready for most teams today. Plan for it; do not depend on it yet.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## When to Use WebSockets
|
|
102
|
+
|
|
103
|
+
### Chat and Messaging
|
|
104
|
+
|
|
105
|
+
Chat requires bidirectional communication with low latency. Users send messages (client-to-server) and receive messages from others (server-to-client) simultaneously. Typing indicators, read receipts, and presence updates all demand real-time bidirectional flow.
|
|
106
|
+
|
|
107
|
+
**Real-world example — Slack:** Slack maintains a WebSocket connection per active client. Messages, reactions, typing indicators, presence changes, and channel updates all flow over this connection. When Slack scaled from thousands to millions of concurrent users, they moved from a monolithic WebSocket gateway to a sharded architecture with a message fanout service backed by a distributed pub/sub layer. The WebSocket gateway handles connection management; the fanout service handles message routing.
|
|
108
|
+
|
|
109
|
+
**Real-world example — Discord:** Discord handles over 300 million WebSocket connections. Their gateway infrastructure is built in Elixir, leveraging the BEAM VM's ability to manage millions of lightweight concurrent processes. Discord shards its gateway — each shard handles approximately 5,000 guilds (servers). When a message is sent in a guild, the gateway shard responsible for that guild broadcasts the event to all connected members via their WebSocket connections. Discord can serve nearly two million concurrent users on a single backend server through aggressive optimization of their Elixir services.
|
|
110
|
+
|
|
111
|
+
### Collaborative Editing
|
|
112
|
+
|
|
113
|
+
Real-time collaborative editing (Google Docs, Figma, Notion) requires sub-100ms propagation of changes between users editing the same document simultaneously. WebSocket connections carry operational transforms or CRDT operations between clients and the server.
|
|
114
|
+
|
|
115
|
+
**Real-world example — Figma:** Figma models every document as a tree of objects (similar to the HTML DOM), where each object has an ID and a collection of properties. Figma clients connect to a "multiplayer" service via WebSocket. When a user modifies an element, the operation is sent immediately to the server, which validates it and broadcasts the change to all other connected clients. Figma evaluated CRDTs and Operational Transformations but chose a simplified approach: last-writer-wins on a per-property, per-object basis. This avoids the complexity of full CRDT/OT implementations while handling the vast majority of real-world conflicts in a design tool (two users rarely edit the same property of the same object at the same instant).
|
|
116
|
+
|
|
117
|
+
### Multiplayer Games
|
|
118
|
+
|
|
119
|
+
Games require bidirectional, low-latency communication. Player inputs flow client-to-server; game state updates flow server-to-client. Frame rates of 30-60 updates per second mean each message must arrive within 16-33ms. WebSocket (over TCP) works for turn-based and strategy games. For fast-paced action games, WebRTC data channels (over UDP) or the forthcoming WebTransport (over QUIC) are often preferred to avoid TCP's head-of-line blocking.
|
|
120
|
+
|
|
121
|
+
### Live Trading Platforms
|
|
122
|
+
|
|
123
|
+
Financial trading dashboards display real-time price feeds (server-to-client) and allow order placement (client-to-server). Latency directly affects profitability. WebSocket connections carry streaming market data from the exchange to the client. Order submissions flow back over the same connection. The bidirectional nature eliminates the round-trip overhead of REST calls for time-sensitive operations.
|
|
124
|
+
|
|
125
|
+
### Live Dashboards and Monitoring
|
|
126
|
+
|
|
127
|
+
Operations dashboards, analytics platforms, and monitoring tools that display metrics updating every 1-5 seconds. The server pushes metric updates; the client may send filter or query changes.
|
|
128
|
+
|
|
129
|
+
**Note:** If the dashboard only displays data and the user does not interact in real time, SSE is usually sufficient and simpler. Use WebSocket only when the client needs to send frequent updates back (e.g., adjusting query parameters, subscribing to different metric streams dynamically).
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## When to Use SSE Instead
|
|
134
|
+
|
|
135
|
+
SSE should be the default choice when communication is predominantly server-to-client. The rule of thumb cited by practitioners: **in 80% of cases where teams reach for WebSocket, SSE would have been sufficient.**
|
|
136
|
+
|
|
137
|
+
### Notification Feeds
|
|
138
|
+
|
|
139
|
+
Push notifications, activity streams, social media feeds. The server has new data; the client displays it. The client never needs to send data back over this channel — normal HTTP POST/PUT handles user actions.
|
|
140
|
+
|
|
141
|
+
### Live Scores and Tickers
|
|
142
|
+
|
|
143
|
+
Sports scores, stock prices, election results. Data flows one direction: server to client. Update frequency is typically 1-10 times per second. SSE handles this with zero protocol complexity.
|
|
144
|
+
|
|
145
|
+
### Server Log and Build Output Streaming
|
|
146
|
+
|
|
147
|
+
CI/CD pipelines streaming build logs, server log tailing, deployment status updates. The client watches; it does not send data back.
|
|
148
|
+
|
|
149
|
+
### AI/LLM Response Streaming
|
|
150
|
+
|
|
151
|
+
Streaming responses from large language models token-by-token to the client. This is inherently unidirectional — the server generates tokens, the client displays them. SSE is the standard approach used by OpenAI, Anthropic, and most LLM API providers.
|
|
152
|
+
|
|
153
|
+
### Why SSE Wins in These Cases
|
|
154
|
+
|
|
155
|
+
- **Infrastructure compatibility:** SSE is plain HTTP. Every CDN, load balancer, reverse proxy, and monitoring tool works with it out of the box. WebSocket requires explicit support at every layer.
|
|
156
|
+
- **Automatic reconnection:** The `EventSource` browser API reconnects automatically with `Last-Event-ID`, enabling seamless resumption. WebSocket reconnection must be implemented manually.
|
|
157
|
+
- **HTTP/2 multiplexing:** Multiple SSE streams share a single TCP connection, eliminating the per-stream connection overhead.
|
|
158
|
+
- **Simpler scaling:** SSE connections are stateless from the server's perspective (the server writes to an HTTP response stream). Standard HTTP load balancing works. No sticky sessions required.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## When NOT to Use WebSockets
|
|
163
|
+
|
|
164
|
+
This section is equally important as the "when to use" section. WebSocket complexity has overwhelmed more teams than it has helped.
|
|
165
|
+
|
|
166
|
+
### Request-Response Patterns
|
|
167
|
+
|
|
168
|
+
If your application's communication pattern is "client asks, server answers," you do not need WebSocket. REST or GraphQL over HTTP handles this with better tooling, caching, and observability. Adding WebSocket to avoid "the latency of HTTP" for normal API calls is premature optimization that introduces operational complexity far exceeding any latency savings.
|
|
169
|
+
|
|
170
|
+
### Low-Frequency Updates
|
|
171
|
+
|
|
172
|
+
If data changes once per minute or less, simple polling (a GET request every 30-60 seconds) is simpler, cheaper, and more reliable than maintaining a persistent connection. The overhead of an HTTP request every 30 seconds is negligible. The overhead of keeping 100,000 WebSocket connections alive 24/7 for data that updates once a minute is substantial.
|
|
173
|
+
|
|
174
|
+
**The break-even point:** WebSocket becomes more efficient than polling when update frequency exceeds roughly one update every 1-2 seconds. Below that threshold, polling or long polling is usually the better choice.
|
|
175
|
+
|
|
176
|
+
### Mobile Applications with Background Restrictions
|
|
177
|
+
|
|
178
|
+
iOS and Android aggressively kill background connections to conserve battery. A WebSocket connection that works perfectly in the foreground will be terminated within seconds to minutes of the app going to the background. You must implement reconnection logic, state reconciliation on reconnect, and push notification fallback for background delivery.
|
|
179
|
+
|
|
180
|
+
This means you need WebSocket AND push notifications AND reconciliation logic — three systems instead of one. Many mobile-first teams have discovered that push notifications plus periodic polling provides better user experience with far less complexity than WebSocket on mobile.
|
|
181
|
+
|
|
182
|
+
### When You Cannot Afford the Scaling Complexity
|
|
183
|
+
|
|
184
|
+
Scaling WebSocket is fundamentally harder than scaling stateless HTTP services. Each WebSocket connection is a piece of server state pinned to a specific server instance. You cannot simply add more servers behind a load balancer — you need sticky sessions or a pub/sub fanout layer. Deploying new versions requires draining connections gracefully. Monitoring must track per-connection metrics. Memory usage grows linearly with connection count.
|
|
185
|
+
|
|
186
|
+
**Real cost of WebSocket at scale:** Teams that underestimate this complexity routinely spend months building connection management infrastructure that they expected to take weeks. If your team does not have experience operating stateful services, consider managed real-time services (Ably, Pusher, Supabase Realtime) before building your own WebSocket infrastructure.
|
|
187
|
+
|
|
188
|
+
### When Corporate Firewalls Block WebSocket
|
|
189
|
+
|
|
190
|
+
Some enterprise networks, corporate proxies, and older network infrastructure block WebSocket connections or terminate them after a timeout. If your users are behind such networks, WebSocket connections will fail silently or disconnect repeatedly. SSE over HTTP typically passes through these environments without issue.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## How It Works: Connection Lifecycle and Scaling
|
|
195
|
+
|
|
196
|
+
### Connection Lifecycle
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
Client Server
|
|
200
|
+
| |
|
|
201
|
+
|--- HTTP GET /ws Upgrade ---> | 1. Handshake (HTTP)
|
|
202
|
+
|<-- 101 Switching Protocols -- | 2. Protocol switch
|
|
203
|
+
| |
|
|
204
|
+
|<== WebSocket Frame (text) ==> | 3. Bidirectional messages
|
|
205
|
+
|<== WebSocket Frame (binary) =>| (either side, any time)
|
|
206
|
+
|<== Ping ===================> | 4. Heartbeat (keep-alive)
|
|
207
|
+
|<== Pong <==================== |
|
|
208
|
+
| |
|
|
209
|
+
|--- Close Frame (1000) ------> | 5. Graceful close
|
|
210
|
+
|<-- Close Frame (1000) ------- |
|
|
211
|
+
| [TCP FIN] | 6. TCP teardown
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Key lifecycle points:**
|
|
215
|
+
|
|
216
|
+
1. **Handshake:** Standard HTTP request with `Upgrade: websocket`. This is the only point where HTTP authentication headers, cookies, and query parameters are available. After the upgrade, HTTP headers are gone.
|
|
217
|
+
|
|
218
|
+
2. **Message framing:** WebSocket frames are lightweight — 2-14 bytes of overhead per frame depending on payload size and masking. Compare to HTTP headers at 200-800 bytes per request.
|
|
219
|
+
|
|
220
|
+
3. **Ping/Pong (heartbeat):** The protocol includes built-in ping/pong frames for keep-alive. The server sends a ping; the client must respond with a pong. If no pong arrives within a timeout, the server considers the connection dead. This is essential for detecting zombie connections — connections where the client has disconnected (phone in a tunnel, browser tab closed on a crashed OS) but the TCP connection has not been properly closed.
|
|
221
|
+
|
|
222
|
+
4. **Close handshake:** Either side initiates a close by sending a close frame with a status code. The other side responds with a close frame. Then TCP is torn down. Status codes include 1000 (normal), 1001 (going away), 1008 (policy violation), 1011 (server error).
|
|
223
|
+
|
|
224
|
+
### Heartbeat and Dead Connection Detection
|
|
225
|
+
|
|
226
|
+
Without heartbeats, dead connections accumulate silently. A server that does not implement ping/pong will hold connections to clients that disconnected hours ago, leaking memory and file descriptors.
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
// Server-side heartbeat (Node.js with ws library)
|
|
230
|
+
const interval = setInterval(() => {
|
|
231
|
+
wss.clients.forEach((ws) => {
|
|
232
|
+
if (ws.isAlive === false) return ws.terminate();
|
|
233
|
+
ws.isAlive = false;
|
|
234
|
+
ws.ping();
|
|
235
|
+
});
|
|
236
|
+
}, 30000);
|
|
237
|
+
|
|
238
|
+
wss.on('connection', (ws) => {
|
|
239
|
+
ws.isAlive = true;
|
|
240
|
+
ws.on('pong', () => { ws.isAlive = true; });
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Heartbeat interval is a trade-off: too frequent wastes bandwidth on mobile networks; too infrequent delays dead connection detection. 15-30 seconds is a common production interval.
|
|
245
|
+
|
|
246
|
+
### Reconnection Strategies
|
|
247
|
+
|
|
248
|
+
Connections will drop. Networks are unreliable. Servers restart during deployments. Clients move between WiFi and cellular. Reconnection logic is not optional — it is a core requirement.
|
|
249
|
+
|
|
250
|
+
**Exponential backoff with jitter** is the standard approach:
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
function reconnect(attempt = 0) {
|
|
254
|
+
const baseDelay = 1000; // 1 second
|
|
255
|
+
const maxDelay = 30000; // 30 seconds
|
|
256
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
257
|
+
const jitter = delay * (0.5 + Math.random() * 0.5);
|
|
258
|
+
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
const ws = new WebSocket(url);
|
|
261
|
+
ws.onopen = () => { attempt = 0; /* reset on success */ };
|
|
262
|
+
ws.onclose = () => reconnect(attempt + 1);
|
|
263
|
+
}, jitter);
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Why jitter is critical:** Without jitter, if a server restarts and 50,000 clients reconnect, they all use the same backoff schedule and hit the server in synchronized waves (1s, 2s, 4s, 8s...). Jitter randomizes the reconnection time within each backoff window, spreading the load. This prevents the **reconnection storm** (also called the thundering herd problem), which can take down a server that was otherwise healthy enough to accept connections.
|
|
268
|
+
|
|
269
|
+
**Graceful draining during deployments:** When deploying a new server version, do not kill connections abruptly. Send a close frame with status 1001 (going away) and a retry hint. Drain connections in batches (e.g., 10% of connections every 5 seconds) rather than all at once. This is sometimes called the "funnel strategy" — gradually offboarding clients to prevent a sudden reconnection storm against the new instances.
|
|
270
|
+
|
|
271
|
+
### Authentication on WebSocket
|
|
272
|
+
|
|
273
|
+
WebSocket authentication is awkward because the protocol provides no built-in mechanism after the initial handshake. There are four common approaches, each with trade-offs:
|
|
274
|
+
|
|
275
|
+
**1. Token in query parameter (common but flawed):**
|
|
276
|
+
```javascript
|
|
277
|
+
new WebSocket('wss://api.example.com/ws?token=eyJhbGci...')
|
|
278
|
+
```
|
|
279
|
+
Simple to implement. But the token appears in server logs, proxy logs, and browser history. Not suitable for sensitive tokens. Acceptable for short-lived, single-use tokens.
|
|
280
|
+
|
|
281
|
+
**2. Cookie-based (most transparent):**
|
|
282
|
+
If the WebSocket endpoint is on the same domain as the web application, cookies are sent automatically with the upgrade request. The server validates the session cookie during the handshake. This works seamlessly but is vulnerable to CSRF if you do not validate the `Origin` header.
|
|
283
|
+
|
|
284
|
+
**3. First-message authentication (most secure):**
|
|
285
|
+
Open the connection without credentials. Send a JWT or token as the first message. The server validates the token before accepting any other messages. If validation fails, the server sends an error and closes the connection. This keeps credentials out of URLs and logs.
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
ws.onopen = () => {
|
|
289
|
+
ws.send(JSON.stringify({ type: 'auth', token: jwt }));
|
|
290
|
+
};
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**4. Ticket-based (hybrid):**
|
|
294
|
+
The client first calls a REST endpoint to obtain a short-lived, single-use WebSocket ticket. Then connects with that ticket. The server validates the ticket during the handshake and invalidates it immediately. This combines the simplicity of query-parameter auth with the security of short-lived tokens.
|
|
295
|
+
|
|
296
|
+
**Token refresh on long-lived connections:** JWTs expire. A WebSocket connection may outlive the token that authenticated it. Implement token refresh over the WebSocket channel — the server requests a new token before the current one expires, or the client proactively sends a refreshed token.
|
|
297
|
+
|
|
298
|
+
### Horizontal Scaling: The Core Challenge
|
|
299
|
+
|
|
300
|
+
A single WebSocket server can handle 10,000-100,000 concurrent connections depending on hardware, message volume, and application logic. When you need more, you scale horizontally — multiple server instances behind a load balancer. This is where WebSocket's statefulness creates real problems.
|
|
301
|
+
|
|
302
|
+
**The problem:** User A is connected to Server 1. User B is connected to Server 2. User A sends a message to User B. Server 1 has no knowledge of User B's connection — that state lives on Server 2.
|
|
303
|
+
|
|
304
|
+
**Solution 1: Sticky sessions (simple but fragile)**
|
|
305
|
+
|
|
306
|
+
Configure the load balancer to route all requests from the same client to the same server (via IP hash, cookie, or connection ID). This ensures a client's WebSocket connection always reaches the same server.
|
|
307
|
+
|
|
308
|
+
- **Limitation:** If Server 1 goes down, all its clients must reconnect to different servers, losing any in-memory state. Scaling up (adding Server 3) does not redistribute existing connections. Sticky sessions create uneven load distribution over time.
|
|
309
|
+
|
|
310
|
+
**Solution 2: Pub/Sub fanout (production standard)**
|
|
311
|
+
|
|
312
|
+
Use a message bus (Redis Pub/Sub, NATS, Kafka) to broadcast messages between server instances. When Server 1 receives a message for a chat room, it publishes to a Redis channel. All servers subscribe to that channel and forward the message to their locally connected clients who are in that room.
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
Client A ──→ WS Server 1 ──→ Redis Pub/Sub ──→ WS Server 2 ──→ Client B
|
|
316
|
+
│
|
|
317
|
+
└──→ WS Server 3 ──→ Client C
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
This is the standard architecture used by Socket.IO (with its Redis adapter), Discord, Slack, and most production real-time systems.
|
|
321
|
+
|
|
322
|
+
**Redis Pub/Sub specifics:**
|
|
323
|
+
- Fire-and-forget delivery — if a server is down when a message is published, that server's clients miss the message. Acceptable for ephemeral data (typing indicators, presence). Not acceptable for chat messages (use a persistent store as the source of truth).
|
|
324
|
+
- Single Redis instance handles approximately 500,000 messages/second. Redis Cluster can scale further.
|
|
325
|
+
- No message persistence. If you need replay, use Redis Streams or Kafka instead.
|
|
326
|
+
|
|
327
|
+
**NATS specifics:**
|
|
328
|
+
- Higher throughput than Redis Pub/Sub (millions of messages/second per node).
|
|
329
|
+
- Built-in clustering and subject-based routing.
|
|
330
|
+
- JetStream provides persistence and replay when needed.
|
|
331
|
+
- Increasingly popular as a WebSocket fanout layer in Go-based systems.
|
|
332
|
+
|
|
333
|
+
**Solution 3: Consistent hashing (for room-based systems)**
|
|
334
|
+
|
|
335
|
+
Route all connections for a given room/channel to the same server using consistent hashing. This eliminates the need for cross-server fanout within a room but requires a routing layer and re-balancing logic when servers are added or removed.
|
|
336
|
+
|
|
337
|
+
Discord uses a variant of this: each gateway shard is responsible for a specific set of guilds, and all connections for a guild route to the same shard.
|
|
338
|
+
|
|
339
|
+
### Presence and Room Management
|
|
340
|
+
|
|
341
|
+
**Rooms/channels:** Group connections by topic, conversation, or entity. A client subscribes to rooms; messages sent to a room are broadcast to all room members. This is application-level logic built on top of WebSocket — the protocol itself has no concept of rooms.
|
|
342
|
+
|
|
343
|
+
**Presence:** Tracking which users are currently online. This requires aggregating connection state across all server instances. Common approaches:
|
|
344
|
+
- **Heartbeat-based:** Each server periodically publishes its connected user list to a shared store (Redis). A user is "online" if any server reports them connected. A user goes "offline" when no server reports them for N heartbeat intervals.
|
|
345
|
+
- **Event-based:** Servers publish connect/disconnect events to a pub/sub channel. A central presence service aggregates these events.
|
|
346
|
+
|
|
347
|
+
Presence at scale is deceptively hard. Users have multiple devices (phone, laptop, tablet). Each device is a separate connection, possibly to a different server. "Online" means at least one connection exists. "Offline" means zero connections — but you must account for brief disconnects during network switches (a user walking from WiFi to cellular should not appear offline for 5 seconds).
|
|
348
|
+
|
|
349
|
+
### Message Ordering
|
|
350
|
+
|
|
351
|
+
WebSocket guarantees message ordering within a single connection (TCP provides this). But in a distributed system with multiple servers and a pub/sub layer, global ordering is not guaranteed. Two messages published to Redis from different servers may arrive at a third server in either order.
|
|
352
|
+
|
|
353
|
+
If ordering matters (chat messages in a conversation), use a monotonically increasing sequence number assigned by a single authoritative source (e.g., the database insert ID or a centralized sequence service). Clients reorder messages by sequence number, not by arrival order.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Trade-Offs Matrix
|
|
358
|
+
|
|
359
|
+
| Dimension | WebSocket | SSE | Long Polling | WebTransport |
|
|
360
|
+
|---|---|---|---|---|
|
|
361
|
+
| **Direction** | Bidirectional | Server → Client | Simulated bidirectional | Bidirectional + datagrams |
|
|
362
|
+
| **Protocol overhead** | 2-14 bytes/frame | ~5 bytes/event | 200-800 bytes/exchange | Similar to WebSocket |
|
|
363
|
+
| **Connection setup** | HTTP upgrade handshake | Standard HTTP GET | Standard HTTP GET | QUIC handshake |
|
|
364
|
+
| **Browser support** | Universal (98%+) | Universal except IE (97%+) | Universal (100%) | Chrome, Edge, partial Firefox (~75%) |
|
|
365
|
+
| **Infrastructure compat** | Requires WS-aware proxies | Works everywhere (HTTP) | Works everywhere (HTTP) | Requires HTTP/3 infrastructure |
|
|
366
|
+
| **Reconnection** | Manual implementation | Built-in with Last-Event-ID | Implicit (each request is new) | Manual implementation |
|
|
367
|
+
| **Scaling difficulty** | High (stateful) | Medium (HTTP-based) | Low (stateless) | High (stateful) |
|
|
368
|
+
| **Head-of-line blocking** | Yes (TCP) | Yes (TCP) | N/A (discrete requests) | No (QUIC streams) |
|
|
369
|
+
| **Binary data** | Native support | Base64 encoding needed | Base64 encoding needed | Native support |
|
|
370
|
+
| **Multiplexing** | One stream per connection | Multiple via HTTP/2 | N/A | Multiple streams per connection |
|
|
371
|
+
| **Latency** | Lowest (persistent conn) | Low (persistent conn) | High (per-request overhead) | Lowest (no HOL blocking) |
|
|
372
|
+
| **Mobile battery impact** | High (persistent conn) | Moderate | Low (periodic) | TBD |
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Evolution Path
|
|
377
|
+
|
|
378
|
+
Start simple. Escalate only when the simpler approach becomes a bottleneck. This is not theoretical advice — it is the path that successful production systems have followed.
|
|
379
|
+
|
|
380
|
+
### Level 1: Polling (Start Here)
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
Client ──GET /api/messages?since=timestamp──→ Server
|
|
384
|
+
every 5-30 seconds
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Works for: dashboards updating every 30 seconds, notification badges, status pages. Zero infrastructure complexity. Stateless servers. Standard HTTP caching. You can serve millions of users with a CDN in front if the data is not user-specific.
|
|
388
|
+
|
|
389
|
+
**Move to Level 2 when:** Update latency must be under 5 seconds, or polling frequency exceeds once per 2 seconds (at which point the HTTP overhead becomes significant).
|
|
390
|
+
|
|
391
|
+
### Level 2: SSE (Server-Sent Events)
|
|
392
|
+
|
|
393
|
+
```
|
|
394
|
+
Client ──GET /events──→ Server (keeps connection open, pushes events)
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Works for: live feeds, notifications, streaming responses, real-time dashboards. Standard HTTP infrastructure. Automatic reconnection. HTTP/2 multiplexing eliminates connection limits.
|
|
398
|
+
|
|
399
|
+
**Move to Level 3 when:** The client must send frequent real-time data to the server (not just occasional HTTP requests), or you need binary data frames, or you need sub-50ms latency.
|
|
400
|
+
|
|
401
|
+
### Level 3: WebSocket (Self-Managed)
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
Client ←═══ WebSocket ═══→ Server
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Works for: chat, collaborative editing, multiplayer games, trading platforms. Full bidirectional communication. Requires connection management, heartbeat, reconnection, and horizontal scaling infrastructure.
|
|
408
|
+
|
|
409
|
+
**Move to Level 4 when:** You need to scale beyond what your team can comfortably operate, or you need global edge distribution, or you are spending more engineering time on WebSocket infrastructure than on your product.
|
|
410
|
+
|
|
411
|
+
### Level 4: Managed Real-Time Service
|
|
412
|
+
|
|
413
|
+
```
|
|
414
|
+
Client ←═══ Ably / Pusher / Supabase Realtime ═══→ Your Server
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Works for: teams that need real-time without the operational burden. The managed service handles connection management, global distribution, scaling, presence, and message guarantees. You publish messages via an API; the service delivers them to connected clients.
|
|
418
|
+
|
|
419
|
+
**Trade-off:** Vendor lock-in, per-message pricing, less control over protocol details. But you get global edge infrastructure, guaranteed uptime, and zero operational burden for the real-time layer.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Failure Modes
|
|
424
|
+
|
|
425
|
+
### Connection Leaks (Memory Exhaustion)
|
|
426
|
+
|
|
427
|
+
**Symptom:** Server memory grows linearly over hours/days. Eventual OOM kill.
|
|
428
|
+
|
|
429
|
+
**Cause:** Connections that the client has abandoned but the server has not detected. The client closed the browser tab, the phone entered a tunnel, the laptop lid was closed — but no TCP FIN was sent. Without heartbeat/ping-pong, the server holds these zombie connections indefinitely.
|
|
430
|
+
|
|
431
|
+
**Prevention:** Implement server-side ping/pong with a strict timeout (e.g., ping every 30s, terminate if no pong within 10s). Monitor `connections_active` vs `connections_established` — a growing gap indicates leaks. Set file descriptor limits and connection caps per server. Log connection duration distributions; connections lasting >24 hours in most applications are likely zombies.
|
|
432
|
+
|
|
433
|
+
### Reconnection Storms (Thundering Herd)
|
|
434
|
+
|
|
435
|
+
**Symptom:** Server restarts or network blip causes all clients to reconnect simultaneously, overloading the server.
|
|
436
|
+
|
|
437
|
+
**Cause:** All clients detect the disconnect at the same time and retry immediately or with the same backoff schedule (no jitter).
|
|
438
|
+
|
|
439
|
+
**Prevention:** Always use exponential backoff with random jitter. During deployments, drain connections in batches (funnel strategy). Over-provision capacity to handle the reconnection surge. Consider a "connection queue" that rate-limits new WebSocket handshakes during high-load periods.
|
|
440
|
+
|
|
441
|
+
**Real cost:** A team at a mid-size startup reported that a single server restart caused 80,000 simultaneous reconnection attempts, taking down all three backup servers in a cascade. The root cause was missing jitter in their reconnection logic.
|
|
442
|
+
|
|
443
|
+
### Message Ordering Violations
|
|
444
|
+
|
|
445
|
+
**Symptom:** Chat messages appear in the wrong order. Collaborative edits produce incorrect state.
|
|
446
|
+
|
|
447
|
+
**Cause:** Messages routed through different pub/sub paths or server instances arrive out of order. TCP guarantees ordering within a single connection, but the pub/sub fanout layer does not.
|
|
448
|
+
|
|
449
|
+
**Prevention:** Assign monotonically increasing sequence numbers at the authoritative source (typically the database or a sequence service). Clients buffer and reorder by sequence number. For collaborative editing, use vector clocks or lamport timestamps.
|
|
450
|
+
|
|
451
|
+
### Mobile Background Disconnects
|
|
452
|
+
|
|
453
|
+
**Symptom:** Mobile users report missed messages or delayed notifications when the app is backgrounded.
|
|
454
|
+
|
|
455
|
+
**Cause:** iOS terminates background network connections within ~30 seconds. Android is similarly aggressive with Doze mode. The WebSocket connection dies silently when the app is backgrounded.
|
|
456
|
+
|
|
457
|
+
**Prevention:** Implement a dual-channel strategy: WebSocket for foreground real-time delivery, push notifications (APNs/FCM) for background delivery. On app foreground, reconnect the WebSocket and reconcile state by fetching missed messages from the server (using a "since" cursor or sequence number).
|
|
458
|
+
|
|
459
|
+
### Backpressure and Slow Consumers
|
|
460
|
+
|
|
461
|
+
**Symptom:** Server memory spikes when a client on a slow connection cannot consume messages fast enough.
|
|
462
|
+
|
|
463
|
+
**Cause:** The server queues outbound messages in memory for each client connection. If a client's network is slow (mobile on 2G), messages accumulate faster than they can be sent. With thousands of such clients, memory explodes.
|
|
464
|
+
|
|
465
|
+
**Prevention:** Set per-connection outbound buffer limits. When the buffer exceeds the limit, either drop messages (acceptable for ephemeral data like cursor positions), send a "catch up from server" signal and disconnect the client, or downgrade to sending only the latest state (conflation). Monitor per-connection send queue depth.
|
|
466
|
+
|
|
467
|
+
### Split-Brain in Presence
|
|
468
|
+
|
|
469
|
+
**Symptom:** Users appear online/offline incorrectly, or presence updates are delayed by minutes.
|
|
470
|
+
|
|
471
|
+
**Cause:** Presence aggregation across multiple servers is eventually consistent. Server 1 reports User A as connected; Server 2 has not received the heartbeat yet. During network partitions between servers, presence can diverge.
|
|
472
|
+
|
|
473
|
+
**Prevention:** Use a TTL-based presence model — a user is online if their presence record in Redis has not expired. Set TTL to 2-3x the heartbeat interval. Accept that presence is inherently approximate (not strongly consistent) and design the UX accordingly.
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Technology Landscape
|
|
478
|
+
|
|
479
|
+
### Raw WebSocket Libraries
|
|
480
|
+
|
|
481
|
+
**`ws` (Node.js):** The most popular Node.js WebSocket library. Minimal abstraction — gives you a raw WebSocket server with no opinions about rooms, auth, or reconnection. Handles 50,000+ connections per server. Use this when you want full control and minimal overhead.
|
|
482
|
+
|
|
483
|
+
**`gorilla/websocket` (Go, now archived) / `nhooyr.io/websocket` (Go):** High-performance Go WebSocket libraries. Go's goroutine model handles massive concurrency well — a single Go server can manage hundreds of thousands of connections. `nhooyr.io/websocket` is the actively maintained choice as of 2025.
|
|
484
|
+
|
|
485
|
+
**`tokio-tungstenite` (Rust):** For the highest performance requirements. Rust's zero-cost abstractions and lack of garbage collection make it suitable for systems targeting millions of connections per server.
|
|
486
|
+
|
|
487
|
+
### Frameworks with Built-in Real-Time
|
|
488
|
+
|
|
489
|
+
**Socket.IO (Node.js):** The most widely used real-time framework. Provides rooms, namespaces, automatic reconnection, fallback to long polling, and a Redis adapter for horizontal scaling. Socket.IO adds approximately 5-10% overhead compared to raw `ws` due to its protocol wrapper, but the developer experience improvements are significant for most teams.
|
|
490
|
+
|
|
491
|
+
**Caution:** Socket.IO uses its own protocol on top of WebSocket. Socket.IO clients cannot connect to raw WebSocket servers and vice versa. This is a one-way door — choosing Socket.IO means your clients must use the Socket.IO client library. If you need interoperability with third-party WebSocket clients, use raw WebSocket.
|
|
492
|
+
|
|
493
|
+
**Phoenix Channels (Elixir):** Built on the BEAM VM, Phoenix Channels provide real-time communication with built-in presence tracking and pub/sub. The BEAM's process model — millions of lightweight processes with isolated memory — makes Phoenix exceptionally well-suited for WebSocket workloads. Discord's gateway is built on this foundation. Phoenix Channels handle connection management, heartbeat, reconnection, topic-based routing, and presence out of the box.
|
|
494
|
+
|
|
495
|
+
**ActionCable (Rails):** Rails' built-in WebSocket framework. Integrates with Redis for pub/sub. Convenient for Rails applications but limited in performance compared to dedicated WebSocket servers. Suitable for applications with thousands, not hundreds of thousands, of concurrent connections.
|
|
496
|
+
|
|
497
|
+
**Django Channels (Python):** Adds WebSocket support to Django via ASGI. Uses a channel layer (typically Redis) for cross-process communication. Python's GIL limits per-process concurrency, so scaling requires multiple worker processes.
|
|
498
|
+
|
|
499
|
+
### Managed Real-Time Services
|
|
500
|
+
|
|
501
|
+
**Ably:** Enterprise-grade managed real-time messaging. Global edge network, message guarantees (exactly-once delivery), presence, history/replay, and connection state recovery. Pricing is per-message and per-connection.
|
|
502
|
+
|
|
503
|
+
**Pusher:** One of the original managed real-time services. Simple API, good documentation, generous free tier. Primarily targets pub/sub use cases (channels with publish/subscribe). Less feature-rich than Ably for complex use cases.
|
|
504
|
+
|
|
505
|
+
**Supabase Realtime:** Built on Elixir/Phoenix. Provides real-time subscriptions to Postgres changes — when a row changes in your database, connected clients receive the update automatically. Particularly compelling for applications already using Supabase for their backend.
|
|
506
|
+
|
|
507
|
+
**PubNub:** Global real-time messaging infrastructure. Focus on IoT and mobile messaging. Provides message persistence, access control, and push notification integration.
|
|
508
|
+
|
|
509
|
+
### Backend Fanout Infrastructure
|
|
510
|
+
|
|
511
|
+
**Redis Pub/Sub:** The default choice for cross-server message fanout. Simple, fast (~500K messages/sec per instance), widely supported. No persistence — messages are fire-and-forget.
|
|
512
|
+
|
|
513
|
+
**Redis Streams:** Persistent, ordered log with consumer groups. Use when you need message replay and guaranteed delivery, not just fire-and-forget fanout.
|
|
514
|
+
|
|
515
|
+
**NATS:** High-performance messaging system. Higher throughput than Redis Pub/Sub (millions of messages/sec). JetStream adds persistence. Excellent for Go-based systems. Supports subject-based routing with wildcards.
|
|
516
|
+
|
|
517
|
+
**Kafka:** Overkill for most WebSocket fanout use cases (designed for event streaming, not ephemeral pub/sub). Consider Kafka when your fanout layer also needs to feed analytics pipelines, audit logs, or stream processing.
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## Decision Tree
|
|
522
|
+
|
|
523
|
+
```
|
|
524
|
+
Do you need real-time updates?
|
|
525
|
+
├── No → Standard REST/GraphQL. Stop here.
|
|
526
|
+
└── Yes
|
|
527
|
+
├── How frequent are updates?
|
|
528
|
+
│ ├── Less than once per 30 seconds → Polling. Stop here.
|
|
529
|
+
│ └── More frequent → Continue
|
|
530
|
+
│
|
|
531
|
+
├── Does the client need to send real-time data to the server?
|
|
532
|
+
│ ├── No (server → client only)
|
|
533
|
+
│ │ ├── Text data? → SSE. Stop here.
|
|
534
|
+
│ │ └── Binary data or need multiplexing? → WebSocket or WebTransport.
|
|
535
|
+
│ │
|
|
536
|
+
│ └── Yes (bidirectional)
|
|
537
|
+
│ ├── Can your team operate stateful infrastructure?
|
|
538
|
+
│ │ ├── No → Use managed service (Ably, Pusher, Supabase Realtime).
|
|
539
|
+
│ │ └── Yes
|
|
540
|
+
│ │ ├── Scale: < 10K connections → Single WebSocket server.
|
|
541
|
+
│ │ ├── Scale: 10K-500K connections → WebSocket + Redis Pub/Sub.
|
|
542
|
+
│ │ ├── Scale: 500K-5M connections → Sharded WebSocket + NATS/Redis Cluster.
|
|
543
|
+
│ │ └── Scale: > 5M connections → Custom gateway (Elixir/Go/Rust) or managed service.
|
|
544
|
+
│ │
|
|
545
|
+
│ └── Is latency critical (<10ms) and TCP HOL blocking unacceptable?
|
|
546
|
+
│ ├── Yes → WebTransport (if browser support sufficient) or WebRTC data channels.
|
|
547
|
+
│ └── No → WebSocket.
|
|
548
|
+
│
|
|
549
|
+
└── Special case: Database change notifications?
|
|
550
|
+
└── Supabase Realtime, Hasura Subscriptions, or CDC + SSE.
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Implementation Sketch
|
|
556
|
+
|
|
557
|
+
A minimal but production-aware WebSocket server in Node.js with `ws`, illustrating the patterns discussed above:
|
|
558
|
+
|
|
559
|
+
```javascript
|
|
560
|
+
// server.js — WebSocket server with heartbeat, auth, rooms, and Redis fanout
|
|
561
|
+
import { WebSocketServer } from 'ws';
|
|
562
|
+
import { createClient } from 'redis';
|
|
563
|
+
import { verify } from 'jsonwebtoken';
|
|
564
|
+
|
|
565
|
+
const wss = new WebSocketServer({ port: 8080 });
|
|
566
|
+
const rooms = new Map(); // roomId -> Set<ws>
|
|
567
|
+
|
|
568
|
+
// Redis pub/sub for horizontal scaling
|
|
569
|
+
const redisSub = createClient();
|
|
570
|
+
const redisPub = createClient();
|
|
571
|
+
await redisSub.connect();
|
|
572
|
+
await redisPub.connect();
|
|
573
|
+
|
|
574
|
+
// Subscribe to cross-server messages
|
|
575
|
+
await redisSub.subscribe('chat:broadcast', (message) => {
|
|
576
|
+
const { roomId, data, originServer } = JSON.parse(message);
|
|
577
|
+
if (originServer === SERVER_ID) return; // Skip own messages
|
|
578
|
+
broadcastToRoom(roomId, data);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
// Heartbeat: detect dead connections
|
|
582
|
+
const HEARTBEAT_INTERVAL = 30_000;
|
|
583
|
+
const HEARTBEAT_TIMEOUT = 10_000;
|
|
584
|
+
|
|
585
|
+
const heartbeat = setInterval(() => {
|
|
586
|
+
wss.clients.forEach((ws) => {
|
|
587
|
+
if (!ws.isAlive) return ws.terminate();
|
|
588
|
+
ws.isAlive = false;
|
|
589
|
+
ws.ping();
|
|
590
|
+
});
|
|
591
|
+
}, HEARTBEAT_INTERVAL);
|
|
592
|
+
|
|
593
|
+
wss.on('connection', (ws, req) => {
|
|
594
|
+
ws.isAlive = true;
|
|
595
|
+
ws.isAuthenticated = false;
|
|
596
|
+
ws.rooms = new Set();
|
|
597
|
+
|
|
598
|
+
ws.on('pong', () => { ws.isAlive = true; });
|
|
599
|
+
|
|
600
|
+
// Authentication: first message must be auth token
|
|
601
|
+
const authTimeout = setTimeout(() => {
|
|
602
|
+
if (!ws.isAuthenticated) {
|
|
603
|
+
ws.close(4001, 'Authentication timeout');
|
|
604
|
+
}
|
|
605
|
+
}, 5000);
|
|
606
|
+
|
|
607
|
+
ws.on('message', (raw) => {
|
|
608
|
+
const msg = JSON.parse(raw);
|
|
609
|
+
|
|
610
|
+
// First message must authenticate
|
|
611
|
+
if (!ws.isAuthenticated) {
|
|
612
|
+
if (msg.type !== 'auth') {
|
|
613
|
+
return ws.close(4002, 'First message must be auth');
|
|
614
|
+
}
|
|
615
|
+
try {
|
|
616
|
+
ws.user = verify(msg.token, process.env.JWT_SECRET);
|
|
617
|
+
ws.isAuthenticated = true;
|
|
618
|
+
clearTimeout(authTimeout);
|
|
619
|
+
ws.send(JSON.stringify({ type: 'auth:ok' }));
|
|
620
|
+
} catch {
|
|
621
|
+
ws.close(4003, 'Invalid token');
|
|
622
|
+
}
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Handle authenticated messages
|
|
627
|
+
switch (msg.type) {
|
|
628
|
+
case 'join':
|
|
629
|
+
joinRoom(ws, msg.roomId);
|
|
630
|
+
break;
|
|
631
|
+
case 'leave':
|
|
632
|
+
leaveRoom(ws, msg.roomId);
|
|
633
|
+
break;
|
|
634
|
+
case 'message':
|
|
635
|
+
handleMessage(ws, msg);
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
ws.on('close', () => {
|
|
641
|
+
clearTimeout(authTimeout);
|
|
642
|
+
ws.rooms.forEach((roomId) => leaveRoom(ws, roomId));
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
function joinRoom(ws, roomId) {
|
|
647
|
+
if (!rooms.has(roomId)) rooms.set(roomId, new Set());
|
|
648
|
+
rooms.get(roomId).add(ws);
|
|
649
|
+
ws.rooms.add(roomId);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function leaveRoom(ws, roomId) {
|
|
653
|
+
rooms.get(roomId)?.delete(ws);
|
|
654
|
+
if (rooms.get(roomId)?.size === 0) rooms.delete(roomId);
|
|
655
|
+
ws.rooms.delete(roomId);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function handleMessage(ws, msg) {
|
|
659
|
+
const data = JSON.stringify({
|
|
660
|
+
type: 'message',
|
|
661
|
+
from: ws.user.id,
|
|
662
|
+
roomId: msg.roomId,
|
|
663
|
+
body: msg.body,
|
|
664
|
+
ts: Date.now(),
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
// Broadcast locally
|
|
668
|
+
broadcastToRoom(msg.roomId, data);
|
|
669
|
+
|
|
670
|
+
// Broadcast to other servers via Redis
|
|
671
|
+
redisPub.publish('chat:broadcast', JSON.stringify({
|
|
672
|
+
roomId: msg.roomId,
|
|
673
|
+
data,
|
|
674
|
+
originServer: SERVER_ID,
|
|
675
|
+
}));
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function broadcastToRoom(roomId, data) {
|
|
679
|
+
const members = rooms.get(roomId);
|
|
680
|
+
if (!members) return;
|
|
681
|
+
for (const client of members) {
|
|
682
|
+
if (client.readyState === 1) { // WebSocket.OPEN
|
|
683
|
+
client.send(data);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Graceful shutdown: drain connections
|
|
689
|
+
process.on('SIGTERM', () => {
|
|
690
|
+
clearInterval(heartbeat);
|
|
691
|
+
wss.clients.forEach((ws) => {
|
|
692
|
+
ws.close(1001, 'Server shutting down');
|
|
693
|
+
});
|
|
694
|
+
setTimeout(() => process.exit(0), 5000);
|
|
695
|
+
});
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**Client-side reconnection with exponential backoff:**
|
|
699
|
+
|
|
700
|
+
```javascript
|
|
701
|
+
class ReconnectingWebSocket {
|
|
702
|
+
constructor(url, options = {}) {
|
|
703
|
+
this.url = url;
|
|
704
|
+
this.maxRetries = options.maxRetries ?? 10;
|
|
705
|
+
this.baseDelay = options.baseDelay ?? 1000;
|
|
706
|
+
this.maxDelay = options.maxDelay ?? 30000;
|
|
707
|
+
this.attempt = 0;
|
|
708
|
+
this.handlers = new Map();
|
|
709
|
+
this.connect();
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
connect() {
|
|
713
|
+
this.ws = new WebSocket(this.url);
|
|
714
|
+
|
|
715
|
+
this.ws.onopen = () => {
|
|
716
|
+
this.attempt = 0; // Reset on successful connection
|
|
717
|
+
this.authenticate();
|
|
718
|
+
this.emit('open');
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
this.ws.onclose = (event) => {
|
|
722
|
+
if (event.code === 1000) return; // Normal close, don't reconnect
|
|
723
|
+
this.scheduleReconnect();
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
this.ws.onmessage = (event) => {
|
|
727
|
+
const msg = JSON.parse(event.data);
|
|
728
|
+
this.emit(msg.type, msg);
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
scheduleReconnect() {
|
|
733
|
+
if (this.attempt >= this.maxRetries) {
|
|
734
|
+
this.emit('maxRetriesReached');
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
const delay = Math.min(
|
|
738
|
+
this.baseDelay * Math.pow(2, this.attempt),
|
|
739
|
+
this.maxDelay
|
|
740
|
+
);
|
|
741
|
+
const jitter = delay * (0.5 + Math.random() * 0.5);
|
|
742
|
+
this.attempt++;
|
|
743
|
+
setTimeout(() => this.connect(), jitter);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
send(type, payload) {
|
|
747
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
748
|
+
this.ws.send(JSON.stringify({ type, ...payload }));
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
on(event, handler) {
|
|
753
|
+
if (!this.handlers.has(event)) this.handlers.set(event, []);
|
|
754
|
+
this.handlers.get(event).push(handler);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
emit(event, data) {
|
|
758
|
+
this.handlers.get(event)?.forEach((h) => h(data));
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
---
|
|
764
|
+
|
|
765
|
+
## Cross-References
|
|
766
|
+
|
|
767
|
+
- **[push-and-sync](../patterns/push-and-sync.md)** — Patterns for synchronizing state between client and server after reconnection; essential complement to WebSocket reconnection logic.
|
|
768
|
+
- **[api-design-rest](../integration/api-design-rest.md)** — REST remains the right choice for request-response patterns; WebSocket should complement REST, not replace it.
|
|
769
|
+
- **[event-driven](../patterns/event-driven.md)** — WebSocket is often the client-facing delivery mechanism for an event-driven backend architecture.
|
|
770
|
+
- **[horizontal-vs-vertical](../scaling/horizontal-vs-vertical.md)** — WebSocket's statefulness creates unique horizontal scaling challenges covered in depth here.
|
|
771
|
+
- **[stateless-design](../foundations/stateless-design.md)** — WebSocket is inherently stateful; understanding stateless design principles helps minimize the stateful surface area.
|
|
772
|
+
|
|
773
|
+
---
|
|
774
|
+
|
|
775
|
+
## Sources
|
|
776
|
+
|
|
777
|
+
- [Ably: WebSocket Architecture Best Practices](https://ably.com/topic/websocket-architecture-best-practices)
|
|
778
|
+
- [Ably: WebSockets vs SSE](https://ably.com/blog/websockets-vs-sse)
|
|
779
|
+
- [Ably: Scaling Pub/Sub with WebSockets and Redis](https://ably.com/blog/scaling-pub-sub-with-websockets-and-redis)
|
|
780
|
+
- [Ably: Can WebTransport Replace WebSockets?](https://ably.com/blog/can-webtransport-replace-websockets)
|
|
781
|
+
- [Ably: Socket.IO vs WebSocket](https://ably.com/topic/socketio-vs-websocket)
|
|
782
|
+
- [How Figma's Multiplayer Technology Works](https://www.figma.com/blog/how-figmas-multiplayer-technology-works/)
|
|
783
|
+
- [Figma: Making Multiplayer More Reliable](https://www.figma.com/blog/making-multiplayer-more-reliable/)
|
|
784
|
+
- [How Discord Handles Two and Half Million Concurrent Voice Users](https://discord.com/blog/how-discord-handles-two-and-half-million-concurrent-voice-users-using-webrtc)
|
|
785
|
+
- [Discord: Architecting for Hyperscale](https://d4dummies.com/architecting-for-hyperscale-an-in-depth-analysis-of-discords-billion-message-per-day-infrastructure/)
|
|
786
|
+
- [7 WebSocket Scaling Patterns for 1M Connections](https://dev.to/jsgurujobs/7-websocket-scaling-patterns-that-let-nodejs-handle-1m-real-time-connections-2gf2)
|
|
787
|
+
- [Deal with Reconnection Storm — Two Strategies](https://amirsoleimani.medium.com/deal-with-reconnection-storm-two-strategies-4a835d0457f6)
|
|
788
|
+
- [WebSocket.org: The Future of WebSockets — HTTP/3 and WebTransport](https://websocket.org/guides/future-of-websockets/)
|
|
789
|
+
- [Heroku: WebSocket Security](https://devcenter.heroku.com/articles/websocket-security)
|
|
790
|
+
- [Horizontally Scaling Node.js and WebSockets with Redis](https://goldfirestudios.com/horizontally-scaling-node-js-and-websockets-with-redis)
|
|
791
|
+
- [ByteByteGo: Short/Long Polling, SSE, WebSocket](https://bytebytego.com/guides/shortlong-polling-sse-websocket/)
|