diff --git a/src/client.ts b/src/client.ts index f200b03d..1ddfd287 100644 --- a/src/client.ts +++ b/src/client.ts @@ -83,7 +83,7 @@ type Mention = { chanId: number; msgId: number; type: MessageType; - time: number; + time: Date; text: string; from: UserInMessage; }; @@ -312,7 +312,7 @@ class Client { networks: [network.getFilteredClone(this.lastActiveChannel, -1)], }); - if (!(network as NetworkWithIrcFramework).validate(client)) { + if (!network.validate(client)) { return; } diff --git a/src/models/msg.ts b/src/models/msg.ts index f2674ba6..3f2bf84a 100644 --- a/src/models/msg.ts +++ b/src/models/msg.ts @@ -7,8 +7,9 @@ export type UserInMessage = Partial & { mode: string; }; +// TODO: this should be a part of preview in src/plugins/links export type MessagePreview = { - shown: boolean; + shown: boolean | null; link: string; body: string; }; @@ -58,7 +59,7 @@ class Msg { // we should probably make Msgs that extend this class and use those // throughout. I'll leave any similar fields below. new_nick!: string; - highlight!: boolean; + highlight?: boolean; showInActive?: boolean; new_ident!: string; new_host!: string; @@ -103,7 +104,7 @@ class Msg { self: false, }); - if (this.time.getTime() > 0) { + if (this.time?.getTime() > 0) { this.time = new Date(this.time); } else { this.time = new Date(); diff --git a/src/models/network.ts b/src/models/network.ts index e77f81e5..afbf118d 100644 --- a/src/models/network.ts +++ b/src/models/network.ts @@ -177,7 +177,7 @@ class Network { ); } - validate(this: NetworkWithIrcFramework, client: Client) { + validate(this: Network, client: Client) { // Remove !, :, @ and whitespace characters from nicknames and usernames const cleanNick = (str: string) => str.replace(/[\x00\s:!@]/g, "_").substring(0, 100); @@ -454,7 +454,7 @@ class Network { this.channels.forEach((channel) => channel.destroy()); } - setNick(this: NetworkWithIrcFramework, nick: string) { + setNick(this: Network, nick: string) { this.nick = nick; this.highlightRegex = new RegExp( // Do not match characters and numbers (unless IRC color) @@ -472,7 +472,10 @@ class Network { this.keepNick = null; } - this.irc.options.nick = nick; + // TODO: setNick is called in validate() before irc exists. Is that a problem? + if (this.irc) { + this.irc.options.nick = nick; + } } getFilteredClone(lastActiveChannel: number, lastMessage: number) { diff --git a/src/plugins/dev-server.ts b/src/plugins/dev-server.ts index 3344225a..6aabe296 100644 --- a/src/plugins/dev-server.ts +++ b/src/plugins/dev-server.ts @@ -13,16 +13,18 @@ export default (app) => { "webpack-hot-middleware/client?path=storage/__webpack_hmr" ); + webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); + const compiler = webpack(webpackConfig); app.use( webpackDevMiddleware(compiler, { index: "/", - publicPath: webpackConfig.output.publicPath, + publicPath: webpackConfig.output?.publicPath, }) ).use( webpackDevMiddleware(compiler, { - path: "/storage/__webpack_hmr", + publicPath: "/storage/__webpack_hmr", }) ); }; diff --git a/src/plugins/irc-events/link.ts b/src/plugins/irc-events/link.ts index 6ceddfb9..a29a5e43 100644 --- a/src/plugins/irc-events/link.ts +++ b/src/plugins/irc-events/link.ts @@ -12,7 +12,14 @@ import storage from "../storage"; import Client, {IrcEventHandler} from "../../client"; import Chan from "../../models/chan"; import Msg from "../../models/msg"; -const currentFetchPromises = new Map(); +import {Cheerio} from "cheerio"; + +type FetchRequest = { + data: Record; + type: string; + size: number; +}; +const currentFetchPromises = new Map>(); const imageTypeRegex = /^image\/.+/; const mediaTypeRegex = /^(audio|video)\/.+/; @@ -146,7 +153,7 @@ function parseHtml(preview, res, client: Client) { }); } -function parseHtmlMedia($: cheerio.Root, preview, client) { +function parseHtmlMedia($: Cheerio, preview, client: Client) { return new Promise((resolve, reject) => { if (Config.values.disableMediaPreview) { reject(); @@ -417,10 +424,10 @@ function fetch(uri, headers) { ); } - promise = new Promise((resolve, reject) => { + promise = new Promise((resolve, reject) => { let buffer = Buffer.from(""); let contentLength = 0; - let contentType; + let contentType: string | undefined; let limit = Config.values.prefetchMaxImageSize * 1024; try { @@ -438,14 +445,14 @@ function fetch(uri, headers) { contentLength = parseInt(res.headers["content-length"], 10) || 0; contentType = res.headers["content-type"]; - if (imageTypeRegex.test(contentType)) { + if (contentType && imageTypeRegex.test(contentType)) { // response is an image // if Content-Length header reports a size exceeding the prefetch limit, abort fetch // and if file is not to be stored we don't need to download further either if (contentLength > limit || !Config.values.prefetchStorage) { gotStream.destroy(); } - } else if (mediaTypeRegex.test(contentType)) { + } else if (contentType && mediaTypeRegex.test(contentType)) { // We don't need to download the file any further after we received content-type header gotStream.destroy(); } else { diff --git a/src/plugins/irc-events/message.ts b/src/plugins/irc-events/message.ts index b04aa175..1954bcad 100644 --- a/src/plugins/irc-events/message.ts +++ b/src/plugins/irc-events/message.ts @@ -58,7 +58,7 @@ export default function (irc, network) { data.from_server && (!data.target || !network.getChannel(data.target) || - network.getChannel(data.target).type !== ChanType.CHANNEL) + network.getChannel(data.target)?.type !== ChanType.CHANNEL) ) { chan = network.channels[0]; from = chan.getUser(data.nick); @@ -128,7 +128,7 @@ export default function (irc, network) { // Self messages in channels are never highlighted // Non-self messages are highlighted as soon as the nick is detected if (!msg.highlight && !msg.self) { - msg.highlight = network.highlightRegex.test(data.message); + msg.highlight = network.highlightRegex?.test(data.message); // If we still don't have a highlight, test against custom highlights if there's any if (!msg.highlight && client.highlightRegex) { @@ -205,7 +205,7 @@ export default function (irc, network) { chanId: chan.id, msgId: msg.id, type: msg.type, - time: msg.time.getTime(), + time: msg.time, text: msg.text, from: msg.from, }); diff --git a/src/plugins/irc-events/mode.ts b/src/plugins/irc-events/mode.ts index 77c44ef3..1ef2f782 100644 --- a/src/plugins/irc-events/mode.ts +++ b/src/plugins/irc-events/mode.ts @@ -4,6 +4,7 @@ import _ from "lodash"; import {IrcEventHandler} from "../../client"; import Msg, {MessageType} from "../../models/msg"; +import User from "../../models/user"; export default function (irc, network) { const client = this; @@ -74,7 +75,7 @@ export default function (irc, network) { self: data.nick === irc.user.nick, }); - const users = []; + const users: User[] = []; for (const param of data.raw_params) { if (targetChan.findUser(param)) { @@ -88,7 +89,7 @@ export default function (irc, network) { targetChan.pushMessage(client, msg); - let usersUpdated; + let usersUpdated = false; const userModeSortPriority = {}; const supportsMultiPrefix = network.irc.network.cap.isEnabled("multi-prefix"); diff --git a/webpack.config.ts b/webpack.config.ts index d1ebdd5b..b0f8990a 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -158,9 +158,7 @@ export default (env: any, argv: any) => { config.devtool = "eval"; config.stats = "errors-only"; config.output!.path = path.resolve(__dirname, "test/public"); - config.entry = { - "testclient.js": [path.resolve(__dirname, "test/client/index.js")], - }; + config.entry!["testclient.js"] = [path.resolve(__dirname, "test/client/index.js")]; // Add the istanbul plugin to babel-loader options for (const rule of config.module!.rules!) { @@ -194,7 +192,7 @@ export default (env: any, argv: any) => { ]; } - if (argv.mode === "production") { + if (argv?.mode === "production") { // ... }