serverless-ircd 0.6.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 (247) hide show
  1. package/.github/workflows/ci.yml +6 -1
  2. package/.gitmodules +3 -0
  3. package/CHANGELOG.md +214 -0
  4. package/README.md +110 -23
  5. package/apps/aws-stack/package.json +1 -1
  6. package/apps/cf-tcp-container/package.json +1 -1
  7. package/apps/cf-worker/package.json +1 -1
  8. package/apps/cf-worker/src/origin-allowlist.ts +99 -0
  9. package/apps/cf-worker/src/worker.ts +89 -9
  10. package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
  11. package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
  12. package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
  13. package/apps/cf-worker/tests/smoke.test.ts +28 -2
  14. package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
  15. package/apps/cf-worker/wrangler.test.toml +23 -0
  16. package/apps/cf-worker/wrangler.toml +54 -0
  17. package/apps/local-cli/package.json +1 -1
  18. package/apps/web/landing/index.html +217 -0
  19. package/apps/web/package.json +28 -0
  20. package/apps/web/scripts/build.mjs +125 -0
  21. package/apps/web/src/build-env.ts +43 -0
  22. package/apps/web/src/config-schema.ts +138 -0
  23. package/apps/web/static/config.json +28 -0
  24. package/apps/web/static/config.prod.json +28 -0
  25. package/apps/web/static/config.staging.json +28 -0
  26. package/apps/web/tests/build-env.test.ts +63 -0
  27. package/apps/web/tests/build-smoke.test.ts +103 -0
  28. package/apps/web/tests/config-schema.test.ts +432 -0
  29. package/apps/web/tests/workspace.test.ts +12 -0
  30. package/apps/web/tsconfig.json +10 -0
  31. package/apps/web/upstream/.browserslistrc +3 -0
  32. package/apps/web/upstream/.editorconfig +9 -0
  33. package/apps/web/upstream/.eslintignore +3 -0
  34. package/apps/web/upstream/.eslintrc.js +90 -0
  35. package/apps/web/upstream/.github/FUNDING.yml +12 -0
  36. package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  37. package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  38. package/apps/web/upstream/.github/workflows/push.yml +26 -0
  39. package/apps/web/upstream/.github/workflows/release.yml +33 -0
  40. package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
  41. package/apps/web/upstream/.prettierrc.js +9 -0
  42. package/apps/web/upstream/.stylelintignore +5 -0
  43. package/apps/web/upstream/.stylelintrc.js +21 -0
  44. package/apps/web/upstream/LICENSE +201 -0
  45. package/apps/web/upstream/README.md +76 -0
  46. package/apps/web/upstream/babel.config.js +25 -0
  47. package/apps/web/upstream/crowdin.yml +3 -0
  48. package/apps/web/upstream/index.html +35 -0
  49. package/apps/web/upstream/jest.config.js +7 -0
  50. package/apps/web/upstream/jsdoc.json +22 -0
  51. package/apps/web/upstream/package.json +80 -0
  52. package/apps/web/upstream/scripts/pre-commit +43 -0
  53. package/apps/web/upstream/src/components/App.vue +516 -0
  54. package/apps/web/upstream/src/components/AppSettings.vue +587 -0
  55. package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
  56. package/apps/web/upstream/src/components/Avatar.vue +105 -0
  57. package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
  58. package/apps/web/upstream/src/components/BufferKey.vue +121 -0
  59. package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
  60. package/apps/web/upstream/src/components/Captcha.vue +85 -0
  61. package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
  62. package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
  63. package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
  64. package/apps/web/upstream/src/components/ChannelList.vue +345 -0
  65. package/apps/web/upstream/src/components/Container.vue +401 -0
  66. package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
  67. package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
  68. package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
  69. package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
  70. package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
  71. package/apps/web/upstream/src/components/MessageList.vue +1028 -0
  72. package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
  73. package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
  74. package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
  75. package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
  76. package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
  77. package/apps/web/upstream/src/components/Nicklist.vue +309 -0
  78. package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
  79. package/apps/web/upstream/src/components/NotConnected.vue +271 -0
  80. package/apps/web/upstream/src/components/SelfUser.vue +283 -0
  81. package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
  82. package/apps/web/upstream/src/components/ServerView.vue +126 -0
  83. package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
  84. package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
  85. package/apps/web/upstream/src/components/Sidebar.vue +429 -0
  86. package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
  87. package/apps/web/upstream/src/components/SidebarState.vue +145 -0
  88. package/apps/web/upstream/src/components/StartupError.vue +35 -0
  89. package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
  90. package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
  91. package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
  92. package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
  93. package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
  94. package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
  95. package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
  96. package/apps/web/upstream/src/components/UserBox.vue +728 -0
  97. package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
  98. package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
  99. package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
  100. package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
  101. package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
  102. package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
  103. package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
  104. package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
  105. package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
  106. package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
  107. package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
  108. package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
  109. package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
  110. package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
  111. package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
  112. package/apps/web/upstream/src/helpers/Colours.js +128 -0
  113. package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
  114. package/apps/web/upstream/src/helpers/Md5.js +193 -0
  115. package/apps/web/upstream/src/helpers/Misc.js +401 -0
  116. package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
  117. package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
  118. package/apps/web/upstream/src/libs/AudioManager.js +60 -0
  119. package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
  120. package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
  121. package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
  122. package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
  123. package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
  124. package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
  125. package/apps/web/upstream/src/libs/IPC.js +51 -0
  126. package/apps/web/upstream/src/libs/InputHandler.js +921 -0
  127. package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
  128. package/apps/web/upstream/src/libs/Logger.js +71 -0
  129. package/apps/web/upstream/src/libs/Message.js +169 -0
  130. package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
  131. package/apps/web/upstream/src/libs/MessageParser.js +249 -0
  132. package/apps/web/upstream/src/libs/Notifications.js +78 -0
  133. package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
  134. package/apps/web/upstream/src/libs/ServerSession.js +102 -0
  135. package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
  136. package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
  137. package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
  138. package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
  139. package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
  140. package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
  141. package/apps/web/upstream/src/libs/bufferTools.js +177 -0
  142. package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
  143. package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
  144. package/apps/web/upstream/src/libs/settingTools.js +31 -0
  145. package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
  146. package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
  147. package/apps/web/upstream/src/libs/state/UserState.js +89 -0
  148. package/apps/web/upstream/src/libs/state/common.js +26 -0
  149. package/apps/web/upstream/src/libs/state.js +961 -0
  150. package/apps/web/upstream/src/libs/storage/Local.js +51 -0
  151. package/apps/web/upstream/src/main.js +566 -0
  152. package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
  153. package/apps/web/upstream/src/res/configTemplates.js +373 -0
  154. package/apps/web/upstream/src/res/globalStyle.css +277 -0
  155. package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
  156. package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
  157. package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
  158. package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
  159. package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
  160. package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
  161. package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
  162. package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
  163. package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
  164. package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
  165. package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
  166. package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
  167. package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
  168. package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
  169. package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
  170. package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
  171. package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
  172. package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
  173. package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
  174. package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
  175. package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
  176. package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
  177. package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
  178. package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
  179. package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
  180. package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
  181. package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
  182. package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
  183. package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
  184. package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
  185. package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
  186. package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
  187. package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
  188. package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
  189. package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
  190. package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
  191. package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
  192. package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
  193. package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
  194. package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
  195. package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
  196. package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
  197. package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
  198. package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
  199. package/apps/web/upstream/src/res/localesList.json +27 -0
  200. package/apps/web/upstream/src/res/logo.png +0 -0
  201. package/apps/web/upstream/src/thirdparty/about.html +43 -0
  202. package/apps/web/upstream/src/thirdparty/index.js +5 -0
  203. package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
  204. package/apps/web/upstream/static/config.json +28 -0
  205. package/apps/web/upstream/static/emoticons/smile.png +0 -0
  206. package/apps/web/upstream/static/favicon.png +0 -0
  207. package/apps/web/upstream/static/highlight.mp3 +0 -0
  208. package/apps/web/upstream/static/highlight.ogg +0 -0
  209. package/apps/web/upstream/static/locales/.gitignore +2 -0
  210. package/apps/web/upstream/static/plugins/customise.html.example +10 -0
  211. package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
  212. package/apps/web/upstream/static/themes/common/base.css +1064 -0
  213. package/apps/web/upstream/static/themes/dark/theme.css +196 -0
  214. package/apps/web/upstream/static/themes/default/theme.css +92 -0
  215. package/apps/web/upstream/static/themes/elite/theme.css +248 -0
  216. package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
  217. package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
  218. package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
  219. package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
  220. package/apps/web/upstream/static/themes/sky/theme.css +107 -0
  221. package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
  222. package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
  223. package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
  224. package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
  225. package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
  226. package/apps/web/upstream/vue.config.js +150 -0
  227. package/apps/web/upstream/yarn.lock +9767 -0
  228. package/apps/web/vitest.config.ts +13 -0
  229. package/biome.json +1 -0
  230. package/docs/Home.md +1 -0
  231. package/docs/WebClientGuide.md +535 -0
  232. package/package.json +2 -2
  233. package/packages/aws-adapter/package.json +1 -1
  234. package/packages/cf-adapter/package.json +1 -1
  235. package/packages/cf-adapter/tests/cf-harness.ts +12 -1
  236. package/packages/in-memory-runtime/package.json +1 -1
  237. package/packages/irc-core/package.json +1 -1
  238. package/packages/irc-core/reports/mutation/mutation.html +342 -0
  239. package/packages/irc-core/tests/batch.test.ts +15 -0
  240. package/packages/irc-core/tests/numerics.test.ts +13 -0
  241. package/packages/irc-core/tests/parser.test.ts +109 -0
  242. package/packages/irc-server/package.json +1 -1
  243. package/packages/irc-test-support/package.json +1 -1
  244. package/packages/irc-test-support/src/scenarios.ts +24 -2
  245. package/tools/ci-hardening/package.json +1 -1
  246. package/tools/load-test/package.json +1 -1
  247. package/tools/tcp-ws-forwarder/package.json +1 -1
