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
package/.github/workflows/ci.yml
CHANGED
|
@@ -42,6 +42,32 @@ jobs:
|
|
|
42
42
|
node-version: 24
|
|
43
43
|
cache: pnpm
|
|
44
44
|
|
|
45
|
+
# DynamoDB Local capability for `aws-adapter` coverage.
|
|
46
|
+
#
|
|
47
|
+
# The `aws-adapter` package's vitest `globalSetup` boots a real
|
|
48
|
+
# DynamoDB Local instance so the integration suite (handlers,
|
|
49
|
+
# aws-runtime, transactions, …) can be exercised under coverage.
|
|
50
|
+
# Without it, 171 of 294 tests `describe.skipIf` away and the
|
|
51
|
+
# package drops to ~42% coverage, blowing the 90% gate.
|
|
52
|
+
#
|
|
53
|
+
# The self-hosted Gitea runner image (`ubuntu-latest`) ships with
|
|
54
|
+
# neither Docker (testcontainers' Ryuk reaper fails with "Failed
|
|
55
|
+
# to connect to Reaper" without a `docker.sock` mount or
|
|
56
|
+
# privileged mode) nor a JRE. We install a JRE here via the
|
|
57
|
+
# canonical `setup-java` action so the globalSetup's ZIP fallback
|
|
58
|
+
# can fire — this is the only strategy the runner image can
|
|
59
|
+
# support without host-level privileged-mode configuration.
|
|
60
|
+
#
|
|
61
|
+
# `DDB_LOCAL_STRATEGY=zip` is pinned on the coverage step below
|
|
62
|
+
# so the globalSetup skips the testcontainers probe entirely
|
|
63
|
+
# (otherwise it blocks for ~60s waiting for Ryuk before falling
|
|
64
|
+
# back, which is flaky and wastes CI minutes).
|
|
65
|
+
- name: Setup Java (JRE for DynamoDB Local ZIP fallback)
|
|
66
|
+
uses: actions/setup-java@v4
|
|
67
|
+
with:
|
|
68
|
+
distribution: temurin
|
|
69
|
+
java-version: '11'
|
|
70
|
+
|
|
45
71
|
- name: Install dependencies
|
|
46
72
|
run: pnpm install --frozen-lockfile
|
|
47
73
|
|
|
@@ -52,6 +78,12 @@ jobs:
|
|
|
52
78
|
run: pnpm typecheck
|
|
53
79
|
|
|
54
80
|
- name: Test with coverage
|
|
81
|
+
# `DDB_LOCAL_STRATEGY=zip` pins the DynamoDB Local boot to the
|
|
82
|
+
# Java ZIP fallback (see the `Setup Java` step above for why).
|
|
83
|
+
# This skips the testcontainers probe so the runner does not
|
|
84
|
+
# block ~60s waiting for Ryuk before falling back.
|
|
85
|
+
env:
|
|
86
|
+
DDB_LOCAL_STRATEGY: zip
|
|
55
87
|
run: pnpm coverage
|
|
56
88
|
|
|
57
89
|
- name: Coverage gate (coverage-thresholds enforced per package)
|
|
@@ -90,7 +122,7 @@ jobs:
|
|
|
90
122
|
|
|
91
123
|
- name: Upload coverage
|
|
92
124
|
if: always()
|
|
93
|
-
uses: actions/upload-artifact@
|
|
125
|
+
uses: actions/upload-artifact@v3
|
|
94
126
|
with:
|
|
95
127
|
name: coverage
|
|
96
128
|
path: |
|
|
@@ -119,7 +151,12 @@ jobs:
|
|
|
119
151
|
run: pnpm install --frozen-lockfile
|
|
120
152
|
|
|
121
153
|
- name: Build workspace (irc-core mutation targets)
|
|
122
|
-
|
|
154
|
+
# Scope the build to irc-core and its workspace deps only. The
|
|
155
|
+
# mutation spot-check mutates irc-core/protocol and irc-core/commands,
|
|
156
|
+
# so building the rest of the workspace (notably @serverless-ircd/web,
|
|
157
|
+
# which spawns `yarn` to build the Kiwi upstream SPA) is unnecessary
|
|
158
|
+
# and fails on runner images that don't ship yarn.
|
|
159
|
+
run: pnpm turbo run build --filter=@serverless-ircd/irc-core...
|
|
123
160
|
|
|
124
161
|
- name: Stryker spot-check on irc-core/protocol
|
|
125
162
|
# Mutation score threshold >=80% is enforced by the
|
|
@@ -135,7 +172,7 @@ jobs:
|
|
|
135
172
|
|
|
136
173
|
- name: Upload mutation report
|
|
137
174
|
if: always()
|
|
138
|
-
uses: actions/upload-artifact@
|
|
175
|
+
uses: actions/upload-artifact@v3
|
|
139
176
|
with:
|
|
140
177
|
name: mutation-report
|
|
141
178
|
path: packages/irc-core/reports/mutation
|
|
@@ -16,11 +16,7 @@ name: deploy-cf-tcp
|
|
|
16
16
|
# CF_TCP_ORIGIN_ADDRESS Hostname/IP of the container origin.
|
|
17
17
|
|
|
18
18
|
on:
|
|
19
|
-
push
|
|
20
|
-
branches: [main]
|
|
21
|
-
paths:
|
|
22
|
-
- 'apps/cf-tcp-container/**'
|
|
23
|
-
- '.github/workflows/deploy-cf-tcp.yml'
|
|
19
|
+
# Automatic push trigger disabled; deploy only runs manually.
|
|
24
20
|
workflow_dispatch:
|
|
25
21
|
|
|
26
22
|
concurrency:
|
package/.gitmodules
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,480 @@ For the release process itself — versioning policy, pre-release checklist,
|
|
|
10
10
|
cutting a tag, rolling back — see [`docs/release.md`](docs/release.md).
|
|
11
11
|
Cross-reference `progress.md` / `tickets.md` for per-ticket detail.
|
|
12
12
|
|
|
13
|
+
## [0.7.0] - 2026-08-04
|
|
14
|
+
|
|
15
|
+
The headline is the **web client (Phase 14)**: a vendored **Kiwi IRC**
|
|
16
|
+
SPA served at `/app/` and a static project landing page served at `/`
|
|
17
|
+
directly by the Cloudflare Worker, with **Cross-Site WebSocket
|
|
18
|
+
Hijacking (CSWSH) defense** wired into the WS upgrade path. The browser
|
|
19
|
+
opens a native `wss://` straight to the existing IRC-over-WebSocket
|
|
20
|
+
endpoint — no proxy, gateway, or transport adaptation in the hot path.
|
|
21
|
+
Alongside it: a round of **test hardening** (mutation-killing tests for
|
|
22
|
+
`irc-core`'s parser / batch / numerics, and CF-harness / scenario fixes
|
|
23
|
+
for slow transports).
|
|
24
|
+
|
|
25
|
+
### Added — Web client (`@serverless-ircd/web`, `@serverless-ircd/cf-worker`)
|
|
26
|
+
|
|
27
|
+
Six Phase 14 tickets light up the project's browser surface. The Worker
|
|
28
|
+
becomes the single origin for the landing page, the SPA, **and** the
|
|
29
|
+
WebSocket. Same-origin by default — which is what makes the CSWSH
|
|
30
|
+
defense almost zero-config.
|
|
31
|
+
|
|
32
|
+
- **`apps/web` workspace package (`@serverless-ircd/web`)**: a new
|
|
33
|
+
pnpm workspace package owning the Kiwi build orchestration and config
|
|
34
|
+
schema. The package layout reserves `dist/app/` for the Kiwi SPA
|
|
35
|
+
(served at `/app/`) and `dist/index.html` for the landing page
|
|
36
|
+
(served at `/`). No `@serverless-ircd/*` runtime dependency —
|
|
37
|
+
Kiwi talks to the Worker over plain WebSocket.
|
|
38
|
+
- **Kiwi IRC vendored as a git submodule** (`apps/web/upstream/`,
|
|
39
|
+
tag-pinned): `scripts/build.mjs` patches the upstream `publicPath`
|
|
40
|
+
to `/app/`, runs `yarn build` inside the submodule, copies
|
|
41
|
+
`upstream/dist/` → `apps/web/dist/app/`, then layers our validated
|
|
42
|
+
`static/config.json` over the upstream default. The patch runs in
|
|
43
|
+
`finally` so the submodule stays clean; every hashed asset URL comes
|
|
44
|
+
out `/app/static/...` instead of root-relative. `.gitmodules` updated;
|
|
45
|
+
`biome.json` ignores `apps/web/upstream/**`. `git submodule update
|
|
46
|
+
--init` is now part of the contributor quickstart.
|
|
47
|
+
- **Per-env config matrix + Zod schema** (`apps/web/src/config-schema.ts`,
|
|
48
|
+
`apps/web/src/build-env.ts`): `static/config.json`,
|
|
49
|
+
`static/config.staging.json`, `static/config.prod.json` are validated
|
|
50
|
+
against a Zod schema **before** being baked into
|
|
51
|
+
`dist/app/static/config.json`. `pnpm --filter web build` accepts a
|
|
52
|
+
`--env <staging|prod>` flag (unit-tested in isolation from the slow
|
|
53
|
+
Kiwi build). A malformed config (missing `server`, out-of-range
|
|
54
|
+
`port`, non-`#` channel, `direct: false`, …) aborts the build with
|
|
55
|
+
an aggregated, field-listing error rather than shipping a broken SPA.
|
|
56
|
+
The Kiwi `startupOptions.server` uses the `{{hostname}}` template
|
|
57
|
+
(resolved by the browser to `window.location.hostname` at load time),
|
|
58
|
+
so **one build artifact targets staging, prod, and preview deploys
|
|
59
|
+
without a per-env hostname**.
|
|
60
|
+
- **Cloudflare Worker `[assets]` binding** (`apps/cf-worker/wrangler.toml`,
|
|
61
|
+
`apps/cf-worker/src/worker.ts`): the non-WS, non-`/health` branch of
|
|
62
|
+
the worker's `fetch` falls through to `env.ASSETS`, which serves
|
|
63
|
+
`apps/web/dist`. Per-env (`[env.staging.assets]`) blocks ship so
|
|
64
|
+
`wrangler deploy --env staging` deploys the Worker and the SPA in
|
|
65
|
+
one command. `run_worker_first = true` is set so WS upgrades aren't
|
|
66
|
+
intercepted by the asset platform serving `dist/index.html` at `/`
|
|
67
|
+
with a `200 OK` (the WS endpoint and the landing page share path
|
|
68
|
+
`/`; only the Worker can tell them apart).
|
|
69
|
+
- **Static landing page** (`apps/web/landing/index.html`): framework-
|
|
70
|
+
free HTML + inline CSS, no JavaScript. The project's front door —
|
|
71
|
+
explains what ServerlessIRCd is, links to `/app/` (the IRC client),
|
|
72
|
+
the docs, and the source repo. The build copies it verbatim to
|
|
73
|
+
`dist/index.html`. Renders without JS; responsive; the build-smoke
|
|
74
|
+
suite asserts the `/app/` link, the docs link, and the viewport meta
|
|
75
|
+
tag so they cannot regress.
|
|
76
|
+
- **`/health` is an explicit route**: the previous catch-all plaintext
|
|
77
|
+
liveness string now lives at `GET /health` so `/` is free for the
|
|
78
|
+
landing page. WS upgrades still route to `ConnectionDO`.
|
|
79
|
+
|
|
80
|
+
### Added — CSWSH defense (`@serverless-ircd/cf-worker`)
|
|
81
|
+
|
|
82
|
+
WebSocket upgrades do **not** follow the same-origin policy. A
|
|
83
|
+
malicious page can `new WebSocket('wss://irc.example.com/')` from the
|
|
84
|
+
victim's browser and drive an IRC session with the victim's
|
|
85
|
+
credentials. The Worker now rejects upgrades whose `Origin` is not
|
|
86
|
+
allowed — see `apps/cf-worker/src/origin-allowlist.ts` and
|
|
87
|
+
`docs/WebClientGuide.md` §5.
|
|
88
|
+
|
|
89
|
+
- **Two enforcement modes, evaluated in order:**
|
|
90
|
+
1. **Explicit allowlist** — when the `WEB_ORIGINS` var is set, only
|
|
91
|
+
listed origins proceed. Use this for cross-origin deployments
|
|
92
|
+
(SPA on a different domain than the Worker, e.g. Cloudflare
|
|
93
|
+
Pages).
|
|
94
|
+
2. **Auto-derive (same-origin)** — when `WEB_ORIGINS` is unset/empty
|
|
95
|
+
(the default), the Worker compares the browser's `Origin` against
|
|
96
|
+
the request's own origin (`${protocol}//${host}`). If they match,
|
|
97
|
+
the page opening the WS is the same origin as the server → safe.
|
|
98
|
+
- **`WEB_ORIGINS` is optional.** Because mode 2 is the default and
|
|
99
|
+
requires zero per-env configuration, most deployments never need to
|
|
100
|
+
set it: the SPA and the Worker are on the same origin. It works for
|
|
101
|
+
`*.workers.dev`, custom domains, and preview URLs alike.
|
|
102
|
+
- **Non-browser clients pass through unchanged.** curl, WeeChat, the
|
|
103
|
+
`tcp-ws-forwarder`, and scripted test harnesses never send `Origin`;
|
|
104
|
+
their upgrades are allowed in both modes so existing tooling keeps
|
|
105
|
+
working.
|
|
106
|
+
- **No fail-open path.** A browser-sent `Origin` that is not allowed
|
|
107
|
+
→ `403 Forbidden`. The extreme edge case (no allowlist AND
|
|
108
|
+
`Host` undeterminable, which never fires on Cloudflare) is
|
|
109
|
+
fail-closed `403`. The pure policy is exhaustively unit-tested in
|
|
110
|
+
`apps/cf-worker/tests/origin-allowlist.test.ts`; the worker
|
|
111
|
+
integration is covered by `tests/ws-origin.test.ts`.
|
|
112
|
+
|
|
113
|
+
### Added — Documentation (`docs/WebClientGuide.md`)
|
|
114
|
+
|
|
115
|
+
End-to-end contributor/operator doc covering: how the SPA, landing
|
|
116
|
+
page, and WS endpoint fit on one origin; prerequisites (incl. `yarn`
|
|
117
|
+
for the Kiwi build only); the quickstart (`git submodule update --init`
|
|
118
|
+
→ `pnpm --filter web build:staging` → `pnpm deploy:cf:staging`); a
|
|
119
|
+
walkthrough of the build pipeline and the per-env config matrix; the
|
|
120
|
+
CSWSH rationale and the optional `WEB_ORIGINS` var; local dev
|
|
121
|
+
(`wrangler dev` serves everything on `http://localhost:8787`); an
|
|
122
|
+
optional Cloudflare Pages alternative for cross-origin prod deploys;
|
|
123
|
+
the optional `webircgateway` SockJS fallback (strictly opt-in, not
|
|
124
|
+
needed for normal operation); landing-page customisation; and a
|
|
125
|
+
troubleshooting section. The acceptance criterion is that a new
|
|
126
|
+
contributor can deploy a staging SPA following only this doc.
|
|
127
|
+
|
|
128
|
+
### Added — Test hardening (`@serverless-ircd/irc-core`, `@serverless-ircd/cf-adapter`, `@serverless-ircd/irc-test-support`)
|
|
129
|
+
|
|
130
|
+
- **Mutation-killing tests for `irc-core`**: the parser, batch, and
|
|
131
|
+
numerics suites were expanded to kill surviving Stryker mutants —
|
|
132
|
+
command-token anchors, strict source-prefix shape, malformed-input
|
|
133
|
+
diagnostic text, middle-param whitespace collapsing,
|
|
134
|
+
`unescapeTagValue` boundary conditions; empty-batch framing metadata
|
|
135
|
+
surviving elision; and `numericToName` round-trip parity against the
|
|
136
|
+
registry. A generated Stryker mutation report is committed under
|
|
137
|
+
`packages/irc-core/reports/mutation/`.
|
|
138
|
+
- **CF harness / scenario fixes for slow transports**: the CF test
|
|
139
|
+
harness now waits for the end of the registration burst (`376` /
|
|
140
|
+
`422`) instead of `001`, so late MOTD frames do not pollute
|
|
141
|
+
`received` after a test clears it. The NOTICE scenario now only
|
|
142
|
+
rejects NOTICE-relevant error numerics (rather than any numeric),
|
|
143
|
+
preventing delayed welcome / MOTD lines from false-positiving the
|
|
144
|
+
RFC no-error-replies check. No production code changed.
|
|
145
|
+
|
|
146
|
+
### Changed
|
|
147
|
+
|
|
148
|
+
- **Cloudflare Worker routing.** `/health` is the new liveness route;
|
|
149
|
+
the root `/` now serves the landing page from the `[assets]`
|
|
150
|
+
binding. WS upgrades still route to `ConnectionDO`. Operators who
|
|
151
|
+
scraped the root `/` for the plaintext health string must update
|
|
152
|
+
to `/health`.
|
|
153
|
+
|
|
154
|
+
### ⚠️ Migration required
|
|
155
|
+
|
|
156
|
+
- **New optional runtime var: `WEB_ORIGINS`.** Optional — same-origin
|
|
157
|
+
auto-derive is the default. Set it only for cross-origin SPA
|
|
158
|
+
deployments (SPA on Cloudflare Pages, Worker serving the WS only,
|
|
159
|
+
etc.):
|
|
160
|
+
```toml
|
|
161
|
+
# apps/cf-worker/wrangler.toml
|
|
162
|
+
[vars]
|
|
163
|
+
WEB_ORIGINS = "https://irc.example.com,https://web.example.com"
|
|
164
|
+
```
|
|
165
|
+
- **New build prerequisite for the SPA.** Building `apps/web` needs
|
|
166
|
+
the Kiwi submodule (`git submodule update --init apps/web/upstream`)
|
|
167
|
+
and `yarn` (provided by `corepack enable`). The CF deploy workflow
|
|
168
|
+
runs `pnpm build` (which builds the SPA + landing page) before
|
|
169
|
+
`wrangler deploy`. If you deploy manually and skip the SPA build,
|
|
170
|
+
the Worker still works but `/app/` and `/` return 404 from the asset
|
|
171
|
+
layer.
|
|
172
|
+
- **`/health` is the new liveness route.** Operators who scraped `/`
|
|
173
|
+
for the plaintext health string must update to `/health`.
|
|
174
|
+
- **New workspace package.** `apps/web` is a new private package
|
|
175
|
+
(`@serverless-ircd/web`); `pnpm install` picks it up automatically
|
|
176
|
+
from the existing `pnpm-workspace.yaml` glob.
|
|
177
|
+
- **No persisted-state schema change.** `PERSISTED_STATE_VERSION`
|
|
178
|
+
stays `1`. **Code rollback across this release is safe** — the
|
|
179
|
+
web-client work adds the `[assets]` binding and the `/health` route
|
|
180
|
+
but touches no Durable Object state.
|
|
181
|
+
- No toolchain change. Node ≥ 24 / pnpm 11 (from v0.4.0) still apply.
|
|
182
|
+
|
|
183
|
+
### Known limitations
|
|
184
|
+
|
|
185
|
+
- **Phase 14 is partial.** The Playwright headless-browser e2e
|
|
186
|
+
against the deployed staging frontend remains pending
|
|
187
|
+
— the SPA is exercised via the existing WS smoke
|
|
188
|
+
(`scripts/smoke.mjs`) and the new `apps/web` unit / build-smoke
|
|
189
|
+
suite, but no browser-driven end-to-end test runs in CI yet.
|
|
190
|
+
- **The web client is Cloudflare-only.** The `[assets]` binding is a
|
|
191
|
+
Cloudflare Worker feature; AWS deployments continue to require an
|
|
192
|
+
external static host for the SPA (and must add the SPA's origin to
|
|
193
|
+
the Worker-style `WEB_ORIGINS` equivalent if/when an AWS-side
|
|
194
|
+
CSWSH check lands).
|
|
195
|
+
- Same transport limits as v0.6.0: the **CF TCP path requires
|
|
196
|
+
Cloudflare Spectrum (Enterprise tier)** plus a stateful Container
|
|
197
|
+
origin; the **AWS TCP path** uses NLB + Lambda streaming and is
|
|
198
|
+
subject to Lambda idle-timeout / stream-duration limits. The
|
|
199
|
+
WebSocket path remains the zero-extra-deps default.
|
|
200
|
+
- **mTLS (for SASL `EXTERNAL`) requires a custom domain + uploaded
|
|
201
|
+
CA/trust-store** on both platforms and is not enabled by default.
|
|
202
|
+
- **Client compatibility sweep** (WeeChat / HexChat / IRCCloud /
|
|
203
|
+
TheLounge / matrix-IRC bridge) remains pending.
|
|
204
|
+
- **Coverage hardening is partial.** `aws-adapter` and `aws-stack`
|
|
205
|
+
clear the 90% gate (v0.6.0); the remaining packages
|
|
206
|
+
(`cf-adapter`, `local-cli`, `load-test`, `cf-tcp-container`,
|
|
207
|
+
`tcp-ws-forwarder`, `irc-test-support`, and now `web`) are **above
|
|
208
|
+
the gate but below 100%** — follow-ups drive each to 100%.
|
|
209
|
+
- The IRC services Phase 13 work (NickServ / ChanServ / HostServ /
|
|
210
|
+
OperServ / MemoServ) is pending; `draft/read-marker` and
|
|
211
|
+
`draft/pre-away` ship with in-memory reference stores, so marker /
|
|
212
|
+
away persistence does not survive an adapter restart until a
|
|
213
|
+
services backend lands.
|
|
214
|
+
|
|
215
|
+
### Security
|
|
216
|
+
|
|
217
|
+
- **CSWSH defense added.** WebSocket upgrades from browsers now
|
|
218
|
+
require an allowed `Origin`. Same-origin auto-derive is the default
|
|
219
|
+
(zero config); explicit `WEB_ORIGINS` allowlist for cross-origin
|
|
220
|
+
setups. Non-browser clients (no `Origin`) pass through unchanged.
|
|
221
|
+
There is no fail-open path. See `docs/WebClientGuide.md` §5. No
|
|
222
|
+
other auth path changed (SASL `PLAIN` / `EXTERNAL`, oper gate,
|
|
223
|
+
admission limits, and cloaking are unchanged from v0.6.0).
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## [0.6.0] - 2026-08-03
|
|
228
|
+
|
|
229
|
+
The headline is the **IRCv3 extension sweep (Phase 12)**: ten negotiated
|
|
230
|
+
caps and the user-mode-`S` TLS indicator land in one release, taking the
|
|
231
|
+
negotiated capability surface from "modern baseline" to "draft-leading-
|
|
232
|
+
edge". Alongside it: the **required-`serverName` config gate** (the
|
|
233
|
+
last open v0.5.0 follow-up), a new **`tools/load-test`** client farm
|
|
234
|
+
(Phase 7's 10k-connection harness), and the **coverage / CI unblocks**
|
|
235
|
+
that lift `aws-adapter` over the 90% gate and switch `cf-adapter` /
|
|
236
|
+
`cf-worker` to istanbul (clearing the v0.5.0 workerd-incompatibility
|
|
237
|
+
caveat). Deploy workflows are now **manual-only** (`workflow_dispatch`).
|
|
238
|
+
|
|
239
|
+
### Added — IRCv3 extensions (`@serverless-ircd/irc-core`, `@serverless-ircd/irc-server`)
|
|
240
|
+
|
|
241
|
+
The ten Phase 12 cap tickets light up the remaining negotiated-cap
|
|
242
|
+
surface, and the two non-cap Phase 12 tickets (ISUPPORT tokens and
|
|
243
|
+
user mode `S`) round out the wire-visible advertisement. Each cap
|
|
244
|
+
ships a pure reducer (where applicable), an actor route case,
|
|
245
|
+
advertisement in `SUPPORTED_CAPABILITIES` (or conditional
|
|
246
|
+
advertisement for `sts`), and unit + actor coverage. The
|
|
247
|
+
pure-reducer / dispatch pipeline is unchanged — every cap is plumbed
|
|
248
|
+
through `ctx` and emitted `Effect[]`, never performed in the handler.
|
|
249
|
+
|
|
250
|
+
- **`account-notify`**: pushes `:nick ACCOUNT <name|*>`
|
|
251
|
+
to peers in shared channels (excluding the sender unless
|
|
252
|
+
`echo-message`) on SASL login / logout. Closes the
|
|
253
|
+
`account-tag` / `extended-join` / `account-notify` triple modern
|
|
254
|
+
clients render fully.
|
|
255
|
+
- **`msgid`**: every PRIVMSG / NOTICE / TAGMSG fanned out
|
|
256
|
+
to a cap-enabled peer carries `@+msgid=<id>` from
|
|
257
|
+
`IdFactory.nonce()`. The nonce is **shared between the live fanout
|
|
258
|
+
and the `draft/chathistory` record** so a peer sees the same id live
|
|
259
|
+
and on replay. Legacy peers see no `msgid` tag.
|
|
260
|
+
- **`standard-replies`**: a data-driven
|
|
261
|
+
`numericToStandardReply` table replaces a curated subset of bare
|
|
262
|
+
numerics (`461`, `403`, `432`, `433`, SASL failures, …) with
|
|
263
|
+
`FAIL`/`WARN`/`NOTE COMMAND code context :description` for
|
|
264
|
+
cap-enabled clients. Legacy clients still receive the unchanged
|
|
265
|
+
numeric. Numeric-only replies (MOTD lines, NAMES, …) stay on their
|
|
266
|
+
numeric form.
|
|
267
|
+
- **`MONITOR`**: the modern `ISON` replacement. Implements
|
|
268
|
+
`MONITOR + nick{,nick}` / `- nick` / `C` / `L` / `S` with the
|
|
269
|
+
`730 RPL_MONONLINE` / `731 RPL_MONOFFLINE` / `732 RPL_MONLIST` /
|
|
270
|
+
`734 ERR_MONLISTFULL` numerics. Online/offline transitions push
|
|
271
|
+
`730`/`731` **asynchronously** via the Registry's nick reserve /
|
|
272
|
+
release hooks (a new `MonitorStore` port + push callback). The
|
|
273
|
+
ceiling is config-driven (`MONITOR=<n>`, default 30).
|
|
274
|
+
- **`labeled-response`**: a client-sent `+label=<id>` is
|
|
275
|
+
plumbed through `ctx` and every reply caused by that message is
|
|
276
|
+
wrapped in a single `BATCH +id labeled-response … BATCH -id`. A
|
|
277
|
+
command that produces no reply emits an empty labeled batch (spec-
|
|
278
|
+
mandated). The label travels on every reducer's emitted effects,
|
|
279
|
+
so multi-reply commands accumulate under one batch.
|
|
280
|
+
- **`sts`**: Strict Transport Security. The cap is
|
|
281
|
+
**conditionally advertised** — only when `ServerConfig.sts`
|
|
282
|
+
(`{ duration, port, preload? }`) is supplied. On a plaintext
|
|
283
|
+
listener a compliant client upgrades; on the TLS listener the
|
|
284
|
+
duration is still sent to lock in the policy. Defaults:
|
|
285
|
+
`duration = 30 days`, `port = 6697`.
|
|
286
|
+
- **`draft/typing`**: `TAGMSG <target> +draft/typing=
|
|
287
|
+
active|paused|done` broadcasts to channel members (or routes to a
|
|
288
|
+
nick target), excluding the sender unless `echo-message`. The
|
|
289
|
+
`+draft/typing=*` client tag is whitelisted for clients without
|
|
290
|
+
`message-tags` (per the spec's client-tag exception). Broadcast
|
|
291
|
+
delivery uses **OR-semantics**: a recipient qualifies if it
|
|
292
|
+
negotiated `message-tags` **or** `draft/typing` (a new `caps` field
|
|
293
|
+
on `BroadcastEffect`).
|
|
294
|
+
- **`draft/multiline`**: a cap-enabled
|
|
295
|
+
client sends `BATCH +id draft/multiline :target` + N PRIVMSG/NOTICE
|
|
296
|
+
lines + `BATCH -id`. The server concatenates per spec (with `\n`),
|
|
297
|
+
enforces a configurable byte budget (`multilineMaxBytes`, default
|
|
298
|
+
4096), and broadcasts the batched replay to multiline peers / a
|
|
299
|
+
single joined PRIVMSG (carrying `+draft/multiline`) to legacy
|
|
300
|
+
peers. **Nick-target routing**, **chathistory recording** (one
|
|
301
|
+
record per batch carrying the joined body, assigned `msgid`, and
|
|
302
|
+
the `+draft/multiline` client tag), and **tag gating** (the
|
|
303
|
+
`+draft/multiline` tag is stripped for peers without
|
|
304
|
+
`message-tags`) all land in the completion ticket.
|
|
305
|
+
- **`draft/read-marker`**: persists the per-`(account,
|
|
306
|
+
channel)` last-read marker in a new `ReadMarkerStore` port,
|
|
307
|
+
propagates updates via `+draft/read-marker=<msgid>` tags, and
|
|
308
|
+
seeds a fresh connection's marker from the persisted value at
|
|
309
|
+
identify time. `CHATHISTORY BEFORE` honours the marker when no
|
|
310
|
+
explicit pivot is supplied.
|
|
311
|
+
- **`draft/pre-away`**: persists the away reason in a
|
|
312
|
+
new `AwayStore` port keyed by account. On identify (or SASL login)
|
|
313
|
+
the server re-applies the away state and emits the `AWAY` line +
|
|
314
|
+
`306 RPL_NOWAWAY` as if the user had sent `AWAY :reason`
|
|
315
|
+
themselves. `AWAY` (unset) clears the persisted reason.
|
|
316
|
+
- **ISUPPORT tokens for the new caps**: `005
|
|
317
|
+
RPL_ISUPPORT` now advertises `STATUSMSG=@+`, `EXTBAN=<prefix>,q`,
|
|
318
|
+
`ACCOUNTEXTBAN=a` (services-gated), `TYPING`, and `MULTILINE`.
|
|
319
|
+
`MONITOR=<n>` honours `serverConfig.monitorLimit`. Tokens are
|
|
320
|
+
config-derived where applicable.
|
|
321
|
+
- **User mode `S` (TLS connected)**: the transport's
|
|
322
|
+
TLS fact is surfaced end-to-end as a read-only user mode. Set
|
|
323
|
+
once by the registration reducer from `ConnectionState.secure`;
|
|
324
|
+
emitted in `221 … +S`; rejected by `MODE nick +/-S` with `501
|
|
325
|
+
ERR_UMODEUNKNOWNFLAG`; surfaced in WHOIS via the new `276
|
|
326
|
+
RPL_WHOISSECURE`. Each adapter asserts `secure: true` where the
|
|
327
|
+
platform terminates TLS (API Gateway, CF edge, Spectrum, NLB TLS
|
|
328
|
+
listener).
|
|
329
|
+
|
|
330
|
+
### Changed — Required server identity
|
|
331
|
+
|
|
332
|
+
The last open v0.5.0 follow-up closes. The `irc.example.com`
|
|
333
|
+
placeholder `DEFAULT_SERVER_CONFIG` is **removed** from
|
|
334
|
+
`irc-core`; the shared `ServerConfigSchema` rejects a missing
|
|
335
|
+
`serverName` / `networkName` so every adapter **fails fast at boot**
|
|
336
|
+
with a readable, field-listing error.
|
|
337
|
+
|
|
338
|
+
- **`@serverless-ircd/irc-core`**: `DEFAULT_SERVER_CONFIG` removed.
|
|
339
|
+
- **`@serverless-ircd/irc-test-support`**: ships a clearly test-scoped
|
|
340
|
+
`makeTestServerConfig()` baseline (`irc.test.local`) so unit tests
|
|
341
|
+
construct a `ServerConfig` without re-introducing a production
|
|
342
|
+
default.
|
|
343
|
+
- `apps/cf-worker` + `apps/cf-tcp-container`: loaders require
|
|
344
|
+
`SERVER_NAME`; `wrangler.toml` samples switched to
|
|
345
|
+
`irc.your-domain.invalid`.
|
|
346
|
+
- `apps/aws-stack` + `apps/local-cli`: keep obviously-local fallbacks
|
|
347
|
+
(`irc.localhost`) documented as *"production MUST override"*;
|
|
348
|
+
`local-cli` gains `--server-name` / `--network-name` flags.
|
|
349
|
+
|
|
350
|
+
### Added — Load-test harness (`@serverless-ircd/load-test`)
|
|
351
|
+
|
|
352
|
+
PLAN §7 / Phase 7's 10k-connection harness. A synthetic WebSocket IRC
|
|
353
|
+
client farm: opens N connections, registers (NICK/USER), joins a
|
|
354
|
+
channel, and optionally chats. Captures **p50 / p95 / p99 latency per
|
|
355
|
+
phase** (connect / register / join / message) plus the **drop rate**,
|
|
356
|
+
and prints a markdown report to stdout (or `--report <path>`).
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
pnpm --filter load-test start -- \
|
|
360
|
+
--target wss://irc.staging.example.com/ \
|
|
361
|
+
--connections 10000 --concurrency 200 --ramp-ms 60000 \
|
|
362
|
+
--channel '#loadtest' --messages 3 --platform cf-staging \
|
|
363
|
+
--report reports/cf-staging-2026-08-03.md
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
The package ships its own vitest suite (config parsing, framing,
|
|
367
|
+
harness, metrics, report) at ≥90% coverage; no production source in
|
|
368
|
+
the irc-core / irc-server packages changed to support it.
|
|
369
|
+
|
|
370
|
+
### Added — Coverage / CI unblocks
|
|
371
|
+
|
|
372
|
+
- **`aws-adapter` clears the 90% gate.** The self-hosted runner image
|
|
373
|
+
ships with neither Docker nor a JRE, so the package's
|
|
374
|
+
testcontainers / Java-ZIP DynamoDB Local boot fell through to
|
|
375
|
+
strategy 3 and 171 of 294 integration tests `describe.skipIf`-ed
|
|
376
|
+
away — dropping coverage to ~42% and blowing the gate. CI now
|
|
377
|
+
installs Temurin JRE 11 via `actions/setup-java@v4` and pins
|
|
378
|
+
`DDB_LOCAL_STRATEGY=zip` on the coverage step so the ZIP fallback
|
|
379
|
+
fires deterministically. The full aws-adapter suite now runs on
|
|
380
|
+
every coverage job. New integration tests cover
|
|
381
|
+
`broadcastWallops` fan-out, `reserveNick` non-conditional error
|
|
382
|
+
propagation, `refreshChannel` empty-members / topic-preservation
|
|
383
|
+
paths, NLB header fallbacks, scan-row type guards, and
|
|
384
|
+
`CREATED_AT` overflow handling. `tools/ci-hardening` gained a
|
|
385
|
+
self-check asserting the JRE install + strategy pin remain wired.
|
|
386
|
+
- **`aws-stack` coverage command repaired.** The CDK `NodejsFunction`
|
|
387
|
+
in the test synth re-bundled the Lambda asset via esbuild ~80
|
|
388
|
+
times per coverage run and OOM-ed CI before vitest could print a
|
|
389
|
+
report. A new `makeLambda()` factory switches between
|
|
390
|
+
`NodejsFunction` (production synth) and an inline-zip `Function`
|
|
391
|
+
stub (tests) via the `IRC_AWS_STACK_TEST_NO_BUNDLE` env var. The
|
|
392
|
+
stub preserves every CloudFormation shape the suite asserts on
|
|
393
|
+
while making bundling a no-op. New
|
|
394
|
+
`tests/synth-no-bundle.test.ts` + `tests/coverage-command.test.ts`
|
|
395
|
+
lock both branches and assert the `pnpm coverage` run prints an
|
|
396
|
+
`All files` row.
|
|
397
|
+
- **`cf-adapter` / `cf-worker` switch to istanbul coverage.** This
|
|
398
|
+
**resolves the v0.5.0 known limitation**: `@vitest/coverage-v8`
|
|
399
|
+
v4.1.x imports `node:inspector/promises`, which the
|
|
400
|
+
`@cloudflare/vitest-pool-workers` (workerd) pool cannot resolve.
|
|
401
|
+
Both packages now use `@vitest/coverage-istanbul` so `pnpm
|
|
402
|
+
coverage` loads under workerd. Edge-case suites were expanded
|
|
403
|
+
(serialize/deserialize/migrate, connection-do pure helpers,
|
|
404
|
+
`broadcastWallops` fan-out, `changeNick` shard routing,
|
|
405
|
+
ChannelDO broadcast/cache, RegistryDO `listEntries`, SASL seed
|
|
406
|
+
parsing).
|
|
407
|
+
|
|
408
|
+
### Changed — Deploy workflows are now manual-only
|
|
409
|
+
|
|
410
|
+
`deploy-cf.yml`, `deploy-cf-tcp.yml`, and `deploy-aws.yml` dropped
|
|
411
|
+
their `push: branches: [main]` triggers and now run on
|
|
412
|
+
`workflow_dispatch` only. Staging deploys are no longer fired
|
|
413
|
+
automatically on every merge to `main`; a maintainer kicks them off
|
|
414
|
+
by hand. The release runbook (`docs/Release-Process.md`) is the
|
|
415
|
+
canonical reference either way — there was never a CI auto-deploy to
|
|
416
|
+
production.
|
|
417
|
+
|
|
418
|
+
### Changed — `@vitest/coverage-istanbul` peer
|
|
419
|
+
|
|
420
|
+
The root lockfile (`pnpm-lock.yaml`) registers the
|
|
421
|
+
`@vitest/coverage-istanbul` peer introduced by the cf-adapter /
|
|
422
|
+
cf-worker coverage switch. No operator action; `pnpm install`
|
|
423
|
+
resolves it.
|
|
424
|
+
|
|
425
|
+
### ⚠️ Migration required
|
|
426
|
+
|
|
427
|
+
- **`serverName` is now required at boot.** Operators who relied on
|
|
428
|
+
the silent `irc.example.com` placeholder must supply an explicit
|
|
429
|
+
value via their adapter's config knob:
|
|
430
|
+
- **Cloudflare Worker / TCP container**: set `SERVER_NAME` (and
|
|
431
|
+
`NETWORK_NAME` if desired) in `wrangler.toml` `[vars]` or via
|
|
432
|
+
`wrangler secret put`. The samples switched to
|
|
433
|
+
`irc.your-domain.invalid` — replace with your real hostname.
|
|
434
|
+
- **AWS**: the CDK stack's `serverName` prop / `SERVER_NAME` env
|
|
435
|
+
var. The local fallback is `irc.localhost` and is explicitly
|
|
436
|
+
documented as "production MUST override".
|
|
437
|
+
- **`local-cli`**: new `--server-name <h>` / `--network-name <n>`
|
|
438
|
+
flags (default `irc.localhost` / `LocalNet`).
|
|
439
|
+
A missing value now throws an aggregated `"Invalid server
|
|
440
|
+
config:"` error at boot listing every offending field.
|
|
441
|
+
- **No persisted-state schema change.** `PERSISTED_STATE_VERSION`
|
|
442
|
+
stays `1`. The user-mode-`S` work adds a `secure` field and a
|
|
443
|
+
`userModes.tls` field to the persisted shape, but both are purely
|
|
444
|
+
**additive with `false` defaults** and the cf-adapter `migrate()`
|
|
445
|
+
path backfills them on pre-feature records. **Code rollback across
|
|
446
|
+
this release is safe.**
|
|
447
|
+
- No toolchain change. Node ≥ 24 / pnpm 11 (from v0.4.0) still apply.
|
|
448
|
+
|
|
449
|
+
### Known limitations
|
|
450
|
+
|
|
451
|
+
- Same transport limits as v0.5.0: the **CF TCP path requires
|
|
452
|
+
Cloudflare Spectrum (Enterprise tier)** plus a stateful Container
|
|
453
|
+
origin; the **AWS TCP path** uses NLB + Lambda streaming and is
|
|
454
|
+
subject to Lambda idle-timeout / stream-duration limits. The
|
|
455
|
+
WebSocket path remains the zero-extra-deps default.
|
|
456
|
+
- **mTLS (for SASL `EXTERNAL`) requires a custom domain + uploaded
|
|
457
|
+
CA/trust-store** on both platforms and is not enabled by default.
|
|
458
|
+
- `STATS` ships the `u` + `l` query letters; the full RFC matrix
|
|
459
|
+
(`k`, `K`, `q`, `g`, `x`, `z`, …) is intentionally out of scope for
|
|
460
|
+
v1 — unknown letters get the charybdis-style empty body + `219`.
|
|
461
|
+
- **Client compatibility sweep** (WeeChat / HexChat / IRCCloud /
|
|
462
|
+
TheLounge / matrix-IRC bridge) remains pending.
|
|
463
|
+
- **Coverage hardening is partial.** `aws-adapter` and `aws-stack`
|
|
464
|
+
now clear the 90% gate, and `cf-adapter` / `cf-worker` run under
|
|
465
|
+
istanbul; the remaining packages (`cf-adapter`, `local-cli`,
|
|
466
|
+
`load-test`, `cf-tcp-container`, `tcp-ws-forwarder`,
|
|
467
|
+
`irc-test-support`) are **above the gate but below 100%** —
|
|
468
|
+
follow-ups drive each to 100%.
|
|
469
|
+
- The IRC services (NickServ / ChanServ / HostServ / OperServ /
|
|
470
|
+
MemoServ) Phase 13 work is pending; `draft/read-marker` and
|
|
471
|
+
`draft/pre-away` ship with in-memory reference stores, so marker /
|
|
472
|
+
away persistence does not survive an adapter restart until a
|
|
473
|
+
services backend lands.
|
|
474
|
+
- The web client Phase 14 work (vendor Kiwi IRC, serve SPA from the
|
|
475
|
+
Worker, WS Origin allowlist) is pending.
|
|
476
|
+
|
|
477
|
+
### Security
|
|
478
|
+
|
|
479
|
+
- None. No vulnerabilities have been reported or fixed in this
|
|
480
|
+
release. The new caps add surface area but ship no new auth path
|
|
481
|
+
(the SASL `PLAIN` / `EXTERNAL` paths and the oper gate are
|
|
482
|
+
unchanged); the required-`serverName` change rejects misconfigured
|
|
483
|
+
deploys at boot rather than advertising a placeholder identity.
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
13
487
|
## [0.5.0] - 2026-08-02
|
|
14
488
|
|
|
15
489
|
The headline is **protocol completion**: the deferred IRC verbs land
|