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,249 @@
1
+ 'kiwi public';
2
+
3
+ import { trim } from 'lodash';
4
+
5
+ import * as EmojiProvider from '@/libs/EmojiProvider';
6
+ import formatIrcMessage, { createNewBlock } from '@/libs/MessageFormatter';
7
+ import { urlRegex, channelRegex } from '@/helpers/TextFormatting';
8
+
9
+ /**
10
+ * Receives a message, parses its irc blocks, and then finds urls, users, channels and emoji. Each
11
+ * content is extracted to a separate block.
12
+ * E.g. the message:
13
+ * "this is a message www.google.com and #kiwiirc"
14
+ * will be split into the blocks:
15
+ * ["this is a message "]["www.google.com"][" and "]["#kiwiirc"]
16
+ * The special content blocks will also contain additional info about their content according to
17
+ * their type, such as the url, nick colour, emoji code...
18
+ * @param {Array} blocks Array of style blocks from MessageFormatter
19
+ * @param {Array} userList List of users to find within the message
20
+ * @returns An array of blocks, where each special content will be extracted into a separate block.
21
+ */
22
+ export default function parseMessage(message, formatOpts = {}, userList = null) {
23
+ const blocks = formatIrcMessage(message, formatOpts);
24
+ let formatedBlocks = blocks.reduce(
25
+ (acc, block, i) => acc.concat(processBlock(block, userList)),
26
+ []
27
+ );
28
+
29
+ return formatedBlocks;
30
+ }
31
+
32
+ /**
33
+ * Receives a block, splits it into words and tries finding channels, urls, nicks, and emoji.
34
+ * @param {Object} block A block that came from MessageFormatter.formatIrcMessage()
35
+ * @param {Object} userList List of users to find within the message
36
+ * @returns An array of blocks, where each special content will be extracted into a separate block.
37
+ */
38
+ function processBlock(block, userList) {
39
+ const wordsRegex = /\S+/g;
40
+
41
+ let wordMatch;
42
+ let word;
43
+ const specialMatches = [];
44
+ // Array containing the special matches. Each `specialMatch` is an object with:
45
+ // {
46
+ // index: <index of the match>
47
+ // match: <match, i.e. the text that will be extracted into a new block>
48
+ // block: <the block that will replace the match>
49
+ // }
50
+
51
+ // eslint-disable-next-line no-cond-assign
52
+ while ((wordMatch = wordsRegex.exec(block.content)) !== null) {
53
+ // `wordMatch` is an array with the match and the index of the match. We need that so
54
+ // we can re-construct the original message.
55
+ const matchInfo = wordMatch;
56
+ word = wordMatch[0];
57
+
58
+ const matches =
59
+ matchChannel(word) ||
60
+ matchUrl(word) ||
61
+ matchUser(word, userList) ||
62
+ EmojiProvider.matchEmoji(word);
63
+
64
+ if (!matches || !matches.length) {
65
+ continue;
66
+ }
67
+
68
+ matches.forEach((match) => {
69
+ specialMatches.push({
70
+ index: matchInfo.index + match.index,
71
+ match: match.match,
72
+ block: createNewBlock(
73
+ match.match,
74
+ block.styles,
75
+ match.type,
76
+ match.meta
77
+ ),
78
+ });
79
+ });
80
+ }
81
+
82
+ // if there are no special matches, return the original block as is.
83
+ if (specialMatches.length === 0) {
84
+ return [block];
85
+ }
86
+
87
+ // split block with special matches.
88
+ return mergeMatches(block, specialMatches);
89
+ }
90
+
91
+ /**
92
+ * Finds a channel in the word match.
93
+ * @param {String} word Word to be searched for channels.
94
+ * @returns {object} Object with the matched channel, index within the word, and block.
95
+ */
96
+ function matchChannel(word) {
97
+ const channelMatch = channelRegex.exec(word);
98
+ // matches the groups (spaces before)(prefix)(channel)(suffix punctuation)
99
+
100
+ if (channelMatch === null) {
101
+ return false;
102
+ }
103
+
104
+ return [{
105
+ index: channelMatch[1].length + channelMatch[2].length,
106
+ match: channelMatch[3],
107
+ type: 'channel',
108
+ meta: {
109
+ channel: channelMatch[3],
110
+ },
111
+ }];
112
+ }
113
+
114
+ /**
115
+ * Finds an url in the word match.
116
+ * @param {String} word Word to be searched for urls.
117
+ * @returns {Object} Object with the index of the url match in the block content, the
118
+ * url match itself, and the new url text to be placed where the first url was.
119
+ */
120
+ function matchUrl(word) {
121
+ // this check avoids running the urlRegex, which would return the same result
122
+ // but take much more time to process
123
+ if (!(word.includes('://') || word.startsWith('www'))) {
124
+ return false;
125
+ }
126
+
127
+ const urlMatch = urlRegex.exec(word);
128
+
129
+ if (urlMatch === null) {
130
+ return false;
131
+ }
132
+
133
+ let url = urlMatch[0];
134
+
135
+ // Don't allow javascript execution
136
+ if (url.match(/^javascript:/i)) {
137
+ return false;
138
+ }
139
+
140
+ // Trim common punctuation from the end of a link. End of scentences etc.
141
+ let punctuation = '.,;:';
142
+ while (punctuation.indexOf(url[url.length - 1]) > -1) {
143
+ url = url.substr(0, url.length - 1);
144
+ }
145
+
146
+ // Links almost always contain an opening bracket if the last character is a closing
147
+ // bracket and should be part of the URL.
148
+ // If there isn't an opening bracket but the URL ends in a closing bracket, consider the
149
+ // closing bracket as punctuation outside of the URL.
150
+ if (url.indexOf('(') === -1 && url[url.length - 1] === ')') {
151
+ url = url.substr(0, url.length - 1);
152
+ }
153
+
154
+ // Add the http if no protocol was found
155
+ let urlText = url;
156
+ if (urlText.match(/^www\./i)) {
157
+ urlText = 'http://' + url;
158
+ }
159
+
160
+ return [{
161
+ index: urlMatch.index,
162
+ match: url,
163
+ matchText: urlText,
164
+ type: 'url',
165
+ meta: {
166
+ url: urlText,
167
+ },
168
+ }];
169
+ }
170
+
171
+ /**
172
+ * Finds an user in the word match.
173
+ * @param {String} word Word to be searched for users.
174
+ * @returns {Object} Object with the index of the user match in the block content, the
175
+ * user match itself, and the user colour.
176
+ */
177
+ function matchUser(word, userList) {
178
+ if (!userList) {
179
+ return false;
180
+ }
181
+
182
+ let user = null;
183
+ let punc = ',.!:;+)]?¿\\/<>@';
184
+ let hasProp = Object.prototype.hasOwnProperty;
185
+ let nickIdx = 0;
186
+
187
+ const trimWord = trim(word, punc);
188
+ let normWord = trimWord.toUpperCase();
189
+
190
+ if (hasProp.call(userList, normWord)) {
191
+ user = userList[normWord];
192
+ nickIdx = word.indexOf(trimWord);
193
+ } else {
194
+ return false;
195
+ }
196
+
197
+ return [{
198
+ index: nickIdx,
199
+ match: trimWord,
200
+ type: 'user',
201
+ meta: {
202
+ user: trimWord,
203
+ colour: user.colour,
204
+ },
205
+ }];
206
+ }
207
+
208
+ /**
209
+ * Merges the special matches into the block.
210
+ * @param {Object} block A block that came from MessageFormatter.formatIrcMessage()
211
+ * @param {Array} specialMatches Array of special matches. See definition above
212
+ * @returns An array of blocks, where each special content will be extracted into a separate block.
213
+ */
214
+ function mergeMatches(block, specialMatches) {
215
+ const resultBlocks = [];
216
+ let lastProcessedIndex = 0;
217
+
218
+ // for each special content, creat a block with the text up to the match, and a block with the
219
+ // special content itself.
220
+ specialMatches.forEach((specialMatch, index) => {
221
+ const beforeMatchContent = block.content.substr(
222
+ lastProcessedIndex,
223
+ specialMatch.index - lastProcessedIndex
224
+ );
225
+
226
+ if (beforeMatchContent) {
227
+ resultBlocks.push({
228
+ content: beforeMatchContent,
229
+ styles: { ...block.styles },
230
+ containsContent: !!beforeMatchContent,
231
+ });
232
+ }
233
+
234
+ resultBlocks.push(specialMatch.block);
235
+
236
+ lastProcessedIndex = specialMatch.index + specialMatch.match.length;
237
+ });
238
+
239
+ // remaining content after the last special content.
240
+ if (lastProcessedIndex < block.content.length) {
241
+ resultBlocks.push({
242
+ content: block.content.substr(lastProcessedIndex),
243
+ styles: { ...block.styles },
244
+ containsContent: !!block.content.substr(lastProcessedIndex),
245
+ });
246
+ }
247
+
248
+ return resultBlocks;
249
+ }
@@ -0,0 +1,78 @@
1
+ 'kiwi public';
2
+
3
+ import _ from 'lodash';
4
+
5
+ let isEnabled = false;
6
+
7
+ export function requestPermission(state) {
8
+ // Do we support notifications?
9
+ if (!('Notification' in window)) {
10
+ isEnabled = false;
11
+ return;
12
+ }
13
+
14
+ // Permissions already been granted?
15
+ if (Notification.permission === 'granted') {
16
+ state.$emit('notification.enabled');
17
+ isEnabled = true;
18
+ return;
19
+ }
20
+
21
+ if (Notification.permission !== 'denied') {
22
+ Notification.requestPermission((permission) => {
23
+ if (permission === 'granted') {
24
+ state.$emit('notification.enabled');
25
+ isEnabled = true;
26
+ } else {
27
+ isEnabled = false;
28
+ }
29
+ });
30
+ }
31
+ }
32
+
33
+ export function show(title, body, opts) {
34
+ if (!isEnabled) {
35
+ return false;
36
+ }
37
+
38
+ let notify = new Notification(title, {
39
+ body: body,
40
+ icon: opts.icon,
41
+ });
42
+
43
+ if (opts.ttl) {
44
+ setTimeout(notify.close.bind(notify), opts.ttl);
45
+ }
46
+
47
+ return notify;
48
+ }
49
+
50
+ const throttledShow = _.throttle(show, 2000);
51
+
52
+ export function listenForNewMessages(state) {
53
+ state.$on('notification.show', (message, _opts) => {
54
+ if (!isEnabled) {
55
+ return;
56
+ }
57
+
58
+ let opts = Object.assign({
59
+ title: 'Kiwi IRC',
60
+ message: message,
61
+ icon: '',
62
+ onclick: null,
63
+ ttl: 10000,
64
+ }, _opts);
65
+
66
+ if (!opts.message) {
67
+ return;
68
+ }
69
+
70
+ let notification = throttledShow(opts.title, opts.message, {
71
+ ttl: opts.ttl,
72
+ });
73
+
74
+ if (notification && typeof opts.onclick === 'function') {
75
+ notification.onclick = opts.onclick;
76
+ }
77
+ });
78
+ }
@@ -0,0 +1,270 @@
1
+ 'kiwi public';
2
+
3
+ /** @module */
4
+
5
+ /*
6
+ * Multiplexed channels over a websocket connection
7
+ * * Only allow 1 websocket per server
8
+ * * Multiple channels through a single websocket
9
+ * * A channel per IRC network connection
10
+ * Messages are prefixed with : and the channel name then a space. eg:
11
+ * :1 Here is the data
12
+ *
13
+ * Example protocol chatter:
14
+ * Client > START Client tells the server it's starting a session
15
+ * Server > SESSION 1234 Server sends the client the current session ID
16
+ * Client > :1 Client is creating a new channel, ID 1
17
+ * Server > :1 Server acknowledges the new channel, ID 1
18
+ * Client > :1 some data Client sends data over channel 1 to the server
19
+ * Server > :1 some data Server sends data over channel 1 to the client
20
+ * Client > :2 Client is creating a new channel, ID 2
21
+ * Server > :2 Server acknowledges the new channel, ID 2
22
+ */
23
+
24
+ import SockJS from 'sockjs-client';
25
+ import EventEmitter from 'eventemitter3';
26
+
27
+ const serverConnections = Object.create(null);
28
+ const createdChannels = Object.create(null);
29
+ const controlChannel = '0';
30
+
31
+ /**
32
+ *
33
+ * @param {String} _addr Sockjs endpoint
34
+ * @param {String} sessionId Optional session ID to continue
35
+ * @param {String} _socketChannel The optional multiplexed channel ID. Autogenerated if not provided
36
+ */
37
+ export function createChannelConstructor(_addr, sessionId, _socketChannel) {
38
+ let addr = _addr.toLowerCase();
39
+
40
+ if (!serverConnections[addr]) {
41
+ serverConnections[addr] = createNewConnection(addr, sessionId);
42
+ }
43
+
44
+ // If a channel ID hasn't been specified, create a new one
45
+ let socketChannel = _socketChannel;
46
+ if (!socketChannel) {
47
+ socketChannel = serverConnections[addr].nextChannelId++;
48
+ }
49
+
50
+ return createChannelOnConnection(
51
+ serverConnections[addr],
52
+ socketChannel
53
+ );
54
+ }
55
+
56
+ /*
57
+ * Creates a new socket connection to a kiwi server.
58
+ * Channels will be created on this connection to send data back and forth.
59
+ */
60
+ function createNewConnection(wsAddr, sessionId) {
61
+ let connection = new EventEmitter();
62
+ connection.sessionId = '';
63
+
64
+ serverConnections[wsAddr] = connection;
65
+
66
+ connection.nextChannelId = 1;
67
+ connection.connected = false;
68
+
69
+ connection.reconnect =
70
+ connection.connect = function connect() {
71
+ if (connection.ws) {
72
+ try {
73
+ connection.ws.close();
74
+ } catch (err) {
75
+ // Ignore any closing errors. Most likely due to not
76
+ // being connected yet.
77
+ }
78
+
79
+ connection.ws = null;
80
+ }
81
+ connection.ws = new SockJS(wsAddr);
82
+ connection.ws.onopen = () => {
83
+ let connectStr = sessionId ?
84
+ 'CONTROL SESSION ' + sessionId :
85
+ 'CONTROL START';
86
+ connection.ws.send(`:${controlChannel} ${connectStr}`);
87
+ connection.connected = true;
88
+ connection.emit('open');
89
+ };
90
+ connection.ws.onclose = (err) => {
91
+ connection.connected = false;
92
+ connection.ws = null;
93
+ connection.emit('close', err);
94
+ };
95
+ connection.ws.onmessage = (event) => {
96
+ connection.emit('message', event);
97
+
98
+ // If the message starts with ":channel " then extract that channel and emit
99
+ // an event for it.
100
+ if (event.data[0] === ':') {
101
+ let message = event.data;
102
+ let spacePos = message.indexOf(' ');
103
+
104
+ // If no space, ie. ":1", this is the server acknowledging this channel
105
+ // is now open and ready to be used.
106
+ if (spacePos === -1) {
107
+ connection.emit('open.' + message.substr(1));
108
+ return;
109
+ }
110
+
111
+ let channelId = message.substr(1, spacePos - 1);
112
+ event.data = message.substr(spacePos + 1);
113
+ connection.emit('message.' + channelId, event);
114
+ } else {
115
+ // Core messages. Used for session handling and session syncing
116
+ let parts = event.data.split(' ');
117
+
118
+ if (parts[0] === 'SESSION') {
119
+ connection.sessionId = parts[1];
120
+ }
121
+ }
122
+ };
123
+ };
124
+
125
+ connection.connect();
126
+ return connection;
127
+ }
128
+
129
+ /*
130
+ * Create a channel on a server connection.
131
+ * The ConnectionChannel implements an IrcFramework transport
132
+ */
133
+ function createChannelOnConnection(connection, channelId) {
134
+ // Only allow 1 ConnectionChannel instance per channel
135
+ return function ConnectionChannelWrapper(options) {
136
+ if (!createdChannels[channelId]) {
137
+ createdChannels[channelId] = new ConnectionChannel(options);
138
+ } else if (connection.connected) {
139
+ createdChannels[channelId].initChannel();
140
+ }
141
+
142
+ return createdChannels[channelId];
143
+ };
144
+
145
+ function ConnectionChannel(options) {
146
+ let sendControlBuffer = [];
147
+ let encoding = 'utf8';
148
+ let channel = new EventEmitter();
149
+ channel.id = channelId;
150
+ channel.isOpen = false;
151
+ channel.state = 0; // TODO: Is this used anywhere?
152
+ // 0 = disconnected, 1 = connected
153
+ channel.remoteState = 0;
154
+
155
+ // When the websocket opens, open this channel on it
156
+ connection.on('open', () => {
157
+ connection.ws.send(':' + channelId);
158
+ });
159
+ // When we get confirmation of this channel being opened, send any control
160
+ // messages that were buffered
161
+ connection.on('open.' + channelId, () => {
162
+ channel.isOpen = true;
163
+ // channel.emit('open');
164
+ if (sendControlBuffer.length) {
165
+ sendControlBuffer.forEach((line) => {
166
+ channel.sendControl(line);
167
+ });
168
+ sendControlBuffer = [];
169
+ }
170
+
171
+ channel.setEncoding(encoding);
172
+
173
+ // This channel is now open and can start sending data to the server
174
+ channel.remoteState = 1;
175
+ channel.emit('open');
176
+ });
177
+ connection.on('close', (err) => {
178
+ channel.state = 3;
179
+ channel.remoteState = 0;
180
+ channel.isOpen = false;
181
+ channel.emit('close', err);
182
+ });
183
+ connection.on('message.' + channelId, (event) => {
184
+ if (event.data.indexOf('control ') === 0) {
185
+ // When we get the signal that the connection to the IRC server
186
+ // has connected, start proxying all data
187
+ if (event.data.indexOf('control connected') === 0) {
188
+ channel.remoteState = 1;
189
+ }
190
+
191
+ if (event.data.indexOf('control closed') === 0) {
192
+ let err = event.data.split(' ')[2];
193
+ channel.remoteState = 0;
194
+ channel.emit('close', err);
195
+ }
196
+ }
197
+
198
+ if (channel.remoteState === 1) {
199
+ channel.emit('line', event.data);
200
+ }
201
+ });
202
+
203
+ // Send a control message to the server (not relayed to an IRC network)
204
+ channel.sendControl = function writeTarget(data) {
205
+ if (channel.isOpen) {
206
+ connection.ws.send(':' + channelId + ' ' + data);
207
+ } else {
208
+ sendControlBuffer.push(data);
209
+ }
210
+ };
211
+
212
+ channel.writeLine = function writeTarget(data, cb) {
213
+ // Buffer the data if the socket has not yet been sent
214
+ if (channel.remoteState >= 1) {
215
+ connection.ws.send(':' + channelId + ' ' + data);
216
+ }
217
+
218
+ // Websocket.send() does not support callbacks
219
+ // call the callback in the next tick instead
220
+ if (cb) {
221
+ setTimeout(cb, 0);
222
+ }
223
+ };
224
+
225
+ // Tell the server to connect to an IRC network
226
+ channel.connect = function connect() {
227
+ // Clear any buffered control messages so we have a clean slate
228
+ sendControlBuffer = [];
229
+
230
+ // If the websocket is not connected, try to reconnect it
231
+ if (!connection.ws) {
232
+ connection.reconnect();
233
+ }
234
+
235
+ let host = options.host;
236
+ let port = options.port;
237
+ let tls = options.tls || options.ssl;
238
+ channel.sendControl('HOST ' + host + ':' + (tls ? '+' : '') + port);
239
+ };
240
+
241
+ channel.close = function close() {
242
+ if (channel.remoteState >= 1) {
243
+ connection.ws.send(':' + channelId);
244
+ }
245
+ };
246
+
247
+ // This is not supported but irc-framework transports need it, so just noop it
248
+ channel.setEncoding = function setEncoding(newEncoding) {
249
+ encoding = newEncoding;
250
+ if (connection.connected) {
251
+ connection.ws.send(':' + channelId + ' ENCODING ' + newEncoding);
252
+ }
253
+ return true;
254
+ };
255
+
256
+ channel.disposeSocket = function disposeSocket() {
257
+ // noop
258
+ };
259
+
260
+ channel.initChannel = function initChannel() {
261
+ connection.ws.send(':' + channelId);
262
+ };
263
+ // Let the server know of this new channel if we're already connected
264
+ if (connection.connected) {
265
+ channel.initChannel();
266
+ }
267
+
268
+ return channel;
269
+ }
270
+ }
@@ -0,0 +1,102 @@
1
+ 'kiwi public';
2
+
3
+ import EventEmitter from 'eventemitter3';
4
+ import getState from './state';
5
+ import * as ServerConnection from './ServerConnection';
6
+
7
+ export default class ServerSession {
8
+ constructor(sessionId) {
9
+ let channelConstruct = ServerConnection.createChannelConstructor(
10
+ getState().settings.kiwiServer,
11
+ sessionId || '',
12
+ '0'
13
+ );
14
+
15
+ this.bus = new EventEmitter();
16
+ this.channel = channelConstruct();
17
+ this.channel.on('line', (line) => {
18
+ if (line.indexOf('CONTROL ') === 0) {
19
+ let parts = line.split(' ');
20
+
21
+ // Remove the 'CONTROL' first part
22
+ parts.shift();
23
+
24
+ let command = parts.shift();
25
+ this.bus.emit(command, parts);
26
+ }
27
+ });
28
+ }
29
+
30
+ auth(userId, password) {
31
+ return new Promise((resolve, reject) => {
32
+ this.bus.once('AUTH', (params) => {
33
+ let result = params[0];
34
+
35
+ if (result === 'OK') {
36
+ resolve(true);
37
+ } else {
38
+ reject(result);
39
+ }
40
+ });
41
+
42
+ this.channel.sendControl(`CONTROL AUTH ${userId} ${password}`);
43
+ });
44
+ }
45
+
46
+ getNetworks() {
47
+ return new Promise((resolve) => {
48
+ let networks = Object.create(null);
49
+
50
+ let onListing = (params) => {
51
+ if (params[1] === 'END') {
52
+ this.bus.off('LISTING', onListing);
53
+
54
+ // Convert our networks object to an array first
55
+ let networkArr = [];
56
+ Object.keys(networks).forEach((channeId) => {
57
+ networkArr.push(networks[channeId]);
58
+ });
59
+
60
+ resolve(networkArr);
61
+ return;
62
+ }
63
+
64
+ if (params[0] === 'NETWORK') {
65
+ let props = params.slice(1);
66
+ let network = { buffers: [] };
67
+
68
+ props.forEach((prop) => {
69
+ let parts = prop.split('=');
70
+ if (parts[0] && parts[1]) {
71
+ network[parts[0].toLowerCase()] = parts[1];
72
+ }
73
+ });
74
+
75
+ if (network.channel) {
76
+ networks[network.channel] = network;
77
+ }
78
+ }
79
+
80
+ if (params[0] === 'BUFFER') {
81
+ let props = params.slice(1);
82
+ let buffer = {};
83
+
84
+ props.forEach((prop) => {
85
+ let parts = prop.split('=');
86
+ if (parts[0] && parts[1]) {
87
+ buffer[parts[0].toLowerCase()] = parts[1];
88
+ }
89
+ });
90
+
91
+ let network = networks[buffer.channel];
92
+ if (network) {
93
+ network.buffers.push(buffer);
94
+ }
95
+ }
96
+ };
97
+
98
+ this.bus.on('LISTING', onListing);
99
+ this.channel.sendControl('CONTROL LIST NETWORKS');
100
+ });
101
+ }
102
+ }