serverless-ircd 0.6.0 → 0.8.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 +9 -4
- package/.gitmodules +4 -1
- package/CHANGELOG.md +480 -22
- package/README.md +244 -57
- package/apps/aws-stack/package.json +1 -1
- package/apps/aws-stack/src/aws-stack.ts +186 -18
- package/apps/aws-stack/tests/stack.test.ts +400 -56
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-worker/package.json +1 -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/index.html +18 -0
- package/apps/cf-worker/tests/fixtures/web-dist/webclient/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/wrangler.test.toml +23 -0
- package/apps/cf-worker/wrangler.toml +56 -0
- package/apps/local-cli/package.json +1 -1
- package/apps/local-cli/src/config-loader.ts +8 -0
- package/apps/local-cli/src/main.ts +16 -0
- package/apps/local-cli/src/server.ts +1 -0
- package/apps/local-cli/tests/config-loader.test.ts +14 -0
- package/apps/web/landing/index.html +215 -0
- package/apps/web/package.json +28 -0
- package/apps/web/scripts/build.mjs +132 -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 +1 -0
- package/docs/AWS-Deployment.md +21 -8
- package/docs/Cloudflare-Deployment-Guide.md +22 -6
- package/docs/Home.md +1 -0
- package/docs/PlanExtensions.md +113 -3
- package/docs/Release-Process.md +23 -13
- package/docs/Services.md +546 -0
- package/docs/WebClientGuide.md +536 -0
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/aws-adapter/src/aws-runtime.ts +5 -0
- package/packages/aws-adapter/src/cdk-table-defs.ts +6 -0
- package/packages/aws-adapter/src/config-loader.ts +11 -0
- package/packages/aws-adapter/src/connection-counter.ts +89 -0
- package/packages/aws-adapter/src/dynamo-services-store.ts +649 -0
- package/packages/aws-adapter/src/handlers/connect.ts +55 -51
- package/packages/aws-adapter/src/handlers/default.ts +36 -4
- package/packages/aws-adapter/src/handlers/index.ts +15 -0
- package/packages/aws-adapter/src/handlers/nlb-stream.ts +15 -0
- package/packages/aws-adapter/src/handlers/sweeper.ts +5 -1
- package/packages/aws-adapter/src/index.ts +4 -0
- package/packages/aws-adapter/src/stats.ts +6 -1
- package/packages/aws-adapter/src/tables.ts +34 -4
- package/packages/aws-adapter/tests/aws-harness.ts +3 -0
- package/packages/aws-adapter/tests/config-loader.test.ts +8 -0
- package/packages/aws-adapter/tests/connect.test.ts +158 -32
- package/packages/aws-adapter/tests/connection-counter.test.ts +127 -0
- package/packages/aws-adapter/tests/dynamo-services-store-dynamo.test.ts +183 -0
- package/packages/aws-adapter/tests/dynamo-services-store-unit.test.ts +568 -0
- package/packages/aws-adapter/tests/handlers.test.ts +105 -3
- package/packages/aws-adapter/tests/tables.test.ts +6 -1
- package/packages/cf-adapter/package.json +1 -1
- package/packages/cf-adapter/src/config-loader.ts +11 -0
- package/packages/cf-adapter/src/connection-do.ts +112 -2
- package/packages/cf-adapter/src/d1-services-store.ts +703 -0
- package/packages/cf-adapter/src/env.ts +8 -0
- package/packages/cf-adapter/src/index.ts +5 -0
- package/packages/cf-adapter/tests/cf-harness.ts +12 -1
- package/packages/cf-adapter/tests/config-loader.test.ts +19 -0
- package/packages/cf-adapter/tests/connection-do-nickserv-d1.test.ts +128 -0
- package/packages/cf-adapter/tests/connection-do.test.ts +150 -2
- package/packages/cf-adapter/tests/d1-services-store.test.ts +582 -0
- package/packages/cf-adapter/tests/serialize.test.ts +1 -0
- 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/scripts/generate-build-info.mjs +26 -5
- package/packages/irc-core/src/commands/account-auth.ts +172 -0
- package/packages/irc-core/src/commands/chanserv.ts +882 -0
- package/packages/irc-core/src/commands/hostserv.ts +487 -0
- package/packages/irc-core/src/commands/index.ts +12 -0
- package/packages/irc-core/src/commands/join.ts +164 -8
- package/packages/irc-core/src/commands/markread.ts +202 -0
- package/packages/irc-core/src/commands/memoserv.ts +319 -0
- package/packages/irc-core/src/commands/mode.ts +96 -4
- package/packages/irc-core/src/commands/nickserv.ts +390 -0
- package/packages/irc-core/src/commands/oper.ts +18 -1
- package/packages/irc-core/src/commands/operserv.ts +346 -0
- package/packages/irc-core/src/commands/pre-away.ts +3 -1
- package/packages/irc-core/src/commands/privmsg.ts +42 -0
- package/packages/irc-core/src/commands/read-marker.ts +8 -8
- package/packages/irc-core/src/commands/registration.ts +61 -6
- package/packages/irc-core/src/commands/sasl.ts +18 -49
- package/packages/irc-core/src/commands/tagmsg.ts +41 -6
- package/packages/irc-core/src/commands/topic.ts +37 -0
- package/packages/irc-core/src/config.ts +36 -5
- package/packages/irc-core/src/effects.ts +56 -1
- package/packages/irc-core/src/ports.ts +1653 -84
- package/packages/irc-core/src/protocol/numerics.ts +8 -0
- package/packages/irc-core/src/state/channel.ts +21 -1
- package/packages/irc-core/src/state/connection.ts +25 -1
- package/packages/irc-core/src/types.ts +48 -12
- package/packages/irc-core/tests/batch.test.ts +15 -0
- package/packages/irc-core/tests/commands/chanserv.test.ts +1668 -0
- package/packages/irc-core/tests/commands/chathistory.test.ts +6 -0
- package/packages/irc-core/tests/commands/hostserv.test.ts +935 -0
- package/packages/irc-core/tests/commands/join.test.ts +393 -1
- package/packages/irc-core/tests/commands/markread.test.ts +361 -0
- package/packages/irc-core/tests/commands/memoserv.test.ts +654 -0
- package/packages/irc-core/tests/commands/mode.test.ts +381 -2
- package/packages/irc-core/tests/commands/nickserv.test.ts +807 -0
- package/packages/irc-core/tests/commands/oper.test.ts +13 -0
- package/packages/irc-core/tests/commands/operserv.test.ts +656 -0
- package/packages/irc-core/tests/commands/privmsg.test.ts +147 -0
- package/packages/irc-core/tests/commands/read-marker.test.ts +28 -28
- package/packages/irc-core/tests/commands/registration.test.ts +788 -14
- package/packages/irc-core/tests/commands/sasl.test.ts +185 -12
- package/packages/irc-core/tests/commands/server-info.test.ts +9 -5
- package/packages/irc-core/tests/commands/tagmsg.test.ts +73 -33
- package/packages/irc-core/tests/commands/topic.test.ts +94 -2
- package/packages/irc-core/tests/commands/unified-account.test.ts +416 -0
- package/packages/irc-core/tests/config.test.ts +49 -5
- package/packages/irc-core/tests/effects.test.ts +19 -0
- package/packages/irc-core/tests/message-store.test.ts +63 -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/persistent-services-store.test.ts +582 -0
- package/packages/irc-core/tests/services-store.test.ts +1289 -0
- package/packages/irc-core/tests/state/channel.test.ts +3 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-server/src/actor.ts +71 -16
- package/packages/irc-server/src/dispatch.ts +94 -7
- package/packages/irc-server/src/routing.ts +19 -0
- package/packages/irc-server/tests/actor.test.ts +623 -12
- package/packages/irc-server/tests/dispatch.test.ts +270 -2
- package/packages/irc-server/tests/routing.test.ts +6 -0
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/in-memory-harness.ts +29 -3
- package/packages/irc-test-support/src/index.ts +1 -0
- package/packages/irc-test-support/src/scenarios.ts +24 -2
- package/packages/irc-test-support/tests/in-memory-harness.test.ts +32 -0
- package/tools/ci-hardening/package.json +1 -1
- package/tools/load-test/package.json +1 -1
- package/tools/tcp-ws-forwarder/package.json +1 -1
- package/tools/tcp-ws-forwarder/tests/forwarder.test.ts +2 -2
- package/packages/irc-core/tests/read-marker-store.test.ts +0 -108
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ platform-agnostic core, and two thin adapters run it on **Cloudflare Workers**
|
|
|
6
6
|
|
|
7
7
|
One TypeScript codebase. Two serverless substrates.
|
|
8
8
|
|
|
9
|
-
> **Status:** **v0.
|
|
9
|
+
> **Status:** **v0.8.0 (preview).** The pure protocol core, the
|
|
10
10
|
> `IrcRuntime` port + in-memory runtime, a runnable local CLI server,
|
|
11
11
|
> the **Cloudflare Workers** adapter, and the **AWS** (API Gateway
|
|
12
12
|
> WebSocket + Lambda + DynamoDB + CDK) adapter are all functional and
|
|
@@ -19,30 +19,44 @@ One TypeScript codebase. Two serverless substrates.
|
|
|
19
19
|
> deferred IRC verbs (`KILL`, `REHASH`, `LUSERS` + `STATS`, `TRACE`,
|
|
20
20
|
> `WALLOPS`, `SETNAME`) all land, and the S2S (`CONNECT` / `SQUIT` /
|
|
21
21
|
> `LINKS`) and obsolete RFC 2812 (`SERVICE` / `SUMMON` / `USERS`) verbs
|
|
22
|
-
> are formally dropped.
|
|
23
|
-
>
|
|
22
|
+
> are formally dropped. v0.6.0 landed the **IRCv3 extension sweep**
|
|
23
|
+
> — ten caps (`account-notify`, `msgid`,
|
|
24
24
|
> `standard-replies`, `MONITOR`, `labeled-response`, `sts`,
|
|
25
25
|
> `draft/typing`, `draft/multiline`, `draft/read-marker`,
|
|
26
26
|
> `draft/pre-away`), the ISUPPORT tokens for the new caps, and the
|
|
27
|
-
> read-only user mode `S` (TLS connected)
|
|
28
|
-
>
|
|
29
|
-
>
|
|
30
|
-
>
|
|
31
|
-
>
|
|
32
|
-
>
|
|
33
|
-
>
|
|
34
|
-
>
|
|
35
|
-
>
|
|
36
|
-
> `
|
|
27
|
+
> read-only user mode `S` (TLS connected). **v0.7.0 lands the web
|
|
28
|
+
> client**: a vendored **Kiwi IRC** SPA served at `/webclient/`
|
|
29
|
+
> and a static landing page at `/` directly by the Cloudflare Worker,
|
|
30
|
+
> with **Cross-Site WebSocket Hijacking (CSWSH) defense** wired into
|
|
31
|
+
> the WS upgrade path (same-origin auto-derive by default, optional
|
|
32
|
+
> `WEB_ORIGINS` allowlist for cross-origin deploys) — the browser
|
|
33
|
+
> opens a native `wss://` straight to the existing IRC-over-WebSocket
|
|
34
|
+
> endpoint. **v0.8.0 lands integrated IRC services** — NickServ
|
|
35
|
+
> (`REGISTER` / `IDENTIFY` / `DROP` / `INFO` / `SET ENFORCE` +
|
|
36
|
+
> nick enforcement), ChanServ (`REGISTER` / `DROP` / `SET` /
|
|
37
|
+
> `ACCESS` / `LEVELS` + the `+r` / `+R` / `+M` channel modes),
|
|
38
|
+
> HostServ (`ON` / `OFF` / `REQUEST` + oper `SET` / `APPROVE`),
|
|
39
|
+
> OperServ (`AKILL` / `JUPE` / `RAW`), and MemoServ
|
|
40
|
+
> (`SEND` / `LIST` / `READ` / `DEL`) — backed by a `ServicesStore`
|
|
41
|
+
> port with **persistent D1 (Cloudflare) and DynamoDB (AWS)
|
|
42
|
+
> backends** (write-behind, surviving redeploys). The SASL
|
|
43
|
+
> `AccountStore` and NickServ accounts are **unified** under one
|
|
44
|
+
> scrypt-hashed credential store, `PASS <nick>:<password>` identifies
|
|
45
|
+
> at registration, and `draft/read-marker` gains the timestamp-based
|
|
46
|
+
> `MARKREAD` verb. Remaining 0.x work: the client compatibility sweep
|
|
47
|
+
> (WeeChat / HexChat / IRCCloud / TheLounge), the Playwright
|
|
48
|
+
> browser-driven e2e for the SPA, and driving the remaining
|
|
49
|
+
> sub-100% packages to full coverage. See `CHANGELOG.md` for the
|
|
50
|
+
> per-release manifests.
|
|
37
51
|
|
|
38
52
|
---
|
|
39
53
|
|
|
40
54
|
## Why
|
|
41
55
|
|
|
42
56
|
IRC servers have historically been long-running stateful processes. This
|
|
43
|
-
project
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
project moves the protocol logic into a set of **pure reducers** so that
|
|
58
|
+
the only platform-specific code is the side-effect layer (transports,
|
|
59
|
+
registries, fanout). The consequences:
|
|
46
60
|
|
|
47
61
|
- Every command handler is a trivial unit test: arrange state, apply a message,
|
|
48
62
|
assert the new state and emitted effects.
|
|
@@ -54,7 +68,7 @@ reducers** and the only platform-specific code is the side-effect plumbing
|
|
|
54
68
|
|
|
55
69
|
## Architecture
|
|
56
70
|
|
|
57
|
-
Hexagonal / ports-and-adapters. The core
|
|
71
|
+
Hexagonal / ports-and-adapters. The core implements the IRC protocol; adapters handle I/O.
|
|
58
72
|
|
|
59
73
|
```
|
|
60
74
|
┌─────────────────────────────────────────────────────────────────┐
|
|
@@ -94,7 +108,7 @@ function. Both feed the same `ConnectionActor` through a `Transport`
|
|
|
94
108
|
seam (`WsTextFrameTransport` vs. `TcpByteStreamTransport`); the
|
|
95
109
|
parser/reducer/dispatch pipeline is identical.
|
|
96
110
|
|
|
97
|
-
###
|
|
111
|
+
### Design: pure reducers + location-of-authority
|
|
98
112
|
|
|
99
113
|
Each command handler is a pure function:
|
|
100
114
|
|
|
@@ -119,6 +133,7 @@ Each reducer runs in whichever authority **owns** the state it mutates:
|
|
|
119
133
|
| PRIVMSG/NOTICE to channel | Channel entity | Fanout (reads roster) |
|
|
120
134
|
| Nick collision check | Registry entity | Nick → Connection map |
|
|
121
135
|
| NAMES / WHO / WHOIS | Reads snapshots | (no mutation) |
|
|
136
|
+
| Services (`PRIVMSG NickServ`/`ChanServ`/…) | Connection entity | `ServicesStore` (account/channel/vhost/memo state) |
|
|
122
137
|
|
|
123
138
|
---
|
|
124
139
|
|
|
@@ -127,20 +142,21 @@ Each reducer runs in whichever authority **owns** the state it mutates:
|
|
|
127
142
|
```
|
|
128
143
|
ServerlessIRCd/
|
|
129
144
|
├── packages/
|
|
130
|
-
│ ├── irc-core/ pure protocol + reducers
|
|
145
|
+
│ ├── irc-core/ pure protocol + reducers
|
|
131
146
|
│ ├── irc-server/ orchestration, IrcRuntime port, dispatch
|
|
132
147
|
│ ├── in-memory-runtime/ reference runtime (used by tests + local CLI)
|
|
133
148
|
│ ├── irc-test-support/ parametrized IRC scenario suite + harness seam
|
|
134
149
|
│ ├── cf-adapter/ Durable Objects + CfRuntime
|
|
135
150
|
│ └── aws-adapter/ Lambda + DynamoDB + AwsRuntime
|
|
136
151
|
├── apps/
|
|
137
|
-
│ ├── cf-worker/ worker entry, DO migrations, bindings
|
|
152
|
+
│ ├── cf-worker/ worker entry, DO migrations, bindings, [assets] + CSWSH gate
|
|
138
153
|
│ ├── cf-tcp-container/ Spectrum + Container origin for irc+tls :6697
|
|
139
154
|
│ ├── aws-stack/ CDK stack (APIGW WS + NLB + Lambda streaming + DynamoDB)
|
|
155
|
+
│ ├── web/ vendored Kiwi IRC SPA (→ /webclient/) + static landing page (→ /)
|
|
140
156
|
│ └── local-cli/ runnable WS + TCP server using in-memory-runtime
|
|
141
157
|
├── tools/
|
|
142
158
|
│ ├── tcp-ws-forwarder/ local TCP↔ws/wss bridge for stock IRC clients
|
|
143
|
-
│ ├── load-test/ synthetic WebSocket IRC client
|
|
159
|
+
│ ├── load-test/ synthetic WebSocket IRC client pool (10k conns, p50/p95/p99, drop rate)
|
|
144
160
|
│ ├── ci-hardening/ coverage-gate + mutation-config validators
|
|
145
161
|
│ ├── seed-aws-accounts.ts scrypt-hash SASL PLAIN accounts into DynamoDB
|
|
146
162
|
│ └── seed-cf-accounts.ts scrypt-hash SASL PLAIN accounts into Cloudflare D1
|
|
@@ -174,6 +190,7 @@ pin is resolved automatically:
|
|
|
174
190
|
```bash
|
|
175
191
|
corepack enable # lets the pinned pnpm@11 run on any Node ≥ 24
|
|
176
192
|
|
|
193
|
+
git submodule update --init # docs + apps/web Kiwi upstream sources
|
|
177
194
|
pnpm install # install workspace deps
|
|
178
195
|
|
|
179
196
|
pnpm build # build all packages (turbo)
|
|
@@ -191,6 +208,14 @@ pnpm mutation # Stryker spot-check on irc-core (protocol + commands)
|
|
|
191
208
|
pnpm clean # remove dist/coverage/.turbo + node_modules
|
|
192
209
|
```
|
|
193
210
|
|
|
211
|
+
The web client (`apps/web`) vendors Kiwi IRC as a git submodule. Building it
|
|
212
|
+
needs the upstream sources (`git submodule update --init apps/web/upstream`)
|
|
213
|
+
and `yarn` (Kiwi ships a `yarn.lock`; `corepack enable` provides it):
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
pnpm --filter web build # builds the Kiwi SPA into apps/web/dist/webclient/ (/webclient/)
|
|
217
|
+
```
|
|
218
|
+
|
|
194
219
|
Coverage reports are written to `packages/*/coverage/`. CI (`.github/workflows/ci.yml`)
|
|
195
220
|
runs lint, typecheck, the coverage gate, the parametrized contract suite, and a
|
|
196
221
|
Stryker mutation spot-check on every push and pull request. Coverage thresholds
|
|
@@ -210,7 +235,7 @@ that share one runtime, so a TCP client and a WS client can see each other
|
|
|
210
235
|
|
|
211
236
|
- a **WebSocket** listener (the serverless transport) on `--port`, and
|
|
212
237
|
- an **RFC-style TCP** listener on `--tcp-port` (default `<port> + 1`) so
|
|
213
|
-
real IRC clients (WeeChat, HexChat, irssi, …) can
|
|
238
|
+
real IRC clients (WeeChat, HexChat, irssi, …) can connect directly.
|
|
214
239
|
|
|
215
240
|
First build the workspace (the CLI runs from compiled `dist/`):
|
|
216
241
|
|
|
@@ -243,11 +268,55 @@ On startup it logs a JSON line like:
|
|
|
243
268
|
| `--motd-file <p>` | built-in | Read MOTD lines from this file (one per line). |
|
|
244
269
|
| `--server-name <h>`| `irc.localhost` | Server hostname advertised in `001`/`005`. Production MUST override. |
|
|
245
270
|
| `--network-name <n>`| `LocalNet` | Network name advertised in `005 NETWORK=…`. |
|
|
271
|
+
| `--server-password <p>`| | Server-password gate. When set, every connection must supply `PASS <p>` (or SASL-identify) before `001`. Treat as a secret. |
|
|
246
272
|
| `-h, --help` | | Show help and exit. |
|
|
247
273
|
|
|
248
274
|
Pass `--host 0.0.0.0` to expose the server on all interfaces. `SIGINT` /
|
|
249
275
|
`SIGTERM` perform a graceful shutdown (closes active sockets, then exits).
|
|
250
276
|
|
|
277
|
+
### Server password (`SERVER_PASSWORD` / `--server-password`)
|
|
278
|
+
|
|
279
|
+
All three adapters (Cloudflare Worker, AWS Lambda, local CLI) support an
|
|
280
|
+
optional **server-password gate**. When the knob is set, every connection
|
|
281
|
+
must supply the matching `PASS <value>` before `001 RPL_WELCOME` is
|
|
282
|
+
emitted; when unset or empty the gate is disabled (the default).
|
|
283
|
+
|
|
284
|
+
| Adapter | Knob |
|
|
285
|
+
|----------------|-------------------------------------------------------------------------------|
|
|
286
|
+
| Cloudflare | `wrangler secret put SERVER_PASSWORD` (Workers secret; never a `[vars]` entry). |
|
|
287
|
+
| AWS | `SERVER_PASSWORD` Lambda env var (sourced from Secrets Manager / SSM). |
|
|
288
|
+
| local CLI | `--server-password <p>` flag, or `serverPassword` on `StartServerOptions`. |
|
|
289
|
+
|
|
290
|
+
On a mismatched/missing `PASS` the server emits `464 ERR_PASSWDMISMATCH`
|
|
291
|
+
and disconnects with reason `Bad Password`. **SASL short-circuit:** a
|
|
292
|
+
connection that has authenticated an account via SASL
|
|
293
|
+
(`AUTHENTICATE PLAIN` / `EXTERNAL`) is exempt — the reducer's gate
|
|
294
|
+
treats `state.account !== undefined` as already authorised, so a
|
|
295
|
+
deployment with both `SERVER_PASSWORD` and configured SASL accounts
|
|
296
|
+
does not need to hand the shared password to identified users. The
|
|
297
|
+
server-wide gate is a shared deployment secret (never log it); per-user
|
|
298
|
+
credentials still go through the hashed SASL account store
|
|
299
|
+
(`HashedAccountStore` / D1 / DynamoDB), which is unaffected.
|
|
300
|
+
|
|
301
|
+
**PASS-based account login:** in addition to SASL, a client may identify
|
|
302
|
+
to its NickServ account at registration by sending
|
|
303
|
+
`PASS <nick>:<password>` (the same `<nick>:<password>` literal the
|
|
304
|
+
`SASL_ACCOUNTS` seed tooling uses). When an `AccountStore` is configured,
|
|
305
|
+
`NICK alice` + `PASS alice:hunter2` + `USER …` verifies the credentials
|
|
306
|
+
against the account store and, on success, logs the connection in as
|
|
307
|
+
`alice` — emitting `900 RPL_LOGGEDIN` + `903 RPL_SASLSUCCESS` (the same
|
|
308
|
+
"account is set" numerics SASL uses) before `001 RPL_WELCOME`, stamping
|
|
309
|
+
user mode `+r`, and running the same read-marker / away / memo replay as
|
|
310
|
+
a SASL login. The nick left of the `:` must match the `NICK` sent; a bare
|
|
311
|
+
`PASS <value>` with no colon is always treated as a server-password
|
|
312
|
+
candidate, never as account credentials. A wrong password or unknown nick
|
|
313
|
+
is indistinguishable (no `904`/`464` from the auth path) and the
|
|
314
|
+
connection simply proceeds un-identified when no server password is set.
|
|
315
|
+
This composes with the gate above by precedence: an already-identified
|
|
316
|
+
connection (SASL or PASS-auth) satisfies the gate; a `<nick>:<password>`
|
|
317
|
+
that fails verify never matches a bare shared secret, so a server with
|
|
318
|
+
both configured still rejects it with `464`.
|
|
319
|
+
|
|
251
320
|
### Connecting
|
|
252
321
|
|
|
253
322
|
The WebSocket listener speaks WebSocket text frames (one IRC message per
|
|
@@ -270,9 +339,9 @@ given.
|
|
|
270
339
|
The local CLI ships a built-in TCP listener, so no bridge is needed for local
|
|
271
340
|
development. Deployed stacks (Cloudflare Workers and AWS API Gateway) are
|
|
272
341
|
WebSocket-only, so a stock TCP IRC client (WeeChat, HexChat, irssi, …) cannot
|
|
273
|
-
|
|
342
|
+
connect to them directly. `tools/tcp-ws-forwarder` is a local bridge for that case:
|
|
274
343
|
it listens on a TCP port and, for each connection, opens one WebSocket to a
|
|
275
|
-
`ws://` / `wss://` target and
|
|
344
|
+
`ws://` / `wss://` target and forwards IRC lines both directions — reassembling the TCP
|
|
276
345
|
byte stream into one message per WS frame outbound, and normalizing inbound
|
|
277
346
|
frames back to canonical CRLF.
|
|
278
347
|
|
|
@@ -317,9 +386,9 @@ against any line-oriented WebSocket endpoint.
|
|
|
317
386
|
|
|
318
387
|
## Load testing (`tools/load-test`)
|
|
319
388
|
|
|
320
|
-
A synthetic WebSocket IRC client
|
|
389
|
+
A synthetic WebSocket IRC client pool (PLAN §7). It opens N
|
|
321
390
|
connections to a `ws://` / `wss://` target, registers each (NICK/USER),
|
|
322
|
-
joins a channel, and optionally chats. Per-
|
|
391
|
+
joins a channel, and optionally chats. Per-stage **p50 / p95 / p99
|
|
323
392
|
latency** (connect / register / join / message) and the **drop rate**
|
|
324
393
|
are captured, then printed as a markdown report to stdout (and written
|
|
325
394
|
to `--report <path>` when given).
|
|
@@ -364,6 +433,66 @@ report).
|
|
|
364
433
|
|
|
365
434
|
---
|
|
366
435
|
|
|
436
|
+
## Web client (`apps/web`)
|
|
437
|
+
|
|
438
|
+
A vendored **Kiwi IRC** SPA served at `/webclient/` and a static project
|
|
439
|
+
landing page served at `/`, both baked out of `apps/web/dist/` and
|
|
440
|
+
served directly by the Cloudflare Worker via its `[assets]` binding.
|
|
441
|
+
The browser opens a native `wss://` directly to the Worker's
|
|
442
|
+
IRC-over-WebSocket endpoint — no proxy, gateway, or transport
|
|
443
|
+
adaptation in the request path. See `docs/WebClientGuide.md` for the
|
|
444
|
+
end-to-end contributor/operator guide.
|
|
445
|
+
|
|
446
|
+
Build the SPA + landing page (needs the submodule + `yarn`, provided by
|
|
447
|
+
`corepack enable`):
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
git submodule update --init apps/web/upstream # one-time per clone
|
|
451
|
+
pnpm --filter web build:staging # or :prod / default
|
|
452
|
+
# → apps/web/dist/index.html (landing page, served at /)
|
|
453
|
+
# → apps/web/dist/webclient/index.html (Kiwi SPA, served at /webclient/)
|
|
454
|
+
# → apps/web/dist/webclient/static/config.json (baked, env-specific)
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Then run everything locally (Worker serves SPA + landing page + WS on
|
|
458
|
+
one origin):
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
pnpm build # workspace packages
|
|
462
|
+
pnpm --filter @serverless-ircd/cf-worker dev # http://localhost:8787
|
|
463
|
+
# / → landing page
|
|
464
|
+
# /webclient/ → Kiwi SPA (opens ws://localhost:8787/)
|
|
465
|
+
# /health → plaintext liveness
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Deploy staging (Worker + assets in one command):
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
pnpm deploy:cf:staging # wrangler deploy --env staging
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### WebSocket Origin policy (CSWSH defense)
|
|
475
|
+
|
|
476
|
+
WebSocket upgrades do **not** follow the same-origin policy, so the
|
|
477
|
+
Worker rejects browser upgrades whose `Origin` is not allowed — see
|
|
478
|
+
`apps/cf-worker/src/origin-allowlist.ts` and the SPA guide §5. Two
|
|
479
|
+
modes, evaluated in order:
|
|
480
|
+
|
|
481
|
+
1. **Explicit allowlist** — set `WEB_ORIGINS` (comma-separated) for
|
|
482
|
+
cross-origin deploys (SPA on a different domain than the Worker,
|
|
483
|
+
e.g. Cloudflare Pages). Only listed origins proceed.
|
|
484
|
+
2. **Same-origin auto-derive (the default)** — when `WEB_ORIGINS` is
|
|
485
|
+
unset/empty, the Worker compares the browser's `Origin` against the
|
|
486
|
+
request's own origin. Match → proceed; mismatch → `403 Forbidden`.
|
|
487
|
+
|
|
488
|
+
`WEB_ORIGINS` is **optional** — same-origin auto-derive needs zero
|
|
489
|
+
per-env config and works for `*.workers.dev`, custom domains, and
|
|
490
|
+
preview URLs alike. Non-browser clients (curl, WeeChat, the
|
|
491
|
+
`tcp-ws-forwarder`, scripted harnesses) never send `Origin` and pass
|
|
492
|
+
through unchanged in both modes.
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
367
496
|
## WebSocket transport (IRCv3 subprotocols)
|
|
368
497
|
|
|
369
498
|
The WebSocket entry points (the local CLI, the Cloudflare Worker, and the
|
|
@@ -428,49 +557,49 @@ suite passes against every runtime, both adapters are deployed to staging,
|
|
|
428
557
|
and ≥3 reference clients (WeeChat, HexChat, IRCCloud, TheLounge) connect
|
|
429
558
|
cleanly. Per-release manifests live in `CHANGELOG.md`.
|
|
430
559
|
|
|
431
|
-
- **
|
|
432
|
-
- **
|
|
560
|
+
- **Foundation** (monorepo, turbo, vitest, biome, CI). ✅
|
|
561
|
+
- **Pure protocol engine** — reducers, IRCv3 caps, isupport,
|
|
433
562
|
SASL (`PLAIN`), token-bucket flood control, chat history. ✅ (most in
|
|
434
563
|
**v0.1.0**; SASL/flood/chathistory landed in **v0.2.0**).
|
|
435
|
-
-
|
|
564
|
+
- **`IrcRuntime` port** — in-memory runtime, `ConnectionActor`,
|
|
436
565
|
local CLI, parametrized contract suite. ✅ landed in **v0.1.0**.
|
|
437
|
-
- **
|
|
566
|
+
- **Cloudflare adapter** (ConnectionDO / ChannelDO / RegistryDO).
|
|
438
567
|
✅ landed in **v0.1.0** (staging deploy via CI; prod deploy is manual).
|
|
439
|
-
- **
|
|
568
|
+
- **AWS adapter** (APIGW WS + Lambda + DynamoDB + CDK).
|
|
440
569
|
✅ landed in **v0.2.0** (staging deploy via CI; prod deploy is manual).
|
|
441
|
-
- **
|
|
570
|
+
- **Observability, security hardening, config, CI gates.**
|
|
442
571
|
✅ landed across v0.2.0–v0.4.0 (logger port, server-password, cloaking,
|
|
443
572
|
admission limits, coverage + mutation gates, OPER credential auth, the
|
|
444
573
|
Cloudflare config loader, and AWS max-clients admission); the
|
|
445
574
|
required-`serverName` gate closed in **v0.6.0**.
|
|
446
|
-
- **
|
|
575
|
+
- **TLS hardening & raw TCP transport** (`irc+tls :6697`).
|
|
447
576
|
✅ landed in **v0.4.0**: generalized `ConnectionActor` transport seam,
|
|
448
577
|
Cloudflare Spectrum + Container origin, AWS NLB + Lambda streaming,
|
|
449
578
|
mTLS → SASL `EXTERNAL`, transport-parametrized contract suite, ADR-009.
|
|
450
|
-
- **
|
|
579
|
+
- **Load testing & compatibility sweep.** 🔄 partial as of
|
|
451
580
|
**v0.6.0**: the `tools/load-test` 10k-connection harness is in-tree;
|
|
452
581
|
the formal 10k-connection report per platform and the client
|
|
453
582
|
compatibility matrix (WeeChat / HexChat / IRCCloud / TheLounge) are
|
|
454
583
|
still pending.
|
|
455
|
-
- **
|
|
584
|
+
- **PLAN-FIXES remediation.** ✅ landed across v0.3.0–v0.4.0
|
|
456
585
|
(MessageStore wired into all three adapters, AccountStore end-to-end,
|
|
457
586
|
the DynamoDB `Accounts` table decided, CF enumeration RPCs, AWS QUIT
|
|
458
587
|
fanout, `OPER` / `TAGMSG` / `WHOWAS`, RFC 1459 case-mapping, real
|
|
459
588
|
MOTD, config-driven server identity, AWS max-clients admission,
|
|
460
589
|
CF D1 SASL store, and a sweep of dead-code / stale-comment cleanup).
|
|
461
|
-
- **
|
|
590
|
+
- **Runtime & tooling baseline.** ✅ landed in **v0.4.0**
|
|
462
591
|
(Node ≥ 24 / pnpm 11).
|
|
463
|
-
- **
|
|
592
|
+
- **IRCv3 WebSocket extension.** ✅ landed in **v0.4.0**:
|
|
464
593
|
`text.ircv3.net` / `binary.ircv3.net` subprotocol negotiation +
|
|
465
594
|
per-message framing across the CF Worker, AWS APIGW, local CLI, and
|
|
466
595
|
`tcp-ws-forwarder` (510-byte budget, `1009`/`1003` close codes,
|
|
467
596
|
legacy fallback).
|
|
468
|
-
- **
|
|
597
|
+
- **Deferred IRC verbs.** ✅ landed in **v0.5.0**: `KILL`,
|
|
469
598
|
`REHASH`, `LUSERS` + `STATS`, `TRACE`, `WALLOPS`, `SETNAME`, plus
|
|
470
599
|
the formal drop of the S2S (`CONNECT`/`SQUIT`/`LINKS`) and obsolete
|
|
471
600
|
RFC 2812 (`SERVICE`/`SUMMON`/`USERS`) verbs. The protocol surface is
|
|
472
601
|
feature-complete for modern clients.
|
|
473
|
-
- **
|
|
602
|
+
- **IRCv3 extension sweep.** ✅ landed in **v0.6.0**: ten
|
|
474
603
|
negotiated caps (`account-notify`, `msgid`, `standard-replies`,
|
|
475
604
|
`MONITOR`, `labeled-response`, `sts`, `draft/typing`,
|
|
476
605
|
`draft/multiline`, `draft/read-marker`, `draft/pre-away`), the
|
|
@@ -479,19 +608,32 @@ cleanly. Per-release manifests live in `CHANGELOG.md`.
|
|
|
479
608
|
(TLS connected), and the async push fanout seam (Registry hooks →
|
|
480
609
|
`MONITOR` online/offline, `BroadcastWallops`-style caps-gated
|
|
481
610
|
delivery).
|
|
482
|
-
- **
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
`
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
611
|
+
- **IRC services.** ✅ landed in **v0.8.0**: `ServicesStore` port
|
|
612
|
+
+ integrated NickServ (`REGISTER`/`IDENTIFY`/`DROP`/`INFO`/`SET
|
|
613
|
+
ENFORCE` + nick enforcement), ChanServ (`REGISTER`/`DROP`/`SET`/
|
|
614
|
+
`ACCESS`/`LEVELS` + `+r`/`+R`/`+M`), HostServ
|
|
615
|
+
(`ON`/`OFF`/`REQUEST` + oper `SET`/`APPROVE`), OperServ
|
|
616
|
+
(`AKILL`/`JUPE`/`RAW`), MemoServ (`SEND`/`LIST`/`READ`/`DEL`).
|
|
617
|
+
Persistent backends ship alongside — **D1** on Cloudflare,
|
|
618
|
+
**DynamoDB** on AWS — both write-behind so registrations survive
|
|
619
|
+
redeploys. The SASL `AccountStore` and NickServ accounts are
|
|
620
|
+
**unified** under one scrypt-hashed credential store, `PASS
|
|
621
|
+
<nick>:<password>` identifies at registration, and `draft/read-marker`
|
|
622
|
+
/ `draft/pre-away` now persist through the `ServicesStore` (no longer
|
|
623
|
+
in-memory-only). See `docs/Services.md`.
|
|
624
|
+
- **Web client.** 🔄 partial as of **v0.7.0**: a vendored
|
|
625
|
+
Kiwi IRC SPA is served at `/webclient/` and a static landing page at `/`
|
|
626
|
+
by the Cloudflare Worker via an `[assets]` binding, with a Zod-
|
|
627
|
+
validated per-env config matrix and **CSWSH defense** (same-origin
|
|
628
|
+
auto-derive + optional `WEB_ORIGINS` allowlist). The Playwright
|
|
629
|
+
headless-browser e2e is the remaining open ticket.
|
|
630
|
+
See `docs/WebClientGuide.md` for the contributor/operator guide.
|
|
631
|
+
- **Coverage hardening.** 🔄 partial as of **v0.7.0**: `aws-adapter`
|
|
632
|
+
and `aws-stack` clear the 90% gate (v0.6.0); the CF packages run
|
|
633
|
+
under istanbul (v0.6.0). The remaining packages (`cf-adapter`,
|
|
634
|
+
`local-cli`, `load-test`, `cf-tcp-container`, `tcp-ws-forwarder`,
|
|
635
|
+
`irc-test-support`, `web`) are **above the gate but below 100%** —
|
|
636
|
+
follow-ups drive each to 100%.
|
|
495
637
|
|
|
496
638
|
---
|
|
497
639
|
|
|
@@ -516,10 +658,34 @@ RFC 2812 verbs `SERVICE`/`SUMMON`/`USERS` are **formally dropped** as of
|
|
|
516
658
|
v0.5.0 — they return `421 ERR_UNKNOWNCOMMAND`, and their reserved
|
|
517
659
|
numerics have been removed. S2S linking is a PLAN non-goal.)
|
|
518
660
|
|
|
519
|
-
**Channel modes:** `o v b i k l t n m s p
|
|
661
|
+
**Channel modes:** `o v b i k l t n m s p`, plus the
|
|
662
|
+
services-derived modes `r` (registered), `R` (block unidentified
|
|
663
|
+
join/message), `M` (moderated-identified) — settable only via ChanServ,
|
|
664
|
+
not via `MODE`.
|
|
520
665
|
**User modes:** `i`, `o` (local only), `w`, `s`, and the read-only `S`
|
|
521
666
|
(TLS connected — set by the transport at registration, surfaced in WHOIS
|
|
522
|
-
via `276 RPL_WHOISSECURE`, not settable via `MODE`)
|
|
667
|
+
via `276 RPL_WHOISSECURE`, not settable via `MODE`) and the read-only
|
|
668
|
+
`r` (registered — set by NickServ `IDENTIFY` / SASL login, surfaced as
|
|
669
|
+
`+r`, not settable via `MODE`).
|
|
670
|
+
|
|
671
|
+
**Integrated IRC services** (v0.8.0): the service nicks `NickServ`,
|
|
672
|
+
`ChanServ`, `HostServ`, `OperServ`, and `MemoServ` are reserved and
|
|
673
|
+
routed to dedicated pure reducers when a `ServicesStore` is bound —
|
|
674
|
+
there is **no separate services process and no S2S link**. Reached via
|
|
675
|
+
`PRIVMSG <Service> :<subcommand>`:
|
|
676
|
+
NickServ (`REGISTER` / `IDENTIFY` / `DROP` / `INFO` / `SET ENFORCE` +
|
|
677
|
+
nick enforcement on the `NICK` path), ChanServ (`REGISTER` / `DROP` /
|
|
678
|
+
`SET` / `INFO` / `ACCESS` / `LEVELS` + auto-op on `JOIN`), HostServ
|
|
679
|
+
(`ON` / `OFF` / `REQUEST` + oper `SET` / `APPROVE` / `LIST`, with
|
|
680
|
+
`CHGHOST` fanout), OperServ (`AKILL` / `JUPE` / `UNJUPE` / `RAW`), and
|
|
681
|
+
MemoServ (`SEND` / `LIST` / `READ` / `DEL` with queue delivery at
|
|
682
|
+
identify). The SASL `AccountStore` and NickServ accounts share one
|
|
683
|
+
scrypt-hashed credential store, so a registered nick is also a SASL
|
|
684
|
+
login and vice versa. Backends: D1 on Cloudflare, DynamoDB on AWS,
|
|
685
|
+
in-memory for the local CLI / tests (all write-behind; registrations
|
|
686
|
+
survive redeploys). When no store is bound, services commands reply
|
|
687
|
+
`501` and the rest of the daemon is unaffected. See
|
|
688
|
+
`docs/Services.md` for the full reference.
|
|
523
689
|
|
|
524
690
|
**IRCv3 extensions (negotiated via `CAP`):** `message-tags` (incl. the
|
|
525
691
|
`TAGMSG` command), `server-time`, `account-tag`, `account-notify`
|
|
@@ -536,7 +702,9 @@ shared between live and `draft/chathistory` replay), `standard-replies`
|
|
|
536
702
|
so compliant clients upgrade from plaintext to TLS and pin the secure
|
|
537
703
|
listener), `draft/chathistory`, `safelist`, `draft/typing` (typing-indicator
|
|
538
704
|
broadcast), `draft/multiline=<n>` (multi-line `BATCH`, default 4096-byte
|
|
539
|
-
budget), `draft/read-marker` (per-account persisted last-read
|
|
705
|
+
budget), `draft/read-marker` (per-account persisted last-read, with the
|
|
706
|
+
timestamp-based `MARKREAD <target> [timestamp]` verb plus the
|
|
707
|
+
`+draft/read-marker` tag fanout), and
|
|
540
708
|
`draft/pre-away` (per-account persisted away reason, replayed at
|
|
541
709
|
identify). Case-insensitive nick/channel comparison uses **RFC 1459**
|
|
542
710
|
case-mapping (advertised via `005 CASEMAPPING=rfc1459`). The new
|
|
@@ -563,13 +731,32 @@ bridges a stock TCP client to a deployed WebSocket endpoint.
|
|
|
563
731
|
`irc+tls :6697`, SASL `EXTERNAL`/mTLS, WHOWAS + remaining verbs, D1 account
|
|
564
732
|
store, Node 24/pnpm 11), v0.5.0 (deferred IRC verbs `KILL` / `REHASH`
|
|
565
733
|
/ `LUSERS` + `STATS` / `TRACE` / `WALLOPS` / `SETNAME`, plus the formal
|
|
566
|
-
drop of the S2S and obsolete RFC 2812 verbs),
|
|
734
|
+
drop of the S2S and obsolete RFC 2812 verbs), v0.6.0 (the IRCv3
|
|
567
735
|
extension sweep — `account-notify`, `msgid`, `standard-replies`,
|
|
568
736
|
`MONITOR`, `labeled-response`, `sts`, `draft/typing`, `draft/multiline`,
|
|
569
737
|
`draft/read-marker`, `draft/pre-away`, plus user mode `S`; the
|
|
570
738
|
required-`serverName` gate; `tools/load-test`; aws-adapter / aws-stack
|
|
571
739
|
coverage unblocks; CF packages moved to istanbul; deploys now
|
|
572
|
-
manual-only).
|
|
740
|
+
manual-only), and **v0.7.0** (the web client — vendored Kiwi IRC SPA
|
|
741
|
+
at `/webclient/`, static landing page at `/`, Cloudflare Worker
|
|
742
|
+
`[assets]` binding, per-env Zod-validated config matrix, and CSWSH
|
|
743
|
+
defense via same-origin auto-derive + optional `WEB_ORIGINS`;
|
|
744
|
+
`/health` becomes an explicit route; mutation-killing tests for
|
|
745
|
+
`irc-core`'s parser / batch / numerics), and **v0.8.0** (integrated
|
|
746
|
+
IRC services — NickServ / ChanServ / HostServ / OperServ / MemoServ
|
|
747
|
+
backed by a `ServicesStore` port with persistent D1 + DynamoDB
|
|
748
|
+
backends; unified SASL + NickServ scrypt-hashed account store;
|
|
749
|
+
`PASS <nick>:<password>` registration login; the `draft/read-marker`
|
|
750
|
+
`MARKREAD` verb).
|
|
751
|
+
- `docs/Services.md` — operator and contributor reference for the
|
|
752
|
+
integrated IRC services: architecture (integrated vs. pseudo-client),
|
|
753
|
+
the per-service command tables, the `+r`/`+R`/`+M` modes, nick
|
|
754
|
+
enforcement, adapter backends, and an end-to-end registration
|
|
755
|
+
walkthrough.
|
|
756
|
+
- `docs/WebClientGuide.md` — end-to-end contributor/operator doc for the
|
|
757
|
+
web client: build pipeline, per-env config matrix, CSWSH rationale and
|
|
758
|
+
the optional `WEB_ORIGINS` var, local dev, optional Cloudflare Pages
|
|
759
|
+
alternative, and troubleshooting.
|
|
573
760
|
- `docs/Cloudflare-TCP-Deployment.md` and `docs/AWS-TCP-Deployment.md` —
|
|
574
761
|
end-to-end guides for the `:6697` TCP+TLS variants (Spectrum/Container on
|
|
575
762
|
CF, NLB + Lambda streaming on AWS), including mTLS trust-store setup.
|