@@ -0,0 +1,107 @@
1
+ @import '../common/base.css';
2
+
3
+ :root {
4
+ /* Primary Variables */
5
+ --brand-primary: #78c9dc;
6
+ --brand-primary-hover: #8fd9ea;
7
+ --brand-midtone: #f1f1f1;
8
+ --brand-darktone: #969696;
9
+ --brand-default-bg: #fff;
10
+ --brand-default-fg: #22231f;
11
+
12
+ /* Warning colors */
13
+ --brand-notice: #f6c358;
14
+ --brand-warning: #fcb46e;
15
+ --brand-error: #bf5155;
16
+
17
+ /* Connection Indicator top */
18
+ --comp-workspace-before-bg: var(--brand-primary);
19
+ --comp-bg-kiwi-workspace--disconnected-after-bg: var(--brand-error);
20
+
21
+ /* Container Header */
22
+ --comp-header-bg: var(--brand-default-bg);
23
+ --comp-header-name-fg: var(--brand-default-fg);
24
+ --comp-header-option-active-fg: var(--brand-default-bg);
25
+ --comp-header-option-active-bg: var(--brand-primary);
26
+
27
+ /* StateBrowser */
28
+ --comp-statebrowser-fg: #fff;
29
+ --comp-statebrowser-bg: #4dafc5;
30
+ --comp-statebrowser-bg-networkname: #80c8d8;
31
+ --comp-statebrowser-channel-active-bg: #ffffff0d;
32
+ --comp-statebrowser-channel-active-fg: #fff;
33
+ --comp-usermenu-open-bg: #0e0e0e;
34
+ --comp-statebrowser-network-border: #656565;
35
+
36
+
37
+ /* Sidebars ( Right Side ) */
38
+ --comp-sidebar-bg: #fff;
39
+ --comp-sidebar-fg: #22231f;
40
+ --comp-aboutbuffer-bg: rgba(0, 0, 0, 0.03);
41
+ --comp-aboutbuffer-header-bg: #42b992;
42
+
43
+ /* Misc */
44
+ --brand-link-normal: var(--brand-primary);
45
+ --brand-link--hover: var(--brand-primary-hover);
46
+ --brand-shadow: rgba(0, 0, 0, 0.1);
47
+ --comp-border: #b2b2b2;
48
+ }
49
+
50
+ /* Welcome */
51
+ .kiwi-startup-common-section-info {
52
+ border-left-color: var(--brand-primary);
53
+ }
54
+
55
+ /* StateBrowser */
56
+ .kiwi-statebrowser-usermenu--open {
57
+ background-color: #5d919c;
58
+ }
59
+ .kiwi-statebrowser-network-status .u-link {
60
+ color: #fff;
61
+ }
62
+ .kiwi-network-name-options {
63
+ background-color: #7dc8d9;
64
+ }
65
+ .kiwi-statebrowser-channel-leave {
66
+ background: transparent;
67
+ }
68
+
69
+ /* Sidebar */
70
+ .kiwi-aboutbuffer h4 {
71
+ background-color: #74c9dd;
72
+ }
73
+
74
+ /* IRC Text Colours */
75
+ .irc-fg-colour-white { color: #fff; }
76
+ .irc-fg-colour-black { color: #000; }
77
+ .irc-fg-colour-blue { color: #00f; }
78
+ .irc-fg-colour-green { color: #009300; }
79
+ .irc-fg-colour-light-red { color: #ff5959; }
80
+ .irc-fg-colour-brown { color: #743a00; }
81
+ .irc-fg-colour-purple { color: #a500ff; }
82
+ .irc-fg-colour-orange { color: #ff8c00; }
83
+ .irc-fg-colour-yellow { color: #ff0; }
84
+ .irc-fg-colour-light-green { color: #6fff6f; }
85
+ .irc-fg-colour-cyan { color: #0cc; }
86
+ .irc-fg-colour-light-cyan { color: #6dffff; }
87
+ .irc-fg-colour-light-blue { color: #59b4ff; }
88
+ .irc-fg-colour-pink { color: #f0f; }
89
+ .irc-fg-colour-grey { color: #a6a6a6; }
90
+ .irc-fg-colour-light-grey { color: #e2e2e2; }
91
+
92
+ .irc-bg-colour-white { background-color: #fff; }
93
+ .irc-bg-colour-black { background-color: #000; }
94
+ .irc-bg-colour-blue { background-color: #00f; }
95
+ .irc-bg-colour-green { background-color: #009300; }
96
+ .irc-bg-colour-light-red { background-color: #ff5959; }
97
+ .irc-bg-colour-brown { background-color: #743a00; }
98
+ .irc-bg-colour-purple { background-color: #a500ff; }
99
+ .irc-bg-colour-orange { background-color: #ff8c00; }
100
+ .irc-bg-colour-yellow { background-color: #ff0; }
101
+ .irc-bg-colour-light-green { background-color: #6fff6f; }
102
+ .irc-bg-colour-cyan { background-color: #0cc; }
103
+ .irc-bg-colour-light-cyan { background-color: #6dffff; }
104
+ .irc-bg-colour-light-blue { background-color: #59b4ff; }
105
+ .irc-bg-colour-pink { background-color: #f0f; }
106
+ .irc-bg-colour-grey { background-color: #a6a6a6; }
107
+ .irc-bg-colour-light-grey { background-color: #e2e2e2; }
@@ -0,0 +1,174 @@
1
+ import batchedAdd from '@/libs/batchedAdd';
2
+
3
+ describe('batchedAdd.vue', () => {
4
+ const outOfTickItems = (batchFn, itemCount, endFn) => {
5
+ // Chain out of tick items so not to interfere
6
+ // with the timeout within batchedAdd.js
7
+ let count = 0;
8
+ const nextTimeout = () => {
9
+ count++;
10
+ if (count > itemCount) {
11
+ if (endFn) {
12
+ endFn();
13
+ }
14
+ return;
15
+ }
16
+ setTimeout(() => {
17
+ batchFn('item' + count);
18
+ nextTimeout();
19
+ }, 10);
20
+ };
21
+ nextTimeout();
22
+ };
23
+
24
+ it('should return a batching function', () => {
25
+ let batch = batchedAdd();
26
+ expect(batch).toBeInstanceOf(Function);
27
+ });
28
+
29
+ it('should expose its queue', () => {
30
+ let batch = batchedAdd();
31
+ expect(batch.queue).toBeInstanceOf(Function);
32
+ expect(batch.queue()).toEqual([]);
33
+ });
34
+
35
+ it('should process three items without a batch', (done) => {
36
+ let itemCount = 0;
37
+ let singleItem = () => {
38
+ itemCount++;
39
+ if (itemCount === 3) {
40
+ done();
41
+ }
42
+ };
43
+ let batchItems = () => {
44
+ done(new Error('batch item caught'));
45
+ };
46
+
47
+ let batch = batchedAdd(singleItem, batchItems);
48
+ batch('item1');
49
+ batch('item2');
50
+ batch('item3');
51
+ });
52
+
53
+ it('should process 100 items on the same js tick without a batch', (done) => {
54
+ let itemCount = 0;
55
+ let singleItem = () => {
56
+ itemCount++;
57
+ if (itemCount === 100) {
58
+ done();
59
+ }
60
+ };
61
+ let batchItems = () => {
62
+ done(new Error('batch item caught'));
63
+ };
64
+
65
+ let batch = batchedAdd(singleItem, batchItems);
66
+ for (let i = 0; i < 100; i++) {
67
+ batch('item' + i);
68
+ }
69
+ });
70
+
71
+ it('should process 102 single items, then a batch of 3', (done) => {
72
+ let singleCount = 0;
73
+ let singleItem = () => {
74
+ singleCount++;
75
+ };
76
+ let batchItems = (items) => {
77
+ if (singleCount !== 102) {
78
+ return done(new Error('Expected 102 single items, found ' + singleCount));
79
+ }
80
+
81
+ if (items.length === 1) {
82
+ return done(new Error('Expected 3 batched items, found ' + items.length));
83
+ }
84
+
85
+ return done();
86
+ };
87
+
88
+ let batch = batchedAdd(singleItem, batchItems);
89
+ for (let i = 0; i < 100; i++) {
90
+ batch('item' + i);
91
+ }
92
+ outOfTickItems(batch, 5);
93
+ });
94
+
95
+ it('should process a batched item after three single items on different js ticks', (done) => {
96
+ let singleCount = 0;
97
+ let singleItem = () => {
98
+ singleCount++;
99
+ if (singleCount > 3) {
100
+ done(new Error('Expected 3 single items before a batch, found ' + singleCount));
101
+ }
102
+ };
103
+ let batchItems = () => {
104
+ if (singleCount !== 3) {
105
+ done(new Error('Expected 3 single items before a batch, found ' + singleCount));
106
+ } else {
107
+ done();
108
+ }
109
+ };
110
+
111
+ let batch = batchedAdd(singleItem, batchItems);
112
+ outOfTickItems(batch, 4);
113
+ });
114
+
115
+ it('should process 3 items in a batch', (done) => {
116
+ let singleItem = (item) => {};
117
+ let batchItems = (items) => {
118
+ if (items.length !== 3) {
119
+ done(new Error(`Expected 3 items in a batch, found ${items.length}`));
120
+ } else {
121
+ done();
122
+ }
123
+ };
124
+
125
+ let batch = batchedAdd(singleItem, batchItems);
126
+ outOfTickItems(batch, 6);
127
+ });
128
+
129
+ it('should process a single item after a batch has finished', (done) => {
130
+ let singleCount = 0;
131
+ let batchCount = 0;
132
+ let singleItem = () => {
133
+ if (singleCount === 3 && batchCount === 1) {
134
+ done();
135
+ }
136
+ singleCount++;
137
+ };
138
+ let batchItems = (items) => {
139
+ if (batchCount > 0) {
140
+ done(new Error('Processing a batch more than once'));
141
+ }
142
+ batchCount++;
143
+ };
144
+
145
+ let batch = batchedAdd(singleItem, batchItems);
146
+ outOfTickItems(batch, 6, () => {
147
+ setTimeout(() => {
148
+ // Should revert back to being a single item
149
+ batch('item7');
150
+ }, 1200);
151
+ });
152
+ });
153
+
154
+ it('should process 4 single items', (done) => {
155
+ let singleCount = 0;
156
+ let singleItem = () => {
157
+ singleCount++;
158
+ if (singleCount === 4) {
159
+ done();
160
+ }
161
+ };
162
+ let batchItems = (items) => {
163
+ done(new Error('Items should not be batched'));
164
+ };
165
+
166
+ let batch = batchedAdd(singleItem, batchItems);
167
+ outOfTickItems(batch, 3, () => {
168
+ setTimeout(() => {
169
+ // Should revert back to being a single item
170
+ batch('item4');
171
+ }, 1200);
172
+ });
173
+ }, 3000);
174
+ });
@@ -0,0 +1,125 @@
1
+ import parseMessage from '@/libs/MessageParser';
2
+
3
+ describe('MessageParser.js', () => {
4
+ it('should return valid channel blocks', () => {
5
+ let tests = [
6
+ ['#channel', '#channel'],
7
+ ['#channel;', '#channel'],
8
+ ['#chan;nel', '#chan;nel'],
9
+ ['#channel.', '#channel'],
10
+ ['#chan;el;', '#chan;el'],
11
+ ['#chan[n]el,', '#chan[n]el'],
12
+ ['#channel.name,', '#channel.name'],
13
+ ['#channel.name.,', '#channel.name'],
14
+ ['#channel.,', '#channel'],
15
+ ['#channel-name,', '#channel-name'],
16
+ ['#channel_name,', '#channel_name'],
17
+ ['#channel&name,', '#channel&name'],
18
+ ['@#channel:', '#channel'],
19
+ ['@&channel,', '&channel'],
20
+ ['&@#channel,', '#channel'],
21
+ ['&@&channel,', '&channel'],
22
+ ];
23
+
24
+ tests.forEach((c) => {
25
+ let blocks = parseMessage(c[0]);
26
+ let channelBlocks = blocks.filter((b) => b.type === 'channel');
27
+
28
+ expect(channelBlocks.length).toEqual(1);
29
+ expect(channelBlocks[0].meta.channel).toEqual(c[1]);
30
+ });
31
+ });
32
+
33
+ it('should return valid url blocks', () => {
34
+ let tests = [
35
+ ['www.example.com', 'http://www.example.com'],
36
+ ['http://example.com'],
37
+ ['http://127.0.0.1'],
38
+ ['http://example.com:8080'],
39
+ ['http://127.0.0.1:8001'],
40
+ ['http://example.com/test.html?test=foo#bar'],
41
+ ['http://example.computer/some/path/test.html?test=foo#bar'],
42
+ ['http://127.0.0.1/test.html?test=foo#bar'],
43
+ ['https://www.example.com'],
44
+ ['https://127.0.0.1/test.html?test=foo#bar'],
45
+ ['http://2001:0000:1234:0000:0000:C1C0:ABCD:0876/'],
46
+ ['http://[2001:db8:1f70::999:de8:7648:6e8]:100/'],
47
+ ['ldap://[2001:db8::7]/c=GB?objectClass?one'],
48
+ ['(http://example.com)', 'http://example.com', '(', ')'],
49
+ ];
50
+
51
+ tests.forEach((c) => {
52
+ let blocks = parseMessage(c[0]);
53
+ let urlBlocks = blocks.filter((b) => b.type === 'url');
54
+ let compare = c.length >= 2 ? c[1] : c[0];
55
+
56
+ expect(urlBlocks.length).toEqual(1);
57
+ expect(urlBlocks[0].meta.url).toEqual(compare);
58
+ // check prefix and suffix
59
+ if (c.length === 4) {
60
+ expect(blocks[0].content).toEqual(c[2]);
61
+ expect(blocks[2].content).toEqual(c[3]);
62
+ }
63
+ });
64
+ });
65
+
66
+ it('should reject invalid urls', () => {
67
+ let tests = ['test', 'example.com', 'test:8080', '127.0.0.1/test.html'];
68
+
69
+ tests.forEach((c) => {
70
+ let blocks = parseMessage(c[0]);
71
+ let urlBlocks = blocks.filter((b) => b.type === 'url');
72
+ expect(urlBlocks.length).toEqual(0);
73
+ });
74
+ });
75
+
76
+ it('should return valid user blocks', () => {
77
+ // mock users list
78
+ let users = {
79
+ 'TESTNICK1': { nick: 'TestNick1', username: 'testnick1', colour: '#a1fc5d' },
80
+ 'TESTNICK2': { nick: 'TestNick2', username: 'testnick2', colour: '#7363fe' },
81
+ 'TESTNICK3': { nick: 'TestNick3', username: 'testnick3' },
82
+ 'TESTNICK4_': { nick: 'Test-Nick4_', username: 'testnick4' },
83
+ 'TEST-NICK5': { nick: 'Test-Nick5', username: 'testnick5' },
84
+ 'TESTNICK6-': { nick: 'TestNick6-', username: 'testnick6' },
85
+ };
86
+ let tests = [
87
+ ['testnick1', 'testnick1'],
88
+ ['TestNick1'],
89
+ ['TestNick2'],
90
+ ['Testnick3', 'Testnick3'],
91
+ ['testnick1:', 'testnick1'],
92
+ ['@testnick2', 'testnick2'],
93
+ ['@TestNick2:', 'TestNick2'],
94
+ ['tEsTnIcK4_.', 'tEsTnIcK4_'],
95
+ ['test-nick5'],
96
+ ['testnick6-'],
97
+ ];
98
+
99
+ tests.forEach((c) => {
100
+ let blocks = parseMessage(c[0], {}, users);
101
+ let userBlocks = blocks.filter((b) => b.type === 'user');
102
+ let compare = c.length === 2 ? c[1] : c[0];
103
+
104
+ expect(userBlocks.length).toEqual(1);
105
+ expect(userBlocks[0].meta.user).toEqual(compare);
106
+ expect(userBlocks[0].meta.colour).toEqual(users[compare.toUpperCase()].colour);
107
+ });
108
+ });
109
+
110
+ it('should reject invalid users', () => {
111
+ // mock users list
112
+ let users = {
113
+ TESTNICK1: { nick: 'TestNick1', username: 'testnick1' },
114
+ TESTNICK2: { nick: 'TestNick2', username: 'testnick2' },
115
+ };
116
+ let tests = ['notauser', 'ttestnick', 'testnick11', 'ttestnick11'];
117
+
118
+ tests.forEach((c) => {
119
+ let blocks = parseMessage(c[0], {}, users);
120
+ let userBlocks = blocks.filter((b) => b.type === 'user');
121
+
122
+ expect(userBlocks.length).toEqual(0);
123
+ });
124
+ });
125
+ });
@@ -0,0 +1,24 @@
1
+ import * as Misc from '@/helpers/Misc';
2
+
3
+ describe('Misc.js', () => {
4
+ it('should find mentions of nickname in text', () => {
5
+ let tests = [
6
+ ['foo', 'foo', true], // on its own
7
+ ['Foo', 'foo', true], // different case
8
+ ['foo bar baz', 'foo', true], // start of line
9
+ ['baz foo bar', 'foo', true], // in middle of line
10
+ ['bar baz foo', 'foo', true], // end of line
11
+ ['missing', 'foo', false], // doesnt exist in text
12
+ ['baz food bar', 'foo', false], // dont trigger on substrings
13
+ ['hello food foo bar', 'foo', true], // when substring exists previously
14
+ ['hello, foo?', 'foo', true], // punctuation test
15
+ ['foo: hello', 'foo', true], // another
16
+ ['hello (foo)', 'foo', true], // another
17
+ ];
18
+
19
+ tests.forEach((c) => {
20
+ let doesMention = Misc.mentionsNick(c[0], c[1]);
21
+ expect(doesMention).toEqual(c[2]);
22
+ });
23
+ });
24
+ });
@@ -0,0 +1,58 @@
1
+ import state from '@/libs/state';
2
+ import NetworkState from '@/libs/state/NetworkState';
3
+
4
+ describe('NetworkState', () => {
5
+ it('should return a network state object', () => {
6
+ let s = state.create();
7
+ let network = s.addNetwork('TestNetwork', 'TestNick', {});
8
+ expect(network).toBeInstanceOf(NetworkState);
9
+ expect(network.name).toBe('TestNetwork');
10
+ expect(network.connection.nick).toBe('TestNick');
11
+ expect(network.appState).toBe(s);
12
+ });
13
+
14
+ it('should add a NetworkState to the global state', () => {
15
+ let s = state.create();
16
+ let network = s.addNetwork('TestNetwork', 'TestNick', {
17
+ server: 'irc.irc.com',
18
+ });
19
+ expect(s.networks.length).toEqual(1);
20
+ expect(s.networks[0]).toEqual(network);
21
+ });
22
+
23
+ it('should retrieve a NetworkState from the global state', () => {
24
+ let s = state.create();
25
+ let network = s.addNetwork('TestNetwork', 'TestNick', {
26
+ server: 'irc.irc.com',
27
+ });
28
+ expect(s.getNetwork(network.id)).toEqual(network);
29
+ expect(s.getNetworkFromAddress('irc.irc.com')).toEqual(network);
30
+ expect(s.getNetworkFromAddress('definitely.not.irc.irc.com')).toEqual(undefined);
31
+ });
32
+
33
+ it('automatically has a server buffer', () => {
34
+ let s = state.create();
35
+ let network = s.addNetwork('TestNetwork', 'TestNick', {});
36
+ expect(s.networks[0].buffers.length).toEqual(1);
37
+ expect(s.networks[0].buffers[0]).toEqual(network.serverBuffer());
38
+ expect(network.bufferByName('*')).toEqual(network.serverBuffer());
39
+ });
40
+
41
+ it('correctly adds buffers', () => {
42
+ let s = state.create();
43
+ let network = s.addNetwork('TestNetwork', 'TestNick', {});
44
+ let buffer = s.addBuffer(network.id, '#channel');
45
+ expect(s.networks[0].buffers.length).toEqual(2);
46
+ expect(network.buffers.length).toEqual(2);
47
+ expect(network.bufferByName('#channel')).toEqual(buffer);
48
+ });
49
+
50
+ it('correctly stores local network settings', () => {
51
+ let s = state.create();
52
+ let network = s.addNetwork('TestNetwork', 'TestNick', {});
53
+ expect(network.setting('setting_key')).toEqual(undefined);
54
+
55
+ network.setting('setting_key', 'some value');
56
+ expect(network.setting('setting_key')).toEqual('some value');
57
+ });
58
+ });
@@ -0,0 +1,20 @@
1
+ import Vue from 'vue';
2
+ import StartupError from '@/components/StartupError';
3
+
4
+ Vue.mixin({
5
+ computed: {
6
+ $t() {
7
+ return (key, options) => key;
8
+ },
9
+ },
10
+ });
11
+
12
+ describe('StartupError.vue', () => {
13
+ it('should render correct contents', () => {
14
+ const vm = new Vue({
15
+ el: document.createElement('div'),
16
+ render: (h) => h(StartupError, { props: { error: 'some error' } }),
17
+ });
18
+ expect(vm.$el.querySelector('div').textContent).toEqual('some error');
19
+ });
20
+ });
@@ -0,0 +1,150 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const execSync = require('child_process').execSync;
4
+ const DefinePlugin = require('webpack').DefinePlugin;
5
+ const ProvidePlugin = require('webpack').ProvidePlugin;
6
+ const CopyWebpackPlugin = require('copy-webpack-plugin');
7
+ const StyleLintPlugin = require('stylelint-webpack-plugin');
8
+ const ConvertLocalesPlugin = require('./build/webpack/convert-locales');
9
+ const pkg = require('./package.json');
10
+
11
+ const makeSourceMap = process.argv.indexOf('--nomap') === -1;
12
+
13
+ module.exports = {
14
+ publicPath: '',
15
+ assetsDir: 'static/',
16
+ runtimeCompiler: true,
17
+ transpileDependencies: ['irc-framework', 'ip-regex', 'isomorphic-textencoder'],
18
+ productionSourceMap: makeSourceMap,
19
+ css: {
20
+ sourceMap: makeSourceMap,
21
+ },
22
+ configureWebpack: {
23
+ resolve: {
24
+ extensions: ['.js', '.vue', '.json'],
25
+ alias: {
26
+ vue$: 'vue/dist/vue.common.js',
27
+ },
28
+ fallback: {
29
+ stream: require.resolve('stream-browserify'),
30
+ },
31
+ // This prevents yarn link modules from getting linted
32
+ symlinks: false,
33
+ },
34
+ performance: {
35
+ maxEntrypointSize: 1677722, // 1.6MiB
36
+ maxAssetSize: 1048576, // 1MiB
37
+ },
38
+ optimization: {
39
+ splitChunks: {
40
+ cacheGroups: {
41
+ // replace the vendors test so it does not chunk css files
42
+ vendors: {
43
+ name: 'vendor',
44
+ test: (m) => /[\\/]node_modules[\\/]/.test(m.context) && m.constructor.name !== 'CssModule',
45
+ },
46
+ },
47
+ },
48
+ },
49
+ plugins: [
50
+ new DefinePlugin({
51
+ __VERSION__: JSON.stringify(pkg.version),
52
+ __COMMITHASH__: JSON.stringify(getCommitHash()),
53
+ }),
54
+ new ProvidePlugin({
55
+ Buffer: ['buffer', 'Buffer'],
56
+ }),
57
+ new StyleLintPlugin({
58
+ files: ['src/**/*.{vue,htm,html,css,sss,less,scss}'],
59
+ }),
60
+ new ConvertLocalesPlugin(),
61
+ new CopyWebpackPlugin({
62
+ patterns: [
63
+ {
64
+ from: path.join(__dirname, 'static/'),
65
+ to: path.join(__dirname, 'dist/static/'),
66
+ toType: 'dir',
67
+ globOptions: {
68
+ ignore: ['**/.*', '**/config.local.json'],
69
+ },
70
+ info: { minimized: true },
71
+ },
72
+ ],
73
+ }),
74
+ ],
75
+ },
76
+ chainWebpack: (config) => {
77
+ config.plugin('html').tap((args) => {
78
+ args[0].template = path.join(__dirname, 'index.html');
79
+ args[0].minify = false;
80
+ return args;
81
+ });
82
+
83
+ // add build/ to resolveLoader for exports-loader
84
+ config.resolveLoader.modules.add(path.resolve(__dirname, 'build/webpack/'));
85
+
86
+ // add exports-loader for GobalApi
87
+ const vueRule = config.module.rule('vue');
88
+ const vueOptions = vueRule.uses.get('vue-loader').get('options');
89
+ vueRule.uses.clear();
90
+ vueRule.use('exports-loader').loader('exports-loader');
91
+ vueRule.use('vue-loader').loader('vue-loader').options(vueOptions);
92
+
93
+ const jsRule = config.module.rule('js');
94
+ jsRule.uses.clear();
95
+ jsRule.use('exports-loader').loader('exports-loader');
96
+ jsRule.use('babel-loader').loader('babel-loader');
97
+
98
+ config.module
99
+ .rule('html')
100
+ .test(/\.html$/)
101
+ .exclude.add(path.join(__dirname, 'index.html')).end()
102
+ .use('html-loader')
103
+ .loader('html-loader');
104
+
105
+ // Remove the old 'app' entry
106
+ config.entryPoints.delete('app');
107
+
108
+ // IE11 required by the webpack runtime for async import().
109
+ // babel polyfills don't help us here
110
+ config.entry('app').add('core-js/features/promise');
111
+
112
+ // IE11 play nice with vue-virtual-scroller
113
+ config.entry('app').add('core-js/features/array/virtual/find-index');
114
+ config.entry('app').add('core-js/features/array/virtual/includes');
115
+
116
+ // Kiwiirc main entry point
117
+ config.entry('app').add('./src/main.js');
118
+ },
119
+ };
120
+
121
+ // override config.json with config.local.json if it exists
122
+ if (process.env.NODE_ENV === 'development') {
123
+ let plugins = module.exports.configureWebpack.plugins;
124
+ let localConfig = path.resolve(__dirname, 'static/config.local.json');
125
+ if (fs.existsSync(localConfig)) {
126
+ plugins.push(new CopyWebpackPlugin({
127
+ patterns: [
128
+ {
129
+ from: localConfig,
130
+ to: path.join(__dirname, 'dist/static/config.json'),
131
+ force: true,
132
+ },
133
+ ],
134
+ }));
135
+ }
136
+ }
137
+
138
+ function getCommitHash() {
139
+ let commitHash = 'unknown';
140
+ try {
141
+ commitHash = execSync('git rev-parse --short HEAD').toString().trim();
142
+ const modified = execSync('git diff-index --quiet HEAD -- || echo true').toString();
143
+ if (modified.trim() === 'true') {
144
+ commitHash += '-modified';
145
+ }
146
+ } catch {
147
+ console.error('Failed to get commit hash');
148
+ }
149
+ return commitHash;
150
+ }