serverless-ircd 0.5.0 → 0.7.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/.github/workflows/ci.yml +40 -3
- package/.github/workflows/deploy-aws.yml +1 -2
- package/.github/workflows/deploy-cf-tcp.yml +1 -5
- package/.github/workflows/deploy-cf.yml +1 -2
- package/.gitmodules +3 -0
- package/CHANGELOG.md +474 -0
- package/README.md +219 -22
- package/apps/aws-stack/README.md +33 -0
- package/apps/aws-stack/package.json +1 -1
- package/apps/aws-stack/src/aws-stack.ts +74 -9
- package/apps/aws-stack/tests/coverage-command.test.ts +155 -0
- package/apps/aws-stack/tests/stack.test.ts +2 -2
- package/apps/aws-stack/tests/synth-no-bundle.test.ts +129 -0
- package/apps/aws-stack/tests/vitest.setup.ts +18 -0
- package/apps/aws-stack/vitest.config.ts +3 -0
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-tcp-container/src/config-loader.ts +6 -7
- package/apps/cf-tcp-container/src/container-server.ts +3 -0
- package/apps/cf-tcp-container/tests/config-loader.test.ts +10 -3
- package/apps/cf-tcp-container/wrangler.toml +1 -1
- package/apps/cf-worker/package.json +2 -1
- package/apps/cf-worker/src/origin-allowlist.ts +99 -0
- package/apps/cf-worker/src/worker.ts +89 -9
- package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
- package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
- package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
- package/apps/cf-worker/tests/smoke.test.ts +28 -2
- package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
- package/apps/cf-worker/vitest.config.ts +1 -1
- package/apps/cf-worker/wrangler.test.toml +23 -0
- package/apps/cf-worker/wrangler.toml +59 -3
- package/apps/local-cli/package.json +1 -1
- package/apps/local-cli/src/config-loader.ts +6 -6
- package/apps/local-cli/src/main.ts +20 -0
- package/apps/local-cli/src/server.ts +9 -7
- package/apps/local-cli/tests/e2e.test.ts +112 -28
- package/apps/local-cli/tests/tcp.test.ts +71 -19
- package/apps/local-cli/tests/ws-subprotocol.test.ts +12 -7
- package/apps/web/landing/index.html +217 -0
- package/apps/web/package.json +28 -0
- package/apps/web/scripts/build.mjs +125 -0
- package/apps/web/src/build-env.ts +43 -0
- package/apps/web/src/config-schema.ts +138 -0
- package/apps/web/static/config.json +28 -0
- package/apps/web/static/config.prod.json +28 -0
- package/apps/web/static/config.staging.json +28 -0
- package/apps/web/tests/build-env.test.ts +63 -0
- package/apps/web/tests/build-smoke.test.ts +103 -0
- package/apps/web/tests/config-schema.test.ts +432 -0
- package/apps/web/tests/workspace.test.ts +12 -0
- package/apps/web/tsconfig.json +10 -0
- package/apps/web/upstream/.browserslistrc +3 -0
- package/apps/web/upstream/.editorconfig +9 -0
- package/apps/web/upstream/.eslintignore +3 -0
- package/apps/web/upstream/.eslintrc.js +90 -0
- package/apps/web/upstream/.github/FUNDING.yml +12 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/apps/web/upstream/.github/workflows/push.yml +26 -0
- package/apps/web/upstream/.github/workflows/release.yml +33 -0
- package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
- package/apps/web/upstream/.prettierrc.js +9 -0
- package/apps/web/upstream/.stylelintignore +5 -0
- package/apps/web/upstream/.stylelintrc.js +21 -0
- package/apps/web/upstream/LICENSE +201 -0
- package/apps/web/upstream/README.md +76 -0
- package/apps/web/upstream/babel.config.js +25 -0
- package/apps/web/upstream/crowdin.yml +3 -0
- package/apps/web/upstream/index.html +35 -0
- package/apps/web/upstream/jest.config.js +7 -0
- package/apps/web/upstream/jsdoc.json +22 -0
- package/apps/web/upstream/package.json +80 -0
- package/apps/web/upstream/scripts/pre-commit +43 -0
- package/apps/web/upstream/src/components/App.vue +516 -0
- package/apps/web/upstream/src/components/AppSettings.vue +587 -0
- package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
- package/apps/web/upstream/src/components/Avatar.vue +105 -0
- package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
- package/apps/web/upstream/src/components/BufferKey.vue +121 -0
- package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
- package/apps/web/upstream/src/components/Captcha.vue +85 -0
- package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
- package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
- package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
- package/apps/web/upstream/src/components/ChannelList.vue +345 -0
- package/apps/web/upstream/src/components/Container.vue +401 -0
- package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
- package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
- package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
- package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
- package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
- package/apps/web/upstream/src/components/MessageList.vue +1028 -0
- package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
- package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
- package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
- package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
- package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
- package/apps/web/upstream/src/components/Nicklist.vue +309 -0
- package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
- package/apps/web/upstream/src/components/NotConnected.vue +271 -0
- package/apps/web/upstream/src/components/SelfUser.vue +283 -0
- package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
- package/apps/web/upstream/src/components/ServerView.vue +126 -0
- package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
- package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
- package/apps/web/upstream/src/components/Sidebar.vue +429 -0
- package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
- package/apps/web/upstream/src/components/SidebarState.vue +145 -0
- package/apps/web/upstream/src/components/StartupError.vue +35 -0
- package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
- package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
- package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
- package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
- package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
- package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
- package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
- package/apps/web/upstream/src/components/UserBox.vue +728 -0
- package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
- package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
- package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
- package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
- package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
- package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
- package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
- package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
- package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
- package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
- package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
- package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
- package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
- package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
- package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
- package/apps/web/upstream/src/helpers/Colours.js +128 -0
- package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
- package/apps/web/upstream/src/helpers/Md5.js +193 -0
- package/apps/web/upstream/src/helpers/Misc.js +401 -0
- package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
- package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
- package/apps/web/upstream/src/libs/AudioManager.js +60 -0
- package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
- package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
- package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
- package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
- package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
- package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
- package/apps/web/upstream/src/libs/IPC.js +51 -0
- package/apps/web/upstream/src/libs/InputHandler.js +921 -0
- package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
- package/apps/web/upstream/src/libs/Logger.js +71 -0
- package/apps/web/upstream/src/libs/Message.js +169 -0
- package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
- package/apps/web/upstream/src/libs/MessageParser.js +249 -0
- package/apps/web/upstream/src/libs/Notifications.js +78 -0
- package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
- package/apps/web/upstream/src/libs/ServerSession.js +102 -0
- package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
- package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
- package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
- package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
- package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
- package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
- package/apps/web/upstream/src/libs/bufferTools.js +177 -0
- package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
- package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
- package/apps/web/upstream/src/libs/settingTools.js +31 -0
- package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
- package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
- package/apps/web/upstream/src/libs/state/UserState.js +89 -0
- package/apps/web/upstream/src/libs/state/common.js +26 -0
- package/apps/web/upstream/src/libs/state.js +961 -0
- package/apps/web/upstream/src/libs/storage/Local.js +51 -0
- package/apps/web/upstream/src/main.js +566 -0
- package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
- package/apps/web/upstream/src/res/configTemplates.js +373 -0
- package/apps/web/upstream/src/res/globalStyle.css +277 -0
- package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
- package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
- package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
- package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
- package/apps/web/upstream/src/res/localesList.json +27 -0
- package/apps/web/upstream/src/res/logo.png +0 -0
- package/apps/web/upstream/src/thirdparty/about.html +43 -0
- package/apps/web/upstream/src/thirdparty/index.js +5 -0
- package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
- package/apps/web/upstream/static/config.json +28 -0
- package/apps/web/upstream/static/emoticons/smile.png +0 -0
- package/apps/web/upstream/static/favicon.png +0 -0
- package/apps/web/upstream/static/highlight.mp3 +0 -0
- package/apps/web/upstream/static/highlight.ogg +0 -0
- package/apps/web/upstream/static/locales/.gitignore +2 -0
- package/apps/web/upstream/static/plugins/customise.html.example +10 -0
- package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
- package/apps/web/upstream/static/themes/common/base.css +1064 -0
- package/apps/web/upstream/static/themes/dark/theme.css +196 -0
- package/apps/web/upstream/static/themes/default/theme.css +92 -0
- package/apps/web/upstream/static/themes/elite/theme.css +248 -0
- package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
- package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
- package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
- package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
- package/apps/web/upstream/static/themes/sky/theme.css +107 -0
- package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
- package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
- package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
- package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
- package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
- package/apps/web/upstream/vue.config.js +150 -0
- package/apps/web/upstream/yarn.lock +9767 -0
- package/apps/web/vitest.config.ts +13 -0
- package/biome.json +2 -0
- package/docs/ADR-001-pure-reducers-and-effect-system.md +74 -0
- package/docs/ADR-002-location-of-authority.md +82 -0
- package/docs/ADR-003-durable-object-sharding.md +110 -0
- package/docs/ADR-004-dynamodb-schema.md +96 -0
- package/docs/ADR-005-wss-only-transport-v1.md +83 -0
- package/docs/ADR-006-sasl-mechanism-scope.md +96 -0
- package/docs/ADR-007-deterministic-ports.md +82 -0
- package/docs/ADR-008-monorepo-tooling.md +60 -0
- package/docs/ADR-009-dual-transport-wss-and-irc-tls.md +138 -0
- package/docs/ADR-Index.md +15 -0
- package/docs/AWS-Adapter-Architecture.md +496 -0
- package/docs/AWS-Deployment.md +1275 -0
- package/docs/AWS-TCP-Deployment.md +410 -0
- package/docs/Cloudflare-Deployment-Guide.md +719 -0
- package/docs/Cloudflare-TCP-Deployment.md +510 -0
- package/docs/Home.md +16 -0
- package/docs/Observability.md +87 -0
- package/docs/PlanExtensions.md +812 -0
- package/docs/PlanIRCv3Websocket.md +503 -0
- package/docs/PlanWebClient.md +451 -0
- package/docs/Release-Process.md +443 -0
- package/docs/WebClientGuide.md +535 -0
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/aws-adapter/src/handlers/default.ts +3 -0
- package/packages/aws-adapter/src/handlers/nlb-stream.ts +9 -0
- package/packages/aws-adapter/src/serialize.ts +29 -1
- package/packages/aws-adapter/tests/account-store-dynamo.test.ts +49 -8
- package/packages/aws-adapter/tests/account-store.test.ts +4 -7
- package/packages/aws-adapter/tests/aws-harness.ts +5 -2
- package/packages/aws-adapter/tests/aws-integration.test.ts +8 -4
- package/packages/aws-adapter/tests/aws-runtime.test.ts +79 -0
- package/packages/aws-adapter/tests/config-loader.test.ts +11 -2
- package/packages/aws-adapter/tests/connect.test.ts +9 -9
- package/packages/aws-adapter/tests/disconnect-fanout.test.ts +3 -4
- package/packages/aws-adapter/tests/global-setup.ts +55 -30
- package/packages/aws-adapter/tests/gone-exception.test.ts +4 -9
- package/packages/aws-adapter/tests/handlers.test.ts +90 -4
- package/packages/aws-adapter/tests/message-store.test.ts +6 -5
- package/packages/aws-adapter/tests/nlb-stream.test.ts +60 -8
- package/packages/cf-adapter/package.json +2 -1
- package/packages/cf-adapter/src/connection-do.ts +3 -0
- package/packages/cf-adapter/src/serialize.ts +25 -4
- package/packages/cf-adapter/tests/cf-harness.ts +12 -1
- package/packages/cf-adapter/tests/cf-runtime.test.ts +269 -0
- package/packages/cf-adapter/tests/channel-do.test.ts +117 -0
- package/packages/cf-adapter/tests/config-loader.test.ts +49 -0
- package/packages/cf-adapter/tests/connection-do-pure.test.ts +91 -0
- package/packages/cf-adapter/tests/d1-account-store.test.ts +48 -0
- package/packages/cf-adapter/tests/registry-do.test.ts +104 -0
- package/packages/cf-adapter/tests/serialize.test.ts +308 -0
- package/packages/cf-adapter/vitest.config.ts +1 -1
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/irc-core/package.json +1 -1
- package/packages/irc-core/reports/mutation/mutation.html +342 -0
- package/packages/irc-core/src/caps/capabilities.ts +37 -3
- package/packages/irc-core/src/caps/index.ts +1 -0
- package/packages/irc-core/src/caps/sts.ts +84 -0
- package/packages/irc-core/src/commands/account-notify.ts +53 -0
- package/packages/irc-core/src/commands/away.ts +9 -3
- package/packages/irc-core/src/commands/cap.ts +23 -5
- package/packages/irc-core/src/commands/chathistory.ts +40 -11
- package/packages/irc-core/src/commands/index.ts +34 -0
- package/packages/irc-core/src/commands/isupport.ts +53 -0
- package/packages/irc-core/src/commands/mode.ts +8 -1
- package/packages/irc-core/src/commands/monitor.ts +327 -0
- package/packages/irc-core/src/commands/multiline.ts +256 -0
- package/packages/irc-core/src/commands/pre-away.ts +112 -0
- package/packages/irc-core/src/commands/privmsg.ts +19 -12
- package/packages/irc-core/src/commands/read-marker.ts +108 -0
- package/packages/irc-core/src/commands/registration.ts +8 -0
- package/packages/irc-core/src/commands/sasl.ts +24 -1
- package/packages/irc-core/src/commands/tagmsg.ts +71 -1
- package/packages/irc-core/src/commands/whois.ts +5 -0
- package/packages/irc-core/src/config.ts +65 -10
- package/packages/irc-core/src/effects.ts +14 -0
- package/packages/irc-core/src/ports.ts +389 -0
- package/packages/irc-core/src/protocol/index.ts +14 -0
- package/packages/irc-core/src/protocol/labeled-response.ts +133 -0
- package/packages/irc-core/src/protocol/numerics.ts +15 -0
- package/packages/irc-core/src/protocol/outbound.ts +16 -1
- package/packages/irc-core/src/protocol/standard-replies.ts +277 -0
- package/packages/irc-core/src/state/connection.ts +32 -1
- package/packages/irc-core/src/types.ts +112 -0
- package/packages/irc-core/stryker.commands.conf.json +1 -2
- package/packages/irc-core/tests/away-store.test.ts +73 -0
- package/packages/irc-core/tests/batch.test.ts +15 -0
- package/packages/irc-core/tests/caps/capabilities.test.ts +119 -2
- package/packages/irc-core/tests/caps/sts.test.ts +123 -0
- package/packages/irc-core/tests/commands/account-notify.test.ts +171 -0
- package/packages/irc-core/tests/commands/away.test.ts +85 -2
- package/packages/irc-core/tests/commands/cap.test.ts +165 -0
- package/packages/irc-core/tests/commands/chathistory.test.ts +148 -1
- package/packages/irc-core/tests/commands/echo-message.test.ts +9 -3
- package/packages/irc-core/tests/commands/isupport.test.ts +80 -0
- package/packages/irc-core/tests/commands/mode.test.ts +72 -0
- package/packages/irc-core/tests/commands/monitor.test.ts +411 -0
- package/packages/irc-core/tests/commands/multiline.test.ts +428 -0
- package/packages/irc-core/tests/commands/pre-away.test.ts +241 -0
- package/packages/irc-core/tests/commands/privmsg.test.ts +154 -3
- package/packages/irc-core/tests/commands/read-marker.test.ts +211 -0
- package/packages/irc-core/tests/commands/registration.test.ts +64 -0
- package/packages/irc-core/tests/commands/sasl.test.ts +116 -2
- package/packages/irc-core/tests/commands/tagmsg.test.ts +357 -0
- package/packages/irc-core/tests/commands/whois.test.ts +34 -0
- package/packages/irc-core/tests/config.test.ts +103 -13
- package/packages/irc-core/tests/labeled-response.test.ts +181 -0
- package/packages/irc-core/tests/message-tags.test.ts +114 -0
- package/packages/irc-core/tests/monitor-store.test.ts +200 -0
- package/packages/irc-core/tests/numerics.test.ts +13 -0
- package/packages/irc-core/tests/parser.test.ts +109 -0
- package/packages/irc-core/tests/read-marker-store.test.ts +108 -0
- package/packages/irc-core/tests/standard-replies.test.ts +412 -0
- package/packages/irc-core/tests/types.test.ts +27 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-server/src/actor.ts +450 -3
- package/packages/irc-server/src/dispatch.ts +108 -16
- package/packages/irc-server/tests/actor.test.ts +1432 -39
- package/packages/irc-server/tests/dispatch.test.ts +263 -2
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/index.ts +6 -0
- package/packages/irc-test-support/src/scenarios.ts +24 -2
- package/packages/irc-test-support/src/test-config.ts +54 -0
- package/packages/irc-test-support/tests/test-config.test.ts +51 -0
- package/tools/ci-hardening/package.json +1 -1
- package/tools/ci-hardening/tests/ddb-local.test.ts +82 -0
- package/tools/load-test/package.json +33 -0
- package/tools/load-test/src/client.ts +351 -0
- package/tools/load-test/src/config.ts +313 -0
- package/tools/load-test/src/harness.ts +116 -0
- package/tools/load-test/src/main.ts +120 -0
- package/tools/load-test/src/metrics.ts +168 -0
- package/tools/load-test/src/report.ts +106 -0
- package/tools/load-test/tests/client.test.ts +212 -0
- package/tools/load-test/tests/config.test.ts +152 -0
- package/tools/load-test/tests/framing.test.ts +37 -0
- package/tools/load-test/tests/harness.test.ts +165 -0
- package/tools/load-test/tests/metrics.test.ts +174 -0
- package/tools/load-test/tests/report.test.ts +161 -0
- package/tools/load-test/tests/smoke.test.ts +67 -0
- package/tools/load-test/tsconfig.build.json +12 -0
- package/tools/load-test/tsconfig.test.json +10 -0
- package/tools/load-test/vitest.config.ts +29 -0
- package/tools/tcp-ws-forwarder/package.json +1 -1
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
# AWS TCP+TLS Deployment Guide (`irc+tls` :6697)
|
|
2
|
+
|
|
3
|
+
End-to-end guide for deploying the **raw TCP+TLS** transport of
|
|
4
|
+
ServerlessIRCd to AWS (Phase 7 of `PLAN.md`, TICKET-056). This is the
|
|
5
|
+
RFC 1459/2812-compliant path that older clients, bots, and bridges use.
|
|
6
|
+
The default **wss** transport is documented separately in
|
|
7
|
+
[`AWS-Deployment.md`](./AWS-Deployment.md); the two coexist in a single
|
|
8
|
+
CDK stack and a deployment can enable either or both.
|
|
9
|
+
|
|
10
|
+
> **Read first:** [`ADR-009`](./ADR-009-dual-transport-wss-and-irc-tls.md)
|
|
11
|
+
> for *why* a second transport exists and the per-platform mapping.
|
|
12
|
+
> This doc covers the *how*.
|
|
13
|
+
|
|
14
|
+
**Acceptance criterion (TICKET-058):** a new contributor can deploy
|
|
15
|
+
their own TCP+TLS staging instance following only this doc.
|
|
16
|
+
|
|
17
|
+
Cross-reference: `apps/aws-stack/src/aws-stack.ts` (CDK), the wss path
|
|
18
|
+
(`AWS-Deployment.md`), TICKET-054 (mTLS), ADR-006 (SASL scope).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. What gets deployed
|
|
23
|
+
|
|
24
|
+
The wss path is API Gateway WebSocket → Lambda → DynamoDB. The TCP path
|
|
25
|
+
**cannot** reuse API Gateway (it is WebSocket-only), so it adds a second
|
|
26
|
+
entry point: a **Network Load Balancer** with a `TLS` listener that
|
|
27
|
+
terminates TLS and invokes a **Lambda streaming function** as the
|
|
28
|
+
target. The Lambda reuses the exact same DynamoDB tables and the same
|
|
29
|
+
IRC core as the wss path — only the I/O shell differs.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
IRC client (irc+tls :6697)
|
|
33
|
+
│
|
|
34
|
+
│ TLS handshake (client ⟷ NLB / ACM cert)
|
|
35
|
+
▼
|
|
36
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
37
|
+
│ Network Load Balancer (internet-facing, 2-AZ VPC) │
|
|
38
|
+
│ • TLS listener on :6697 (ACM certificate) │
|
|
39
|
+
│ • terminates TLS, forwards plaintext chunks │
|
|
40
|
+
│ • flow metadata: x-forwarded-for / x-forwarded-port │
|
|
41
|
+
└──────────────────────────┬───────────────────────────────────┘
|
|
42
|
+
│ invoke (per chunk, base64 body)
|
|
43
|
+
▼
|
|
44
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
45
|
+
│ Lambda: IrcNlbHandler (Node 24, nlbStreamHandler) │
|
|
46
|
+
│ • TcpByteStreamTransport reassembles \r\n lines │
|
|
47
|
+
│ (partial-line buffer persisted to Connections row) │
|
|
48
|
+
│ • ConnectionActor + AwsRuntime (same core as $default) │
|
|
49
|
+
│ • connId = nlb-<ip>-<port> (distinct from APIGW ids) │
|
|
50
|
+
└──────────────────────────┬───────────────────────────────────┘
|
|
51
|
+
│ read/write
|
|
52
|
+
▼
|
|
53
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
54
|
+
│ DynamoDB (same 5 tables as the wss path) │
|
|
55
|
+
│ Connections (+ transportBuffer attr) ChannelMeta │
|
|
56
|
+
│ ChannelMembers Nicks Accounts │
|
|
57
|
+
└──────────────────────────────────────────────────────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Both transports live in **one CDK stack** (`IrcAwsStack`). The TCP path
|
|
61
|
+
is opt-in: it is only provisioned when `tcpTlsDomainName` is supplied.
|
|
62
|
+
When enabled, the stack adds (verified by `apps/aws-stack/tests/stack.test.ts`):
|
|
63
|
+
|
|
64
|
+
| Resource | Purpose |
|
|
65
|
+
|---------------------------------------|----------------------------------------------------|
|
|
66
|
+
| `AWS::CertificateManager::Certificate`| TLS cert for the domain (DNS-validated). |
|
|
67
|
+
| `AWS::EC2::Vpc` (`NlbVpc`) | Dedicated 2-AZ VPC, **no NAT gateways**. |
|
|
68
|
+
| `AWS::ElasticLoadBalancingV2::LoadBalancer` | Internet-facing NLB. |
|
|
69
|
+
| `AWS::ElasticLoadBalancingV2::Listener` (`IrcNlbTlsListener`) | `TLS` on :6697. |
|
|
70
|
+
| `AWS::ElasticLoadBalancingV2::TargetGroup` | `TargetType: lambda`, target = `IrcNlbHandler`. |
|
|
71
|
+
| `AWS::Lambda::Function` (`IrcNlbHandler`) | `nlbStreamHandler` export, Node 24. |
|
|
72
|
+
| `CfnOutput: TcpConnectUrl` | `<nlb-dns>:6697`. |
|
|
73
|
+
|
|
74
|
+
The **parser → reducer → dispatch pipeline is shared verbatim** with the
|
|
75
|
+
wss path (`$default`). Only the framing differs: each NLB chunk is a
|
|
76
|
+
fresh Lambda invocation, so the `TcpByteStreamTransport`'s partial-line
|
|
77
|
+
buffer is snapshotted to a `transportBuffer` attribute on the
|
|
78
|
+
`Connections` row and rehydrated on the next chunk — no bytes are lost
|
|
79
|
+
across the compute boundary.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 2. Prerequisites
|
|
84
|
+
|
|
85
|
+
| Requirement | Detail |
|
|
86
|
+
|-------------------|---------------------------------------------------------------------|
|
|
87
|
+
| Everything in `AWS-Deployment.md` §2 | Same CDK v2, pnpm 11, Node 24, AWS account, `cdk bootstrap`. |
|
|
88
|
+
| ACM certificate | Provisioned automatically by the stack for the domain you pass; the hosted zone must exist in Route 53 (or be validated out-of-band) for DNS validation. |
|
|
89
|
+
| A domain | The public hostname (e.g. `irc.example.com`) you will pass as `tcpTlsDomainName`. |
|
|
90
|
+
| NLB Lambda invoke | The target group uses `TargetType.LAMBDA`; no ALB/Lambda-HTTP needed. |
|
|
91
|
+
|
|
92
|
+
No extra IAM beyond what the stack already grants — the CDK adds the
|
|
93
|
+
`elasticloadbalancing.amazonaws.com` invoke permission and the NLB
|
|
94
|
+
handler's DynamoDB grants automatically.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 3. How the TCP path is enabled
|
|
99
|
+
|
|
100
|
+
The `IrcAwsStack` construct accepts an optional prop
|
|
101
|
+
(`apps/aws-stack/src/aws-stack.ts`):
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
export interface IrcStackProps extends StackProps {
|
|
105
|
+
readonly environmentName?: string;
|
|
106
|
+
readonly serverName?: string;
|
|
107
|
+
readonly networkName?: string;
|
|
108
|
+
readonly motdLines?: string[];
|
|
109
|
+
/** When provided, provisions NLB + ACM cert + Lambda streaming target. */
|
|
110
|
+
readonly tcpTlsDomainName?: string;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Omit `tcpTlsDomainName` → only the wss (API Gateway WebSocket) path is
|
|
115
|
+
deployed (the default; what `AWS-Deployment.md` describes). Provide it →
|
|
116
|
+
the TCP+TLS path is **added alongside** the wss path; both share the
|
|
117
|
+
same DynamoDB tables, server identity, and `MANAGEMENT_URL`.
|
|
118
|
+
|
|
119
|
+
`bin/aws.ts` reads `tcpTlsDomainName` from CDK context so it can be
|
|
120
|
+
passed on the CLI without editing source:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const tcpTlsDomainName =
|
|
124
|
+
app.node.tryGetContext('tcpTlsDomainName') as string | undefined;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
…then forwarded into `IrcStackProps.tcpTlsDomainName`. When the context
|
|
128
|
+
var is absent (the default), the prop is omitted and only the wss path
|
|
129
|
+
deploys — the existing pipeline stays green.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 4. Deploy staging (TCP+TLS)
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# From the repo root:
|
|
137
|
+
pnpm deploy:aws:staging -- \
|
|
138
|
+
-c environmentName=staging \
|
|
139
|
+
-c tcpTlsDomainName=irc-staging.example.com
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
This is the same `cdk deploy --all` the wss path uses
|
|
143
|
+
(`apps/aws-stack/package.json` `deploy:staging`), just with the extra
|
|
144
|
+
context var. The deploy will:
|
|
145
|
+
|
|
146
|
+
1. Create the ACM certificate for `irc-staging.example.com` (DNS
|
|
147
|
+
validation via Route 53; if the hosted zone is not in this account,
|
|
148
|
+
validate out-of-band and import the cert ARN — see §9.2).
|
|
149
|
+
2. Provision `NlbVpc`, the internet-facing NLB, the `TLS` listener on
|
|
150
|
+
`:6697`, and the `IrcNlbHandler` Lambda target group.
|
|
151
|
+
3. Grant the NLB handler the same DynamoDB access as the wss handler
|
|
152
|
+
and inject the same table names, `SERVER_NAME`, `NETWORK_NAME`,
|
|
153
|
+
`MOTD`, and `MANAGEMENT_URL`.
|
|
154
|
+
4. Emit the new stack output:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
TcpConnectUrl = <nlb-dns>.elb.<region>.amazonaws.com:6697
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The wss path (`ConnectUrl`, `ManagementUrl`) is **still deployed and
|
|
161
|
+
unchanged** — enabling TCP does not disable wss.
|
|
162
|
+
|
|
163
|
+
### 4.1 Wait for DNS / cert validation
|
|
164
|
+
|
|
165
|
+
The first deploy can take several minutes while ACM validates the
|
|
166
|
+
certificate. `cdk deploy` waits on the certificate resource; do not
|
|
167
|
+
interrupt it. If validation times out, confirm the hosted zone for the
|
|
168
|
+
domain is in this account and Route 53 can write the `_acme-challenge`
|
|
169
|
+
CNAME.
|
|
170
|
+
|
|
171
|
+
### 4.2 Point a DNS record at the NLB (recommended)
|
|
172
|
+
|
|
173
|
+
The NLB prints a long `.elb.amazonaws.com` DNS name. For a stable,
|
|
174
|
+
owned hostname, create an **alias A record** (Route 53) or a CNAME
|
|
175
|
+
pointing `irc-staging.example.com` → the NLB DNS name. Clients then
|
|
176
|
+
connect to `irc-staging.example.com:6697`.
|
|
177
|
+
|
|
178
|
+
(You can connect directly to the raw NLB DNS, but the cert is issued for
|
|
179
|
+
your domain, so TLS SNI/hostname verification wants the owned name.)
|
|
180
|
+
|
|
181
|
+
### 4.3 Smoke test over TLS
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
printf 'NICK smoke\r\nUSER smoke 0 * :Smoke\r\nQUIT :smoke\r\n' | \
|
|
185
|
+
timeout 10 openssl s_client -connect irc-staging.example.com:6697 -quiet | \
|
|
186
|
+
grep -q '001' && echo "SMOKE PASS" || echo "SMOKE FAIL"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 5. Deploy production
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
pnpm deploy:aws:prod -- \
|
|
195
|
+
-c environmentName=production \
|
|
196
|
+
-c tcpTlsDomainName=irc.example.com
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Production deploys are manual. The staging CI workflow
|
|
200
|
+
(`deploy-aws.yml`) deploys only the wss path (`-c environmentName=staging`
|
|
201
|
+
without `tcpTlsDomainName`); there is **no auto-deploy for the TCP path
|
|
202
|
+
yet** — add a `deploy-aws-tcp.yml` workflow (mirroring `deploy-cf-tcp.yml`)
|
|
203
|
+
as a follow-up when the TCP path is ready for continuous staging.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 6. Operational model & limits
|
|
208
|
+
|
|
209
|
+
The NLB + Lambda streaming model has hard platform limits the wss path
|
|
210
|
+
does not. Understanding these is **required** before production:
|
|
211
|
+
|
|
212
|
+
| Limit | Impact on IRC |
|
|
213
|
+
|--------------------------------|------------------------------------------------------------|
|
|
214
|
+
| **NLB idle timeout** (10–350s) | A connection with no client data for this long is closed. IRC clients that only receive (lurkers) hit this. Mitigation: client-side PING, or accept reconnects. |
|
|
215
|
+
| **No server-push** | The Lambda can only respond to a client chunk; it cannot proactively push bytes. Real-time fanout (PRIVMSG broadcast, QUIT) **piggybacks on the recipient's next chunk** (response) or flows via the `MANAGEMENT_URL` (APIGW `postToConnection`) when both transports are deployed. |
|
|
216
|
+
| **No force-close from Lambda** | A `Disconnect("Excess Flood")` effect cannot close the NLB-held socket from inside the invocation. Canonical teardown is the sweeper + `idleSince` TTL (same pattern as the APIGW `$default` path). |
|
|
217
|
+
| **Flow rebalancing** | The NLB may rebalance the underlying flow at any time; the 4-tuple `(ip, port)` stays stable for the connection's life, so `connId` (`nlb-<ip>-<port>`) is stable. |
|
|
218
|
+
| **Lambda invoke per chunk** | Each client byte-chunk is one invocation. The `transportBuffer` reassembly across invocations is correct but adds a DynamoDB write per chunk. Coalescing client writes reduces cost. |
|
|
219
|
+
|
|
220
|
+
Because of the no-server-push limit, **deploying both transports is the
|
|
221
|
+
recommended shape for full-featured IRC**: the wss path (or just the
|
|
222
|
+
`MANAGEMENT_URL` from it) provides the push channel for real-time
|
|
223
|
+
fanout, while the TCP path serves RFC-compliant clients. An NLB-only
|
|
224
|
+
deploy (`managementApi = null`) silently no-ops cross-connection sends —
|
|
225
|
+
documented platform limit, see `packages/aws-adapter/src/handlers/nlb-stream.ts`.
|
|
226
|
+
|
|
227
|
+
State lifecycle is identical to the wss path: the **sweeper** Lambda
|
|
228
|
+
(`rate(5 minutes)`) prunes `Connections` rows past the hard TTL, and the
|
|
229
|
+
**ping-checker** Lambda (`rate(1 minute)`) sends PING / disconnects
|
|
230
|
+
no-PONG. Both cover TCP connections because the `connId` lives in the
|
|
231
|
+
same `Connections` table.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 7. Configuration reference
|
|
236
|
+
|
|
237
|
+
All knobs are CDK context vars (`-c key=value`) or construct props. The
|
|
238
|
+
TCP-specific ones:
|
|
239
|
+
|
|
240
|
+
| Knob (context var / prop) | Purpose | Default when omitted |
|
|
241
|
+
|-------------------------------|--------------------------------------------------|----------------------------|
|
|
242
|
+
| `tcpTlsDomainName` | Domain for the ACM cert + NLB TLS listener. | *(TCP path not provisioned)* |
|
|
243
|
+
| `environmentName` | Env prefix for table names + stack id. | `staging` |
|
|
244
|
+
|
|
245
|
+
The NLB handler Lambda inherits the **same** identity/table knobs as the
|
|
246
|
+
wss handler (`serverName`, `networkName`, `motd`, `environmentName`),
|
|
247
|
+
injected in `aws-stack.ts`:
|
|
248
|
+
|
|
249
|
+
- `SERVER_NAME`, `NETWORK_NAME`, `MOTD` (read by the shared
|
|
250
|
+
`config-loader.ts`).
|
|
251
|
+
- `MANAGEMENT_URL` — the wss stage's callback URL, so cross-connection
|
|
252
|
+
fanout reaches recipients on either transport.
|
|
253
|
+
- `<TABLE>_TABLE` for each of the five tables (prefixed by environment).
|
|
254
|
+
|
|
255
|
+
The Lambda handler entry is the same file
|
|
256
|
+
(`packages/aws-adapter/src/handlers/index.ts`); esbuild tree-shakes to
|
|
257
|
+
the `nlbStreamHandler` export. Runtime `nodejs24.x`; `@aws-sdk/*`
|
|
258
|
+
excluded from the bundle (ships with the runtime).
|
|
259
|
+
|
|
260
|
+
There are **no TCP-specific DynamoDB tables** — the existing `Connections`
|
|
261
|
+
table gains a `transportBuffer` string attribute (SET when non-empty,
|
|
262
|
+
REMOVE when empty) on rows whose `connectionId` starts with `nlb-`.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 8. mTLS (SASL EXTERNAL)
|
|
267
|
+
|
|
268
|
+
SASL `EXTERNAL` needs the client certificate to reach the application
|
|
269
|
+
(ADR-006, TICKET-054). On the TCP path:
|
|
270
|
+
|
|
271
|
+
- The NLB `TLS` listener terminates TLS with the ACM cert.
|
|
272
|
+
- For client-cert (mTLS) verification, configure the NLB listener's
|
|
273
|
+
**mutual TLS / trust store** (AWS: a trust-store bundle of CA certs on
|
|
274
|
+
the listener). The verified client-cert subject is then surfaced and
|
|
275
|
+
the origin's `MtlsIdentityProvider` port resolves it to an account,
|
|
276
|
+
enabling `AUTHENTICATE EXTERNAL` (`903` on success, `904` otherwise).
|
|
277
|
+
- Without a trust store on the listener, EXTERNAL is not available and
|
|
278
|
+
the `sasl` cap advertises `PLAIN` only (driven by whether
|
|
279
|
+
`ctx.mtlsIdentity` is defined — TICKET-079).
|
|
280
|
+
|
|
281
|
+
Cross-reference: TICKET-054 (mTLS support), TICKET-079 (EXTERNAL
|
|
282
|
+
advertisement). The wss path achieves the same via API Gateway
|
|
283
|
+
custom-domain mTLS (`AWS-Deployment.md`).
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 9. Troubleshooting
|
|
288
|
+
|
|
289
|
+
### 9.1 `cdk deploy` hangs on the ACM certificate
|
|
290
|
+
|
|
291
|
+
DNS validation is waiting on a CNAME it cannot create. Confirm the
|
|
292
|
+
hosted zone for `tcpTlsDomainName` is in this AWS account/region. If the
|
|
293
|
+
zone is elsewhere, validate out-of-band and import the certificate:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
// In aws-stack.ts, replace `new Certificate(...)` with:
|
|
297
|
+
import { Certificate, Certificate.fromCertificateArn } from 'aws-cdk-lib/aws-certificatemanager';
|
|
298
|
+
const cert = Certificate.fromCertificateArn(this, 'TlsCert', 'arn:aws:acm:...:certificate/...');
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
(This is a code edit; the default path assumes in-account Route 53.)
|
|
302
|
+
|
|
303
|
+
### 9.2 Client connects to :6697 but gets no `001`
|
|
304
|
+
|
|
305
|
+
TLS completed (NLB + cert are fine) but the Lambda did not respond with
|
|
306
|
+
the welcome block. Causes:
|
|
307
|
+
|
|
308
|
+
- The first chunk did not contain a complete `NICK`/`USER` line (split
|
|
309
|
+
across chunks). The `transportBuffer` will complete it on the next
|
|
310
|
+
chunk — send the rest. A well-behaved client sends the full handshake
|
|
311
|
+
in one write.
|
|
312
|
+
- CloudWatch Logs for `IrcNlbHandler` show an actor throw. The handler
|
|
313
|
+
catches and logs (`[nlb-stream] actor.receiveTextFrame failed`); it
|
|
314
|
+
does **not** crash — the connection continues, but a malformed line is
|
|
315
|
+
dropped. Tail with `aws logs tail /aws/lambda/<IrcNlbHandler>`.
|
|
316
|
+
- `MANAGEMENT_URL` is wrong → cross-connection fanout no-ops, but
|
|
317
|
+
self-reply (welcome, PONG) still works, so `001` should still appear.
|
|
318
|
+
|
|
319
|
+
### 9.3 Broadcasts (PRIVMSG to a channel) don't reach TCP recipients
|
|
320
|
+
|
|
321
|
+
The no-server-push limit (§6). Outbound bytes only flow when the
|
|
322
|
+
recipient sends a chunk (the Lambda response). For real-time delivery,
|
|
323
|
+
ensure the deploy includes the wss path so `MANAGEMENT_URL` is set —
|
|
324
|
+
then fanout uses `ApiGatewayManagementApi.postToConnection`, which works
|
|
325
|
+
for both transports. If `MANAGEMENT_URL` is unset, `managementApi` is
|
|
326
|
+
`null` and cross-connection sends are silent no-ops.
|
|
327
|
+
|
|
328
|
+
### 9.4 Lurkers get disconnected after a few minutes
|
|
329
|
+
|
|
330
|
+
The NLB idle timeout. A receiving-only client sends no chunks, so the
|
|
331
|
+
Lambda is never invoked and the NLB closes the idle flow. Mitigations:
|
|
332
|
+
|
|
333
|
+
- Configure the client to send a periodic `PING` (most clients do).
|
|
334
|
+
- Raise the NLB idle timeout (max 350s) — but this only delays, it does
|
|
335
|
+
not eliminate, the issue. The wss path does not have this limit and is
|
|
336
|
+
preferred for lurkers.
|
|
337
|
+
|
|
338
|
+
### 9.5 Messages split across chunks get lost
|
|
339
|
+
|
|
340
|
+
This is a transport-layer regression, not config — the
|
|
341
|
+
`TcpByteStreamTransport` + `transportBuffer` persistence is contract-
|
|
342
|
+
tested (`packages/aws-adapter/tests/nlb-stream.test.ts`). If you see it,
|
|
343
|
+
run `pnpm --filter @serverless-ircd/aws-adapter test`; a failure there
|
|
344
|
+
will pinpoint it.
|
|
345
|
+
|
|
346
|
+
### 9.6 `TcpConnectUrl` output is missing
|
|
347
|
+
|
|
348
|
+
`tcpTlsDomainName` was not passed. Confirm `-c tcpTlsDomainName=...` is
|
|
349
|
+
on the `cdk deploy` command and that `bin/aws.ts` forwards it into
|
|
350
|
+
`IrcStackProps` (§3). Without it, only the wss resources deploy.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## 10. Cost notes (versus the wss path)
|
|
355
|
+
|
|
356
|
+
| Dimension | wss path (APIGW WebSocket) | TCP path (NLB + Lambda streaming) |
|
|
357
|
+
|------------------------|----------------------------------------|----------------------------------------------|
|
|
358
|
+
| **Per-message** | APIGW WebSocket + 1 Lambda invoke. | **1 Lambda invoke per byte-chunk** (more invokes for chatty clients). |
|
|
359
|
+
| **Idle connections** | APIGW connection minutes. | NLB LCUs (Load Balancer Capacity Units) per hour; no Lambda cost when idle. |
|
|
360
|
+
| **TLS termination** | APIGW (managed). | NLB (per-LCU) + ACM (free). |
|
|
361
|
+
| **State** | DynamoDB (shared). | DynamoDB (shared) + extra `transportBuffer` write per chunk. |
|
|
362
|
+
| **Cross-connection fanout** | `postToConnection` per recipient. | Same — but only works if `MANAGEMENT_URL` (wss path) is deployed. |
|
|
363
|
+
|
|
364
|
+
The dominant cost driver on the TCP path is **invocations per chunk**.
|
|
365
|
+
Clients that coalesce writes (send the full `NICK\r\nUSER\r\n` in one
|
|
366
|
+
chunk, not byte-by-byte) are dramatically cheaper. Recommend the wss
|
|
367
|
+
path for high-fanout / lurker-heavy workloads and the TCP path for
|
|
368
|
+
RFC-compliant clients that need it.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 11. Quick reference
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
# Staging (TCP+TLS added alongside wss)
|
|
376
|
+
pnpm deploy:aws:staging -- \
|
|
377
|
+
-c environmentName=staging \
|
|
378
|
+
-c tcpTlsDomainName=irc-staging.example.com
|
|
379
|
+
|
|
380
|
+
# Read the TCP endpoint from stack outputs
|
|
381
|
+
aws cloudformation describe-stacks \
|
|
382
|
+
--stack-name IrcAwsStack-staging \
|
|
383
|
+
--query 'Stacks[0].Outputs[?OutputKey==`TcpConnectUrl`].OutputValue' \
|
|
384
|
+
--output text
|
|
385
|
+
|
|
386
|
+
# Smoke over TLS
|
|
387
|
+
printf 'NICK smoke\r\nUSER smoke 0 * :Smoke\r\nQUIT :smoke\r\n' | \
|
|
388
|
+
openssl s_client -connect irc-staging.example.com:6697 -quiet | grep '001'
|
|
389
|
+
|
|
390
|
+
# Production (manual)
|
|
391
|
+
pnpm deploy:aws:prod -- \
|
|
392
|
+
-c environmentName=production \
|
|
393
|
+
-c tcpTlsDomainName=irc.example.com
|
|
394
|
+
|
|
395
|
+
# Tests (synth-time assertions for the NLB path)
|
|
396
|
+
pnpm --filter @serverless-ircd/aws-stack test
|
|
397
|
+
pnpm --filter @serverless-ircd/aws-adapter test
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Key files:
|
|
401
|
+
|
|
402
|
+
| Path | What |
|
|
403
|
+
|---------------------------------------------------|--------------------------------------------|
|
|
404
|
+
| `apps/aws-stack/src/aws-stack.ts` | CDK stack — NLB/VPC/cert conditional block.|
|
|
405
|
+
| `apps/aws-stack/bin/aws.ts` | Reads `tcpTlsDomainName` from context. |
|
|
406
|
+
| `packages/aws-adapter/src/handlers/nlb-stream.ts` | `handleNlbStream` + `deriveNlbConnectionId`.|
|
|
407
|
+
| `packages/aws-adapter/src/handlers/index.ts` | `nlbStreamHandler` Lambda export. |
|
|
408
|
+
| `apps/aws-stack/tests/stack.test.ts` | Synth-time NLB assertions (lines 466–559). |
|
|
409
|
+
| `packages/aws-adapter/tests/nlb-stream.test.ts` | NLB framing/transport-buffer unit tests. |
|
|
410
|
+
| `docs/AWS-Deployment.md` | The wss path this sits alongside. |
|