diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index 196e40eb..4cfb32de 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -112,7 +112,6 @@ class Chat { // The websocket connection, emits events from the chat server this.source = new ChatSource(); - this.source.on('REFRESH', () => window.location.reload(false)); this.source.on('PING', (data) => this.source.send('PONG', data)); this.source.on('CONNECTING', (data) => this.onCONNECTING(data)); this.source.on('ME', (data) => this.onME(data)); @@ -140,6 +139,7 @@ class Chat { this.source.on('GIFTSUB', (data) => this.onGIFTSUB(data)); this.source.on('MASSGIFT', (data) => this.onMASSGIFT(data)); this.source.on('DONATION', (data) => this.onDONATION(data)); + this.source.on('UPDATEUSER', (data) => this.onUPDATEUSER(data)); this.source.on('ADDPHRASE', (data) => this.onADDPHRASE(data)); this.source.on('REMOVEPHRASE', (data) => this.onREMOVEPHRASE(data)); @@ -973,13 +973,19 @@ class Chat { onDISPATCH({ data }) { if (data && typeof data === 'object') { let users = []; - const now = Date.now(); - if (Object.hasOwn(data, 'nick')) users.push(this.addUser(data)); - if (Object.hasOwn(data, 'users')) - users = users.concat( - Array.from(data.users).map((d) => this.addUser(d)) - ); - users.forEach((u) => this.autocomplete.add(u.nick, false, now)); + if (data.users) { + users = users.concat(data.users.map((d) => this.addUser(d))); + } + if (data.user) { + users.push(this.addUser(data.user)); + } else if (data.nick) { + users.push(this.addUser(data)); + } + // For sub recipients in `GIFTSUB` events. + if (data.recipient) { + users.push(this.addUser(data.recipient)); + } + users.forEach((u) => this.autocomplete.add(u.nick, false, Date.now())); } } @@ -1241,46 +1247,19 @@ class Chat { } onSUBSCRIPTION(data) { - const user = this.users.get(data.nick) ?? new ChatUser(data.nick); - MessageBuilder.subscription( - data.data, - user, - data.tier, - data.tierlabel, - data.streak, - data.timestamp - ).into(this); + MessageBuilder.subscription(data).into(this); } onGIFTSUB(data) { - const user = this.users.get(data.nick) ?? new ChatUser(data.nick); - MessageBuilder.gift( - data.data, - user, - data.tier, - data.tierlabel, - data.giftee, - data.timestamp - ).into(this); + MessageBuilder.gift(data).into(this); } onMASSGIFT(data) { - const user = this.users.get(data.nick) ?? new ChatUser(data.nick); - MessageBuilder.massgift( - data.data, - user, - data.tier, - data.tierlabel, - data.quantity, - data.timestamp - ).into(this); + MessageBuilder.massgift(data).into(this); } onDONATION(data) { - const user = this.users.get(data.nick) ?? new ChatUser(data.nick); - MessageBuilder.donation(data.data, user, data.amount, data.timestamp).into( - this - ); + MessageBuilder.donation(data).into(this); } onADDPHRASE(data) { @@ -1440,6 +1419,12 @@ class Chat { } } + onUPDATEUSER(data) { + if (this.user?.id === data.id) { + this.setUser(data); + } + } + cmdSHOWPOLL() { if (this.chatpoll.poll) { this.chatpoll.show(); diff --git a/assets/chat/js/formatters.test.js b/assets/chat/js/formatters/AmazonAssociatesTagInjector.test.js similarity index 97% rename from assets/chat/js/formatters.test.js rename to assets/chat/js/formatters/AmazonAssociatesTagInjector.test.js index ef7abaa1..1ab908df 100644 --- a/assets/chat/js/formatters.test.js +++ b/assets/chat/js/formatters/AmazonAssociatesTagInjector.test.js @@ -1,4 +1,4 @@ -import { AmazonAssociatesTagInjector } from './formatters'; +import AmazonAssociatesTagInjector from './AmazonAssociatesTagInjector'; const chatStub = { config: { diff --git a/assets/chat/js/formatters/UrlFormatter.js b/assets/chat/js/formatters/UrlFormatter.js index 4809a5c9..b897f972 100644 --- a/assets/chat/js/formatters/UrlFormatter.js +++ b/assets/chat/js/formatters/UrlFormatter.js @@ -71,16 +71,31 @@ export default class UrlFormatter { const m = decodedUrl.match(self.linkregex); if (m) { const encodedUrl = self.encodeUrl(m[0]); + const normalizedUrl = this.normalizeUrl(encodedUrl); const maxUrlLength = 90; - let urlText = encodedUrl; + let urlText = normalizedUrl; if (urlText.length > maxUrlLength) { urlText = `${urlText.slice(0, 40)}...${urlText.slice(-40)}`; } const extra = self.encodeUrl(decodedUrl.substring(m[0].length)); - const href = `${scheme ? '' : 'http://'}${encodedUrl}`; + const href = `${scheme ? '' : 'http://'}${normalizedUrl}`; return `${urlText}${extra}`; } return url; }); } + + /** + * @param {string} url + * @return {string} The normalized URL. + */ + normalizeUrl(url) { + if (/(x|twitter)\.com\/\w{1,15}\/status\/\d{2,19}\?/i.test(url)) { + // Remove the query string from xeet URLs to protect users from clicking + // on a link to a xeet they've already seen. + return url.split('?')[0]; + } + + return url; + } } diff --git a/assets/chat/js/formatters/UrlFormatter.test.js b/assets/chat/js/formatters/UrlFormatter.test.js new file mode 100644 index 00000000..de1bdfea --- /dev/null +++ b/assets/chat/js/formatters/UrlFormatter.test.js @@ -0,0 +1,29 @@ +import UrlFormatter from './UrlFormatter'; + +const urlFormatter = new UrlFormatter(); + +describe('Normalizing URLs', () => { + test('Remove the query string from a tweet URL', () => { + expect( + urlFormatter.normalizeUrl('https://twitter.com/jack/status/20?lang=en') + ).toBe('https://twitter.com/jack/status/20'); + }); + + test('Remove the query string from a xeet URL', () => { + expect( + urlFormatter.normalizeUrl('https://x.com/jack/status/20?lang=en') + ).toBe('https://x.com/jack/status/20'); + }); + + test("Don't modify a URL to a tweet that doesn't contain a query string", () => { + expect(urlFormatter.normalizeUrl('https://x.com/jack/status/20')).toBe( + 'https://x.com/jack/status/20' + ); + }); + + test("Don't modify a URL that isn't Twitter or X", () => { + expect( + urlFormatter.normalizeUrl('https://www.twitch.tv/search?term=vtuber') + ).toBe('https://www.twitch.tv/search?term=vtuber'); + }); +}); diff --git a/assets/chat/js/menus/ChatUserInfoMenu.js b/assets/chat/js/menus/ChatUserInfoMenu.js index e1ac2137..48b23986 100644 --- a/assets/chat/js/menus/ChatUserInfoMenu.js +++ b/assets/chat/js/menus/ChatUserInfoMenu.js @@ -38,7 +38,10 @@ export default class ChatUserInfoMenu extends ChatMenuFloating { this.configureButtons(); this.chat.output.on('contextmenu', '.msg-chat .user', (e) => { + // If the target has this class, it's a sub tier label styled to match the + // username color of the sub (which requires the `user` class). if (e.currentTarget.classList.contains('tier')) return false; + const message = $(e.currentTarget).closest('.msg-chat'); this.showUser(e, message); @@ -219,6 +222,8 @@ export default class ChatUserInfoMenu extends ChatMenuFloating { } addContent(message) { + // Don't display messages if the giftee was clicked in a gift sub event + // because the message belongs to the gifter. this.messageArray = message[0].querySelector('.text') && this.clickedNick !== message.data('giftee') @@ -326,6 +331,8 @@ export default class ChatUserInfoMenu extends ChatMenuFloating { this.messageArray.forEach((element) => { const text = element.find('.text')[0].innerText; const nick = element.data('username'); + + // Create a new `ChatUser` to remove username styles for a cleaner look. const msg = MessageBuilder.message(text, new ChatUser(nick)); displayedMessages.push(msg.html(this.chat)); }); diff --git a/assets/chat/js/menus/ChatUserMenu.js b/assets/chat/js/menus/ChatUserMenu.js index 6a588546..a6e94f30 100644 --- a/assets/chat/js/menus/ChatUserMenu.js +++ b/assets/chat/js/menus/ChatUserMenu.js @@ -1,6 +1,7 @@ import $ from 'jquery'; import { debounce } from 'throttle-debounce'; import ChatMenu from './ChatMenu'; +import ChatUser from '../user'; // sections in order. const UserMenuSections = [ @@ -20,12 +21,8 @@ const UserMenuSections = [ ]; function userComparator(a, b) { - const u1 = this.chat.users.get(a.getAttribute('data-username').toLowerCase()); - const u2 = this.chat.users.get(b.getAttribute('data-username').toLowerCase()); - if (!u1 || !u2) return 0; - - const u1Nick = u1.nick.toLowerCase(); - const u2Nick = u2.nick.toLowerCase(); + const u1Nick = a.getAttribute('data-username').toLowerCase(); + const u2Nick = b.getAttribute('data-username').toLowerCase(); if (u1Nick < u2Nick) return -1; if (u1Nick > u2Nick) return 1; return 0; @@ -76,9 +73,10 @@ export default class ChatUserMenu extends ChatMenu { } return true; }); - this.chat.source.on('JOIN', (data) => this.addAndRedraw(data.nick)); - this.chat.source.on('QUIT', (data) => this.removeAndRedraw(data.nick)); - this.chat.source.on('NAMES', () => this.addAll()); + this.chat.source.on('JOIN', (data) => this.addAndRedraw(data)); + this.chat.source.on('QUIT', (data) => this.removeAndRedraw(data)); + this.chat.source.on('NAMES', (data) => this.addAll(data.users)); + this.chat.source.on('UPDATEUSER', (data) => this.replaceAndRedraw(data)); this.searchinput.on( 'keyup', debounce( @@ -146,7 +144,7 @@ export default class ChatUserMenu extends ChatMenu { return features !== '' ? `${features}` : ''; } - addAll() { + addAll(users) { this.totalcount = 0; this.container.empty(); this.sections = new Map(); @@ -157,25 +155,32 @@ export default class ChatUserMenu extends ChatMenu { this.flairSection.set(flair, data.name) ); }); - [...this.chat.users.keys()].forEach((username) => - this.addElement(username) - ); + users.forEach((u) => this.addElement(u)); this.sort(); this.filter(); this.redraw(); } - addAndRedraw(username) { - if (!this.hasElement(username)) { - this.addElement(username, true); + addAndRedraw(user) { + if (!this.hasElement(user)) { + this.addElement(user, true); this.filter(); this.redraw(); } } - removeAndRedraw(username) { - if (this.hasElement(username)) { - this.removeElement(username); + removeAndRedraw(user) { + if (this.hasElement(user)) { + this.removeElement(user); + this.redraw(); + } + } + + replaceAndRedraw(user) { + if (this.hasElement(user)) { + this.removeElement(user); + this.addElement(user, true); + this.filter(); this.redraw(); } } @@ -219,19 +224,19 @@ export default class ChatUserMenu extends ChatMenu { this.container.append(section); } - removeElement(username) { - this.container.find(`.user-entry[data-username="${username}"]`).remove(); + removeElement(user) { + this.container.find(`.user-entry[data-user-id="${user.id}"]`).remove(); this.totalcount -= 1; } - addElement(username, sort = false) { - const user = this.chat.users.get(username.toLowerCase()); + addElement(messageUser, sort = false) { + const user = new ChatUser(messageUser); const label = !user.username || user.username === '' ? 'Anonymous' : user.username; const features = user.features.length === 0 ? 'nofeature' : user.features.join(' '); const usr = $( - `
${label}
` + `
${label}
` ); const section = this.sections.get(this.highestSection(user)); @@ -254,9 +259,9 @@ export default class ChatUserMenu extends ChatMenu { this.totalcount += 1; } - hasElement(username) { + hasElement(user) { return ( - this.container.find(`.user-entry[data-username="${username}"]`).length > 0 + this.container.find(`.user-entry[data-user-id="${user.id}"]`).length > 0 ); } diff --git a/assets/chat/js/messages/MessageBuilder.js b/assets/chat/js/messages/MessageBuilder.js index 888c660f..91c54485 100644 --- a/assets/chat/js/messages/MessageBuilder.js +++ b/assets/chat/js/messages/MessageBuilder.js @@ -1,6 +1,7 @@ import MessageTypes from './MessageTypes'; import ChatUIMessage from './ChatUIMessage'; import ChatMessage from './ChatMessage'; +import ChatUser from '../user'; import ChatUserMessage from './ChatUserMessage'; import ChatEmoteMessage from './ChatEmoteMessage'; import PinnedMessage from './PinnedMessage'; @@ -59,47 +60,49 @@ export default class MessageBuilder { return new PinnedMessage(message, user, timestamp, uuid); } - static subscription( - message, - user, - tier, - tierLabel, - streak, - timestamp = null - ) { + static subscription(data) { return new ChatRegularSubscriptionMessage( - message, - user, - tier, - tierLabel, - streak, - timestamp + data.data, + new ChatUser(data.user), + data.tier, + data.tierLabel, + data.streak, + data.timestamp, + data.uuid ); } - static gift(message, user, tier, tierLabel, giftee, timestamp = null) { + static gift(data) { return new ChatGiftedSubscriptionMessage( - message, - user, - tier, - tierLabel, - giftee, - timestamp + data.data, + new ChatUser(data.user), + data.tier, + data.tierLabel, + new ChatUser(data.recipient), + data.timestamp, + data.uuid ); } - static massgift(message, user, tier, tierLabel, quantity, timestamp = null) { + static massgift(data) { return new ChatMassSubscriptionMessage( - message, - user, - tier, - tierLabel, - quantity, - timestamp + data.data, + new ChatUser(data.user), + data.tier, + data.tierLabel, + data.quantity, + data.timestamp, + data.uuid ); } - static donation(message, user, currency, timestamp = null) { - return new ChatDonationMessage(message, user, currency, timestamp); + static donation(data) { + return new ChatDonationMessage( + data.data, + new ChatUser(data.user), + data.amount, + data.timestamp, + data.uuid + ); } } diff --git a/assets/chat/js/messages/subscriptions/ChatGiftedSubscriptionMessage.js b/assets/chat/js/messages/subscriptions/ChatGiftedSubscriptionMessage.js index 565f7764..07be0899 100644 --- a/assets/chat/js/messages/subscriptions/ChatGiftedSubscriptionMessage.js +++ b/assets/chat/js/messages/subscriptions/ChatGiftedSubscriptionMessage.js @@ -1,5 +1,4 @@ import { usernameColorFlair } from '../ChatUserMessage'; -import ChatUser from '../../user'; import ChatSubscriptionMessage from './ChatSubscriptionMessage'; import MessageTypes from '../MessageTypes'; @@ -23,7 +22,7 @@ export default class ChatGiftedSubscriptionMessage extends ChatSubscriptionMessa }; }, {}); - attributes['data-giftee'] = this.giftee.toLowerCase(); + attributes['data-giftee'] = this.giftee.username.toLowerCase(); message.querySelector('.subscription-icon').classList.add('gift'); @@ -32,11 +31,9 @@ export default class ChatGiftedSubscriptionMessage extends ChatSubscriptionMessa .querySelector('#user-template') ?.content.cloneNode(true).firstElementChild; - const gifteeUser = - chat.users.get(this.giftee.toLowerCase()) ?? new ChatUser(this.giftee); - const gifteeColorFlair = usernameColorFlair(chat.flairs, gifteeUser); + const gifteeColorFlair = usernameColorFlair(chat.flairs, this.giftee); giftee.classList.add(gifteeColorFlair?.name); - giftee.innerText = gifteeUser.username; + giftee.innerText = this.giftee.username; const subscriptionInfo = message.querySelector('.event-info'); const user = message.querySelector('.user'); diff --git a/assets/chat/js/user.js b/assets/chat/js/user.js index 85b8c115..fcec85f0 100644 --- a/assets/chat/js/user.js +++ b/assets/chat/js/user.js @@ -3,11 +3,13 @@ import UserFeature from './features'; class ChatUser { constructor(args = {}) { if (typeof args === 'string') { + this.id = null; this.nick = args; this.username = args; this.createdDate = args; this.features = []; } else { + this.id = args.id || null; this.nick = args.nick || ''; this.username = args.nick || ''; this.createdDate = args.createdDate || ''; diff --git a/package-lock.json b/package-lock.json index 629deafc..b2426ef0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dgg-chat-gui", - "version": "2.33.0", + "version": "2.35.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "dgg-chat-gui", - "version": "2.32.0", + "version": "2.33.0", "license": "SEE LICENSE IN ", "dependencies": { "dotenv": "^16.0.3", @@ -5268,11 +5268,14 @@ } }, "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, "node_modules/eastasianwidth": { @@ -5330,9 +5333,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", - "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -5679,9 +5682,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz", - "integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==", + "version": "27.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz", + "integrity": "sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -5690,8 +5693,9 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0", + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -7078,9 +7082,9 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.1.tgz", - "integrity": "sha512-cTUzZ1+NqjGEKjmVgZKLMdiFg3m9MdRXkZW2OEe69WYVi5ONLMmlnSZdXzGGMOq0C8jGDrL6EWyEDDUioHO/pA==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", "dev": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", @@ -9744,15 +9748,6 @@ "node": ">=6" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/launch-editor": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", @@ -10740,9 +10735,9 @@ } }, "node_modules/overlayscrollbars": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.1.1.tgz", - "integrity": "sha512-xvs2g8Tcq9+CZDpLEUchN3YUzjJhnTWw9kwqT/qcC53FIkOyP9mqnRMot5sW16tcsPT1KaMyzF0AMXw/7E4a8g==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.2.1.tgz", + "integrity": "sha512-5oMxq4UCiEVLiOSvovbX8p+P2NtPosjHC0KkIcaobnYuxGwMyTOwBCtBdqO1tXrrA02VVrNzuIjGMLisO2mIwg==" }, "node_modules/p-limit": { "version": "2.3.0", @@ -13268,9 +13263,9 @@ } }, "node_modules/webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -13281,7 +13276,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -13291,7 +13286,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -13489,9 +13484,9 @@ } }, "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -17755,9 +17750,9 @@ } }, "dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" }, "eastasianwidth": { "version": "0.2.0", @@ -17805,9 +17800,9 @@ "dev": true }, "enhanced-resolve": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", - "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -18270,9 +18265,9 @@ } }, "eslint-plugin-jest": { - "version": "27.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz", - "integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==", + "version": "27.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz", + "integrity": "sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==", "dev": true, "requires": { "@typescript-eslint/utils": "^5.10.0" @@ -19104,9 +19099,9 @@ } }, "html-webpack-plugin": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.1.tgz", - "integrity": "sha512-cTUzZ1+NqjGEKjmVgZKLMdiFg3m9MdRXkZW2OEe69WYVi5ONLMmlnSZdXzGGMOq0C8jGDrL6EWyEDDUioHO/pA==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", "dev": true, "requires": { "@types/html-minifier-terser": "^6.0.0", @@ -21062,12 +21057,6 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, - "klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true - }, "launch-editor": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", @@ -21796,9 +21785,9 @@ } }, "overlayscrollbars": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.1.1.tgz", - "integrity": "sha512-xvs2g8Tcq9+CZDpLEUchN3YUzjJhnTWw9kwqT/qcC53FIkOyP9mqnRMot5sW16tcsPT1KaMyzF0AMXw/7E4a8g==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.2.1.tgz", + "integrity": "sha512-5oMxq4UCiEVLiOSvovbX8p+P2NtPosjHC0KkIcaobnYuxGwMyTOwBCtBdqO1tXrrA02VVrNzuIjGMLisO2mIwg==" }, "p-limit": { "version": "2.3.0", @@ -23670,9 +23659,9 @@ "dev": true }, "webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -23683,7 +23672,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -23693,7 +23682,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -23701,9 +23690,9 @@ }, "dependencies": { "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "requires": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", diff --git a/package.json b/package.json index 04d07295..f5abb564 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dgg-chat-gui", - "version": "2.33.0", + "version": "2.35.0", "description": "Destiny.gg chat client front-end", "main": "destiny", "scripts": {