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.
Files changed (394) hide show
  1. package/.github/workflows/ci.yml +40 -3
  2. package/.github/workflows/deploy-aws.yml +1 -2
  3. package/.github/workflows/deploy-cf-tcp.yml +1 -5
  4. package/.github/workflows/deploy-cf.yml +1 -2
  5. package/.gitmodules +3 -0
  6. package/CHANGELOG.md +474 -0
  7. package/README.md +219 -22
  8. package/apps/aws-stack/README.md +33 -0
  9. package/apps/aws-stack/package.json +1 -1
  10. package/apps/aws-stack/src/aws-stack.ts +74 -9
  11. package/apps/aws-stack/tests/coverage-command.test.ts +155 -0
  12. package/apps/aws-stack/tests/stack.test.ts +2 -2
  13. package/apps/aws-stack/tests/synth-no-bundle.test.ts +129 -0
  14. package/apps/aws-stack/tests/vitest.setup.ts +18 -0
  15. package/apps/aws-stack/vitest.config.ts +3 -0
  16. package/apps/cf-tcp-container/package.json +1 -1
  17. package/apps/cf-tcp-container/src/config-loader.ts +6 -7
  18. package/apps/cf-tcp-container/src/container-server.ts +3 -0
  19. package/apps/cf-tcp-container/tests/config-loader.test.ts +10 -3
  20. package/apps/cf-tcp-container/wrangler.toml +1 -1
  21. package/apps/cf-worker/package.json +2 -1
  22. package/apps/cf-worker/src/origin-allowlist.ts +99 -0
  23. package/apps/cf-worker/src/worker.ts +89 -9
  24. package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
  25. package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
  26. package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
  27. package/apps/cf-worker/tests/smoke.test.ts +28 -2
  28. package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
  29. package/apps/cf-worker/vitest.config.ts +1 -1
  30. package/apps/cf-worker/wrangler.test.toml +23 -0
  31. package/apps/cf-worker/wrangler.toml +59 -3
  32. package/apps/local-cli/package.json +1 -1
  33. package/apps/local-cli/src/config-loader.ts +6 -6
  34. package/apps/local-cli/src/main.ts +20 -0
  35. package/apps/local-cli/src/server.ts +9 -7
  36. package/apps/local-cli/tests/e2e.test.ts +112 -28
  37. package/apps/local-cli/tests/tcp.test.ts +71 -19
  38. package/apps/local-cli/tests/ws-subprotocol.test.ts +12 -7
  39. package/apps/web/landing/index.html +217 -0
  40. package/apps/web/package.json +28 -0
  41. package/apps/web/scripts/build.mjs +125 -0
  42. package/apps/web/src/build-env.ts +43 -0
  43. package/apps/web/src/config-schema.ts +138 -0
  44. package/apps/web/static/config.json +28 -0
  45. package/apps/web/static/config.prod.json +28 -0
  46. package/apps/web/static/config.staging.json +28 -0
  47. package/apps/web/tests/build-env.test.ts +63 -0
  48. package/apps/web/tests/build-smoke.test.ts +103 -0
  49. package/apps/web/tests/config-schema.test.ts +432 -0
  50. package/apps/web/tests/workspace.test.ts +12 -0
  51. package/apps/web/tsconfig.json +10 -0
  52. package/apps/web/upstream/.browserslistrc +3 -0
  53. package/apps/web/upstream/.editorconfig +9 -0
  54. package/apps/web/upstream/.eslintignore +3 -0
  55. package/apps/web/upstream/.eslintrc.js +90 -0
  56. package/apps/web/upstream/.github/FUNDING.yml +12 -0
  57. package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  58. package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  59. package/apps/web/upstream/.github/workflows/push.yml +26 -0
  60. package/apps/web/upstream/.github/workflows/release.yml +33 -0
  61. package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
  62. package/apps/web/upstream/.prettierrc.js +9 -0
  63. package/apps/web/upstream/.stylelintignore +5 -0
  64. package/apps/web/upstream/.stylelintrc.js +21 -0
  65. package/apps/web/upstream/LICENSE +201 -0
  66. package/apps/web/upstream/README.md +76 -0
  67. package/apps/web/upstream/babel.config.js +25 -0
  68. package/apps/web/upstream/crowdin.yml +3 -0
  69. package/apps/web/upstream/index.html +35 -0
  70. package/apps/web/upstream/jest.config.js +7 -0
  71. package/apps/web/upstream/jsdoc.json +22 -0
  72. package/apps/web/upstream/package.json +80 -0
  73. package/apps/web/upstream/scripts/pre-commit +43 -0
  74. package/apps/web/upstream/src/components/App.vue +516 -0
  75. package/apps/web/upstream/src/components/AppSettings.vue +587 -0
  76. package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
  77. package/apps/web/upstream/src/components/Avatar.vue +105 -0
  78. package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
  79. package/apps/web/upstream/src/components/BufferKey.vue +121 -0
  80. package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
  81. package/apps/web/upstream/src/components/Captcha.vue +85 -0
  82. package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
  83. package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
  84. package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
  85. package/apps/web/upstream/src/components/ChannelList.vue +345 -0
  86. package/apps/web/upstream/src/components/Container.vue +401 -0
  87. package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
  88. package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
  89. package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
  90. package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
  91. package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
  92. package/apps/web/upstream/src/components/MessageList.vue +1028 -0
  93. package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
  94. package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
  95. package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
  96. package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
  97. package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
  98. package/apps/web/upstream/src/components/Nicklist.vue +309 -0
  99. package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
  100. package/apps/web/upstream/src/components/NotConnected.vue +271 -0
  101. package/apps/web/upstream/src/components/SelfUser.vue +283 -0
  102. package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
  103. package/apps/web/upstream/src/components/ServerView.vue +126 -0
  104. package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
  105. package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
  106. package/apps/web/upstream/src/components/Sidebar.vue +429 -0
  107. package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
  108. package/apps/web/upstream/src/components/SidebarState.vue +145 -0
  109. package/apps/web/upstream/src/components/StartupError.vue +35 -0
  110. package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
  111. package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
  112. package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
  113. package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
  114. package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
  115. package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
  116. package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
  117. package/apps/web/upstream/src/components/UserBox.vue +728 -0
  118. package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
  119. package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
  120. package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
  121. package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
  122. package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
  123. package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
  124. package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
  125. package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
  126. package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
  127. package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
  128. package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
  129. package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
  130. package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
  131. package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
  132. package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
  133. package/apps/web/upstream/src/helpers/Colours.js +128 -0
  134. package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
  135. package/apps/web/upstream/src/helpers/Md5.js +193 -0
  136. package/apps/web/upstream/src/helpers/Misc.js +401 -0
  137. package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
  138. package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
  139. package/apps/web/upstream/src/libs/AudioManager.js +60 -0
  140. package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
  141. package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
  142. package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
  143. package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
  144. package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
  145. package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
  146. package/apps/web/upstream/src/libs/IPC.js +51 -0
  147. package/apps/web/upstream/src/libs/InputHandler.js +921 -0
  148. package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
  149. package/apps/web/upstream/src/libs/Logger.js +71 -0
  150. package/apps/web/upstream/src/libs/Message.js +169 -0
  151. package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
  152. package/apps/web/upstream/src/libs/MessageParser.js +249 -0
  153. package/apps/web/upstream/src/libs/Notifications.js +78 -0
  154. package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
  155. package/apps/web/upstream/src/libs/ServerSession.js +102 -0
  156. package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
  157. package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
  158. package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
  159. package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
  160. package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
  161. package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
  162. package/apps/web/upstream/src/libs/bufferTools.js +177 -0
  163. package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
  164. package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
  165. package/apps/web/upstream/src/libs/settingTools.js +31 -0
  166. package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
  167. package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
  168. package/apps/web/upstream/src/libs/state/UserState.js +89 -0
  169. package/apps/web/upstream/src/libs/state/common.js +26 -0
  170. package/apps/web/upstream/src/libs/state.js +961 -0
  171. package/apps/web/upstream/src/libs/storage/Local.js +51 -0
  172. package/apps/web/upstream/src/main.js +566 -0
  173. package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
  174. package/apps/web/upstream/src/res/configTemplates.js +373 -0
  175. package/apps/web/upstream/src/res/globalStyle.css +277 -0
  176. package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
  177. package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
  178. package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
  179. package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
  180. package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
  181. package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
  182. package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
  183. package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
  184. package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
  185. package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
  186. package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
  187. package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
  188. package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
  189. package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
  190. package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
  191. package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
  192. package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
  193. package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
  194. package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
  195. package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
  196. package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
  197. package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
  198. package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
  199. package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
  200. package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
  201. package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
  202. package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
  203. package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
  204. package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
  205. package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
  206. package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
  207. package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
  208. package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
  209. package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
  210. package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
  211. package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
  212. package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
  213. package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
  214. package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
  215. package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
  216. package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
  217. package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
  218. package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
  219. package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
  220. package/apps/web/upstream/src/res/localesList.json +27 -0
  221. package/apps/web/upstream/src/res/logo.png +0 -0
  222. package/apps/web/upstream/src/thirdparty/about.html +43 -0
  223. package/apps/web/upstream/src/thirdparty/index.js +5 -0
  224. package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
  225. package/apps/web/upstream/static/config.json +28 -0
  226. package/apps/web/upstream/static/emoticons/smile.png +0 -0
  227. package/apps/web/upstream/static/favicon.png +0 -0
  228. package/apps/web/upstream/static/highlight.mp3 +0 -0
  229. package/apps/web/upstream/static/highlight.ogg +0 -0
  230. package/apps/web/upstream/static/locales/.gitignore +2 -0
  231. package/apps/web/upstream/static/plugins/customise.html.example +10 -0
  232. package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
  233. package/apps/web/upstream/static/themes/common/base.css +1064 -0
  234. package/apps/web/upstream/static/themes/dark/theme.css +196 -0
  235. package/apps/web/upstream/static/themes/default/theme.css +92 -0
  236. package/apps/web/upstream/static/themes/elite/theme.css +248 -0
  237. package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
  238. package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
  239. package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
  240. package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
  241. package/apps/web/upstream/static/themes/sky/theme.css +107 -0
  242. package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
  243. package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
  244. package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
  245. package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
  246. package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
  247. package/apps/web/upstream/vue.config.js +150 -0
  248. package/apps/web/upstream/yarn.lock +9767 -0
  249. package/apps/web/vitest.config.ts +13 -0
  250. package/biome.json +2 -0
  251. package/docs/ADR-001-pure-reducers-and-effect-system.md +74 -0
  252. package/docs/ADR-002-location-of-authority.md +82 -0
  253. package/docs/ADR-003-durable-object-sharding.md +110 -0
  254. package/docs/ADR-004-dynamodb-schema.md +96 -0
  255. package/docs/ADR-005-wss-only-transport-v1.md +83 -0
  256. package/docs/ADR-006-sasl-mechanism-scope.md +96 -0
  257. package/docs/ADR-007-deterministic-ports.md +82 -0
  258. package/docs/ADR-008-monorepo-tooling.md +60 -0
  259. package/docs/ADR-009-dual-transport-wss-and-irc-tls.md +138 -0
  260. package/docs/ADR-Index.md +15 -0
  261. package/docs/AWS-Adapter-Architecture.md +496 -0
  262. package/docs/AWS-Deployment.md +1275 -0
  263. package/docs/AWS-TCP-Deployment.md +410 -0
  264. package/docs/Cloudflare-Deployment-Guide.md +719 -0
  265. package/docs/Cloudflare-TCP-Deployment.md +510 -0
  266. package/docs/Home.md +16 -0
  267. package/docs/Observability.md +87 -0
  268. package/docs/PlanExtensions.md +812 -0
  269. package/docs/PlanIRCv3Websocket.md +503 -0
  270. package/docs/PlanWebClient.md +451 -0
  271. package/docs/Release-Process.md +443 -0
  272. package/docs/WebClientGuide.md +535 -0
  273. package/package.json +2 -2
  274. package/packages/aws-adapter/package.json +1 -1
  275. package/packages/aws-adapter/src/handlers/default.ts +3 -0
  276. package/packages/aws-adapter/src/handlers/nlb-stream.ts +9 -0
  277. package/packages/aws-adapter/src/serialize.ts +29 -1
  278. package/packages/aws-adapter/tests/account-store-dynamo.test.ts +49 -8
  279. package/packages/aws-adapter/tests/account-store.test.ts +4 -7
  280. package/packages/aws-adapter/tests/aws-harness.ts +5 -2
  281. package/packages/aws-adapter/tests/aws-integration.test.ts +8 -4
  282. package/packages/aws-adapter/tests/aws-runtime.test.ts +79 -0
  283. package/packages/aws-adapter/tests/config-loader.test.ts +11 -2
  284. package/packages/aws-adapter/tests/connect.test.ts +9 -9
  285. package/packages/aws-adapter/tests/disconnect-fanout.test.ts +3 -4
  286. package/packages/aws-adapter/tests/global-setup.ts +55 -30
  287. package/packages/aws-adapter/tests/gone-exception.test.ts +4 -9
  288. package/packages/aws-adapter/tests/handlers.test.ts +90 -4
  289. package/packages/aws-adapter/tests/message-store.test.ts +6 -5
  290. package/packages/aws-adapter/tests/nlb-stream.test.ts +60 -8
  291. package/packages/cf-adapter/package.json +2 -1
  292. package/packages/cf-adapter/src/connection-do.ts +3 -0
  293. package/packages/cf-adapter/src/serialize.ts +25 -4
  294. package/packages/cf-adapter/tests/cf-harness.ts +12 -1
  295. package/packages/cf-adapter/tests/cf-runtime.test.ts +269 -0
  296. package/packages/cf-adapter/tests/channel-do.test.ts +117 -0
  297. package/packages/cf-adapter/tests/config-loader.test.ts +49 -0
  298. package/packages/cf-adapter/tests/connection-do-pure.test.ts +91 -0
  299. package/packages/cf-adapter/tests/d1-account-store.test.ts +48 -0
  300. package/packages/cf-adapter/tests/registry-do.test.ts +104 -0
  301. package/packages/cf-adapter/tests/serialize.test.ts +308 -0
  302. package/packages/cf-adapter/vitest.config.ts +1 -1
  303. package/packages/in-memory-runtime/package.json +1 -1
  304. package/packages/irc-core/package.json +1 -1
  305. package/packages/irc-core/reports/mutation/mutation.html +342 -0
  306. package/packages/irc-core/src/caps/capabilities.ts +37 -3
  307. package/packages/irc-core/src/caps/index.ts +1 -0
  308. package/packages/irc-core/src/caps/sts.ts +84 -0
  309. package/packages/irc-core/src/commands/account-notify.ts +53 -0
  310. package/packages/irc-core/src/commands/away.ts +9 -3
  311. package/packages/irc-core/src/commands/cap.ts +23 -5
  312. package/packages/irc-core/src/commands/chathistory.ts +40 -11
  313. package/packages/irc-core/src/commands/index.ts +34 -0
  314. package/packages/irc-core/src/commands/isupport.ts +53 -0
  315. package/packages/irc-core/src/commands/mode.ts +8 -1
  316. package/packages/irc-core/src/commands/monitor.ts +327 -0
  317. package/packages/irc-core/src/commands/multiline.ts +256 -0
  318. package/packages/irc-core/src/commands/pre-away.ts +112 -0
  319. package/packages/irc-core/src/commands/privmsg.ts +19 -12
  320. package/packages/irc-core/src/commands/read-marker.ts +108 -0
  321. package/packages/irc-core/src/commands/registration.ts +8 -0
  322. package/packages/irc-core/src/commands/sasl.ts +24 -1
  323. package/packages/irc-core/src/commands/tagmsg.ts +71 -1
  324. package/packages/irc-core/src/commands/whois.ts +5 -0
  325. package/packages/irc-core/src/config.ts +65 -10
  326. package/packages/irc-core/src/effects.ts +14 -0
  327. package/packages/irc-core/src/ports.ts +389 -0
  328. package/packages/irc-core/src/protocol/index.ts +14 -0
  329. package/packages/irc-core/src/protocol/labeled-response.ts +133 -0
  330. package/packages/irc-core/src/protocol/numerics.ts +15 -0
  331. package/packages/irc-core/src/protocol/outbound.ts +16 -1
  332. package/packages/irc-core/src/protocol/standard-replies.ts +277 -0
  333. package/packages/irc-core/src/state/connection.ts +32 -1
  334. package/packages/irc-core/src/types.ts +112 -0
  335. package/packages/irc-core/stryker.commands.conf.json +1 -2
  336. package/packages/irc-core/tests/away-store.test.ts +73 -0
  337. package/packages/irc-core/tests/batch.test.ts +15 -0
  338. package/packages/irc-core/tests/caps/capabilities.test.ts +119 -2
  339. package/packages/irc-core/tests/caps/sts.test.ts +123 -0
  340. package/packages/irc-core/tests/commands/account-notify.test.ts +171 -0
  341. package/packages/irc-core/tests/commands/away.test.ts +85 -2
  342. package/packages/irc-core/tests/commands/cap.test.ts +165 -0
  343. package/packages/irc-core/tests/commands/chathistory.test.ts +148 -1
  344. package/packages/irc-core/tests/commands/echo-message.test.ts +9 -3
  345. package/packages/irc-core/tests/commands/isupport.test.ts +80 -0
  346. package/packages/irc-core/tests/commands/mode.test.ts +72 -0
  347. package/packages/irc-core/tests/commands/monitor.test.ts +411 -0
  348. package/packages/irc-core/tests/commands/multiline.test.ts +428 -0
  349. package/packages/irc-core/tests/commands/pre-away.test.ts +241 -0
  350. package/packages/irc-core/tests/commands/privmsg.test.ts +154 -3
  351. package/packages/irc-core/tests/commands/read-marker.test.ts +211 -0
  352. package/packages/irc-core/tests/commands/registration.test.ts +64 -0
  353. package/packages/irc-core/tests/commands/sasl.test.ts +116 -2
  354. package/packages/irc-core/tests/commands/tagmsg.test.ts +357 -0
  355. package/packages/irc-core/tests/commands/whois.test.ts +34 -0
  356. package/packages/irc-core/tests/config.test.ts +103 -13
  357. package/packages/irc-core/tests/labeled-response.test.ts +181 -0
  358. package/packages/irc-core/tests/message-tags.test.ts +114 -0
  359. package/packages/irc-core/tests/monitor-store.test.ts +200 -0
  360. package/packages/irc-core/tests/numerics.test.ts +13 -0
  361. package/packages/irc-core/tests/parser.test.ts +109 -0
  362. package/packages/irc-core/tests/read-marker-store.test.ts +108 -0
  363. package/packages/irc-core/tests/standard-replies.test.ts +412 -0
  364. package/packages/irc-core/tests/types.test.ts +27 -0
  365. package/packages/irc-server/package.json +1 -1
  366. package/packages/irc-server/src/actor.ts +450 -3
  367. package/packages/irc-server/src/dispatch.ts +108 -16
  368. package/packages/irc-server/tests/actor.test.ts +1432 -39
  369. package/packages/irc-server/tests/dispatch.test.ts +263 -2
  370. package/packages/irc-test-support/package.json +1 -1
  371. package/packages/irc-test-support/src/index.ts +6 -0
  372. package/packages/irc-test-support/src/scenarios.ts +24 -2
  373. package/packages/irc-test-support/src/test-config.ts +54 -0
  374. package/packages/irc-test-support/tests/test-config.test.ts +51 -0
  375. package/tools/ci-hardening/package.json +1 -1
  376. package/tools/ci-hardening/tests/ddb-local.test.ts +82 -0
  377. package/tools/load-test/package.json +33 -0
  378. package/tools/load-test/src/client.ts +351 -0
  379. package/tools/load-test/src/config.ts +313 -0
  380. package/tools/load-test/src/harness.ts +116 -0
  381. package/tools/load-test/src/main.ts +120 -0
  382. package/tools/load-test/src/metrics.ts +168 -0
  383. package/tools/load-test/src/report.ts +106 -0
  384. package/tools/load-test/tests/client.test.ts +212 -0
  385. package/tools/load-test/tests/config.test.ts +152 -0
  386. package/tools/load-test/tests/framing.test.ts +37 -0
  387. package/tools/load-test/tests/harness.test.ts +165 -0
  388. package/tools/load-test/tests/metrics.test.ts +174 -0
  389. package/tools/load-test/tests/report.test.ts +161 -0
  390. package/tools/load-test/tests/smoke.test.ts +67 -0
  391. package/tools/load-test/tsconfig.build.json +12 -0
  392. package/tools/load-test/tsconfig.test.json +10 -0
  393. package/tools/load-test/vitest.config.ts +29 -0
  394. 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
+ ];