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,94 @@
1
+ 'kiwi public';
2
+
3
+ import xhr from 'xhr';
4
+ import _ from 'lodash';
5
+ import JSON5 from 'json5';
6
+ import Logger from './Logger';
7
+
8
+ let log = Logger.namespace('ConfigLoader');
9
+
10
+ export default class ConfigLoader {
11
+ constructor() {
12
+ this.config = Object.create(null);
13
+ this.valReplacements = Object.create(null);
14
+ }
15
+
16
+ addValueReplacement(key, value) {
17
+ this.valReplacements[key] = value;
18
+ return this;
19
+ }
20
+
21
+ loadFromUrl(configUrl) {
22
+ return new Promise((resolve, reject) => {
23
+ xhr({ url: configUrl }, (err, response) => {
24
+ if (err) {
25
+ reject();
26
+ return;
27
+ }
28
+
29
+ let configObj = null;
30
+ try {
31
+ configObj = JSON5.parse(response.body);
32
+ } catch (parseErr) {
33
+ log.error('Config ' + parseErr.message);
34
+ let errMsg = 'Config file error: ' + parseErr.message.replace('JSON5: ', '');
35
+ // Convert "at 22:16" to "at line 22, position 16"
36
+ /* eslint-disable arrow-body-style */
37
+ errMsg = errMsg.replace(/at (\d+):(\d+)/g, (m, m1, m2) => {
38
+ return `line ${m1}, position ${m2}`;
39
+ });
40
+ reject(errMsg);
41
+ return;
42
+ }
43
+
44
+ this.setConfig(configObj);
45
+ resolve(this.config);
46
+ });
47
+ });
48
+ }
49
+
50
+ loadFromObj(configObj) {
51
+ return new Promise((resolve, reject) => {
52
+ this.setConfig(configObj);
53
+ resolve(this.config);
54
+ });
55
+ }
56
+
57
+ setConfig(confObj) {
58
+ let walkObject = (obj, target) => {
59
+ _.each(obj, (_val, key) => {
60
+ let val = _val;
61
+ if (typeof val === 'string') {
62
+ val = this.insertReplacements(val);
63
+ target[key] = val;
64
+ } else if (typeof val === 'object') {
65
+ target[key] = _.isArray(val) ?
66
+ [] :
67
+ {};
68
+ walkObject(val, target[key]);
69
+ } else {
70
+ target[key] = val;
71
+ }
72
+ });
73
+ };
74
+
75
+ this.config = Object.create(null);
76
+ walkObject(confObj, this.config);
77
+ }
78
+
79
+ insertReplacements(input) {
80
+ let out = input;
81
+ let keys = Object.keys(this.valReplacements);
82
+ for (let i = 0; i < keys.length; i++) {
83
+ let k = keys[i];
84
+ if (input === '{{' + k + '}}') {
85
+ // If we have an exact match, return the exact replacement value we have as
86
+ // it may not be a string
87
+ return this.valReplacements[k];
88
+ }
89
+
90
+ out = out.replace('{{' + k + '}}', this.valReplacements[k]);
91
+ }
92
+ return out;
93
+ }
94
+ }
@@ -0,0 +1,46 @@
1
+ 'kiwi public';
2
+
3
+ import { escape } from 'lodash';
4
+ import getState from '@/libs/state';
5
+
6
+ export function matchEmoji(word) {
7
+ const emojis = this.getEmojis(word);
8
+ if (!emojis.length) {
9
+ return false;
10
+ }
11
+ return [{
12
+ index: 0,
13
+ match: word,
14
+ type: 'emoji',
15
+ meta: {
16
+ emoji: emojis[0].code,
17
+ },
18
+ }];
19
+ }
20
+
21
+ export function blockToHtml(block, isSingle, showEmoticons) {
22
+ if (!showEmoticons) {
23
+ return block.content;
24
+ }
25
+
26
+ const emojiLocation = getState().setting('emojiLocation');
27
+ const emoji = block.meta.emoji;
28
+ const classes = 'kiwi-messagelist-emoji' + (isSingle ? ' kiwi-messagelist-emoji--single' : '');
29
+ const src = `${emojiLocation}${emoji}`;
30
+
31
+ return `<img class="${classes}" src="${src}" alt="${escape(block.content)}" title="${escape(block.content)}" />`;
32
+ }
33
+
34
+ export function getEmojis(word) {
35
+ const emojiList = getState().setting('emojis');
36
+ const emojiLocation = getState().setting('emojiLocation');
37
+ if (!emojiList.hasOwnProperty(word)) {
38
+ return [];
39
+ }
40
+ return [{
41
+ ascii: word,
42
+ code: emojiList[word],
43
+ url: emojiLocation + emojiList[word],
44
+ // imgProps allows setting properties of <img>
45
+ }];
46
+ }
@@ -0,0 +1,346 @@
1
+ 'kiwi public';
2
+
3
+ /** @module */
4
+
5
+ import EventEmitter from 'eventemitter3';
6
+ import Vue from 'vue';
7
+ import JSON5 from 'json5';
8
+ import _ from 'lodash';
9
+ import { compareVersions } from 'compare-versions';
10
+ import * as Misc from '@/helpers/Misc';
11
+ import Logger from './Logger';
12
+
13
+ let singletonInstance = null;
14
+ let pluginsToInit = [];
15
+ let nextPluginId = 0;
16
+
17
+ /** The global kiwi API instance */
18
+ export default class GlobalApi extends EventEmitter {
19
+ constructor() {
20
+ super();
21
+
22
+ // Version information from DefinePlugin in vue.config.js
23
+ this.version = __VERSION__; // eslint-disable-line no-undef
24
+ this.commithash = __COMMITHASH__; // eslint-disable-line no-undef
25
+
26
+ /** A reference to the internal Vuejs instance */
27
+ this.Vue = Vue;
28
+ /** Expose JSON5 so that plugins can use the same config format */
29
+ this.JSON5 = JSON5;
30
+ /** The applications internal state */
31
+ this.state = null;
32
+ /** The applications ThemeManager */
33
+ this.themes = null;
34
+ /** Translations library */
35
+ this.i18n = null;
36
+ this.vueI18n = null;
37
+ this.translationUrls = Object.create(null);
38
+
39
+ this.controlInputPlugins = [];
40
+ this.stateBrowserPlugins = [];
41
+ this.channelHeaderPlugins = [];
42
+ this.queryHeaderPlugins = [];
43
+ this.sideBarPlugins = [];
44
+ this.userboxButtonPlugins = [];
45
+ this.userboxInfoPlugins = [];
46
+ this.userboxWhoisPlugins = [];
47
+ this.appSettingsPlugins = [];
48
+ this.serverViewPlugins = [];
49
+ this.aboutBufferPlugins = [];
50
+ this.tabs = Object.create(null);
51
+ this.isReady = false;
52
+ /* eslint-disable no-underscore-dangle */
53
+ this.exports = window._kiwi_exports || {};
54
+
55
+ this.on('init', () => {
56
+ this.isReady = true;
57
+ this.initPlugins();
58
+ });
59
+ }
60
+
61
+ static singleton() {
62
+ singletonInstance = singletonInstance || new GlobalApi();
63
+ return singletonInstance;
64
+ }
65
+
66
+ versionMatches(v) {
67
+ return compareVersions(this.version, v) >= 0;
68
+ }
69
+
70
+ /**
71
+ * Register a plugin with kiwi
72
+ *
73
+ * Plugins being loaded at startup will be registered once Kiwi is ready. At any
74
+ * other point the plugin will be registered instantly
75
+ * @param {String} pluginName The name of this plugin
76
+ * @param {Function} fn A callback function to start the plugin. function(kiwi, logger)
77
+ */
78
+ plugin(pluginName, fn) {
79
+ let plugin = { name: pluginName, fn: fn };
80
+ if (this.isReady) {
81
+ this.initPlugin(plugin);
82
+ } else {
83
+ pluginsToInit.push(plugin);
84
+ }
85
+ }
86
+
87
+ // Init any plugins that were added before we were ready
88
+ initPlugins() {
89
+ pluginsToInit.forEach((plugin) => this.initPlugin(plugin));
90
+ pluginsToInit = [];
91
+ }
92
+
93
+ initPlugin(plugin) {
94
+ let pluginLogger = Logger.namespace(`Plugin ${plugin.name}`);
95
+ try {
96
+ plugin.fn(this, pluginLogger);
97
+ this.state.$emit('plugin.loaded', { name: plugin.name });
98
+ } catch (err) {
99
+ pluginLogger.error(err.stack);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Get a reference to an internal Kiwi module
105
+ *
106
+ * E.g. require('helpers/TextFormatting');
107
+ * @param {String} mod The module path
108
+ */
109
+ require(modPath) {
110
+ let path = modPath.replace(/\//g, '.');
111
+ let mod = _.get(this.exports, path);
112
+ if (typeof mod === 'undefined') {
113
+ Logger.error('Module does not exist: ' + modPath);
114
+ }
115
+
116
+ return mod;
117
+ }
118
+
119
+ setState(state) {
120
+ this.state = state;
121
+
122
+ // Hacky, but since Vues emitter doesnt support 'all', hijack its $emit call
123
+ // so that we can forward the event on to plugins
124
+ let stateEmit = this.state.$emit;
125
+ let thisEmit = this.emit;
126
+
127
+ this.state.$emit = (...args) => {
128
+ try {
129
+ thisEmit.call(this, 'all', args[0], ...args.slice(1));
130
+ thisEmit.call(this, ...args);
131
+ } catch (err) {
132
+ Logger.error(err.stack);
133
+ }
134
+
135
+ return stateEmit.call(this.state, ...args);
136
+ };
137
+
138
+ // Let plugins emit events into the internal state
139
+ this.emit = (...args) => {
140
+ stateEmit.call(this.state, ...args);
141
+ thisEmit.call(this, ...args);
142
+ };
143
+ }
144
+
145
+ setThemeManager(themeManager) {
146
+ this.themes = themeManager;
147
+ }
148
+
149
+ /**
150
+ * Change the logging level output
151
+ * @param {number} newLevel The new logging level
152
+ */
153
+ logLevel(newLevel) {
154
+ Logger.setLevel(newLevel);
155
+ }
156
+
157
+ get log() {
158
+ return Logger;
159
+ }
160
+
161
+ /**
162
+ * Add a DOM element to different parts of the Kiwi UI
163
+ * - addUi('input', componentObject)
164
+ * - addUi('browser', componentObject)
165
+ * - addUi('header_channel', componentObject)
166
+ * - addUi('header_query', componentObject)
167
+ * - addUi('userbox_button', componentObject)
168
+ * - addUi('about_buffer', componentObject)
169
+ * @param {string} type Where this component should be added
170
+ * @param {object} component The vue.js component object
171
+ * @param {object} args Optional arguments for this plugin { title: '', props: {} }
172
+ */
173
+ addUi(type, component, args = {}) {
174
+ const plugin = Misc.makePluginObject(nextPluginId++, component, args);
175
+
176
+ switch (type) {
177
+ case 'input':
178
+ this.controlInputPlugins.push(plugin);
179
+ break;
180
+ case 'browser':
181
+ this.stateBrowserPlugins.push(plugin);
182
+ break;
183
+ case 'header_channel':
184
+ this.channelHeaderPlugins.push(plugin);
185
+ break;
186
+ case 'header_query':
187
+ this.queryHeaderPlugins.push(plugin);
188
+ break;
189
+ case 'userbox_button':
190
+ this.userboxButtonPlugins.push(plugin);
191
+ break;
192
+ case 'userbox_info':
193
+ this.userboxInfoPlugins.push(plugin);
194
+ break;
195
+ case 'userbox_whois':
196
+ this.userboxWhoisPlugins.push(plugin);
197
+ break;
198
+ case 'about_buffer':
199
+ this.aboutBufferPlugins.push(plugin);
200
+ break;
201
+ default:
202
+ break;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Add a Vue component as a tab to different tabbed views in the Kiwi API
208
+ * - addTab('channel', 'title', component, props)
209
+ * - addTab('settings', 'title', component, props)
210
+ * - addTab('server', 'title', component, props)
211
+ * @param {String} type The type of tab to add. This determines where it will be shown
212
+ * @param {String} title The title shown on the tab
213
+ * @param {Object} component The vue.js component object that is displayed in this tab
214
+ * @param {Object} props Optional properties for the vue.js component
215
+ */
216
+ addTab(type, title, component, props) {
217
+ const plugin = Misc.makePluginObject(nextPluginId++, component, { props, title });
218
+
219
+ switch (type) {
220
+ case 'channel':
221
+ this.sideBarPlugins.push(plugin);
222
+ break;
223
+ case 'settings':
224
+ this.appSettingsPlugins.push(plugin);
225
+ break;
226
+ case 'server':
227
+ this.serverViewPlugins.push(plugin);
228
+ break;
229
+ default:
230
+ break;
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Register a Vue component that may be shown in future. It is shown over the entire
236
+ * client alongside the StateBrowser
237
+ * @param {String} name A name to reference this view in future
238
+ * @param {Object} component The vue.js component object to create the view
239
+ * @param {Object} props Optional properties the the vue.js component
240
+ */
241
+ addView(name, component, props) {
242
+ const plugin = Misc.makePluginObject(nextPluginId++, component, { props });
243
+ this.tabs[name] = plugin;
244
+ }
245
+
246
+ /**
247
+ * Show a previously registered view
248
+ * @param {String} name The name of previously registered view to show
249
+ */
250
+ showView(name) {
251
+ // null disables any active component and reverts the UI back to the buffers
252
+ let tab = this.tabs[name];
253
+ if (tab) {
254
+ this.state.$emit('active.component', tab.component, tab.props);
255
+ } else {
256
+ this.state.$emit('active.component', null);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Show a Vue.js component in the sidebar
262
+ * @param {Object} component The vue.js component object to render
263
+ * @param {Object} props Optional properties for the vue.js component
264
+ */
265
+ showInSidebar(component, props) {
266
+ const plugin = Misc.makePluginObject(0, component, { props });
267
+ this.state.$emit('sidebar.component', plugin.component, plugin.props);
268
+ }
269
+
270
+ /**
271
+ * Add a custom startup screen that may be loaded by the configuration file
272
+ * @param {String} name The name of this startup screen
273
+ * @param {Object} component The vue.js component object
274
+ */
275
+ addStartup(name, component) {
276
+ const plugin = Misc.makePluginObject(0, component);
277
+ let startups = this.state.getStartups();
278
+ startups[name] = plugin.component;
279
+ }
280
+
281
+ /**
282
+ * Replace an existing kiwiirc component/module with a custom one
283
+ * @param {String} dest The module path to replace
284
+ * @param {Object} source The new module to insert in place
285
+ */
286
+ replaceModule(dest, source) {
287
+ let mod = this.require(dest);
288
+ if (!mod) {
289
+ throw new Error(`The module ${dest} does not exist`);
290
+ }
291
+
292
+ Misc.replaceObjectProps(mod, source);
293
+ }
294
+
295
+ /**
296
+ * Add default config params for a plugin
297
+ * @param {String} namespace Base config location eg: 'plugin-conference'
298
+ * @param {Object} defaultConfig Configuration object
299
+ */
300
+ setConfigDefaults(namespace, defaultConfig) {
301
+ let base = `settings.${namespace}`;
302
+ let getSetting = (key) => this.state.getSetting(`${base}.${key}`);
303
+ let setSetting = (key, value) => this.state.setSetting(`${base}.${key}`, value);
304
+ let walkConfig = (obj, _target) => {
305
+ _.each(obj, (val, key) => {
306
+ let target = [..._target, key];
307
+ let targetName = target.join('.');
308
+ if (typeof val === 'object' && !_.isArray(val)) {
309
+ walkConfig(val, target);
310
+ } else if (typeof getSetting(targetName) === 'undefined') {
311
+ setSetting(targetName, val);
312
+ }
313
+ });
314
+ };
315
+ walkConfig(defaultConfig, []);
316
+ }
317
+
318
+ /**
319
+ * Add translations for use in a plugin
320
+ * @param {String} namespace Translations namespace eg: 'plugin-conference'
321
+ * @param {Object} translations Translations object
322
+ */
323
+ addTranslations(namespace, translations) {
324
+ Object.entries(translations).forEach(([lang, data]) => {
325
+ this.i18n.addResourceBundle(lang, namespace, data);
326
+ });
327
+ }
328
+
329
+ /**
330
+ * Add url path to translation files
331
+ * @param {String} namespace Translations namespace eg: 'plugin-conference'
332
+ * @param {String} url Translations url path, supported replacements: {{lng}} {{ns}}
333
+ * @param {Object} fallbackLocale Optional fallback 'en-us' locale data from bundle
334
+ */
335
+ addTranslationFiles(namespace, url, fallbackLocale) {
336
+ if (!url.includes('{{lng}}')) {
337
+ this.log.error('A plugin tried to addTranslationsFiles() without {{lng}} in the url');
338
+ return;
339
+ }
340
+ this.translationUrls[namespace] = url;
341
+ if (fallbackLocale) {
342
+ this.i18n.addResourceBundle('en-us', namespace, fallbackLocale);
343
+ }
344
+ this.i18n.loadNamespaces(namespace);
345
+ }
346
+ }
@@ -0,0 +1,51 @@
1
+ 'kiwi public';
2
+
3
+ import EventEmitter from 'eventemitter3';
4
+
5
+ class IpcBroadcastChannel extends EventEmitter {
6
+ init() {
7
+ try {
8
+ // Privacy settings in firefox 104~ block broadcast channels in iframes
9
+ this.bc = new BroadcastChannel('kiwi-ipc');
10
+ this.bc.onmessage = this.onmessage.bind(this);
11
+ } catch {
12
+ // catch
13
+ }
14
+ }
15
+
16
+ send(msg) {
17
+ if (this.bc) {
18
+ this.bc.postMessage(msg);
19
+ }
20
+ }
21
+
22
+ onmessage(msg) {
23
+ this.emit('message', msg);
24
+ }
25
+ }
26
+
27
+ class IpcLocalStorage extends EventEmitter {
28
+ init() {
29
+ window.addEventListener('storage', this.onmessage.bind(this));
30
+ }
31
+
32
+ send(msg) {
33
+ localStorage.setItem('kiwi-ipc', JSON.stringify(msg));
34
+ localStorage.removeItem('kiwi-ipc');
35
+ }
36
+
37
+ onmessage(msg) {
38
+ if (msg.key === 'kiwi-ipc' && msg.newValue) {
39
+ try {
40
+ let parsedMsg = {
41
+ data: JSON.parse(msg.newValue),
42
+ };
43
+ this.emit('message', parsedMsg);
44
+ } catch (e) {
45
+ this.emit('error');
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ export default (window.BroadcastChannel ? new IpcBroadcastChannel() : new IpcLocalStorage());