serverless-ircd 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +40 -3
- package/.github/workflows/deploy-aws.yml +1 -2
- package/.github/workflows/deploy-cf-tcp.yml +1 -5
- package/.github/workflows/deploy-cf.yml +1 -2
- package/.gitmodules +3 -0
- package/CHANGELOG.md +474 -0
- package/README.md +219 -22
- package/apps/aws-stack/README.md +33 -0
- package/apps/aws-stack/package.json +1 -1
- package/apps/aws-stack/src/aws-stack.ts +74 -9
- package/apps/aws-stack/tests/coverage-command.test.ts +155 -0
- package/apps/aws-stack/tests/stack.test.ts +2 -2
- package/apps/aws-stack/tests/synth-no-bundle.test.ts +129 -0
- package/apps/aws-stack/tests/vitest.setup.ts +18 -0
- package/apps/aws-stack/vitest.config.ts +3 -0
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-tcp-container/src/config-loader.ts +6 -7
- package/apps/cf-tcp-container/src/container-server.ts +3 -0
- package/apps/cf-tcp-container/tests/config-loader.test.ts +10 -3
- package/apps/cf-tcp-container/wrangler.toml +1 -1
- package/apps/cf-worker/package.json +2 -1
- package/apps/cf-worker/src/origin-allowlist.ts +99 -0
- package/apps/cf-worker/src/worker.ts +89 -9
- package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
- package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
- package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
- package/apps/cf-worker/tests/smoke.test.ts +28 -2
- package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
- package/apps/cf-worker/vitest.config.ts +1 -1
- package/apps/cf-worker/wrangler.test.toml +23 -0
- package/apps/cf-worker/wrangler.toml +59 -3
- package/apps/local-cli/package.json +1 -1
- package/apps/local-cli/src/config-loader.ts +6 -6
- package/apps/local-cli/src/main.ts +20 -0
- package/apps/local-cli/src/server.ts +9 -7
- package/apps/local-cli/tests/e2e.test.ts +112 -28
- package/apps/local-cli/tests/tcp.test.ts +71 -19
- package/apps/local-cli/tests/ws-subprotocol.test.ts +12 -7
- package/apps/web/landing/index.html +217 -0
- package/apps/web/package.json +28 -0
- package/apps/web/scripts/build.mjs +125 -0
- package/apps/web/src/build-env.ts +43 -0
- package/apps/web/src/config-schema.ts +138 -0
- package/apps/web/static/config.json +28 -0
- package/apps/web/static/config.prod.json +28 -0
- package/apps/web/static/config.staging.json +28 -0
- package/apps/web/tests/build-env.test.ts +63 -0
- package/apps/web/tests/build-smoke.test.ts +103 -0
- package/apps/web/tests/config-schema.test.ts +432 -0
- package/apps/web/tests/workspace.test.ts +12 -0
- package/apps/web/tsconfig.json +10 -0
- package/apps/web/upstream/.browserslistrc +3 -0
- package/apps/web/upstream/.editorconfig +9 -0
- package/apps/web/upstream/.eslintignore +3 -0
- package/apps/web/upstream/.eslintrc.js +90 -0
- package/apps/web/upstream/.github/FUNDING.yml +12 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/apps/web/upstream/.github/workflows/push.yml +26 -0
- package/apps/web/upstream/.github/workflows/release.yml +33 -0
- package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
- package/apps/web/upstream/.prettierrc.js +9 -0
- package/apps/web/upstream/.stylelintignore +5 -0
- package/apps/web/upstream/.stylelintrc.js +21 -0
- package/apps/web/upstream/LICENSE +201 -0
- package/apps/web/upstream/README.md +76 -0
- package/apps/web/upstream/babel.config.js +25 -0
- package/apps/web/upstream/crowdin.yml +3 -0
- package/apps/web/upstream/index.html +35 -0
- package/apps/web/upstream/jest.config.js +7 -0
- package/apps/web/upstream/jsdoc.json +22 -0
- package/apps/web/upstream/package.json +80 -0
- package/apps/web/upstream/scripts/pre-commit +43 -0
- package/apps/web/upstream/src/components/App.vue +516 -0
- package/apps/web/upstream/src/components/AppSettings.vue +587 -0
- package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
- package/apps/web/upstream/src/components/Avatar.vue +105 -0
- package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
- package/apps/web/upstream/src/components/BufferKey.vue +121 -0
- package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
- package/apps/web/upstream/src/components/Captcha.vue +85 -0
- package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
- package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
- package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
- package/apps/web/upstream/src/components/ChannelList.vue +345 -0
- package/apps/web/upstream/src/components/Container.vue +401 -0
- package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
- package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
- package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
- package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
- package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
- package/apps/web/upstream/src/components/MessageList.vue +1028 -0
- package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
- package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
- package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
- package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
- package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
- package/apps/web/upstream/src/components/Nicklist.vue +309 -0
- package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
- package/apps/web/upstream/src/components/NotConnected.vue +271 -0
- package/apps/web/upstream/src/components/SelfUser.vue +283 -0
- package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
- package/apps/web/upstream/src/components/ServerView.vue +126 -0
- package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
- package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
- package/apps/web/upstream/src/components/Sidebar.vue +429 -0
- package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
- package/apps/web/upstream/src/components/SidebarState.vue +145 -0
- package/apps/web/upstream/src/components/StartupError.vue +35 -0
- package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
- package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
- package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
- package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
- package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
- package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
- package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
- package/apps/web/upstream/src/components/UserBox.vue +728 -0
- package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
- package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
- package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
- package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
- package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
- package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
- package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
- package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
- package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
- package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
- package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
- package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
- package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
- package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
- package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
- package/apps/web/upstream/src/helpers/Colours.js +128 -0
- package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
- package/apps/web/upstream/src/helpers/Md5.js +193 -0
- package/apps/web/upstream/src/helpers/Misc.js +401 -0
- package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
- package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
- package/apps/web/upstream/src/libs/AudioManager.js +60 -0
- package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
- package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
- package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
- package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
- package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
- package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
- package/apps/web/upstream/src/libs/IPC.js +51 -0
- package/apps/web/upstream/src/libs/InputHandler.js +921 -0
- package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
- package/apps/web/upstream/src/libs/Logger.js +71 -0
- package/apps/web/upstream/src/libs/Message.js +169 -0
- package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
- package/apps/web/upstream/src/libs/MessageParser.js +249 -0
- package/apps/web/upstream/src/libs/Notifications.js +78 -0
- package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
- package/apps/web/upstream/src/libs/ServerSession.js +102 -0
- package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
- package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
- package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
- package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
- package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
- package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
- package/apps/web/upstream/src/libs/bufferTools.js +177 -0
- package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
- package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
- package/apps/web/upstream/src/libs/settingTools.js +31 -0
- package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
- package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
- package/apps/web/upstream/src/libs/state/UserState.js +89 -0
- package/apps/web/upstream/src/libs/state/common.js +26 -0
- package/apps/web/upstream/src/libs/state.js +961 -0
- package/apps/web/upstream/src/libs/storage/Local.js +51 -0
- package/apps/web/upstream/src/main.js +566 -0
- package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
- package/apps/web/upstream/src/res/configTemplates.js +373 -0
- package/apps/web/upstream/src/res/globalStyle.css +277 -0
- package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
- package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
- package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
- package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
- package/apps/web/upstream/src/res/localesList.json +27 -0
- package/apps/web/upstream/src/res/logo.png +0 -0
- package/apps/web/upstream/src/thirdparty/about.html +43 -0
- package/apps/web/upstream/src/thirdparty/index.js +5 -0
- package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
- package/apps/web/upstream/static/config.json +28 -0
- package/apps/web/upstream/static/emoticons/smile.png +0 -0
- package/apps/web/upstream/static/favicon.png +0 -0
- package/apps/web/upstream/static/highlight.mp3 +0 -0
- package/apps/web/upstream/static/highlight.ogg +0 -0
- package/apps/web/upstream/static/locales/.gitignore +2 -0
- package/apps/web/upstream/static/plugins/customise.html.example +10 -0
- package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
- package/apps/web/upstream/static/themes/common/base.css +1064 -0
- package/apps/web/upstream/static/themes/dark/theme.css +196 -0
- package/apps/web/upstream/static/themes/default/theme.css +92 -0
- package/apps/web/upstream/static/themes/elite/theme.css +248 -0
- package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
- package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
- package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
- package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
- package/apps/web/upstream/static/themes/sky/theme.css +107 -0
- package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
- package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
- package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
- package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
- package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
- package/apps/web/upstream/vue.config.js +150 -0
- package/apps/web/upstream/yarn.lock +9767 -0
- package/apps/web/vitest.config.ts +13 -0
- package/biome.json +2 -0
- package/docs/ADR-001-pure-reducers-and-effect-system.md +74 -0
- package/docs/ADR-002-location-of-authority.md +82 -0
- package/docs/ADR-003-durable-object-sharding.md +110 -0
- package/docs/ADR-004-dynamodb-schema.md +96 -0
- package/docs/ADR-005-wss-only-transport-v1.md +83 -0
- package/docs/ADR-006-sasl-mechanism-scope.md +96 -0
- package/docs/ADR-007-deterministic-ports.md +82 -0
- package/docs/ADR-008-monorepo-tooling.md +60 -0
- package/docs/ADR-009-dual-transport-wss-and-irc-tls.md +138 -0
- package/docs/ADR-Index.md +15 -0
- package/docs/AWS-Adapter-Architecture.md +496 -0
- package/docs/AWS-Deployment.md +1275 -0
- package/docs/AWS-TCP-Deployment.md +410 -0
- package/docs/Cloudflare-Deployment-Guide.md +719 -0
- package/docs/Cloudflare-TCP-Deployment.md +510 -0
- package/docs/Home.md +16 -0
- package/docs/Observability.md +87 -0
- package/docs/PlanExtensions.md +812 -0
- package/docs/PlanIRCv3Websocket.md +503 -0
- package/docs/PlanWebClient.md +451 -0
- package/docs/Release-Process.md +443 -0
- package/docs/WebClientGuide.md +535 -0
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/aws-adapter/src/handlers/default.ts +3 -0
- package/packages/aws-adapter/src/handlers/nlb-stream.ts +9 -0
- package/packages/aws-adapter/src/serialize.ts +29 -1
- package/packages/aws-adapter/tests/account-store-dynamo.test.ts +49 -8
- package/packages/aws-adapter/tests/account-store.test.ts +4 -7
- package/packages/aws-adapter/tests/aws-harness.ts +5 -2
- package/packages/aws-adapter/tests/aws-integration.test.ts +8 -4
- package/packages/aws-adapter/tests/aws-runtime.test.ts +79 -0
- package/packages/aws-adapter/tests/config-loader.test.ts +11 -2
- package/packages/aws-adapter/tests/connect.test.ts +9 -9
- package/packages/aws-adapter/tests/disconnect-fanout.test.ts +3 -4
- package/packages/aws-adapter/tests/global-setup.ts +55 -30
- package/packages/aws-adapter/tests/gone-exception.test.ts +4 -9
- package/packages/aws-adapter/tests/handlers.test.ts +90 -4
- package/packages/aws-adapter/tests/message-store.test.ts +6 -5
- package/packages/aws-adapter/tests/nlb-stream.test.ts +60 -8
- package/packages/cf-adapter/package.json +2 -1
- package/packages/cf-adapter/src/connection-do.ts +3 -0
- package/packages/cf-adapter/src/serialize.ts +25 -4
- package/packages/cf-adapter/tests/cf-harness.ts +12 -1
- package/packages/cf-adapter/tests/cf-runtime.test.ts +269 -0
- package/packages/cf-adapter/tests/channel-do.test.ts +117 -0
- package/packages/cf-adapter/tests/config-loader.test.ts +49 -0
- package/packages/cf-adapter/tests/connection-do-pure.test.ts +91 -0
- package/packages/cf-adapter/tests/d1-account-store.test.ts +48 -0
- package/packages/cf-adapter/tests/registry-do.test.ts +104 -0
- package/packages/cf-adapter/tests/serialize.test.ts +308 -0
- package/packages/cf-adapter/vitest.config.ts +1 -1
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/irc-core/package.json +1 -1
- package/packages/irc-core/reports/mutation/mutation.html +342 -0
- package/packages/irc-core/src/caps/capabilities.ts +37 -3
- package/packages/irc-core/src/caps/index.ts +1 -0
- package/packages/irc-core/src/caps/sts.ts +84 -0
- package/packages/irc-core/src/commands/account-notify.ts +53 -0
- package/packages/irc-core/src/commands/away.ts +9 -3
- package/packages/irc-core/src/commands/cap.ts +23 -5
- package/packages/irc-core/src/commands/chathistory.ts +40 -11
- package/packages/irc-core/src/commands/index.ts +34 -0
- package/packages/irc-core/src/commands/isupport.ts +53 -0
- package/packages/irc-core/src/commands/mode.ts +8 -1
- package/packages/irc-core/src/commands/monitor.ts +327 -0
- package/packages/irc-core/src/commands/multiline.ts +256 -0
- package/packages/irc-core/src/commands/pre-away.ts +112 -0
- package/packages/irc-core/src/commands/privmsg.ts +19 -12
- package/packages/irc-core/src/commands/read-marker.ts +108 -0
- package/packages/irc-core/src/commands/registration.ts +8 -0
- package/packages/irc-core/src/commands/sasl.ts +24 -1
- package/packages/irc-core/src/commands/tagmsg.ts +71 -1
- package/packages/irc-core/src/commands/whois.ts +5 -0
- package/packages/irc-core/src/config.ts +65 -10
- package/packages/irc-core/src/effects.ts +14 -0
- package/packages/irc-core/src/ports.ts +389 -0
- package/packages/irc-core/src/protocol/index.ts +14 -0
- package/packages/irc-core/src/protocol/labeled-response.ts +133 -0
- package/packages/irc-core/src/protocol/numerics.ts +15 -0
- package/packages/irc-core/src/protocol/outbound.ts +16 -1
- package/packages/irc-core/src/protocol/standard-replies.ts +277 -0
- package/packages/irc-core/src/state/connection.ts +32 -1
- package/packages/irc-core/src/types.ts +112 -0
- package/packages/irc-core/stryker.commands.conf.json +1 -2
- package/packages/irc-core/tests/away-store.test.ts +73 -0
- package/packages/irc-core/tests/batch.test.ts +15 -0
- package/packages/irc-core/tests/caps/capabilities.test.ts +119 -2
- package/packages/irc-core/tests/caps/sts.test.ts +123 -0
- package/packages/irc-core/tests/commands/account-notify.test.ts +171 -0
- package/packages/irc-core/tests/commands/away.test.ts +85 -2
- package/packages/irc-core/tests/commands/cap.test.ts +165 -0
- package/packages/irc-core/tests/commands/chathistory.test.ts +148 -1
- package/packages/irc-core/tests/commands/echo-message.test.ts +9 -3
- package/packages/irc-core/tests/commands/isupport.test.ts +80 -0
- package/packages/irc-core/tests/commands/mode.test.ts +72 -0
- package/packages/irc-core/tests/commands/monitor.test.ts +411 -0
- package/packages/irc-core/tests/commands/multiline.test.ts +428 -0
- package/packages/irc-core/tests/commands/pre-away.test.ts +241 -0
- package/packages/irc-core/tests/commands/privmsg.test.ts +154 -3
- package/packages/irc-core/tests/commands/read-marker.test.ts +211 -0
- package/packages/irc-core/tests/commands/registration.test.ts +64 -0
- package/packages/irc-core/tests/commands/sasl.test.ts +116 -2
- package/packages/irc-core/tests/commands/tagmsg.test.ts +357 -0
- package/packages/irc-core/tests/commands/whois.test.ts +34 -0
- package/packages/irc-core/tests/config.test.ts +103 -13
- package/packages/irc-core/tests/labeled-response.test.ts +181 -0
- package/packages/irc-core/tests/message-tags.test.ts +114 -0
- package/packages/irc-core/tests/monitor-store.test.ts +200 -0
- package/packages/irc-core/tests/numerics.test.ts +13 -0
- package/packages/irc-core/tests/parser.test.ts +109 -0
- package/packages/irc-core/tests/read-marker-store.test.ts +108 -0
- package/packages/irc-core/tests/standard-replies.test.ts +412 -0
- package/packages/irc-core/tests/types.test.ts +27 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-server/src/actor.ts +450 -3
- package/packages/irc-server/src/dispatch.ts +108 -16
- package/packages/irc-server/tests/actor.test.ts +1432 -39
- package/packages/irc-server/tests/dispatch.test.ts +263 -2
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/index.ts +6 -0
- package/packages/irc-test-support/src/scenarios.ts +24 -2
- package/packages/irc-test-support/src/test-config.ts +54 -0
- package/packages/irc-test-support/tests/test-config.test.ts +51 -0
- package/tools/ci-hardening/package.json +1 -1
- package/tools/ci-hardening/tests/ddb-local.test.ts +82 -0
- package/tools/load-test/package.json +33 -0
- package/tools/load-test/src/client.ts +351 -0
- package/tools/load-test/src/config.ts +313 -0
- package/tools/load-test/src/harness.ts +116 -0
- package/tools/load-test/src/main.ts +120 -0
- package/tools/load-test/src/metrics.ts +168 -0
- package/tools/load-test/src/report.ts +106 -0
- package/tools/load-test/tests/client.test.ts +212 -0
- package/tools/load-test/tests/config.test.ts +152 -0
- package/tools/load-test/tests/framing.test.ts +37 -0
- package/tools/load-test/tests/harness.test.ts +165 -0
- package/tools/load-test/tests/metrics.test.ts +174 -0
- package/tools/load-test/tests/report.test.ts +161 -0
- package/tools/load-test/tests/smoke.test.ts +67 -0
- package/tools/load-test/tsconfig.build.json +12 -0
- package/tools/load-test/tsconfig.test.json +10 -0
- package/tools/load-test/vitest.config.ts +29 -0
- package/tools/tcp-ws-forwarder/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
let supportedCached = null;
|
|
2
|
+
|
|
3
|
+
export function get(name) {
|
|
4
|
+
if (!isSupported()) {
|
|
5
|
+
return Promise.resolve();
|
|
6
|
+
}
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
resolve(window.localStorage.getItem(name));
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function set(name, val) {
|
|
13
|
+
if (!isSupported()) {
|
|
14
|
+
return Promise.resolve();
|
|
15
|
+
}
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
resolve(window.localStorage.setItem(name, val));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isSupported() {
|
|
22
|
+
if (supportedCached === null) {
|
|
23
|
+
supportedCached = storageAvailable('localStorage');
|
|
24
|
+
}
|
|
25
|
+
return supportedCached;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#Testing_for_availability
|
|
29
|
+
function storageAvailable(type) {
|
|
30
|
+
let storage;
|
|
31
|
+
try {
|
|
32
|
+
let x = '__storage_test__';
|
|
33
|
+
storage = window[type];
|
|
34
|
+
storage.setItem(x, x);
|
|
35
|
+
storage.removeItem(x);
|
|
36
|
+
return true;
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return e instanceof DOMException && (
|
|
39
|
+
// everything except Firefox
|
|
40
|
+
e.code === 22 ||
|
|
41
|
+
// Firefox
|
|
42
|
+
e.code === 1014 ||
|
|
43
|
+
// test name field too, because code might not be present
|
|
44
|
+
// everything except Firefox
|
|
45
|
+
e.name === 'QuotaExceededError' ||
|
|
46
|
+
// Firefox
|
|
47
|
+
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
|
|
48
|
+
// acknowledge QuotaExceededError only if there's something already stored
|
|
49
|
+
storage.length !== 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import Vue from 'vue';
|
|
3
|
+
import JSON5 from 'json5';
|
|
4
|
+
import i18next from 'i18next';
|
|
5
|
+
import i18nextHTTP from 'i18next-http-backend';
|
|
6
|
+
import VueI18Next from '@panter/vue-i18next';
|
|
7
|
+
import VueVirtualScroller from 'vue-virtual-scroller';
|
|
8
|
+
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
|
|
9
|
+
|
|
10
|
+
// fetch polyfill
|
|
11
|
+
import 'whatwg-fetch';
|
|
12
|
+
// polyfill for vue-virtual-scroller & ie11
|
|
13
|
+
import 'intersection-observer';
|
|
14
|
+
|
|
15
|
+
import App from '@/components/App';
|
|
16
|
+
import StartupError from '@/components/StartupError';
|
|
17
|
+
import Logger from '@/libs/Logger';
|
|
18
|
+
import ConfigLoader from '@/libs/ConfigLoader';
|
|
19
|
+
import getState from '@/libs/state';
|
|
20
|
+
import ThemeManager from '@/libs/ThemeManager';
|
|
21
|
+
import InputHandler from '@/libs/InputHandler';
|
|
22
|
+
import StatePersistence from '@/libs/StatePersistence';
|
|
23
|
+
import * as Storage from '@/libs/storage/Local';
|
|
24
|
+
import * as Misc from '@/helpers/Misc';
|
|
25
|
+
import GlobalApi from '@/libs/GlobalApi';
|
|
26
|
+
import { AudioManager } from '@/libs/AudioManager';
|
|
27
|
+
import { SoundBleep } from '@/libs/SoundBleep';
|
|
28
|
+
import WindowTitle from '@/libs/WindowTitle';
|
|
29
|
+
import { configTemplates } from '@/res/configTemplates';
|
|
30
|
+
|
|
31
|
+
import AvailableLocales from '@/res/locales/available.json';
|
|
32
|
+
import FallbackLocale from '@/../static/locales/en-us.json';
|
|
33
|
+
|
|
34
|
+
// Global utilities
|
|
35
|
+
import '@/components/utils/TabbedView';
|
|
36
|
+
import '@/components/utils/InputText';
|
|
37
|
+
import '@/components/utils/IrcInput';
|
|
38
|
+
import '@/components/utils/InputPrompt';
|
|
39
|
+
import '@/components/utils/InputConfirm';
|
|
40
|
+
import '@/components/utils/TransitionExpand';
|
|
41
|
+
|
|
42
|
+
Vue.use(VueVirtualScroller);
|
|
43
|
+
|
|
44
|
+
let logLevelMatch = window.location.href.match(/kiwi-loglevel=(\d)/);
|
|
45
|
+
if (logLevelMatch && logLevelMatch[1]) {
|
|
46
|
+
let newLevel = parseInt(logLevelMatch[1], 10);
|
|
47
|
+
Logger.setLevel(newLevel);
|
|
48
|
+
Logger('Logging level set to', newLevel);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let log = Logger.namespace('main');
|
|
52
|
+
|
|
53
|
+
// Add the global API as soon as possible so that things can start listening to it
|
|
54
|
+
let api = window.kiwi = GlobalApi.singleton();
|
|
55
|
+
|
|
56
|
+
// Third party imports now have access to the state and api
|
|
57
|
+
/* eslint-disable import/first */
|
|
58
|
+
import '@/thirdparty/';
|
|
59
|
+
|
|
60
|
+
function getQueryVariable(variable) {
|
|
61
|
+
let query = window.location.search.substring(1);
|
|
62
|
+
let vars = query.split('&');
|
|
63
|
+
for (let i = 0; i < vars.length; i++) {
|
|
64
|
+
let pair = vars[i].split('=');
|
|
65
|
+
if (pair[0] === variable) {
|
|
66
|
+
return pair[1];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Add a handy this.listen() fn to Vue instances. Saves on the need to add an event listener
|
|
74
|
+
// and then manually remove them all the time.
|
|
75
|
+
Vue.mixin({
|
|
76
|
+
beforeDestroy: function beforeDestroy() {
|
|
77
|
+
(this.listeningEvents || []).forEach((fn) => fn());
|
|
78
|
+
},
|
|
79
|
+
methods: {
|
|
80
|
+
listen: function listen(source, event, fn) {
|
|
81
|
+
this.listeningEvents = this.listeningEvents || [];
|
|
82
|
+
let off = () => {
|
|
83
|
+
(source.removeEventListener || source.$off || source.off).call(source, event, fn);
|
|
84
|
+
};
|
|
85
|
+
this.listeningEvents.push(off);
|
|
86
|
+
(source.addEventListener || source.$on || source.on).call(source, event, fn);
|
|
87
|
+
return off;
|
|
88
|
+
},
|
|
89
|
+
listenOnce: function listenOnce(source, event, _fn) {
|
|
90
|
+
let fn = _fn;
|
|
91
|
+
this.listeningEvents = this.listeningEvents || [];
|
|
92
|
+
let off = () => {
|
|
93
|
+
(source.removeEventListener || source.$off || source.off).call(source, event, fn);
|
|
94
|
+
};
|
|
95
|
+
this.listeningEvents.push(off);
|
|
96
|
+
|
|
97
|
+
if (source.addEventListener) {
|
|
98
|
+
// Create our own once handler as the DOM doesn't support this itself
|
|
99
|
+
fn = function onceFn(...args) {
|
|
100
|
+
source.removeEventListener(event, onceFn);
|
|
101
|
+
fn(...args);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
source.addEventListener(event, fn);
|
|
105
|
+
} else {
|
|
106
|
+
(source.$once || source.once).call(source, event, fn);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return off;
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Timer functions that are auto cleaned up when a component is destroyed
|
|
115
|
+
Vue.mixin({
|
|
116
|
+
beforeDestroy: function beforeDestroy() {
|
|
117
|
+
(this.timerEvents || []).forEach((tmr) => clearTimeout(tmr));
|
|
118
|
+
},
|
|
119
|
+
methods: {
|
|
120
|
+
setInterval(...args) {
|
|
121
|
+
this.timerEvents = this.timerEvents || [];
|
|
122
|
+
let v = setInterval(...args);
|
|
123
|
+
this.timerEvents.push(v);
|
|
124
|
+
return v;
|
|
125
|
+
},
|
|
126
|
+
setTimeout(...args) {
|
|
127
|
+
this.timerEvents = this.timerEvents || [];
|
|
128
|
+
let v = setTimeout(...args);
|
|
129
|
+
this.timerEvents.push(v);
|
|
130
|
+
return v;
|
|
131
|
+
},
|
|
132
|
+
clearInterval(timerId) {
|
|
133
|
+
return this.clearTimeout(timerId);
|
|
134
|
+
},
|
|
135
|
+
clearTimeout(timerId) {
|
|
136
|
+
this.timerEvents = this.timerEvents || [];
|
|
137
|
+
for (let idx = this.timerEvents.length - 1; idx >= 0; idx--) {
|
|
138
|
+
if (this.timerEvents[idx] === timerId) {
|
|
139
|
+
this.timerEvents.splice(idx, 1);
|
|
140
|
+
clearTimeout(timerId);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Make the state available to all components by default
|
|
150
|
+
Vue.mixin({
|
|
151
|
+
computed: {
|
|
152
|
+
$state() {
|
|
153
|
+
return getState();
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Allow adding existing raw elements to component templates
|
|
159
|
+
// Eg: <div v-rawElement="domElement"></div>
|
|
160
|
+
// Eg: <div v-rawElement="{el: domElement, data:{foo:'bar'}}"></div>
|
|
161
|
+
Vue.directive('rawElement', {
|
|
162
|
+
bind(el, binding) {
|
|
163
|
+
if (binding.value.nodeName) {
|
|
164
|
+
el.appendChild(binding.value);
|
|
165
|
+
} else if (binding.value.el) {
|
|
166
|
+
let rawEl = binding.value.el;
|
|
167
|
+
el.appendChild(rawEl);
|
|
168
|
+
|
|
169
|
+
// Add any data attributes to the raw element
|
|
170
|
+
if (binding.value.data) {
|
|
171
|
+
Object.keys(binding.value.data).forEach((key) => {
|
|
172
|
+
rawEl.dataset[key] = binding.value.data[key];
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Add any properties to the raw element
|
|
177
|
+
if (binding.value.props) {
|
|
178
|
+
Object.keys(binding.value.props).forEach((key) => {
|
|
179
|
+
rawEl[key] = binding.value.props[key];
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Register a global custom directive called `v-focus`
|
|
187
|
+
Vue.directive('focus', {
|
|
188
|
+
// Support conditional eg. v-focus="false"
|
|
189
|
+
bind(el, bindings) {
|
|
190
|
+
el.dataset.focus = bindings.value === undefined || !!bindings.value;
|
|
191
|
+
},
|
|
192
|
+
// When the bound element is inserted into the DOM...
|
|
193
|
+
inserted(el) {
|
|
194
|
+
// dataset properties are strings
|
|
195
|
+
if (el.dataset.focus !== 'true') {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// Element is input so focus it
|
|
199
|
+
if (el.tagName === 'INPUT') {
|
|
200
|
+
el.focus();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Try to focus the first input element
|
|
204
|
+
let input = el.getElementsByTagName('input')[0];
|
|
205
|
+
if (input) {
|
|
206
|
+
input.focus();
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
let ROSymbol = Symbol('resizeobserver');
|
|
212
|
+
Vue.directive('resizeobserver', {
|
|
213
|
+
bind(el, bindings) {
|
|
214
|
+
let cb = bindings.value || function noop() {};
|
|
215
|
+
el[ROSymbol] = new ResizeObserver(cb);
|
|
216
|
+
el[ROSymbol].observe(el);
|
|
217
|
+
},
|
|
218
|
+
unbind(el) {
|
|
219
|
+
el[ROSymbol].unobserve(el);
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
loadApp();
|
|
224
|
+
|
|
225
|
+
function loadApp() {
|
|
226
|
+
let configFile = 'static/config.json';
|
|
227
|
+
let configObj = null;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Finding the config file
|
|
231
|
+
* In order, looks in the following places:
|
|
232
|
+
* 1. If a 'config' argument is in the query string, static/config_THEVALUE_.json
|
|
233
|
+
* 2. If a window.kiwiConfig function exists, use it's return value as the config object.
|
|
234
|
+
* 3. If a <meta name="kiwiconfig" content=""> is found, then the content becomes the config
|
|
235
|
+
* URL.
|
|
236
|
+
* 4. If a <script name="kiwiconfig" type="application/json"></script> is found, then the
|
|
237
|
+
* content becomes the config JSON without making another web request.
|
|
238
|
+
*/
|
|
239
|
+
if (getQueryVariable('config')) {
|
|
240
|
+
configFile = 'static/config_' + getQueryVariable('config') + '.json';
|
|
241
|
+
} else if (typeof window.kiwiConfig === 'function') {
|
|
242
|
+
try {
|
|
243
|
+
configObj = window.kiwiConfig();
|
|
244
|
+
} catch (err) {
|
|
245
|
+
log.error('Config file: ' + err.stack);
|
|
246
|
+
showError();
|
|
247
|
+
}
|
|
248
|
+
} else if (document.querySelector('meta[name="kiwiconfig"]')) {
|
|
249
|
+
configFile = document.querySelector('meta[name="kiwiconfig"]').content;
|
|
250
|
+
} else if (document.querySelector('script[name="kiwiconfig"]')) {
|
|
251
|
+
let configContents = document.querySelector('script[name="kiwiconfig"]').innerHTML;
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
configObj = JSON5.parse(configContents);
|
|
255
|
+
} catch (parseErr) {
|
|
256
|
+
log.error('Config file: ' + parseErr.stack);
|
|
257
|
+
showError();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let configLoader = new ConfigLoader();
|
|
262
|
+
configLoader
|
|
263
|
+
.addValueReplacement('protocol', window.location.protocol)
|
|
264
|
+
.addValueReplacement('wsprotocol', window.location.protocol === 'https:' ? 'wss:' : 'ws:')
|
|
265
|
+
.addValueReplacement('tls', window.location.protocol === 'https:')
|
|
266
|
+
.addValueReplacement('hostname', window.location.hostname)
|
|
267
|
+
.addValueReplacement('host', window.location.host)
|
|
268
|
+
.addValueReplacement('port', window.location.port || (
|
|
269
|
+
window.location.protocol === 'https:' ?
|
|
270
|
+
443 :
|
|
271
|
+
80
|
|
272
|
+
))
|
|
273
|
+
.addValueReplacement('hash', (window.location.hash || '').substr(1))
|
|
274
|
+
.addValueReplacement('query', (window.location.search || '').substr(1))
|
|
275
|
+
.addValueReplacement('referrer', window.document.referrer);
|
|
276
|
+
|
|
277
|
+
(configObj ? configLoader.loadFromObj(configObj) : configLoader.loadFromUrl(configFile))
|
|
278
|
+
.then(applyConfig)
|
|
279
|
+
.then(initState)
|
|
280
|
+
.then(initInputCommands)
|
|
281
|
+
.then(initLocales)
|
|
282
|
+
.then(initThemes)
|
|
283
|
+
.then(loadPlugins)
|
|
284
|
+
.then(initSound)
|
|
285
|
+
.then(startApp)
|
|
286
|
+
.catch(showError);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function applyConfig(config) {
|
|
290
|
+
Misc.dedotObject(config);
|
|
291
|
+
// if we have a config template apply that before other configs
|
|
292
|
+
if (configTemplates[config.template]) {
|
|
293
|
+
applyConfigObj(configTemplates[config.template], getState().settings);
|
|
294
|
+
}
|
|
295
|
+
applyConfigObj(config, getState().settings);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Recursively merge an object onto another via Vue.$set
|
|
299
|
+
function applyConfigObj(obj, target) {
|
|
300
|
+
// Keys in the newObjects array will get new objects created (empty) before merging from config
|
|
301
|
+
let newObjects = ['emojis', 'autocompleteTokens'];
|
|
302
|
+
_.each(obj, (val, key) => {
|
|
303
|
+
if (typeof val === 'object') {
|
|
304
|
+
if (
|
|
305
|
+
// Key does not exist or is not the correct data type
|
|
306
|
+
typeof target[key] !== 'object' ||
|
|
307
|
+
// Key requires a new object/array before merging config data
|
|
308
|
+
(target === getState().settings && newObjects.includes(key))
|
|
309
|
+
) {
|
|
310
|
+
// Create the correct type of object
|
|
311
|
+
let newVal = _.isArray(val) ?
|
|
312
|
+
[] :
|
|
313
|
+
{};
|
|
314
|
+
|
|
315
|
+
Vue.set(target, key, newVal);
|
|
316
|
+
}
|
|
317
|
+
applyConfigObj(val, target[key]);
|
|
318
|
+
} else {
|
|
319
|
+
Vue.set(target, key, val);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function loadPlugins() {
|
|
325
|
+
return new Promise((resolve, reject) => {
|
|
326
|
+
let plugins = getState().settings.plugins || [];
|
|
327
|
+
let pluginIdx = -1;
|
|
328
|
+
|
|
329
|
+
loadNextScript();
|
|
330
|
+
|
|
331
|
+
function loadNextScript(sSrc, fOnload) {
|
|
332
|
+
let plugin = plugins[++pluginIdx];
|
|
333
|
+
|
|
334
|
+
if (!plugin) {
|
|
335
|
+
resolve();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (plugin.url.indexOf('.js') > -1) {
|
|
340
|
+
// The plugin is a .js file so inject it as a script
|
|
341
|
+
let scr = document.createElement('script');
|
|
342
|
+
scr.onerror = () => {
|
|
343
|
+
log.error(`Error loading plugin '${plugin.name}' from '${plugin.url}'`);
|
|
344
|
+
loadNextScript();
|
|
345
|
+
};
|
|
346
|
+
scr.onload = () => {
|
|
347
|
+
loadNextScript();
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
document.body.appendChild(scr);
|
|
351
|
+
scr.src = plugin.url;
|
|
352
|
+
} else {
|
|
353
|
+
// Treat the plugin as a HTML document and just inject it into the document
|
|
354
|
+
fetch(plugin.url)
|
|
355
|
+
.then((response) => {
|
|
356
|
+
if (!response.ok) {
|
|
357
|
+
throw new Error(response.status + ' ' + response.statusText);
|
|
358
|
+
}
|
|
359
|
+
return response.text();
|
|
360
|
+
})
|
|
361
|
+
.then((pluginRaw) => {
|
|
362
|
+
let el = document.createElement('div');
|
|
363
|
+
el.id = 'kiwi_plugin_' + plugin.name.replace(/[ "']/g, '');
|
|
364
|
+
el.style.display = 'none';
|
|
365
|
+
el.innerHTML = pluginRaw;
|
|
366
|
+
|
|
367
|
+
// The browser won't execute any script elements so we need to extract them
|
|
368
|
+
// and place them into the DOM using our own script elements
|
|
369
|
+
let scripts = [...el.querySelectorAll('script')];
|
|
370
|
+
|
|
371
|
+
// IE11 does not support nodes.forEach()
|
|
372
|
+
scripts.forEach((limitedScr) => {
|
|
373
|
+
limitedScr.parentElement.removeChild(limitedScr);
|
|
374
|
+
let scr = document.createElement('script');
|
|
375
|
+
scr.text = limitedScr.text;
|
|
376
|
+
el.appendChild(scr);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
document.body.appendChild(el);
|
|
380
|
+
loadNextScript();
|
|
381
|
+
}).catch(() => {
|
|
382
|
+
log.error(`Error loading plugin '${plugin.name}' from '${plugin.url}'`);
|
|
383
|
+
loadNextScript();
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function initLocales() {
|
|
391
|
+
Vue.use(VueI18Next);
|
|
392
|
+
|
|
393
|
+
i18next.use(i18nextHTTP);
|
|
394
|
+
i18next.init({
|
|
395
|
+
supportedLngs: AvailableLocales.locales,
|
|
396
|
+
compatibilityJSON: 'v3',
|
|
397
|
+
fallbackLng: 'en-us',
|
|
398
|
+
lowerCaseLng: true,
|
|
399
|
+
backend: {
|
|
400
|
+
loadPath: (langs, namespaces) => {
|
|
401
|
+
// If allowMultiLoading is false, langs and namespaces will have only one element
|
|
402
|
+
const namespace = namespaces[0];
|
|
403
|
+
|
|
404
|
+
return (namespace === 'translation') ?
|
|
405
|
+
'static/locales/{{lng}}.json' :
|
|
406
|
+
api.translationUrls[namespace];
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
// allow cross domain requests
|
|
410
|
+
crossDomain: false,
|
|
411
|
+
|
|
412
|
+
// allow credentials on cross domain requests
|
|
413
|
+
withCredentials: false,
|
|
414
|
+
|
|
415
|
+
// your backend server supports multiloading
|
|
416
|
+
allowMultiLoading: false,
|
|
417
|
+
},
|
|
418
|
+
interpolation: {
|
|
419
|
+
// We let vuejs handle HTML output escaping
|
|
420
|
+
escapeValue: false,
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Build in the english translation so it can be used as a fallback
|
|
425
|
+
i18next.addResourceBundle('en-us', 'translation', FallbackLocale);
|
|
426
|
+
|
|
427
|
+
// Make the translation services available via the global API
|
|
428
|
+
api.i18n = i18next;
|
|
429
|
+
api.vueI18n = new VueI18Next(i18next);
|
|
430
|
+
|
|
431
|
+
// Override the $t function so that empty translations fallback to en-us
|
|
432
|
+
Vue.mixin({
|
|
433
|
+
computed: {
|
|
434
|
+
$t() {
|
|
435
|
+
return (key, options) => {
|
|
436
|
+
const vueI18n = this.$i18n || api.vueI18n;
|
|
437
|
+
let val = vueI18n.i18next.t(key, options, vueI18n.i18nLoadedAt);
|
|
438
|
+
if (!val) {
|
|
439
|
+
let opts = options || {};
|
|
440
|
+
opts.lng = 'en-us';
|
|
441
|
+
val = vueI18n.i18next.t(key, opts, vueI18n.i18nLoadedAt);
|
|
442
|
+
}
|
|
443
|
+
return val;
|
|
444
|
+
};
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
const setDefaultLanguage = () => {
|
|
450
|
+
let defaultLang = getState().setting('language');
|
|
451
|
+
let preferredLangs = _.clone(window.navigator && window.navigator.languages) || [];
|
|
452
|
+
|
|
453
|
+
// our configs default lang overrides all others
|
|
454
|
+
if (defaultLang) {
|
|
455
|
+
preferredLangs.unshift(defaultLang);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// set a default language
|
|
459
|
+
i18next.changeLanguage('en-us');
|
|
460
|
+
|
|
461
|
+
// Go through our browser languages until we find one that we support
|
|
462
|
+
for (let idx = 0; idx < preferredLangs.length; idx++) {
|
|
463
|
+
let lang = preferredLangs[idx];
|
|
464
|
+
|
|
465
|
+
// if this is a language such as 'fr', add a following one of 'fr-fr' to cover
|
|
466
|
+
// both cases
|
|
467
|
+
if (lang.length === 2) {
|
|
468
|
+
preferredLangs.splice(idx + 1, 0, lang + '-' + lang);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (_.includes(AvailableLocales.locales, lang.toLowerCase())) {
|
|
472
|
+
i18next.changeLanguage(lang, (err, t) => {
|
|
473
|
+
if (err) {
|
|
474
|
+
// setting the language failed so set default again
|
|
475
|
+
i18next.changeLanguage('en-us');
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
setDefaultLanguage();
|
|
483
|
+
|
|
484
|
+
// Update the language if the setting changes.
|
|
485
|
+
getState().$watch('user_settings.language', (lang) => {
|
|
486
|
+
if (!lang && !getState().setting('language')) {
|
|
487
|
+
setDefaultLanguage();
|
|
488
|
+
} else {
|
|
489
|
+
i18next.changeLanguage(lang || getState().setting('language') || 'en-us');
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
async function initState() {
|
|
495
|
+
let stateKey = getState().settings.startupOptions.state_key;
|
|
496
|
+
|
|
497
|
+
// Default to a preset key if it wasn't set
|
|
498
|
+
if (typeof stateKey === 'undefined') {
|
|
499
|
+
stateKey = 'kiwi-state';
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
let persistLog = Logger.namespace('StatePersistence');
|
|
503
|
+
let persist = new StatePersistence(stateKey || '', getState(), Storage, persistLog);
|
|
504
|
+
persist.includeBuffers = !!getState().settings.startupOptions.remember_buffers;
|
|
505
|
+
|
|
506
|
+
if (stateKey) {
|
|
507
|
+
await persist.loadStateIfExists();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
api.setState(getState());
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function initThemes() {
|
|
514
|
+
let themeMgr = ThemeManager.instance(getState());
|
|
515
|
+
api.setThemeManager(themeMgr);
|
|
516
|
+
|
|
517
|
+
let argTheme = getQueryVariable('theme');
|
|
518
|
+
if (argTheme) {
|
|
519
|
+
themeMgr.setTheme(argTheme);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function initSound() {
|
|
524
|
+
let sound = new SoundBleep();
|
|
525
|
+
let bleep = new AudioManager(sound);
|
|
526
|
+
|
|
527
|
+
bleep.listen(getState());
|
|
528
|
+
bleep.watchForMessages(getState());
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function initInputCommands() {
|
|
532
|
+
/* eslint-disable no-new */
|
|
533
|
+
new InputHandler(getState());
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function startApp() {
|
|
537
|
+
new WindowTitle(getState());
|
|
538
|
+
|
|
539
|
+
api.emit('init');
|
|
540
|
+
|
|
541
|
+
/* eslint-disable no-new */
|
|
542
|
+
new Vue({
|
|
543
|
+
el: '#app',
|
|
544
|
+
render: (h) => h(App),
|
|
545
|
+
i18n: api.vueI18n,
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
api.emit('ready');
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function showError(err) {
|
|
552
|
+
if (err) {
|
|
553
|
+
log.error('Error starting Kiwi IRC:', err);
|
|
554
|
+
} else {
|
|
555
|
+
log.error('Unknown error starting Kiwi IRC');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/* eslint-disable no-new */
|
|
559
|
+
new Vue({
|
|
560
|
+
el: '#app',
|
|
561
|
+
render: (h) => h(
|
|
562
|
+
StartupError,
|
|
563
|
+
{ props: { error: err } },
|
|
564
|
+
),
|
|
565
|
+
});
|
|
566
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
|
|
5
|
+
// command descriptions can be either a static string or a translation key prefixed with locale_id_
|
|
6
|
+
export default [
|
|
7
|
+
{ command: 'msg', alias: [], description: 'locale_id_command_msg' },
|
|
8
|
+
{ command: 'action', alias: [], description: 'locale_id_command_action' },
|
|
9
|
+
{ command: 'join', alias: [], description: 'locale_id_command_join' },
|
|
10
|
+
{ command: 'part', alias: [], description: 'locale_id_command_part' },
|
|
11
|
+
{ command: 'cycle', alias: [], description: 'locale_id_command_cycle' },
|
|
12
|
+
{ command: 'nick', alias: [], description: 'locale_id_command_nick' },
|
|
13
|
+
{ command: 'query', alias: [], description: 'locale_id_command_query' },
|
|
14
|
+
{ command: 'invite', alias: [], description: 'locale_id_command_invite' },
|
|
15
|
+
{ command: 'topic', alias: [], description: 'locale_id_command_topic' },
|
|
16
|
+
{ command: 'notice', alias: [], description: 'locale_id_command_notice' },
|
|
17
|
+
{ command: 'quote', alias: [], description: 'locale_id_command_quote' },
|
|
18
|
+
{ command: 'kick', alias: [], description: 'locale_id_command_kick' },
|
|
19
|
+
{ command: 'clear', alias: [], description: 'locale_id_command_clear' },
|
|
20
|
+
{ command: 'ctcp', alias: [], description: 'locale_id_command_ctcp' },
|
|
21
|
+
{ command: 'quit', alias: [], description: 'locale_id_command_quit' },
|
|
22
|
+
{ command: 'server', alias: [], description: 'locale_id_command_server' },
|
|
23
|
+
{ command: 'whois', alias: [], description: 'locale_id_command_whois' },
|
|
24
|
+
{ command: 'whowas', alias: [], description: 'locale_id_command_whowas' },
|
|
25
|
+
{ command: 'away', alias: [], description: 'locale_id_command_away' },
|
|
26
|
+
{ command: 'back', alias: ['active'], description: 'locale_id_command_back' },
|
|
27
|
+
{ command: 'encoding', alias: [], description: 'locale_id_command_encoding' },
|
|
28
|
+
{ command: 'ignore', alias: [], description: 'locale_id_command_ignore' },
|
|
29
|
+
{ command: 'unignore', alias: [], description: 'locale_id_command_unignore' },
|
|
30
|
+
{ command: 'dice', alias: [], description: 'locale_id_command_dice' },
|
|
31
|
+
];
|