{ "version": 3, "sources": ["../../../server/chat.ts"], "sourcesContent": ["/**\r\n * Chat\r\n * Pokemon Showdown - http://pokemonshowdown.com/\r\n *\r\n * This handles chat and chat commands sent from users to chatrooms\r\n * and PMs. The main function you're looking for is Chat.parse\r\n * (scroll down to its definition for details)\r\n *\r\n * Individual commands are put in:\r\n * chat-commands/ - \"core\" commands that shouldn't be modified\r\n * chat-plugins/ - other commands that can be safely modified\r\n *\r\n * The command API is (mostly) documented in chat-plugins/COMMANDS.md\r\n *\r\n * @license MIT\r\n */\r\n\r\n/*\r\n\r\nTo reload chat commands:\r\n\r\n/hotpatch chat\r\n\r\n*/\r\n\r\nimport type {RoomPermission, GlobalPermission} from './user-groups';\r\nimport type {Punishment} from './punishments';\r\nimport type {PartialModlogEntry} from './modlog';\r\nimport {FriendsDatabase, PM} from './friends';\r\nimport {SQL, Repl, FS, Utils} from '../lib';\r\nimport * as Artemis from './artemis';\r\nimport {Dex} from '../sim';\r\nimport * as pathModule from 'path';\r\nimport * as JSX from './chat-jsx';\r\n\r\nexport type PageHandler = (this: PageContext, query: string[], user: User, connection: Connection)\r\n=> Promise | string | null | void | JSX.VNode;\r\nexport interface PageTable {\r\n\t[k: string]: PageHandler | PageTable;\r\n}\r\n\r\nexport type ChatHandler = (\r\n\tthis: CommandContext,\r\n\ttarget: string,\r\n\troom: Room | null,\r\n\tuser: User,\r\n\tconnection: Connection,\r\n\tcmd: string,\r\n\tmessage: string\r\n) => void;\r\nexport type AnnotatedChatHandler = ChatHandler & {\r\n\trequiresRoom: boolean | RoomID,\r\n\thasRoomPermissions: boolean,\r\n\tbroadcastable: boolean,\r\n\tcmd: string,\r\n\tfullCmd: string,\r\n\tisPrivate: boolean,\r\n\tdisabled: boolean,\r\n\taliases: string[],\r\n\trequiredPermission?: GlobalPermission | RoomPermission,\r\n};\r\nexport interface ChatCommands {\r\n\t[k: string]: ChatHandler | string | string[] | ChatCommands;\r\n}\r\nexport interface AnnotatedChatCommands {\r\n\t[k: string]: AnnotatedChatHandler | string | string[] | AnnotatedChatCommands;\r\n}\r\n\r\nexport type HandlerTable = {[key in keyof Handlers]?: Handlers[key]};\r\n\r\ninterface Handlers {\r\n\tonRoomClose: (id: string, user: User, connection: Connection, page: boolean) => any;\r\n\tonRenameRoom: (oldId: RoomID, newID: RoomID, room: BasicRoom) => void;\r\n\tonBattleStart: (user: User, room: GameRoom) => void;\r\n\tonBattleLeave: (user: User, room: GameRoom) => void;\r\n\tonRoomJoin: (room: BasicRoom, user: User, connection: Connection) => void;\r\n\tonDisconnect: (user: User) => void;\r\n\tonRoomDestroy: (roomid: RoomID) => void;\r\n\tonBattleEnd: (battle: RoomBattle, winner: ID, players: ID[]) => void;\r\n\tonLadderSearch: (user: User, connection: Connection, format: ID) => void;\r\n\tonBattleRanked: (\r\n\t\tbattle: Rooms.RoomBattle, winner: ID, ratings: (AnyObject | null | undefined)[], players: ID[]\r\n\t) => void;\r\n\tonRename: (user: User, oldID: ID, newID: ID) => void;\r\n\tonTicketCreate: (ticket: import('./chat-plugins/helptickets').TicketState, user: User) => void;\r\n}\r\n\r\nexport interface ChatPlugin {\r\n\tcommands?: AnnotatedChatCommands;\r\n\tpages?: PageTable;\r\n\tdestroy?: () => void;\r\n\troomSettings?: SettingsHandler | SettingsHandler[];\r\n\t[k: string]: any;\r\n}\r\n\r\nexport type SettingsHandler = (\r\n\troom: Room,\r\n\tuser: User,\r\n\tconnection: Connection\r\n) => {\r\n\tlabel: string,\r\n\tpermission: boolean | RoomPermission,\r\n\t// button label, command | disabled\r\n\toptions: [string, string | true][],\r\n};\r\n\r\nexport type CRQHandler = (this: CommandContext, target: string, user: User, trustable?: boolean) => any;\r\nexport type RoomCloseHandler = (id: string, user: User, connection: Connection, page: boolean) => any;\r\n\r\n/**\r\n * Chat filters can choose to:\r\n * 1. return false OR null - to not send a user's message\r\n * 2. return an altered string - to alter a user's message\r\n * 3. return undefined to send the original message through\r\n */\r\nexport type ChatFilter = ((\r\n\tthis: CommandContext,\r\n\tmessage: string,\r\n\tuser: User,\r\n\troom: Room | null,\r\n\tconnection: Connection,\r\n\ttargetUser: User | null,\r\n\toriginalMessage: string\r\n) => string | false | null | undefined | void) & {priority?: number};\r\n\r\nexport type NameFilter = (name: string, user: User) => string;\r\nexport type NicknameFilter = (name: string, user: User) => string | false;\r\nexport type StatusFilter = (status: string, user: User) => string;\r\nexport type PunishmentFilter = (user: User | ID, punishment: Punishment) => void;\r\nexport type LoginFilter = (user: User, oldUser: User | null, userType: string) => void;\r\nexport type HostFilter = (host: string, user: User, connection: Connection, hostType: string) => void;\r\n\r\nexport interface Translations {\r\n\tname?: string;\r\n\tstrings: {[english: string]: string};\r\n}\r\n\r\nconst LINK_WHITELIST = [\r\n\t'*.pokemonshowdown.com', 'psim.us', 'smogtours.psim.us',\r\n\t'*.smogon.com', '*.pastebin.com', '*.hastebin.com',\r\n];\r\n\r\nconst MAX_MESSAGE_LENGTH = 1000;\r\n\r\nconst BROADCAST_COOLDOWN = 20 * 1000;\r\nconst MESSAGE_COOLDOWN = 5 * 60 * 1000;\r\n\r\nconst MAX_PARSE_RECURSION = 10;\r\n\r\nconst VALID_COMMAND_TOKENS = '/!';\r\nconst BROADCAST_TOKEN = '!';\r\n\r\nconst PLUGIN_DATABASE_PATH = './databases/chat-plugins.db';\r\nconst MAX_PLUGIN_LOADING_DEPTH = 3;\r\n\r\nimport {formatText, linkRegex, stripFormatting} from './chat-formatter';\r\n\r\n// @ts-ignore no typedef available\r\nimport ProbeModule = require('probe-image-size');\r\nconst probe: (url: string) => Promise<{width: number, height: number}> = ProbeModule;\r\n\r\nconst EMOJI_REGEX = /[\\p{Emoji_Modifier_Base}\\p{Emoji_Presentation}\\uFE0F]/u;\r\n\r\nconst TRANSLATION_DIRECTORY = pathModule.resolve(__dirname, '..', 'translations');\r\n\r\nclass PatternTester {\r\n\t// This class sounds like a RegExp\r\n\t// In fact, one could in theory implement it as a RegExp subclass\r\n\t// However, ES2016 RegExp subclassing is a can of worms, and it wouldn't allow us\r\n\t// to tailor the test method for fast command parsing.\r\n\treadonly elements: string[];\r\n\treadonly fastElements: Set;\r\n\tregexp: RegExp | null;\r\n\tconstructor() {\r\n\t\tthis.elements = [];\r\n\t\tthis.fastElements = new Set();\r\n\t\tthis.regexp = null;\r\n\t}\r\n\tfastNormalize(elem: string) {\r\n\t\treturn elem.slice(0, -1);\r\n\t}\r\n\tupdate() {\r\n\t\tconst slowElements = this.elements.filter(elem => !this.fastElements.has(this.fastNormalize(elem)));\r\n\t\tif (slowElements.length) {\r\n\t\t\tthis.regexp = new RegExp('^(' + slowElements.map(elem => '(?:' + elem + ')').join('|') + ')', 'i');\r\n\t\t}\r\n\t}\r\n\tregister(...elems: string[]) {\r\n\t\tfor (const elem of elems) {\r\n\t\t\tthis.elements.push(elem);\r\n\t\t\tif (/^[^ ^$?|()[\\]]+ $/.test(elem)) {\r\n\t\t\t\tthis.fastElements.add(this.fastNormalize(elem));\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.update();\r\n\t}\r\n\ttestCommand(text: string) {\r\n\t\tconst spaceIndex = text.indexOf(' ');\r\n\t\tif (this.fastElements.has(spaceIndex >= 0 ? text.slice(0, spaceIndex) : text)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!this.regexp) return false;\r\n\t\treturn this.regexp.test(text);\r\n\t}\r\n\ttest(text: string) {\r\n\t\tif (!text.includes('\\n')) return null;\r\n\t\tif (this.testCommand(text)) return text;\r\n\t\t// The PM matching is a huge mess, and really needs to be replaced with\r\n\t\t// the new multiline command system soon.\r\n\t\tconst pmMatches = /^(\\/(?:pm|w|whisper|msg) [^,]*, ?)(.*)/i.exec(text);\r\n\t\tif (pmMatches && this.testCommand(pmMatches[2])) {\r\n\t\t\tif (text.split('\\n').every(line => line.startsWith(pmMatches[1]))) {\r\n\t\t\t\treturn text.replace(/\\n\\/(?:pm|w|whisper|msg) [^,]*, ?/g, '\\n');\r\n\t\t\t}\r\n\t\t\treturn text;\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n}\r\n\r\n/*********************************************************\r\n * Parser\r\n *********************************************************/\r\n\r\n/**\r\n * An ErrorMessage will, if used in a command/page context, simply show the user\r\n * the error, rather than logging a crash. It's used to simplify showing errors.\r\n *\r\n * Outside of a command/page context, it would still cause a crash.\r\n */\r\nexport class ErrorMessage extends Error {\r\n\tconstructor(message: string) {\r\n\t\tsuper(message);\r\n\t\tthis.name = 'ErrorMessage';\r\n\t\tError.captureStackTrace(this, ErrorMessage);\r\n\t}\r\n}\r\n\r\nexport class Interruption extends Error {\r\n\tconstructor() {\r\n\t\tsuper('');\r\n\t\tthis.name = 'Interruption';\r\n\t\tError.captureStackTrace(this, ErrorMessage);\r\n\t}\r\n}\r\n\r\n// These classes need to be declared here because they aren't hoisted\r\nexport abstract class MessageContext {\r\n\treadonly user: User;\r\n\tlanguage: ID | null;\r\n\trecursionDepth: number;\r\n\tconstructor(user: User, language: ID | null = null) {\r\n\t\tthis.user = user;\r\n\t\tthis.language = language;\r\n\t\tthis.recursionDepth = 0;\r\n\t}\r\n\r\n\tsplitOne(target: string) {\r\n\t\tconst commaIndex = target.indexOf(',');\r\n\t\tif (commaIndex < 0) {\r\n\t\t\treturn [target.trim(), ''];\r\n\t\t}\r\n\t\treturn [target.slice(0, commaIndex).trim(), target.slice(commaIndex + 1).trim()];\r\n\t}\r\n\tmeansYes(text: string) {\r\n\t\tswitch (text.toLowerCase().trim()) {\r\n\t\tcase 'on': case 'enable': case 'yes': case 'true': case 'allow': case '1':\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\tmeansNo(text: string) {\r\n\t\tswitch (text.toLowerCase().trim()) {\r\n\t\tcase 'off': case 'disable': case 'no': case 'false': case 'disallow': case '0':\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\t/**\r\n\t * Given an array of strings (or a comma-delimited string), check the\r\n\t * first and last string for a format/mod/gen. If it exists, remove\r\n\t * it from the array.\r\n\t *\r\n\t * @returns `format` (null if no format was found), `dex` (the dex\r\n\t * for the format/mod, or the default dex if none was found), and\r\n\t * `targets` (the rest of the array).\r\n\t */\r\n\tsplitFormat(target: string | string[], atLeastOneTarget?: boolean) {\r\n\t\tconst targets = typeof target === 'string' ? target.split(',') : target;\r\n\t\tif (!targets[0].trim()) targets.pop();\r\n\r\n\t\tif (targets.length > (atLeastOneTarget ? 1 : 0)) {\r\n\t\t\tconst {dex, format, isMatch} = this.extractFormat(targets[0].trim());\r\n\t\t\tif (isMatch) {\r\n\t\t\t\ttargets.shift();\r\n\t\t\t\treturn {dex, format, targets};\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (targets.length > 1) {\r\n\t\t\tconst {dex, format, isMatch} = this.extractFormat(targets[targets.length - 1].trim());\r\n\t\t\tif (isMatch) {\r\n\t\t\t\ttargets.pop();\r\n\t\t\t\treturn {dex, format, targets};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst room = (this as any as CommandContext).room;\r\n\t\tconst {dex, format} = this.extractFormat(room?.settings.defaultFormat || room?.battle?.format);\r\n\t\treturn {dex, format, targets};\r\n\t}\r\n\textractFormat(formatOrMod?: string): {dex: ModdedDex, format: Format | null, isMatch: boolean} {\r\n\t\tif (!formatOrMod) {\r\n\t\t\treturn {dex: Dex.includeData(), format: null, isMatch: false};\r\n\t\t}\r\n\r\n\t\tconst format = Dex.formats.get(formatOrMod);\r\n\t\tif (format.exists) {\r\n\t\t\treturn {dex: Dex.forFormat(format), format: format, isMatch: true};\r\n\t\t}\r\n\r\n\t\tif (toID(formatOrMod) in Dex.dexes) {\r\n\t\t\treturn {dex: Dex.mod(toID(formatOrMod)).includeData(), format: null, isMatch: true};\r\n\t\t}\r\n\r\n\t\treturn this.extractFormat();\r\n\t}\r\n\tsplitUser(target: string, {exactName}: {exactName?: boolean} = {}) {\r\n\t\tconst [inputUsername, rest] = this.splitOne(target).map(str => str.trim());\r\n\t\tconst targetUser = Users.get(inputUsername, exactName);\r\n\r\n\t\treturn {\r\n\t\t\ttargetUser,\r\n\t\t\tinputUsername,\r\n\t\t\ttargetUsername: targetUser ? targetUser.name : inputUsername,\r\n\t\t\trest,\r\n\t\t};\r\n\t}\r\n\trequireUser(target: string, options: {allowOffline?: boolean, exactName?: boolean} = {}) {\r\n\t\tconst {targetUser, targetUsername, rest} = this.splitUser(target, options);\r\n\r\n\t\tif (!targetUser) {\r\n\t\t\tthrow new Chat.ErrorMessage(`The user \"${targetUsername}\" is offline or misspelled.`);\r\n\t\t}\r\n\t\tif (!options.allowOffline && !targetUser.connected) {\r\n\t\t\tthrow new Chat.ErrorMessage(`The user \"${targetUsername}\" is offline.`);\r\n\t\t}\r\n\r\n\t\t// `inputUsername` and `targetUsername` are never needed because we already handle the \"user not found\" error messages\r\n\t\t// just use `targetUser.name` where previously necessary\r\n\t\treturn {targetUser, rest};\r\n\t}\r\n\tgetUserOrSelf(target: string, {exactName}: {exactName?: boolean} = {}) {\r\n\t\tif (!target.trim()) return this.user;\r\n\r\n\t\treturn Users.get(target, exactName);\r\n\t}\r\n\ttr(strings: TemplateStringsArray | string, ...keys: any[]) {\r\n\t\treturn Chat.tr(this.language, strings, ...keys);\r\n\t}\r\n}\r\n\r\nexport class PageContext extends MessageContext {\r\n\treadonly connection: Connection;\r\n\troom: Room | null;\r\n\tpageid: string;\r\n\tinitialized: boolean;\r\n\ttitle: string;\r\n\targs: string[];\r\n\tconstructor(options: {pageid: string, user: User, connection: Connection, language?: ID}) {\r\n\t\tsuper(options.user, options.language);\r\n\r\n\t\tthis.connection = options.connection;\r\n\t\tthis.room = null;\r\n\t\tthis.pageid = options.pageid;\r\n\t\tthis.args = this.pageid.split('-');\r\n\r\n\t\tthis.initialized = false;\r\n\t\tthis.title = 'Page';\r\n\t}\r\n\r\n\tcheckCan(permission: RoomPermission, target: User | null, room: Room): boolean;\r\n\tcheckCan(permission: GlobalPermission, target?: User | null): boolean;\r\n\tcheckCan(permission: string, target: User | null = null, room: Room | null = null) {\r\n\t\tif (!this.user.can(permission as any, target, room as any)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`

Permission denied.

`);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivatelyCheckCan(permission: RoomPermission, target: User | null, room: Room): boolean;\r\n\tprivatelyCheckCan(permission: GlobalPermission, target?: User | null): boolean;\r\n\tprivatelyCheckCan(permission: string, target: User | null = null, room: Room | null = null) {\r\n\t\tif (!this.user.can(permission as any, target, room as any)) {\r\n\t\t\tthis.pageDoesNotExist();\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpageDoesNotExist(): never {\r\n\t\tthrow new Chat.ErrorMessage(`Page \"${this.pageid}\" not found`);\r\n\t}\r\n\r\n\trequireRoom(pageid?: string) {\r\n\t\tconst room = this.extractRoom(pageid);\r\n\t\tif (!room) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Invalid link: This page requires a room ID.`);\r\n\t\t}\r\n\r\n\t\tthis.room = room;\r\n\t\treturn room;\r\n\t}\r\n\textractRoom(pageid?: string) {\r\n\t\tif (!pageid) pageid = this.pageid;\r\n\t\tconst parts = pageid.split('-');\r\n\r\n\t\t// The roomid for the page should be view-pagename-roomid\r\n\t\tconst room = Rooms.get(parts[2]) || null;\r\n\r\n\t\tthis.room = room;\r\n\t\treturn room;\r\n\t}\r\n\r\n\tsetHTML(html: string) {\r\n\t\tconst roomid = this.room ? `[${this.room.roomid}] ` : '';\r\n\t\tlet content = `|title|${roomid}${this.title}\\n|pagehtml|${html}`;\r\n\t\tif (!this.initialized) {\r\n\t\t\tcontent = `|init|html\\n${content}`;\r\n\t\t\tthis.initialized = true;\r\n\t\t}\r\n\t\tthis.send(content);\r\n\t}\r\n\terrorReply(message: string) {\r\n\t\tthis.setHTML(`

${message}

`);\r\n\t}\r\n\r\n\tsend(content: string) {\r\n\t\tthis.connection.send(`>${this.pageid}\\n${content}`);\r\n\t}\r\n\tclose() {\r\n\t\tthis.send('|deinit');\r\n\t}\r\n\r\n\tasync resolve(pageid?: string) {\r\n\t\tif (pageid) this.pageid = pageid;\r\n\r\n\t\tconst parts = this.pageid.split('-');\r\n\t\tparts.shift(); // first part is always `view`\r\n\r\n\t\tif (!this.connection.openPages) this.connection.openPages = new Set();\r\n\t\tthis.connection.openPages.add(parts.join('-'));\r\n\r\n\t\tlet handler: PageHandler | PageTable = Chat.pages;\r\n\t\twhile (handler) {\r\n\t\t\tif (typeof handler === 'function') {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\thandler = handler[parts.shift() || 'default'] || handler[''];\r\n\t\t}\r\n\r\n\t\tthis.args = parts;\r\n\r\n\t\tlet res;\r\n\t\ttry {\r\n\t\t\tif (typeof handler !== 'function') this.pageDoesNotExist();\r\n\t\t\tres = await handler.call(this, parts, this.user, this.connection);\r\n\t\t} catch (err: any) {\r\n\t\t\tif (err.name?.endsWith('ErrorMessage')) {\r\n\t\t\t\tif (err.message) this.errorReply(err.message);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (err.name.endsWith('Interruption')) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tMonitor.crashlog(err, 'A chat page', {\r\n\t\t\t\tuser: this.user.name,\r\n\t\t\t\troom: this.room && this.room.roomid,\r\n\t\t\t\tpageid: this.pageid,\r\n\t\t\t});\r\n\t\t\tthis.setHTML(\r\n\t\t\t\t`
` +\r\n\t\t\t\t`Pokemon Showdown crashed!
Don't worry, we're working on fixing it.` +\r\n\t\t\t\t`
`\r\n\t\t\t);\r\n\t\t}\r\n\t\tif (typeof res === 'object' && res) res = JSX.render(res);\r\n\t\tif (typeof res === 'string') {\r\n\t\t\tthis.setHTML(res);\r\n\t\t\tres = undefined;\r\n\t\t}\r\n\t\treturn res;\r\n\t}\r\n}\r\n\r\n/**\r\n * This is a message sent in a PM or to a chat/battle room.\r\n *\r\n * There are three cases to be aware of:\r\n * - PM to user: `context.pmTarget` will exist and `context.room` will be `null`\r\n * - message to room: `context.room` will exist and `context.pmTarget` will be `null`\r\n * - console command (PM to `~`): `context.pmTarget` and `context.room` will both be `null`\r\n */\r\nexport class CommandContext extends MessageContext {\r\n\tmessage: string;\r\n\tpmTarget: User | null;\r\n\troom: Room | null;\r\n\tconnection: Connection;\r\n\r\n\tcmd: string;\r\n\tcmdToken: string;\r\n\ttarget: string;\r\n\tfullCmd: string;\r\n\thandler: AnnotatedChatHandler | null;\r\n\r\n\tisQuiet: boolean;\r\n\tbypassRoomCheck?: boolean;\r\n\tbroadcasting: boolean;\r\n\tbroadcastToRoom: boolean;\r\n\t/** Used only by !rebroadcast */\r\n\tbroadcastPrefix: string;\r\n\tbroadcastMessage: string;\r\n\tconstructor(options: {\r\n\t\tmessage: string, user: User, connection: Connection,\r\n\t\troom?: Room | null, pmTarget?: User | null, cmd?: string, cmdToken?: string, target?: string, fullCmd?: string,\r\n\t\trecursionDepth?: number, isQuiet?: boolean, broadcastPrefix?: string, bypassRoomCheck?: boolean,\r\n\t}) {\r\n\t\tsuper(\r\n\t\t\toptions.user, options.room && options.room.settings.language ?\r\n\t\t\t\toptions.room.settings.language : options.user.language\r\n\t\t);\r\n\r\n\t\tthis.message = options.message || ``;\r\n\t\tthis.recursionDepth = options.recursionDepth || 0;\r\n\r\n\t\t// message context\r\n\t\tthis.pmTarget = options.pmTarget || null;\r\n\t\tthis.room = options.room || null;\r\n\t\tthis.connection = options.connection;\r\n\r\n\t\t// command context\r\n\t\tthis.cmd = options.cmd || '';\r\n\t\tthis.cmdToken = options.cmdToken || '';\r\n\t\tthis.target = options.target || ``;\r\n\t\tthis.fullCmd = options.fullCmd || '';\r\n\t\tthis.handler = null;\r\n\t\tthis.isQuiet = options.isQuiet || false;\r\n\t\tthis.bypassRoomCheck = options.bypassRoomCheck || false;\r\n\r\n\t\t// broadcast context\r\n\t\tthis.broadcasting = false;\r\n\t\tthis.broadcastToRoom = true;\r\n\t\tthis.broadcastPrefix = options.broadcastPrefix || '';\r\n\t\tthis.broadcastMessage = '';\r\n\t}\r\n\r\n\t// TODO: return should be void | boolean | Promise\r\n\tparse(\r\n\t\tmsg?: string,\r\n\t\toptions: Partial<{isQuiet: boolean, broadcastPrefix: string, bypassRoomCheck: boolean}> = {}\r\n\t): any {\r\n\t\tif (typeof msg === 'string') {\r\n\t\t\t// spawn subcontext\r\n\t\t\tconst subcontext = new CommandContext({\r\n\t\t\t\tmessage: msg,\r\n\t\t\t\tuser: this.user,\r\n\t\t\t\tconnection: this.connection,\r\n\t\t\t\troom: this.room,\r\n\t\t\t\tpmTarget: this.pmTarget,\r\n\t\t\t\trecursionDepth: this.recursionDepth + 1,\r\n\t\t\t\tbypassRoomCheck: this.bypassRoomCheck,\r\n\t\t\t\t...options,\r\n\t\t\t});\r\n\t\t\tif (subcontext.recursionDepth > MAX_PARSE_RECURSION) {\r\n\t\t\t\tthrow new Error(\"Too much command recursion\");\r\n\t\t\t}\r\n\t\t\treturn subcontext.parse();\r\n\t\t}\r\n\t\tlet message: string | void | boolean | Promise = this.message;\r\n\r\n\t\tconst parsedCommand = Chat.parseCommand(message);\r\n\t\tif (parsedCommand) {\r\n\t\t\tthis.cmd = parsedCommand.cmd;\r\n\t\t\tthis.fullCmd = parsedCommand.fullCmd;\r\n\t\t\tthis.cmdToken = parsedCommand.cmdToken;\r\n\t\t\tthis.target = parsedCommand.target;\r\n\t\t\tthis.handler = parsedCommand.handler;\r\n\t\t}\r\n\r\n\t\tif (!this.bypassRoomCheck && this.room && !(this.user.id in this.room.users)) {\r\n\t\t\treturn this.popupReply(`You tried to send \"${message}\" to the room \"${this.room.roomid}\" but it failed because you were not in that room.`);\r\n\t\t}\r\n\r\n\t\tif (this.user.statusType === 'idle' && !['unaway', 'unafk', 'back'].includes(this.cmd)) {\r\n\t\t\tthis.user.setStatusType('online');\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tif (this.handler) {\r\n\t\t\t\tif (this.handler.disabled) {\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\t\t\t`The command /${this.cmd} is temporarily unavailable due to technical difficulties. Please try again in a few hours.`\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t\tmessage = this.run(this.handler);\r\n\t\t\t} else {\r\n\t\t\t\tif (this.cmdToken) {\r\n\t\t\t\t\t// To guard against command typos, show an error message\r\n\t\t\t\t\tif (!(this.shouldBroadcast() && !/[a-z0-9]/.test(this.cmd.charAt(0)))) {\r\n\t\t\t\t\t\tthis.commandDoesNotExist();\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (!VALID_COMMAND_TOKENS.includes(message.charAt(0)) &&\r\n\t\t\t\t\t\tVALID_COMMAND_TOKENS.includes(message.trim().charAt(0))) {\r\n\t\t\t\t\tmessage = message.trim();\r\n\t\t\t\t\tif (!message.startsWith(BROADCAST_TOKEN)) {\r\n\t\t\t\t\t\tmessage = message.charAt(0) + message;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tmessage = this.checkChat(message);\r\n\t\t\t}\r\n\t\t} catch (err: any) {\r\n\t\t\tif (err.name?.endsWith('ErrorMessage')) {\r\n\t\t\t\tthis.errorReply(err.message);\r\n\t\t\t\tthis.update();\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tif (err.name.endsWith('Interruption')) {\r\n\t\t\t\tthis.update();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tMonitor.crashlog(err, 'A chat command', {\r\n\t\t\t\tuser: this.user.name,\r\n\t\t\t\troom: this.room?.roomid,\r\n\t\t\t\tpmTarget: this.pmTarget?.name,\r\n\t\t\t\tmessage: this.message,\r\n\t\t\t});\r\n\t\t\tthis.sendReply(`|html|
Pokemon Showdown crashed!
Don't worry, we're working on fixing it.
`);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Output the message\r\n\t\tif (message && typeof (message as any).then === 'function') {\r\n\t\t\tthis.update();\r\n\t\t\treturn (message as Promise).then(resolvedMessage => {\r\n\t\t\t\tif (resolvedMessage && resolvedMessage !== true) {\r\n\t\t\t\t\tthis.sendChatMessage(resolvedMessage);\r\n\t\t\t\t}\r\n\t\t\t\tthis.update();\r\n\t\t\t\tif (resolvedMessage === false) return false;\r\n\t\t\t}).catch(err => {\r\n\t\t\t\tif (err.name?.endsWith('ErrorMessage')) {\r\n\t\t\t\t\tthis.errorReply(err.message);\r\n\t\t\t\t\tthis.update();\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t\tif (err.name.endsWith('Interruption')) {\r\n\t\t\t\t\tthis.update();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tMonitor.crashlog(err, 'An async chat command', {\r\n\t\t\t\t\tuser: this.user.name,\r\n\t\t\t\t\troom: this.room?.roomid,\r\n\t\t\t\t\tpmTarget: this.pmTarget?.name,\r\n\t\t\t\t\tmessage: this.message,\r\n\t\t\t\t});\r\n\t\t\t\tthis.sendReply(`|html|
Pokemon Showdown crashed!
Don't worry, we're working on fixing it.
`);\r\n\t\t\t\treturn false;\r\n\t\t\t});\r\n\t\t} else if (message && message !== true) {\r\n\t\t\tthis.sendChatMessage(message as string);\r\n\t\t\tmessage = true;\r\n\t\t}\r\n\r\n\t\tthis.update();\r\n\r\n\t\treturn message;\r\n\t}\r\n\r\n\tsendChatMessage(message: string) {\r\n\t\tif (this.pmTarget) {\r\n\t\t\tconst blockInvites = this.pmTarget.settings.blockInvites;\r\n\t\t\tif (blockInvites && /^<<.*>>$/.test(message.trim())) {\r\n\t\t\t\tif (\r\n\t\t\t\t\t!this.user.can('lock') && blockInvites === true ||\r\n\t\t\t\t\t!Users.globalAuth.atLeast(this.user, blockInvites as GroupSymbol)\r\n\t\t\t\t) {\r\n\t\t\t\t\tChat.maybeNotifyBlocked(`invite`, this.pmTarget, this.user);\r\n\t\t\t\t\treturn this.errorReply(`${this.pmTarget.name} is blocking room invites.`);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tChat.sendPM(message, this.user, this.pmTarget);\r\n\t\t} else if (this.room) {\r\n\t\t\tthis.room.add(`|c|${this.user.getIdentity(this.room)}|${message}`);\r\n\t\t\tif (this.room.game && this.room.game.onLogMessage) {\r\n\t\t\t\tthis.room.game.onLogMessage(message, this.user);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis.connection.popup(`Your message could not be sent:\\n\\n${message}\\n\\nIt needs to be sent to a user or room.`);\r\n\t\t}\r\n\t}\r\n\trun(handler: string | AnnotatedChatHandler) {\r\n\t\tif (typeof handler === 'string') handler = Chat.commands[handler] as AnnotatedChatHandler;\r\n\t\tif (!handler.broadcastable && this.cmdToken === '!') {\r\n\t\t\tthis.errorReply(`The command \"${this.fullCmd}\" can't be broadcast.`);\r\n\t\t\tthis.errorReply(`Use /${this.fullCmd} instead.`);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tlet result: any = handler.call(this, this.target, this.room, this.user, this.connection, this.cmd, this.message);\r\n\t\tif (result === undefined) result = false;\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tcheckFormat(room: BasicRoom | null | undefined, user: User, message: string) {\r\n\t\tif (!room) return true;\r\n\t\tif (\r\n\t\t\t!room.settings.filterStretching && !room.settings.filterCaps &&\r\n\t\t\t!room.settings.filterEmojis && !room.settings.filterLinks\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (user.can('mute', null, room)) return true;\r\n\r\n\t\tif (room.settings.filterStretching && /(.+?)\\1{5,}/i.test(user.name)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your username contains too much stretching, which this room doesn't allow.`);\r\n\t\t}\r\n\t\tif (room.settings.filterLinks) {\r\n\t\t\tconst bannedLinks = this.checkBannedLinks(message);\r\n\t\t\tif (bannedLinks.length) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\t\t`You have linked to ${bannedLinks.length > 1 ? 'unrecognized external websites' : 'an unrecognized external website'} ` +\r\n\t\t\t\t\t`(${bannedLinks.join(', ')}), which this room doesn't allow.`\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (room.settings.filterCaps && /[A-Z\\s]{6,}/.test(user.name)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your username contains too many capital letters, which this room doesn't allow.`);\r\n\t\t}\r\n\t\tif (room.settings.filterEmojis && EMOJI_REGEX.test(user.name)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your username contains emojis, which this room doesn't allow.`);\r\n\t\t}\r\n\t\t// Removes extra spaces and null characters\r\n\t\tmessage = message.trim().replace(/[ \\u0000\\u200B-\\u200F]+/g, ' ');\r\n\r\n\t\tif (room.settings.filterStretching && /(.+?)\\1{7,}/i.test(message)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your message contains too much stretching, which this room doesn't allow.`);\r\n\t\t}\r\n\t\tif (room.settings.filterCaps && /[A-Z\\s]{18,}/.test(message)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your message contains too many capital letters, which this room doesn't allow.`);\r\n\t\t}\r\n\t\tif (room.settings.filterEmojis && EMOJI_REGEX.test(message)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your message contains emojis, which this room doesn't allow.`);\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tcheckSlowchat(room: Room | null | undefined, user: User) {\r\n\t\tif (!room?.settings.slowchat) return true;\r\n\t\tif (user.can('show', null, room)) return true;\r\n\t\tconst lastActiveSeconds = (Date.now() - user.lastMessageTime) / 1000;\r\n\t\tif (lastActiveSeconds < room.settings.slowchat) {\r\n\t\t\tthrow new Chat.ErrorMessage(this.tr`This room has slow-chat enabled. You can only talk once every ${room.settings.slowchat} seconds.`);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tcheckBanwords(room: BasicRoom | null | undefined, message: string): boolean {\r\n\t\tif (!room) return true;\r\n\t\tif (!room.banwordRegex) {\r\n\t\t\tif (room.settings.banwords && room.settings.banwords.length) {\r\n\t\t\t\troom.banwordRegex = new RegExp('(?:\\\\b|(?!\\\\w))(?:' + room.settings.banwords.join('|') + ')(?:\\\\b|\\\\B(?!\\\\w))', 'i');\r\n\t\t\t} else {\r\n\t\t\t\troom.banwordRegex = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!message) return true;\r\n\t\tif (room.banwordRegex !== true && room.banwordRegex.test(message)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your username, status, or message contained a word banned by this room.`);\r\n\t\t}\r\n\t\treturn this.checkBanwords(room.parent as ChatRoom, message);\r\n\t}\r\n\tcheckGameFilter() {\r\n\t\tif (!this.room?.game || !this.room.game.onChatMessage) return;\r\n\t\treturn this.room.game.onChatMessage(this.message, this.user);\r\n\t}\r\n\tpmTransform(originalMessage: string, sender?: User, receiver?: User | null | string) {\r\n\t\tif (!sender) {\r\n\t\t\tif (this.room) throw new Error(`Not a PM`);\r\n\t\t\tsender = this.user;\r\n\t\t\treceiver = this.pmTarget;\r\n\t\t}\r\n\t\tconst targetIdentity = typeof receiver === 'string' ? ` ${receiver}` : receiver ? receiver.getIdentity() : '~';\r\n\t\tconst prefix = `|pm|${sender.getIdentity()}|${targetIdentity}|`;\r\n\t\treturn originalMessage.split('\\n').map(message => {\r\n\t\t\tif (message.startsWith('||')) {\r\n\t\t\t\treturn prefix + `/text ` + message.slice(2);\r\n\t\t\t} else if (message.startsWith(`|html|`)) {\r\n\t\t\t\treturn prefix + `/raw ` + message.slice(6);\r\n\t\t\t} else if (message.startsWith(`|uhtml|`)) {\r\n\t\t\t\tconst [uhtmlid, html] = Utils.splitFirst(message.slice(7), '|');\r\n\t\t\t\treturn prefix + `/uhtml ${uhtmlid},${html}`;\r\n\t\t\t} else if (message.startsWith(`|uhtmlchange|`)) {\r\n\t\t\t\tconst [uhtmlid, html] = Utils.splitFirst(message.slice(13), '|');\r\n\t\t\t\treturn prefix + `/uhtmlchange ${uhtmlid},${html}`;\r\n\t\t\t} else if (message.startsWith(`|modaction|`)) {\r\n\t\t\t\treturn prefix + `/log ` + message.slice(11);\r\n\t\t\t} else if (message.startsWith(`|raw|`)) {\r\n\t\t\t\treturn prefix + `/raw ` + message.slice(5);\r\n\t\t\t} else if (message.startsWith(`|error|`)) {\r\n\t\t\t\treturn prefix + `/error ` + message.slice(7);\r\n\t\t\t} else if (message.startsWith(`|c~|`)) {\r\n\t\t\t\treturn prefix + message.slice(4);\r\n\t\t\t} else if (message.startsWith(`|c|~|/`)) {\r\n\t\t\t\treturn prefix + message.slice(5);\r\n\t\t\t} else if (message.startsWith(`|c|~|`)) {\r\n\t\t\t\treturn prefix + `/text ` + message.slice(5);\r\n\t\t\t}\r\n\t\t\treturn prefix + `/text ` + message;\r\n\t\t}).join(`\\n`);\r\n\t}\r\n\tsendReply(data: string) {\r\n\t\tif (this.isQuiet) return;\r\n\t\tif (this.broadcasting && this.broadcastToRoom) {\r\n\t\t\t// broadcasting\r\n\t\t\tthis.add(data);\r\n\t\t} else {\r\n\t\t\t// not broadcasting\r\n\t\t\tif (!this.room) {\r\n\t\t\t\tdata = this.pmTransform(data);\r\n\t\t\t\tthis.connection.send(data);\r\n\t\t\t} else {\r\n\t\t\t\tthis.connection.sendTo(this.room, data);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\terrorReply(message: string) {\r\n\t\tif (this.bypassRoomCheck) { // if they're not in the room, we still want a good error message for them\r\n\t\t\treturn this.popupReply(\r\n\t\t\t\t`|html|${message.replace(/\\n/ig, '
')}
`\r\n\t\t\t);\r\n\t\t}\r\n\t\tthis.sendReply(`|error|` + message.replace(/\\n/g, `\\n|error|`));\r\n\t}\r\n\taddBox(htmlContent: string | JSX.VNode) {\r\n\t\tif (typeof htmlContent !== 'string') htmlContent = JSX.render(htmlContent);\r\n\t\tthis.add(`|html|
${htmlContent}
`);\r\n\t}\r\n\tsendReplyBox(htmlContent: string | JSX.VNode) {\r\n\t\tif (typeof htmlContent !== 'string') htmlContent = JSX.render(htmlContent);\r\n\t\tthis.sendReply(`|c|${this.room && this.broadcasting ? this.user.getIdentity() : '~'}|/raw
${htmlContent}
`);\r\n\t}\r\n\tpopupReply(message: string) {\r\n\t\tthis.connection.popup(message);\r\n\t}\r\n\tadd(data: string) {\r\n\t\tif (this.room) {\r\n\t\t\tthis.room.add(data);\r\n\t\t} else {\r\n\t\t\tthis.send(data);\r\n\t\t}\r\n\t}\r\n\tsend(data: string) {\r\n\t\tif (this.room) {\r\n\t\t\tthis.room.send(data);\r\n\t\t} else {\r\n\t\t\tdata = this.pmTransform(data);\r\n\t\t\tthis.user.send(data);\r\n\t\t\tif (this.pmTarget && this.pmTarget !== this.user) {\r\n\t\t\t\tthis.pmTarget.send(data);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/** like privateModAction, but also notify Staff room */\r\n\tprivateGlobalModAction(msg: string) {\r\n\t\tthis.privateModAction(msg);\r\n\t\tif (this.room?.roomid !== 'staff') {\r\n\t\t\tRooms.get('staff')?.addByUser(this.user, `${this.room ? `<<${this.room.roomid}>>` : ``} ${msg}`).update();\r\n\t\t}\r\n\t}\r\n\taddGlobalModAction(msg: string) {\r\n\t\tthis.addModAction(msg);\r\n\t\tif (this.room?.roomid !== 'staff') {\r\n\t\t\tRooms.get('staff')?.addByUser(this.user, `${this.room ? `<<${this.room.roomid}>>` : ``} ${msg}`).update();\r\n\t\t}\r\n\t}\r\n\r\n\tprivateModAction(msg: string) {\r\n\t\tif (this.room) {\r\n\t\t\tif (this.room.roomid === 'staff') {\r\n\t\t\t\tthis.room.addByUser(this.user, `(${msg})`);\r\n\t\t\t} else {\r\n\t\t\t\tthis.room.sendModsByUser(this.user, `(${msg})`);\r\n\t\t\t\t// roomlogging in staff causes a duplicate log message, since we do addByUser\r\n\t\t\t\t// and roomlogging in pms has no effect, so we can _just_ call this here\r\n\t\t\t\tthis.roomlog(`(${msg})`);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst data = this.pmTransform(`|modaction|${msg}`);\r\n\t\t\tthis.user.send(data);\r\n\t\t\tif (this.pmTarget && this.pmTarget !== this.user && this.pmTarget.isStaff) {\r\n\t\t\t\tthis.pmTarget.send(data);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tglobalModlog(action: string, user: string | User | null = null, note: string | null = null, ip?: string) {\r\n\t\tconst entry: PartialModlogEntry = {\r\n\t\t\taction,\r\n\t\t\tisGlobal: true,\r\n\t\t\tloggedBy: this.user.id,\r\n\t\t\tnote: note?.replace(/\\n/gm, ' ') || '',\r\n\t\t};\r\n\t\tif (user) {\r\n\t\t\tif (typeof user === 'string') {\r\n\t\t\t\tentry.userid = toID(user);\r\n\t\t\t} else {\r\n\t\t\t\tentry.ip = user.latestIp;\r\n\t\t\t\tconst userid = user.getLastId();\r\n\t\t\t\tentry.userid = userid;\r\n\t\t\t\tif (user.autoconfirmed && user.autoconfirmed !== userid) entry.autoconfirmedID = user.autoconfirmed;\r\n\t\t\t\tconst alts = user.getAltUsers(false, true).slice(1).map(alt => alt.getLastId());\r\n\t\t\t\tif (alts.length) entry.alts = alts;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (ip) entry.ip = ip;\r\n\t\tif (this.room) {\r\n\t\t\tthis.room.modlog(entry);\r\n\t\t} else {\r\n\t\t\tRooms.global.modlog(entry);\r\n\t\t}\r\n\t}\r\n\tmodlog(\r\n\t\taction: string,\r\n\t\tuser: string | User | null = null,\r\n\t\tnote: string | null = null,\r\n\t\toptions: Partial<{noalts: any, noip: any}> = {}\r\n\t) {\r\n\t\tconst entry: PartialModlogEntry = {\r\n\t\t\taction,\r\n\t\t\tloggedBy: this.user.id,\r\n\t\t\tnote: note?.replace(/\\n/gm, ' ') || '',\r\n\t\t};\r\n\t\tif (user) {\r\n\t\t\tif (typeof user === 'string') {\r\n\t\t\t\tentry.userid = toID(user);\r\n\t\t\t} else {\r\n\t\t\t\tconst userid = user.getLastId();\r\n\t\t\t\tentry.userid = userid;\r\n\t\t\t\tif (!options.noalts) {\r\n\t\t\t\t\tif (user.autoconfirmed && user.autoconfirmed !== userid) entry.autoconfirmedID = user.autoconfirmed;\r\n\t\t\t\t\tconst alts = user.getAltUsers(false, true).slice(1).map(alt => alt.getLastId());\r\n\t\t\t\t\tif (alts.length) entry.alts = alts;\r\n\t\t\t\t}\r\n\t\t\t\tif (!options.noip) entry.ip = user.latestIp;\r\n\t\t\t}\r\n\t\t}\r\n\t\t(this.room || Rooms.global).modlog(entry);\r\n\t}\r\n\tparseSpoiler(reason: string) {\r\n\t\tif (!reason) return {publicReason: \"\", privateReason: \"\"};\r\n\r\n\t\tlet publicReason = reason;\r\n\t\tlet privateReason = reason;\r\n\t\tconst targetLowercase = reason.toLowerCase();\r\n\t\tif (targetLowercase.includes('spoiler:') || targetLowercase.includes('spoilers:')) {\r\n\t\t\tconst proofIndex = targetLowercase.indexOf(targetLowercase.includes('spoilers:') ? 'spoilers:' : 'spoiler:');\r\n\t\t\tconst proofOffset = (targetLowercase.includes('spoilers:') ? 9 : 8);\r\n\t\t\tconst proof = reason.slice(proofIndex + proofOffset).trim();\r\n\t\t\tpublicReason = reason.slice(0, proofIndex).trim();\r\n\t\t\tprivateReason = `${publicReason}${proof ? ` (PROOF: ${proof})` : ''}`;\r\n\t\t}\r\n\t\treturn {publicReason, privateReason};\r\n\t}\r\n\troomlog(data: string) {\r\n\t\tif (this.room) this.room.roomlog(data);\r\n\t}\r\n\tstafflog(data: string) {\r\n\t\t(Rooms.get('staff') || Rooms.lobby || this.room)?.roomlog(data);\r\n\t}\r\n\taddModAction(msg: string) {\r\n\t\tif (this.room) {\r\n\t\t\tthis.room.addByUser(this.user, msg);\r\n\t\t} else {\r\n\t\t\tthis.send(`|modaction|${msg}`);\r\n\t\t}\r\n\t}\r\n\tupdate() {\r\n\t\tif (this.room) this.room.update();\r\n\t}\r\n\tfilter(message: string) {\r\n\t\treturn Chat.filter(message, this);\r\n\t}\r\n\tstatusfilter(status: string) {\r\n\t\treturn Chat.statusfilter(status, this.user);\r\n\t}\r\n\tcheckCan(permission: RoomPermission, target: User | ID | null, room: Room): undefined;\r\n\tcheckCan(permission: GlobalPermission, target?: User | ID | null): undefined;\r\n\tcheckCan(permission: string, target: User | ID | null = null, room: Room | null = null) {\r\n\t\tif (!Users.Auth.hasPermission(this.user, permission, target, room, this.fullCmd)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`${this.cmdToken}${this.fullCmd} - Access denied.`);\r\n\t\t}\r\n\t}\r\n\tprivatelyCheckCan(permission: RoomPermission, target: User | ID | null, room: Room): boolean;\r\n\tprivatelyCheckCan(permission: GlobalPermission, target?: User | ID | null): boolean;\r\n\tprivatelyCheckCan(permission: string, target: User | ID | null = null, room: Room | null = null) {\r\n\t\tthis.handler!.isPrivate = true;\r\n\t\tif (Users.Auth.hasPermission(this.user, permission, target, room, this.fullCmd)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tthis.commandDoesNotExist();\r\n\t}\r\n\tcanUseConsole() {\r\n\t\tif (!this.user.hasConsoleAccess(this.connection)) {\r\n\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\tthis.cmdToken + this.fullCmd + \" - Requires console access, please set up `Config.consoleips`.\"\r\n\t\t\t);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tshouldBroadcast() {\r\n\t\treturn this.cmdToken === BROADCAST_TOKEN;\r\n\t}\r\n\tcheckBroadcast(overrideCooldown?: boolean | string, suppressMessage?: string | null) {\r\n\t\tif (this.broadcasting || !this.shouldBroadcast()) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (this.user.locked && !(this.room?.roomid.startsWith('help-') || this.pmTarget?.can('lock'))) {\r\n\t\t\tthis.errorReply(`You cannot broadcast this command's information while locked.`);\r\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\r\n\t\t}\r\n\r\n\t\tif (this.room && !this.user.can('show', null, this.room)) {\r\n\t\t\tthis.errorReply(`You need to be voiced to broadcast this command's information.`);\r\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\r\n\t\t}\r\n\r\n\t\tif (!this.room && !this.pmTarget) {\r\n\t\t\tthis.errorReply(`Broadcasting a command with \"!\" in a PM or chatroom will show it that user or room.`);\r\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\r\n\t\t}\r\n\r\n\t\t// broadcast cooldown\r\n\t\tconst broadcastMessage = (suppressMessage || this.message).toLowerCase().replace(/[^a-z0-9\\s!,]/g, '');\r\n\t\tconst cooldownMessage = overrideCooldown === true ? null : (overrideCooldown || broadcastMessage);\r\n\r\n\t\tif (\r\n\t\t\tcooldownMessage && this.room && this.room.lastBroadcast === cooldownMessage &&\r\n\t\t\tthis.room.lastBroadcastTime >= Date.now() - BROADCAST_COOLDOWN\r\n\t\t) {\r\n\t\t\tthrow new Chat.ErrorMessage(`You can't broadcast this because it was just broadcasted. If this was intentional, use !rebroadcast ${this.message}`);\r\n\t\t}\r\n\r\n\t\tconst message = this.checkChat(suppressMessage || this.message);\r\n\t\tif (!message) {\r\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\r\n\t\t}\r\n\r\n\t\t// checkChat will only return true with no message\r\n\t\tthis.message = message;\r\n\t\tthis.broadcastMessage = broadcastMessage;\r\n\t\treturn true;\r\n\t}\r\n\trunBroadcast(overrideCooldown?: boolean | string, suppressMessage: string | null = null) {\r\n\t\tif (this.broadcasting || !this.shouldBroadcast()) {\r\n\t\t\t// Already being broadcast, or the user doesn't intend to broadcast.\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (!this.broadcastMessage) {\r\n\t\t\t// Permission hasn't been checked yet. Do it now.\r\n\t\t\tthis.checkBroadcast(overrideCooldown, suppressMessage);\r\n\t\t}\r\n\r\n\t\tthis.broadcasting = true;\r\n\r\n\t\tconst message = `${this.broadcastPrefix}${suppressMessage || this.message}`;\r\n\t\tif (this.pmTarget) {\r\n\t\t\tthis.sendReply(`|c~|${message}`);\r\n\t\t} else {\r\n\t\t\tthis.sendReply(`|c|${this.user.getIdentity(this.room)}|${message}`);\r\n\t\t}\r\n\t\tif (this.room) {\r\n\t\t\t// We don't want broadcasted messages in a room to be translated\r\n\t\t\t// according to a user's personal language setting.\r\n\t\t\tthis.language = this.room.settings.language || null;\r\n\t\t\tif (overrideCooldown !== true) {\r\n\t\t\t\tthis.room.lastBroadcast = overrideCooldown || this.broadcastMessage;\r\n\t\t\t\tthis.room.lastBroadcastTime = Date.now();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\t/* The sucrase transformation of optional chaining is too expensive to be used in a hot function like this. */\r\n\t/* eslint-disable @typescript-eslint/prefer-optional-chain */\r\n\tcheckChat(message: string, room?: Room | null, targetUser?: User | null): string;\r\n\tcheckChat(message?: null, room?: Room | null, targetUser?: User | null): void;\r\n\tcheckChat(message: string | null = null, room: Room | null = null, targetUser: User | null = null) {\r\n\t\tif (!targetUser && this.pmTarget) {\r\n\t\t\ttargetUser = this.pmTarget;\r\n\t\t}\r\n\t\tif (targetUser) {\r\n\t\t\troom = null;\r\n\t\t} else if (!room) {\r\n\t\t\t// @ts-ignore excludes GlobalRoom above\r\n\t\t\troom = this.room;\r\n\t\t}\r\n\t\tconst user = this.user;\r\n\t\tconst connection = this.connection;\r\n\r\n\t\tif (!user.named) {\r\n\t\t\tthrow new Chat.ErrorMessage(this.tr`You must choose a name before you can talk.`);\r\n\t\t}\r\n\t\tif (!user.can('bypassall')) {\r\n\t\t\tconst lockType = (user.namelocked ? this.tr`namelocked` : user.locked ? this.tr`locked` : ``);\r\n\t\t\tconst lockExpiration = Punishments.checkLockExpiration(user.namelocked || user.locked);\r\n\t\t\tif (room) {\r\n\t\t\t\tif (lockType && !room.settings.isHelp) {\r\n\t\t\t\t\tthis.sendReply(`|html|${this.tr`Get help with this`}`);\r\n\t\t\t\t\tif (user.locked === '#hostfilter') {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are locked due to your proxy / VPN and can't talk in chat.`);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are ${lockType} and can't talk in chat. ${lockExpiration}`);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (!room.persist && !room.roomid.startsWith('help-') && !(user.registered || user.autoconfirmed)) {\r\n\t\t\t\t\tthis.sendReply(\r\n\t\t\t\t\t\tthis.tr`|html|
You must be registered to chat in temporary rooms (like battles).
` +\r\n\t\t\t\t\t\tthis.tr`You may register in the menu.`\r\n\t\t\t\t\t);\r\n\t\t\t\t\tthrow new Chat.Interruption();\r\n\t\t\t\t}\r\n\t\t\t\tif (room.isMuted(user)) {\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are muted and cannot talk in this room.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (room.settings.modchat && !room.auth.atLeast(user, room.settings.modchat)) {\r\n\t\t\t\t\tif (room.settings.modchat === 'autoconfirmed') {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\t\t\t\tthis.tr`Because moderated chat is set, your account must be at least one week old and you must have won at least one ladder game to speak in this room.`\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (room.settings.modchat === 'trusted') {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\t\t\t\tthis.tr`Because moderated chat is set, your account must be staff in a public room or have a global rank to speak in this room.`\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tconst groupName = Config.groups[room.settings.modchat] && Config.groups[room.settings.modchat].name ||\r\n\t\t\t\t\t\troom.settings.modchat;\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\t\t\tthis.tr`Because moderated chat is set, you must be of rank ${groupName} or higher to speak in this room.`\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t\tif (!this.bypassRoomCheck && !(user.id in room.users)) {\r\n\t\t\t\t\tconnection.popup(`You can't send a message to this room without being in it.`);\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (targetUser) {\r\n\t\t\t\t// this accounts for users who are autoconfirmed on another alt, but not registered\r\n\t\t\t\tif (!(user.registered || user.autoconfirmed)) {\r\n\t\t\t\t\tthis.sendReply(\r\n\t\t\t\t\t\tthis.tr`|html|
You must be registered to send private messages.
` +\r\n\t\t\t\t\t\tthis.tr`You may register in the menu.`\r\n\t\t\t\t\t);\r\n\t\t\t\t\tthrow new Chat.Interruption();\r\n\t\t\t\t}\r\n\t\t\t\tif (targetUser.id !== user.id && !(targetUser.registered || targetUser.autoconfirmed)) {\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`That user is unregistered and cannot be PMed.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (lockType && !targetUser.can('lock')) {\r\n\t\t\t\t\tthis.sendReply(`|html|${this.tr`Get help with this`}`);\r\n\t\t\t\t\tif (user.locked === '#hostfilter') {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are locked due to your proxy / VPN and can only private message members of the global moderation team.`);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are ${lockType} and can only private message members of the global moderation team. ${lockExpiration}`);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (targetUser.locked && !user.can('lock')) {\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`The user \"${targetUser.name}\" is locked and cannot be PMed.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (Config.pmmodchat && !Users.globalAuth.atLeast(user, Config.pmmodchat) &&\r\n\t\t\t\t\t!Users.Auth.hasPermission(targetUser, 'promote', Config.pmmodchat as GroupSymbol)) {\r\n\t\t\t\t\tconst groupName = Config.groups[Config.pmmodchat] && Config.groups[Config.pmmodchat].name || Config.pmmodchat;\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`On this server, you must be of rank ${groupName} or higher to PM users.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (!this.checkCanPM(targetUser)) {\r\n\t\t\t\t\tChat.maybeNotifyBlocked('pm', targetUser, user);\r\n\t\t\t\t\tif (!targetUser.can('lock')) {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`This user is blocking private messages right now.`);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.sendReply(`|html|${this.tr`If you need help, try opening a help ticket`}`);\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`This ${Config.groups[targetUser.tempGroup].name} is too busy to answer private messages right now. Please contact a different staff member.`);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (!this.checkCanPM(user, targetUser)) {\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are blocking private messages right now.`);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (typeof message !== 'string') return true;\r\n\r\n\t\tif (!message) {\r\n\t\t\tthrow new Chat.ErrorMessage(this.tr`Your message can't be blank.`);\r\n\t\t}\r\n\t\tlet length = message.length;\r\n\t\tlength += 10 * message.replace(/[^\\ufdfd]*/g, '').length;\r\n\t\tif (length > MAX_MESSAGE_LENGTH && !user.can('ignorelimits')) {\r\n\t\t\tthrow new Chat.ErrorMessage(this.tr`Your message is too long: ` + message);\r\n\t\t}\r\n\r\n\t\t// remove zalgo\r\n\t\tmessage = message.replace(\r\n\t\t\t/[\\u0300-\\u036f\\u0483-\\u0489\\u0610-\\u0615\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06ED\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E]{3,}/g,\r\n\t\t\t''\r\n\t\t);\r\n\t\tif (/[\\u3164\\u115f\\u1160\\u239b-\\u23b9]/.test(message)) {\r\n\t\t\tthrow new Chat.ErrorMessage(this.tr`Your message contains banned characters.`);\r\n\t\t}\r\n\r\n\t\t// If the corresponding config option is set, non-AC users cannot send links, except to staff.\r\n\t\tif (Config.restrictLinks && !user.autoconfirmed) {\r\n\t\t\tif (this.checkBannedLinks(message).length && !(targetUser?.can('lock') || room?.settings.isHelp)) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(\"Your account must be autoconfirmed to send links to other users, except for global staff.\");\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.checkFormat(room, user, message);\r\n\r\n\t\tthis.checkSlowchat(room, user);\r\n\r\n\t\tif (!user.can('bypassall')) this.checkBanwords(room, user.name);\r\n\t\tif (user.userMessage && !user.can('bypassall')) this.checkBanwords(room, user.userMessage);\r\n\t\tif (room && !user.can('mute', null, room)) this.checkBanwords(room, message);\r\n\r\n\t\tconst gameFilter = this.checkGameFilter();\r\n\t\tif (typeof gameFilter === 'string') {\r\n\t\t\tif (gameFilter === '') throw new Chat.Interruption();\r\n\t\t\tthrow new Chat.ErrorMessage(gameFilter);\r\n\t\t}\r\n\r\n\t\tif (room?.settings.highTraffic &&\r\n\t\t\ttoID(message).replace(/[^a-z]+/, '').length < 2 &&\r\n\t\t\t!user.can('show', null, room)) {\r\n\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\tthis.tr`Due to this room being a high traffic room, your message must contain at least two letters.`\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tif (room) {\r\n\t\t\tconst normalized = message.trim();\r\n\t\t\tif (\r\n\t\t\t\t!user.can('bypassall') && (['help', 'lobby'].includes(room.roomid)) && (normalized === user.lastMessage) &&\r\n\t\t\t\t((Date.now() - user.lastMessageTime) < MESSAGE_COOLDOWN) && !Config.nothrottle\r\n\t\t\t) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You can't send the same message again so soon.`);\r\n\t\t\t}\r\n\t\t\tuser.lastMessage = message;\r\n\t\t\tuser.lastMessageTime = Date.now();\r\n\t\t}\r\n\r\n\t\tif (Chat.filters.length) {\r\n\t\t\treturn this.filter(message);\r\n\t\t}\r\n\r\n\t\treturn message;\r\n\t}\r\n\tcheckCanPM(targetUser: User, user?: User) {\r\n\t\tif (!user) user = this.user;\r\n\t\tif (user.id === targetUser.id) return true; // lol.\r\n\t\tconst setting = targetUser.settings.blockPMs;\r\n\t\tif (user.can('lock') || !setting) return true;\r\n\t\tif (setting === true && !user.can('lock')) return false; // this is to appease TS\r\n\t\tconst friends = targetUser.friends || new Set();\r\n\t\tif (setting === 'friends') return friends.has(user.id);\r\n\t\treturn Users.globalAuth.atLeast(user, setting as AuthLevel);\r\n\t}\r\n\tcheckPMHTML(targetUser: User) {\r\n\t\tif (!(this.room && (targetUser.id in this.room.users)) && !this.user.can('addhtml')) {\r\n\t\t\tthrow new Chat.ErrorMessage(\"You do not have permission to use PM HTML to users who are not in this room.\");\r\n\t\t}\r\n\t\tconst friends = targetUser.friends || new Set();\r\n\t\tif (targetUser.settings.blockPMs &&\r\n\t\t\t(targetUser.settings.blockPMs === true ||\r\n\t\t\t(targetUser.settings.blockPMs === 'friends' && !friends.has(this.user.id)) ||\r\n\t\t\t!Users.globalAuth.atLeast(this.user, targetUser.settings.blockPMs as AuthLevel)) &&\r\n\t\t\t!this.user.can('lock')\r\n\t\t) {\r\n\t\t\tChat.maybeNotifyBlocked('pm', targetUser, this.user);\r\n\t\t\tthrow new Chat.ErrorMessage(\"This user is currently blocking PMs.\");\r\n\t\t}\r\n\t\tif (targetUser.locked && !this.user.can('lock')) {\r\n\t\t\tthrow new Chat.ErrorMessage(\"This user is currently locked, so you cannot send them HTML.\");\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tcheckBannedLinks(message: string) {\r\n\t\t// RegExp#exec only returns one match, String#match returns all of them\r\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-regexp-exec\r\n\t\treturn (message.match(Chat.linkRegex) || []).filter(link => {\r\n\t\t\tlink = link.toLowerCase();\r\n\t\t\tconst domainMatches = /^(?:http:\\/\\/|https:\\/\\/)?(?:[^/]*\\.)?([^/.]*\\.[^/.]*)\\.?($|\\/|:)/.exec(link);\r\n\t\t\tconst domain = domainMatches?.[1];\r\n\t\t\tconst hostMatches = /^(?:http:\\/\\/|https:\\/\\/)?([^/]*[^/.])\\.?($|\\/|:)/.exec(link);\r\n\t\t\tlet host = hostMatches?.[1];\r\n\t\t\tif (host?.startsWith('www.')) host = host.slice(4);\r\n\t\t\tif (!domain || !host) return null;\r\n\t\t\treturn !(LINK_WHITELIST.includes(host) || LINK_WHITELIST.includes(`*.${domain}`));\r\n\t\t});\r\n\t}\r\n\t/* eslint-enable @typescript-eslint/prefer-optional-chain */\r\n\tcheckEmbedURI(uri: string) {\r\n\t\tif (uri.startsWith('https://')) return uri;\r\n\t\tif (uri.startsWith('//')) return uri;\r\n\t\tif (uri.startsWith('data:')) {\r\n\t\t\treturn uri;\r\n\t\t} else {\r\n\t\t\tthrow new Chat.ErrorMessage(\"Image URLs must begin with 'https://' or 'data:'; 'http://' cannot be used.\");\r\n\t\t}\r\n\t}\r\n\t/**\r\n\t * This is a quick and dirty first-pass \"is this good HTML\" check. The full\r\n\t * sanitization is done on the client by Caja in `src/battle-log.ts`\r\n\t * `BattleLog.sanitizeHTML`.\r\n\t */\r\n\tcheckHTML(htmlContent: string | null) {\r\n\t\thtmlContent = ('' + (htmlContent || '')).trim();\r\n\t\tif (!htmlContent) return '';\r\n\t\tif (/>here.?]]');\r\n\t\t}\r\n\r\n\t\t// check for mismatched tags\r\n\t\tconst tags = htmlContent.match(/|<\\/?[^<>]*/g);\r\n\t\tif (tags) {\r\n\t\t\tconst ILLEGAL_TAGS = [\r\n\t\t\t\t'script', 'head', 'body', 'html', 'canvas', 'base', 'meta', 'link', 'iframe',\r\n\t\t\t];\r\n\t\t\tconst LEGAL_AUTOCLOSE_TAGS = [\r\n\t\t\t\t// void elements (no-close tags)\r\n\t\t\t\t'br', 'area', 'embed', 'hr', 'img', 'source', 'track', 'input', 'wbr', 'col',\r\n\t\t\t\t// autoclose tags\r\n\t\t\t\t'p', 'li', 'dt', 'dd', 'option', 'tr', 'th', 'td', 'thead', 'tbody', 'tfoot', 'colgroup',\r\n\t\t\t\t// PS custom element\r\n\t\t\t\t'psicon', 'youtube',\r\n\t\t\t];\r\n\t\t\tconst stack = [];\r\n\t\t\tfor (const tag of tags) {\r\n\t\t\t\tconst isClosingTag = tag.charAt(1) === '/';\r\n\t\t\t\tconst contentEndLoc = tag.endsWith('/') ? -1 : undefined;\r\n\t\t\t\tconst tagContent = tag.slice(isClosingTag ? 2 : 1, contentEndLoc).replace(/\\s+/, ' ').trim();\r\n\t\t\t\tconst tagNameEndIndex = tagContent.indexOf(' ');\r\n\t\t\t\tconst tagName = tagContent.slice(0, tagNameEndIndex >= 0 ? tagNameEndIndex : undefined).toLowerCase();\r\n\t\t\t\tif (tagName === '!--') continue;\r\n\t\t\t\tif (isClosingTag) {\r\n\t\t\t\t\tif (LEGAL_AUTOCLOSE_TAGS.includes(tagName)) continue;\r\n\t\t\t\t\tif (!stack.length) {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Extraneous without an opening tag.`);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tconst expectedTagName = stack.pop();\r\n\t\t\t\t\tif (tagName !== expectedTagName) {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Extraneous where was expected.`);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (ILLEGAL_TAGS.includes(tagName) || !/^[a-z]+[0-9]?$/.test(tagName)) {\r\n\t\t\t\t\tthrow new Chat.ErrorMessage(`Illegal tag <${tagName}> can't be used here.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (!LEGAL_AUTOCLOSE_TAGS.includes(tagName)) {\r\n\t\t\t\t\tstack.push(tagName);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (tagName === 'img') {\r\n\t\t\t\t\tif (!this.room || (this.room.settings.isPersonal && !this.user.can('lock'))) {\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\t\t\t\t`This tag is not allowed: <${tagContent}>. Images are not allowed outside of chatrooms.`\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!/width ?= ?(?:[0-9]+|\"[0-9]+\")/i.test(tagContent) || !/height ?= ?(?:[0-9]+|\"[0-9]+\")/i.test(tagContent)) {\r\n\t\t\t\t\t\t// Width and height are required because most browsers insert the\r\n\t\t\t\t\t\t// element before width and height are known, and when the\r\n\t\t\t\t\t\t// image is loaded, this changes the height of the chat area, which\r\n\t\t\t\t\t\t// messes up autoscrolling.\r\n\t\t\t\t\t\tthis.errorReply(`This image is missing a width/height attribute: <${tagContent}>`);\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Images without predefined width/height cause problems with scrolling because loading them changes their height.`);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tconst srcMatch = / src ?= ?(?:\"|')?([^ \"']+)(?: ?(?:\"|'))?/i.exec(tagContent);\r\n\t\t\t\t\tif (srcMatch) {\r\n\t\t\t\t\t\tthis.checkEmbedURI(srcMatch[1]);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.errorReply(`This image has a broken src attribute: <${tagContent}>`);\r\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`The src attribute must exist and have no spaces in the URL`);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (tagName === 'button') {\r\n\t\t\t\t\tif ((!this.room || this.room.settings.isPersonal || this.room.settings.isPrivate === true) && !this.user.can('lock')) {\r\n\t\t\t\t\t\tconst buttonName = / name ?= ?\"([^\"]*)\"/i.exec(tagContent)?.[1];\r\n\t\t\t\t\t\tconst buttonValue = / value ?= ?\"([^\"]*)\"/i.exec(tagContent)?.[1];\r\n\t\t\t\t\t\tconst msgCommandRegex = /^\\/(?:msg|pm|w|whisper|botmsg) /;\r\n\t\t\t\t\t\tconst botmsgCommandRegex = /^\\/msgroom (?:[a-z0-9-]+), ?\\/botmsg /;\r\n\t\t\t\t\t\tif (buttonName === 'send' && buttonValue && msgCommandRegex.test(buttonValue)) {\r\n\t\t\t\t\t\t\tconst [pmTarget] = buttonValue.replace(msgCommandRegex, '').split(',');\r\n\t\t\t\t\t\t\tconst auth = this.room ? this.room.auth : Users.globalAuth;\r\n\t\t\t\t\t\t\tif (auth.get(toID(pmTarget)) !== '*' && toID(pmTarget) !== this.user.id) {\r\n\t\t\t\t\t\t\t\tthis.errorReply(`This button is not allowed: <${tagContent}>`);\r\n\t\t\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Your scripted button can't send PMs to ${pmTarget}, because that user is not a Room Bot.`);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else if (buttonName === 'send' && buttonValue && botmsgCommandRegex.test(buttonValue)) {\r\n\t\t\t\t\t\t\t// no need to validate the bot being an actual bot; `/botmsg` will do it for us and is not abusable\r\n\t\t\t\t\t\t} else if (buttonName) {\r\n\t\t\t\t\t\t\tthis.errorReply(`This button is not allowed: <${tagContent}>`);\r\n\t\t\t\t\t\t\tthis.errorReply(`You do not have permission to use most buttons. Here are the two types you're allowed to use:`);\r\n\t\t\t\t\t\t\tthis.errorReply(`1. Linking to a room: `);\r\n\t\t\t\t\t\t\tthrow new Chat.ErrorMessage(`2. Sending a message to a Bot: `);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (stack.length) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`Missing .`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn htmlContent;\r\n\t}\r\n\r\n\t/**\r\n\t * This is to be used for commands that replicate other commands\r\n\t * (for example, `/pm username, command` or `/msgroom roomid, command`)\r\n\t * to ensure they do not crash with too many levels of recursion.\r\n\t */\r\n\tcheckRecursion() {\r\n\t\tif (this.recursionDepth > 5) {\r\n\t\t\tthrow new Chat.ErrorMessage(`/${this.cmd} - Too much command recursion has occurred.`);\r\n\t\t}\r\n\t}\r\n\r\n\trequireRoom(id?: RoomID) {\r\n\t\tif (!this.room) {\r\n\t\t\tthrow new Chat.ErrorMessage(`/${this.cmd} - must be used in a chat room, not a ${this.pmTarget ? \"PM\" : \"console\"}`);\r\n\t\t}\r\n\t\tif (id && this.room.roomid !== id) {\r\n\t\t\tconst targetRoom = Rooms.get(id);\r\n\t\t\tif (!targetRoom) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`This command can only be used in the room '${id}', but that room does not exist.`);\r\n\t\t\t}\r\n\t\t\tthrow new Chat.ErrorMessage(`This command can only be used in the ${targetRoom.title} room.`);\r\n\t\t}\r\n\t\treturn this.room;\r\n\t}\r\n\t// eslint-disable-next-line @typescript-eslint/type-annotation-spacing\r\n\trequireGame(constructor: new (...args: any[]) => T, subGame = false) {\r\n\t\tconst room = this.requireRoom();\r\n\t\tif (subGame) {\r\n\t\t\tif (!room.subGame) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`This command requires a sub-game of ${constructor.name} (this room has no sub-game).`);\r\n\t\t\t}\r\n\t\t\tconst game = room.getGame(constructor, subGame);\r\n\t\t\t// must be a different game\r\n\t\t\tif (!game) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`This command requires a sub-game of ${constructor.name} (this sub-game is ${room.subGame.title}).`);\r\n\t\t\t}\r\n\t\t\treturn game;\r\n\t\t}\r\n\t\tif (!room.game) {\r\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a game of ${constructor.name} (this room has no game).`);\r\n\t\t}\r\n\t\tconst game = room.getGame(constructor);\r\n\t\t// must be a different game\r\n\t\tif (!game) {\r\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a game of ${constructor.name} (this game is ${room.game.title}).`);\r\n\t\t}\r\n\t\treturn game;\r\n\t}\r\n\trequireMinorActivity(constructor: new (...args: any[]) => T) {\r\n\t\tconst room = this.requireRoom();\r\n\t\tif (!room.minorActivity) {\r\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a ${constructor.name} (this room has no minor activity).`);\r\n\t\t}\r\n\t\tconst game = room.getMinorActivity(constructor);\r\n\t\t// must be a different game\r\n\t\tif (!game) {\r\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a ${constructor.name} (this minor activity is a(n) ${room.minorActivity.name}).`);\r\n\t\t}\r\n\t\treturn game;\r\n\t}\r\n\tcommandDoesNotExist(): never {\r\n\t\tif (this.cmdToken === '!') {\r\n\t\t\tthrow new Chat.ErrorMessage(`The command \"${this.cmdToken}${this.fullCmd}\" does not exist.`);\r\n\t\t}\r\n\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t`The command \"${this.cmdToken}${this.fullCmd}\" does not exist. To send a message starting with \"${this.cmdToken}${this.fullCmd}\", type \"${this.cmdToken}${this.cmdToken}${this.fullCmd}\".`\r\n\t\t);\r\n\t}\r\n\trefreshPage(pageid: string) {\r\n\t\tif (this.connection.openPages?.has(pageid)) {\r\n\t\t\tthis.parse(`/join view-${pageid}`);\r\n\t\t}\r\n\t}\r\n\tclosePage(pageid: string) {\r\n\t\tfor (const connection of this.user.connections) {\r\n\t\t\tif (connection.openPages?.has(pageid)) {\r\n\t\t\t\tconnection.send(`>view-${pageid}\\n|deinit`);\r\n\t\t\t\tconnection.openPages.delete(pageid);\r\n\t\t\t\tif (!connection.openPages.size) {\r\n\t\t\t\t\tconnection.openPages = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport const Chat = new class {\r\n\tconstructor() {\r\n\t\tvoid this.loadTranslations().then(() => {\r\n\t\t\tChat.translationsLoaded = true;\r\n\t\t});\r\n\t}\r\n\ttranslationsLoaded = false;\r\n\t/**\r\n\t * As per the node.js documentation at https://nodejs.org/api/timers.html#timers_settimeout_callback_delay_args,\r\n\t * timers with durations that are too long for a 32-bit signed integer will be invoked after 1 millisecond,\r\n\t * which tends to cause unexpected behavior.\r\n\t */\r\n\treadonly MAX_TIMEOUT_DURATION = 2147483647;\r\n\treadonly Friends = new FriendsDatabase();\r\n\treadonly PM = PM;\r\n\r\n\treadonly multiLinePattern = new PatternTester();\r\n\r\n\t/*********************************************************\r\n\t * Load command files\r\n\t *********************************************************/\r\n\tbaseCommands!: AnnotatedChatCommands;\r\n\tcommands!: AnnotatedChatCommands;\r\n\tbasePages!: PageTable;\r\n\tpages!: PageTable;\r\n\treadonly destroyHandlers: (() => void)[] = [Artemis.destroy];\r\n\treadonly crqHandlers: {[k: string]: CRQHandler} = {};\r\n\treadonly handlers: {[k: string]: ((...args: any) => any)[]} = Object.create(null);\r\n\t/** The key is the name of the plugin. */\r\n\treadonly plugins: {[k: string]: ChatPlugin} = {};\r\n\t/** Will be empty except during hotpatch */\r\n\toldPlugins: {[k: string]: ChatPlugin} = {};\r\n\troomSettings: SettingsHandler[] = [];\r\n\r\n\t/*********************************************************\r\n\t * Load chat filters\r\n\t *********************************************************/\r\n\treadonly filters: ChatFilter[] = [];\r\n\tfilter(message: string, context: CommandContext) {\r\n\t\t// Chat filters can choose to:\r\n\t\t// 1. return false OR null - to not send a user's message\r\n\t\t// 2. return an altered string - to alter a user's message\r\n\t\t// 3. return undefined to send the original message through\r\n\t\tconst originalMessage = message;\r\n\t\tfor (const curFilter of Chat.filters) {\r\n\t\t\tconst output = curFilter.call(\r\n\t\t\t\tcontext,\r\n\t\t\t\tmessage,\r\n\t\t\t\tcontext.user,\r\n\t\t\t\tcontext.room,\r\n\t\t\t\tcontext.connection,\r\n\t\t\t\tcontext.pmTarget,\r\n\t\t\t\toriginalMessage\r\n\t\t\t);\r\n\t\t\tif (output === false) return null;\r\n\t\t\tif (!output && output !== undefined) return output;\r\n\t\t\tif (output !== undefined) message = output;\r\n\t\t}\r\n\r\n\t\treturn message;\r\n\t}\r\n\r\n\treadonly namefilters: NameFilter[] = [];\r\n\tnamefilter(name: string, user: User) {\r\n\t\tif (!Config.disablebasicnamefilter) {\r\n\t\t\t// whitelist\r\n\t\t\t// \\u00A1-\\u00BF\\u00D7\\u00F7 Latin punctuation/symbols\r\n\t\t\t// \\u02B9-\\u0362 basic combining accents\r\n\t\t\t// \\u2012-\\u2027\\u2030-\\u205E Latin punctuation/symbols extended\r\n\t\t\t// \\u2050-\\u205F fractions extended\r\n\t\t\t// \\u2190-\\u23FA\\u2500-\\u2BD1 misc symbols\r\n\t\t\t// \\u2E80-\\u32FF CJK symbols\r\n\t\t\t// \\u3400-\\u9FFF CJK\r\n\t\t\t// \\uF900-\\uFAFF\\uFE00-\\uFE6F CJK extended\r\n\t\t\tname = name.replace(\r\n\t\t\t\t// eslint-disable-next-line no-misleading-character-class\r\n\t\t\t\t/[^a-zA-Z0-9 /\\\\.~()<>^*%&=+$#_'?!\"\\u00A1-\\u00BF\\u00D7\\u00F7\\u02B9-\\u0362\\u2012-\\u2027\\u2030-\\u205E\\u2050-\\u205F\\u2190-\\u23FA\\u2500-\\u2BD1\\u2E80-\\u32FF\\u3400-\\u9FFF\\uF900-\\uFAFF\\uFE00-\\uFE6F-]+/g,\r\n\t\t\t\t''\r\n\t\t\t);\r\n\r\n\t\t\t// blacklist\r\n\t\t\t// \\u00a1 upside-down exclamation mark (i)\r\n\t\t\t// \\u2580-\\u2590 black bars\r\n\t\t\t// \\u25A0\\u25Ac\\u25AE\\u25B0 black bars\r\n\t\t\t// \\u534d\\u5350 swastika\r\n\t\t\t// \\u2a0d crossed integral (f)\r\n\t\t\tname = name.replace(/[\\u00a1\\u2580-\\u2590\\u25A0\\u25Ac\\u25AE\\u25B0\\u2a0d\\u534d\\u5350]/g, '');\r\n\r\n\t\t\t// e-mail address\r\n\t\t\tif (name.includes('@') && name.includes('.')) return '';\r\n\r\n\t\t\t// url\r\n\t\t\tif (/[a-z0-9]\\.(com|net|org|us|uk|co|gg|tk|ml|gq|ga|xxx|download|stream)\\b/i.test(name)) name = name.replace(/\\./g, '');\r\n\r\n\t\t\t// Limit the amount of symbols allowed in usernames to 4 maximum, and\r\n\t\t\t// disallow (R) and (C) from being used in the middle of names.\r\n\t\t\tconst nameSymbols = name.replace(\r\n\t\t\t\t/[^\\u00A1-\\u00BF\\u00D7\\u00F7\\u02B9-\\u0362\\u2012-\\u2027\\u2030-\\u205E\\u2050-\\u205F\\u2090-\\u23FA\\u2500-\\u2BD1]+/g,\r\n\t\t\t\t''\r\n\t\t\t);\r\n\t\t\t// \\u00ae\\u00a9 (R) (C)\r\n\t\t\tif (\r\n\t\t\t\tnameSymbols.length > 4 ||\r\n\t\t\t\t/[^a-z0-9][a-z0-9][^a-z0-9]/.test(name.toLowerCase() + ' ') || /[\\u00ae\\u00a9].*[a-zA-Z0-9]/.test(name)\r\n\t\t\t) {\r\n\t\t\t\tname = name.replace(\r\n\t\t\t\t\t// eslint-disable-next-line no-misleading-character-class\r\n\t\t\t\t\t/[\\u00A1-\\u00BF\\u00D7\\u00F7\\u02B9-\\u0362\\u2012-\\u2027\\u2030-\\u205E\\u2050-\\u205F\\u2190-\\u23FA\\u2500-\\u2BD1\\u2E80-\\u32FF\\u3400-\\u9FFF\\uF900-\\uFAFF\\uFE00-\\uFE6F]+/g,\r\n\t\t\t\t\t''\r\n\t\t\t\t).replace(/[^A-Za-z0-9]{2,}/g, ' ').trim();\r\n\t\t\t}\r\n\t\t}\r\n\t\tname = name.replace(/^[^A-Za-z0-9]+/, \"\"); // remove symbols from start\r\n\t\tname = name.replace(/@/g, \"\"); // Remove @ as this is used to indicate status messages\r\n\r\n\t\t// cut name length down to 18 chars\r\n\t\tif (/[A-Za-z0-9]/.test(name.slice(18))) {\r\n\t\t\tname = name.replace(/[^A-Za-z0-9]+/g, \"\");\r\n\t\t} else {\r\n\t\t\tname = name.slice(0, 18);\r\n\t\t}\r\n\r\n\t\tname = Dex.getName(name);\r\n\t\tfor (const curFilter of Chat.namefilters) {\r\n\t\t\tname = curFilter(name, user);\r\n\t\t\tif (!name) return '';\r\n\t\t}\r\n\t\treturn name;\r\n\t}\r\n\r\n\treadonly hostfilters: HostFilter[] = [];\r\n\thostfilter(host: string, user: User, connection: Connection, hostType: string) {\r\n\t\tfor (const curFilter of Chat.hostfilters) {\r\n\t\t\tcurFilter(host, user, connection, hostType);\r\n\t\t}\r\n\t}\r\n\r\n\treadonly loginfilters: LoginFilter[] = [];\r\n\tloginfilter(user: User, oldUser: User | null, usertype: string) {\r\n\t\tfor (const curFilter of Chat.loginfilters) {\r\n\t\t\tcurFilter(user, oldUser, usertype);\r\n\t\t}\r\n\t}\r\n\r\n\treadonly punishmentfilters: PunishmentFilter[] = [];\r\n\tpunishmentfilter(user: User | ID, punishment: Punishment) {\r\n\t\tfor (const curFilter of Chat.punishmentfilters) {\r\n\t\t\tcurFilter(user, punishment);\r\n\t\t}\r\n\t}\r\n\r\n\treadonly nicknamefilters: NicknameFilter[] = [];\r\n\tnicknamefilter(nickname: string, user: User) {\r\n\t\tfor (const curFilter of Chat.nicknamefilters) {\r\n\t\t\tconst filtered = curFilter(nickname, user);\r\n\t\t\tif (filtered === false) return false;\r\n\t\t\tif (!filtered) return '';\r\n\t\t}\r\n\t\treturn nickname;\r\n\t}\r\n\r\n\treadonly statusfilters: StatusFilter[] = [];\r\n\tstatusfilter(status: string, user: User) {\r\n\t\tstatus = status.replace(/\\|/g, '');\r\n\t\tfor (const curFilter of Chat.statusfilters) {\r\n\t\t\tstatus = curFilter(status, user);\r\n\t\t\tif (!status) return '';\r\n\t\t}\r\n\t\treturn status;\r\n\t}\r\n\t/*********************************************************\r\n\t * Translations\r\n\t *********************************************************/\r\n\t/** language id -> language name */\r\n\treadonly languages = new Map();\r\n\t/** language id -> (english string -> translated string) */\r\n\treadonly translations = new Map>();\r\n\r\n\tasync loadTranslations() {\r\n\t\tconst directories = await FS(TRANSLATION_DIRECTORY).readdir();\r\n\r\n\t\t// ensure that english is the first entry when we iterate over Chat.languages\r\n\t\tChat.languages.set('english' as ID, 'English');\r\n\t\tfor (const dirname of directories) {\r\n\t\t\t// translation dirs shouldn't have caps, but things like sourceMaps and the README will\r\n\t\t\tif (/[^a-z0-9]/.test(dirname)) continue;\r\n\t\t\tconst dir = FS(`${TRANSLATION_DIRECTORY}/${dirname}`);\r\n\r\n\t\t\t// For some reason, toID() isn't available as a global when this executes.\r\n\t\t\tconst languageID = Dex.toID(dirname);\r\n\t\t\tconst files = await dir.readdir();\r\n\t\t\tfor (const filename of files) {\r\n\t\t\t\tif (!filename.endsWith('.js')) continue;\r\n\r\n\t\t\t\tconst content: Translations = require(`${TRANSLATION_DIRECTORY}/${dirname}/${filename}`).translations;\r\n\r\n\t\t\t\tif (!Chat.translations.has(languageID)) {\r\n\t\t\t\t\tChat.translations.set(languageID, new Map());\r\n\t\t\t\t}\r\n\t\t\t\tconst translationsSoFar = Chat.translations.get(languageID)!;\r\n\r\n\t\t\t\tif (content.name && !Chat.languages.has(languageID)) {\r\n\t\t\t\t\tChat.languages.set(languageID, content.name);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (content.strings) {\r\n\t\t\t\t\tfor (const key in content.strings) {\r\n\t\t\t\t\t\tconst keyLabels: string[] = [];\r\n\t\t\t\t\t\tconst valLabels: string[] = [];\r\n\t\t\t\t\t\tconst newKey = key.replace(/\\${.+?}/g, str => {\r\n\t\t\t\t\t\t\tkeyLabels.push(str);\r\n\t\t\t\t\t\t\treturn '${}';\r\n\t\t\t\t\t\t}).replace(/\\[TN: ?.+?\\]/g, '');\r\n\t\t\t\t\t\tconst val = content.strings[key].replace(/\\${.+?}/g, (str: string) => {\r\n\t\t\t\t\t\t\tvalLabels.push(str);\r\n\t\t\t\t\t\t\treturn '${}';\r\n\t\t\t\t\t\t}).replace(/\\[TN: ?.+?\\]/g, '');\r\n\t\t\t\t\t\ttranslationsSoFar.set(newKey, [val, keyLabels, valLabels]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!Chat.languages.has(languageID)) {\r\n\t\t\t\t// Fallback in case no translation files provide the language's name\r\n\t\t\t\tChat.languages.set(languageID, \"Unknown Language\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\ttr(language: ID | null): (fStrings: TemplateStringsArray | string, ...fKeys: any) => string;\r\n\ttr(language: ID | null, strings: TemplateStringsArray | string, ...keys: any[]): string;\r\n\ttr(language: ID | null, strings: TemplateStringsArray | string = '', ...keys: any[]) {\r\n\t\tif (!language) language = 'english' as ID;\r\n\t\t// If strings is an array (normally the case), combine before translating.\r\n\t\tconst trString = typeof strings === 'string' ? strings : strings.join('${}');\r\n\r\n\t\tif (Chat.translationsLoaded && !Chat.translations.has(language)) {\r\n\t\t\tthrow new Error(`Trying to translate to a nonexistent language: ${language}`);\r\n\t\t}\r\n\t\tif (!strings.length) {\r\n\t\t\treturn ((fStrings: TemplateStringsArray | string, ...fKeys: any) => Chat.tr(language, fStrings, ...fKeys));\r\n\t\t}\r\n\r\n\t\tconst entry = Chat.translations.get(language)?.get(trString);\r\n\t\tlet [translated, keyLabels, valLabels] = entry || [\"\", [], []];\r\n\t\tif (!translated) translated = trString;\r\n\r\n\t\t// Replace the gaps in the species string\r\n\t\tif (keys.length) {\r\n\t\t\tlet reconstructed = '';\r\n\r\n\t\t\tconst left: (string | null)[] = keyLabels.slice();\r\n\t\t\tfor (const [i, str] of translated.split('${}').entries()) {\r\n\t\t\t\treconstructed += str;\r\n\t\t\t\tif (keys[i]) {\r\n\t\t\t\t\tlet index = left.indexOf(valLabels[i]);\r\n\t\t\t\t\tif (index < 0) {\r\n\t\t\t\t\t\tindex = left.findIndex(val => !!val);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (index < 0) index = i;\r\n\t\t\t\t\treconstructed += keys[index];\r\n\t\t\t\t\tleft[index] = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\ttranslated = reconstructed;\r\n\t\t}\r\n\t\treturn translated;\r\n\t}\r\n\r\n\t/**\r\n\t * SQL handler\r\n\t *\r\n\t * All chat plugins share one database.\r\n\t * Chat.databaseReadyPromise will be truthy if the database is not yet ready.\r\n\t */\r\n\tdatabase = SQL(module, {\r\n\t\tfile: ('Config' in global && Config.nofswriting) ? ':memory:' : PLUGIN_DATABASE_PATH,\r\n\t\tprocesses: global.Config?.chatdbprocesses || 1,\r\n\t});\r\n\tdatabaseReadyPromise: Promise | null = null;\r\n\r\n\tasync prepareDatabase() {\r\n\t\t// PLEASE NEVER ACTUALLY ADD MIGRATIONS\r\n\t\t// things break in weird ways that are hard to reason about, probably because of subprocesses\r\n\t\t// it WILL crash and it WILL make your life and that of your users extremely unpleasant until it is fixed\r\n\t\tif (!PM.isParentProcess) return; // We don't need a database in a subprocess that requires Chat.\r\n\t\tif (!Config.usesqlite) return;\r\n\t\t// check if we have the db_info table, which will always be present unless the schema needs to be initialized\r\n\t\tconst {hasDBInfo} = await this.database.get(\r\n\t\t\t`SELECT count(*) AS hasDBInfo FROM sqlite_master WHERE type = 'table' AND name = 'db_info'`\r\n\t\t);\r\n\t\tif (!hasDBInfo) await this.database.runFile('./databases/schemas/chat-plugins.sql');\r\n\r\n\t\tconst result = await this.database.get(\r\n\t\t\t`SELECT value as curVersion FROM db_info WHERE key = 'version'`\r\n\t\t);\r\n\t\tconst curVersion = parseInt(result.curVersion);\r\n\t\tif (!curVersion) throw new Error(`db_info table is present, but schema version could not be parsed`);\r\n\r\n\t\t// automatically run migrations of the form \"v{number}.sql\" in the migrations/chat-plugins folder\r\n\t\tconst migrationsFolder = './databases/migrations/chat-plugins';\r\n\t\tconst migrationsToRun = [];\r\n\t\tfor (const migrationFile of (await FS(migrationsFolder).readdir())) {\r\n\t\t\tconst migrationVersion = parseInt(/v(\\d+)\\.sql$/.exec(migrationFile)?.[1] || '');\r\n\t\t\tif (!migrationVersion) continue;\r\n\t\t\tif (migrationVersion > curVersion) {\r\n\t\t\t\tmigrationsToRun.push({version: migrationVersion, file: migrationFile});\r\n\t\t\t\tMonitor.adminlog(`Pushing to migrationsToRun: ${migrationVersion} at ${migrationFile} - mainModule ${process.mainModule === module} !process.send ${!process.send}`);\r\n\t\t\t}\r\n\t\t}\r\n\t\tUtils.sortBy(migrationsToRun, ({version}) => version);\r\n\t\tfor (const {file} of migrationsToRun) {\r\n\t\t\tawait this.database.runFile(pathModule.resolve(migrationsFolder, file));\r\n\t\t}\r\n\r\n\t\tChat.destroyHandlers.push(() => void Chat.database?.destroy());\r\n\t}\r\n\r\n\treadonly MessageContext = MessageContext;\r\n\treadonly CommandContext = CommandContext;\r\n\treadonly PageContext = PageContext;\r\n\treadonly ErrorMessage = ErrorMessage;\r\n\treadonly Interruption = Interruption;\r\n\r\n\t// JSX handling\r\n\treadonly JSX = JSX;\r\n\treadonly html = JSX.html;\r\n\treadonly h = JSX.h;\r\n\treadonly Fragment = JSX.Fragment;\r\n\r\n\t/**\r\n\t * Command parser\r\n\t *\r\n\t * Usage:\r\n\t * Chat.parse(message, room, user, connection)\r\n\t *\r\n\t * Parses the message. If it's a command, the command is executed, if\r\n\t * not, it's displayed directly in the room.\r\n\t *\r\n\t * Examples:\r\n\t * Chat.parse(\"/join lobby\", room, user, connection)\r\n\t * will make the user join the lobby.\r\n\t *\r\n\t * Chat.parse(\"Hi, guys!\", room, user, connection)\r\n\t * will return \"Hi, guys!\" if the user isn't muted, or\r\n\t * if he's muted, will warn him that he's muted.\r\n\t *\r\n\t * The return value is the return value of the command handler, if any,\r\n\t * or the message, if there wasn't a command. This value could be a success\r\n\t * or failure (few commands report these) or a Promise for when the command\r\n\t * is done executing, if it's not currently done.\r\n\t *\r\n\t * @param message - the message the user is trying to say\r\n\t * @param room - the room the user is trying to say it in\r\n\t * @param user - the user that sent the message\r\n\t * @param connection - the connection the user sent the message from\r\n\t */\r\n\tparse(message: string, room: Room | null | undefined, user: User, connection: Connection) {\r\n\t\tChat.loadPlugins();\r\n\r\n\t\tconst initialRoomlogLength = room?.log.getLineCount();\r\n\t\tconst context = new CommandContext({message, room, user, connection});\r\n\t\tconst start = Date.now();\r\n\t\tconst result = context.parse();\r\n\t\tif (typeof result?.then === 'function') {\r\n\t\t\tvoid result.then(() => {\r\n\t\t\t\tthis.logSlowMessage(start, context);\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tthis.logSlowMessage(start, context);\r\n\t\t}\r\n\t\tif (room && room.log.getLineCount() !== initialRoomlogLength) {\r\n\t\t\troom.messagesSent++;\r\n\t\t\tfor (const [handler, numMessages] of room.nthMessageHandlers) {\r\n\t\t\t\tif (room.messagesSent % numMessages === 0) handler(room, message);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\tlogSlowMessage(start: number, context: CommandContext) {\r\n\t\tconst timeUsed = Date.now() - start;\r\n\t\tif (timeUsed < 1000) return;\r\n\t\tif (context.cmd === 'search' || context.cmd === 'savereplay') return;\r\n\r\n\t\tconst logMessage = (\r\n\t\t\t`[slow command] ${timeUsed}ms - ${context.user.name} (${context.connection.ip}): ` +\r\n\t\t\t`<${context.room ? context.room.roomid : context.pmTarget ? `PM:${context.pmTarget?.name}` : 'CMD'}> ` +\r\n\t\t\t`${context.message.replace(/\\n/ig, ' ')}`\r\n\t\t);\r\n\r\n\t\tMonitor.slow(logMessage);\r\n\t}\r\n\tsendPM(message: string, user: User, pmTarget: User, onlyRecipient: User | null = null) {\r\n\t\tconst buf = `|pm|${user.getIdentity()}|${pmTarget.getIdentity()}|${message}`;\r\n\t\tif (onlyRecipient) return onlyRecipient.send(buf);\r\n\t\tuser.send(buf);\r\n\t\tif (pmTarget !== user) pmTarget.send(buf);\r\n\t\tpmTarget.lastPM = user.id;\r\n\t\tuser.lastPM = pmTarget.id;\r\n\t}\r\n\r\n\tpackageData: AnyObject = {};\r\n\r\n\tgetPluginName(file: string) {\r\n\t\tconst nameWithExt = pathModule.relative(__dirname, file).replace(/^chat-(?:commands|plugins)./, '');\r\n\t\tlet name = nameWithExt.slice(0, nameWithExt.lastIndexOf('.'));\r\n\t\tif (name.endsWith('/index')) name = name.slice(0, -6);\r\n\t\treturn name;\r\n\t}\r\n\r\n\tloadPluginFile(file: string) {\r\n\t\tif (!file.endsWith('.js')) return;\r\n\t\tthis.loadPlugin(require(file), this.getPluginName(file));\r\n\t}\r\n\r\n\tloadPluginDirectory(dir: string, depth = 0) {\r\n\t\tfor (const file of FS(dir).readdirSync()) {\r\n\t\t\tconst path = pathModule.resolve(dir, file);\r\n\t\t\tif (FS(path).isDirectorySync()) {\r\n\t\t\t\tdepth++;\r\n\t\t\t\tif (depth > MAX_PLUGIN_LOADING_DEPTH) continue;\r\n\t\t\t\tthis.loadPluginDirectory(path, depth);\r\n\t\t\t} else {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tthis.loadPluginFile(path);\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tMonitor.crashlog(e, \"A loading chat plugin\");\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tannotateCommands(commandTable: AnyObject, namespace = ''): AnnotatedChatCommands {\r\n\t\tfor (const cmd in commandTable) {\r\n\t\t\tconst entry = commandTable[cmd];\r\n\t\t\tif (typeof entry === 'object') {\r\n\t\t\t\tthis.annotateCommands(entry, `${namespace}${cmd} `);\r\n\t\t\t}\r\n\t\t\tif (typeof entry === 'string') {\r\n\t\t\t\tconst base = commandTable[entry];\r\n\t\t\t\tif (!base) continue;\r\n\t\t\t\tif (!base.aliases) base.aliases = [];\r\n\t\t\t\tif (!base.aliases.includes(cmd)) base.aliases.push(cmd);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (typeof entry !== 'function') continue;\r\n\r\n\t\t\tconst handlerCode = entry.toString();\r\n\t\t\tentry.requiresRoom = /requireRoom\\((?:'|\"|`)(.*?)(?:'|\"|`)/.exec(handlerCode)?.[1] as RoomID || /this\\.requireRoom\\(/.test(handlerCode);\r\n\t\t\tentry.hasRoomPermissions = /\\bthis\\.(checkCan|can)\\([^,)\\n]*, [^,)\\n]*,/.test(handlerCode);\r\n\t\t\tentry.broadcastable = cmd.endsWith('help') || /\\bthis\\.(?:(check|can|run|should)Broadcast)\\(/.test(handlerCode);\r\n\t\t\tentry.isPrivate = /\\bthis\\.(?:privately(Check)?Can|commandDoesNotExist)\\(/.test(handlerCode);\r\n\t\t\tentry.requiredPermission = /this\\.(?:checkCan|privately(?:Check)?Can)\\(['`\"]([a-zA-Z0-9]+)['\"`](\\)|, )/.exec(handlerCode)?.[1];\r\n\t\t\tif (!entry.aliases) entry.aliases = [];\r\n\r\n\t\t\t// assign properties from the base command if the current command uses CommandContext.run.\r\n\t\t\tconst runsCommand = /this.run\\((?:'|\"|`)(.*?)(?:'|\"|`)\\)/.exec(handlerCode);\r\n\t\t\tif (runsCommand) {\r\n\t\t\t\tconst [, baseCommand] = runsCommand;\r\n\t\t\t\tconst baseEntry = commandTable[baseCommand];\r\n\t\t\t\tif (baseEntry) {\r\n\t\t\t\t\tif (baseEntry.requiresRoom) entry.requiresRoom = baseEntry.requiresRoom;\r\n\t\t\t\t\tif (baseEntry.hasRoomPermissions) entry.hasRoomPermissions = baseEntry.hasRoomPermissions;\r\n\t\t\t\t\tif (baseEntry.broadcastable) entry.broadcastable = baseEntry.broadcastable;\r\n\t\t\t\t\tif (baseEntry.isPrivate) entry.isPrivate = baseEntry.isPrivate;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// This is usually the same as `entry.name`, but some weirdness like\r\n\t\t\t// `commands.a = b` could screw it up. This should make it consistent.\r\n\t\t\tentry.cmd = cmd;\r\n\t\t\tentry.fullCmd = `${namespace}${cmd}`;\r\n\t\t}\r\n\t\treturn commandTable;\r\n\t}\r\n\tloadPlugin(plugin: AnyObject, name: string) {\r\n\t\t// esbuild builds cjs exports in such a way that they use getters, leading to crashes\r\n\t\t// in the plugin.roomSettings = [plugin.roomSettings] action. So, we have to make them not getters\r\n\t\tplugin = {...plugin};\r\n\t\tif (plugin.commands) {\r\n\t\t\tObject.assign(Chat.commands, this.annotateCommands(plugin.commands));\r\n\t\t}\r\n\t\tif (plugin.pages) {\r\n\t\t\tObject.assign(Chat.pages, plugin.pages);\r\n\t\t}\r\n\r\n\t\tif (plugin.destroy) {\r\n\t\t\tChat.destroyHandlers.push(plugin.destroy);\r\n\t\t}\r\n\t\tif (plugin.crqHandlers) {\r\n\t\t\tObject.assign(Chat.crqHandlers, plugin.crqHandlers);\r\n\t\t}\r\n\t\tif (plugin.roomSettings) {\r\n\t\t\tif (!Array.isArray(plugin.roomSettings)) plugin.roomSettings = [plugin.roomSettings];\r\n\t\t\tChat.roomSettings = Chat.roomSettings.concat(plugin.roomSettings);\r\n\t\t}\r\n\t\tif (plugin.chatfilter) Chat.filters.push(plugin.chatfilter);\r\n\t\tif (plugin.namefilter) Chat.namefilters.push(plugin.namefilter);\r\n\t\tif (plugin.hostfilter) Chat.hostfilters.push(plugin.hostfilter);\r\n\t\tif (plugin.loginfilter) Chat.loginfilters.push(plugin.loginfilter);\r\n\t\tif (plugin.punishmentfilter) Chat.punishmentfilters.push(plugin.punishmentfilter);\r\n\t\tif (plugin.nicknamefilter) Chat.nicknamefilters.push(plugin.nicknamefilter);\r\n\t\tif (plugin.statusfilter) Chat.statusfilters.push(plugin.statusfilter);\r\n\t\tif (plugin.onRenameRoom) {\r\n\t\t\tif (!Chat.handlers['onRenameRoom']) Chat.handlers['onRenameRoom'] = [];\r\n\t\t\tChat.handlers['onRenameRoom'].push(plugin.onRenameRoom);\r\n\t\t}\r\n\t\tif (plugin.onRoomClose) {\r\n\t\t\tif (!Chat.handlers['onRoomClose']) Chat.handlers['onRoomClose'] = [];\r\n\t\t\tChat.handlers['onRoomClose'].push(plugin.onRoomClose);\r\n\t\t}\r\n\t\tif (plugin.handlers) {\r\n\t\t\tfor (const handlerName in plugin.handlers) {\r\n\t\t\t\tif (!Chat.handlers[handlerName]) Chat.handlers[handlerName] = [];\r\n\t\t\t\tChat.handlers[handlerName].push(plugin.handlers[handlerName]);\r\n\t\t\t}\r\n\t\t}\r\n\t\tChat.plugins[name] = plugin;\r\n\t}\r\n\tloadPlugins(oldPlugins?: {[k: string]: ChatPlugin}) {\r\n\t\tif (Chat.commands) return;\r\n\t\tif (oldPlugins) Chat.oldPlugins = oldPlugins;\r\n\r\n\t\tvoid FS('package.json').readIfExists().then(data => {\r\n\t\t\tif (data) Chat.packageData = JSON.parse(data);\r\n\t\t});\r\n\r\n\t\t// Install plug-in commands and chat filters\r\n\r\n\r\n\t\tChat.commands = Object.create(null);\r\n\t\tChat.pages = Object.create(null);\r\n\t\tthis.loadPluginDirectory('dist/server/chat-commands');\r\n\t\tChat.baseCommands = Chat.commands;\r\n\t\tChat.basePages = Chat.pages;\r\n\t\tChat.commands = Object.assign(Object.create(null), Chat.baseCommands);\r\n\t\tChat.pages = Object.assign(Object.create(null), Chat.basePages);\r\n\r\n\t\t// Load filters from Config\r\n\t\tthis.loadPlugin(Config, 'config');\r\n\t\tthis.loadPlugin(Tournaments, 'tournaments');\r\n\r\n\t\tthis.loadPluginDirectory('dist/server/chat-plugins');\r\n\t\tChat.oldPlugins = {};\r\n\t\t// lower priority should run later\r\n\t\tUtils.sortBy(Chat.filters, filter => -(filter.priority || 0));\r\n\t}\r\n\r\n\tdestroy() {\r\n\t\tfor (const handler of Chat.destroyHandlers) {\r\n\t\t\thandler();\r\n\t\t}\r\n\t}\r\n\r\n\trunHandlers(name: keyof Handlers, ...args: Parameters) {\r\n\t\tconst handlers = this.handlers[name];\r\n\t\tif (!handlers) return;\r\n\t\tfor (const h of handlers) {\r\n\t\t\tvoid h.call(this, ...args);\r\n\t\t}\r\n\t}\r\n\r\n\thandleRoomRename(oldID: RoomID, newID: RoomID, room: Room) {\r\n\t\tChat.runHandlers('onRenameRoom', oldID, newID, room);\r\n\t}\r\n\r\n\thandleRoomClose(roomid: RoomID, user: User, connection: Connection) {\r\n\t\tChat.runHandlers('onRoomClose', roomid, user, connection, roomid.startsWith('view-'));\r\n\t}\r\n\r\n\t/**\r\n\t * Takes a chat message and returns data about any command it's\r\n\t * trying to use.\r\n\t *\r\n\t * Returning `null` means the chat message isn't trying to use\r\n\t * a command, and returning `{handler: null}` means it's trying\r\n\t * to use a command that doesn't exist.\r\n\t */\r\n\tparseCommand(message: string, recursing = false): {\r\n\t\tcmd: string, fullCmd: string, cmdToken: string, target: string, handler: AnnotatedChatHandler | null,\r\n\t} | null {\r\n\t\tif (!message.trim()) return null;\r\n\r\n\t\t// hardcoded commands\r\n\t\tif (message.startsWith(`>> `)) {\r\n\t\t\tmessage = `/eval ${message.slice(3)}`;\r\n\t\t} else if (message.startsWith(`>>> `)) {\r\n\t\t\tmessage = `/evalbattle ${message.slice(4)}`;\r\n\t\t} else if (message.startsWith('>>sql ')) {\r\n\t\t\tmessage = `/evalsql ${message.slice(6)}`;\r\n\t\t} else if (message.startsWith(`/me`) && /[^A-Za-z0-9 ]/.test(message.charAt(3))) {\r\n\t\t\tmessage = `/mee ${message.slice(3)}`;\r\n\t\t} else if (message.startsWith(`/ME`) && /[^A-Za-z0-9 ]/.test(message.charAt(3))) {\r\n\t\t\tmessage = `/MEE ${message.slice(3)}`;\r\n\t\t}\r\n\r\n\t\tconst cmdToken = message.charAt(0);\r\n\t\tif (!VALID_COMMAND_TOKENS.includes(cmdToken)) return null;\r\n\t\tif (cmdToken === message.charAt(1)) return null;\r\n\t\tif (cmdToken === BROADCAST_TOKEN && /[^A-Za-z0-9]/.test(message.charAt(1))) return null;\r\n\r\n\t\tlet [cmd, target] = Utils.splitFirst(message.slice(1), ' ');\r\n\t\tcmd = cmd.toLowerCase();\r\n\r\n\t\tif (cmd.endsWith(',')) cmd = cmd.slice(0, -1);\r\n\r\n\t\tlet curCommands: AnnotatedChatCommands = Chat.commands;\r\n\t\tlet commandHandler;\r\n\t\tlet fullCmd = cmd;\r\n\t\tlet prevCmdName = '';\r\n\r\n\t\tdo {\r\n\t\t\tif (cmd in curCommands) {\r\n\t\t\t\tcommandHandler = curCommands[cmd];\r\n\t\t\t} else {\r\n\t\t\t\tcommandHandler = undefined;\r\n\t\t\t}\r\n\t\t\tif (typeof commandHandler === 'string') {\r\n\t\t\t\t// in case someone messed up, don't loop\r\n\t\t\t\tcommandHandler = curCommands[commandHandler];\r\n\t\t\t} else if (Array.isArray(commandHandler) && !recursing) {\r\n\t\t\t\treturn this.parseCommand(cmdToken + 'help ' + fullCmd.slice(0, -4), true);\r\n\t\t\t}\r\n\t\t\tif (commandHandler && typeof commandHandler === 'object') {\r\n\t\t\t\t[cmd, target] = Utils.splitFirst(target, ' ');\r\n\t\t\t\tcmd = cmd.toLowerCase();\r\n\r\n\t\t\t\tprevCmdName = fullCmd;\r\n\t\t\t\tfullCmd += ' ' + cmd;\r\n\t\t\t\tcurCommands = commandHandler as AnnotatedChatCommands;\r\n\t\t\t}\r\n\t\t} while (commandHandler && typeof commandHandler === 'object');\r\n\r\n\t\tif (!commandHandler && (curCommands.default || curCommands[''])) {\r\n\t\t\tcommandHandler = curCommands.default || curCommands[''];\r\n\t\t\tfullCmd = prevCmdName;\r\n\t\t\ttarget = `${cmd}${target ? ` ${target}` : ''}`;\r\n\t\t\tcmd = fullCmd.split(' ').shift()!;\r\n\t\t\tif (typeof commandHandler === 'string') {\r\n\t\t\t\tcommandHandler = curCommands[commandHandler];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!commandHandler && !recursing) {\r\n\t\t\tfor (const g in Config.groups) {\r\n\t\t\t\tconst groupid = Config.groups[g].id;\r\n\t\t\t\tif (fullCmd === groupid) {\r\n\t\t\t\t\treturn this.parseCommand(`/promote ${target}, ${g}`, true);\r\n\t\t\t\t} else if (fullCmd === 'global' + groupid) {\r\n\t\t\t\t\treturn this.parseCommand(`/globalpromote ${target}, ${g}`, true);\r\n\t\t\t\t} else if (fullCmd === 'de' + groupid || fullCmd === 'un' + groupid ||\r\n\t\t\t\t\t\tfullCmd === 'globalde' + groupid || fullCmd === 'deglobal' + groupid) {\r\n\t\t\t\t\treturn this.parseCommand(`/demote ${target}`, true);\r\n\t\t\t\t} else if (fullCmd === 'room' + groupid) {\r\n\t\t\t\t\treturn this.parseCommand(`/roompromote ${target}, ${g}`, true);\r\n\t\t\t\t} else if (fullCmd === 'forceroom' + groupid) {\r\n\t\t\t\t\treturn this.parseCommand(`/forceroompromote ${target}, ${g}`, true);\r\n\t\t\t\t} else if (fullCmd === 'roomde' + groupid || fullCmd === 'deroom' + groupid || fullCmd === 'roomun' + groupid) {\r\n\t\t\t\t\treturn this.parseCommand(`/roomdemote ${target}`, true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tcmd: cmd,\r\n\t\t\tcmdToken: cmdToken,\r\n\t\t\ttarget: target,\r\n\t\t\tfullCmd: fullCmd,\r\n\t\t\thandler: commandHandler as AnnotatedChatHandler | null,\r\n\t\t};\r\n\t}\r\n\tallCommands(table: ChatCommands = Chat.commands) {\r\n\t\tconst results: AnnotatedChatHandler[] = [];\r\n\t\tfor (const cmd in table) {\r\n\t\t\tconst handler = table[cmd];\r\n\t\t\tif (Array.isArray(handler) || !handler || ['string', 'boolean'].includes(typeof handler)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (typeof handler === 'object') {\r\n\t\t\t\tresults.push(...this.allCommands(handler));\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tresults.push(handler as AnnotatedChatHandler);\r\n\t\t}\r\n\t\tif (table !== Chat.commands) return results;\r\n\t\treturn results.filter((handler, i) => results.indexOf(handler) === i);\r\n\t}\r\n\r\n\t/**\r\n\t * Strips HTML from a string.\r\n\t */\r\n\tstripHTML(htmlContent: string) {\r\n\t\tif (!htmlContent) return '';\r\n\t\treturn htmlContent.replace(/<[^>]*>/g, '');\r\n\t}\r\n\t/**\r\n\t * Validates input regex and ensures it won't crash.\r\n\t */\r\n\tvalidateRegex(word: string) {\r\n\t\tword = word.trim();\r\n\t\tif ((word.endsWith('|') && !word.endsWith('\\\\|')) || word.startsWith('|')) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Your regex was rejected because it included an unterminated |.`);\r\n\t\t}\r\n\t\ttry {\r\n\t\t\t// eslint-disable-next-line no-new\r\n\t\t\tnew RegExp(word);\r\n\t\t} catch (e: any) {\r\n\t\t\tthrow new Chat.ErrorMessage(\r\n\t\t\t\te.message.startsWith('Invalid regular expression: ') ?\r\n\t\t\t\t\te.message :\r\n\t\t\t\t\t`Invalid regular expression: /${word}/: ${e.message}`\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns singular (defaulting to '') if num is 1, or plural\r\n\t * (defaulting to 's') otherwise. Helper function for pluralizing\r\n\t * words.\r\n\t */\r\n\tplural(num: any, pluralSuffix = 's', singular = '') {\r\n\t\tif (num && typeof num.length === 'number') {\r\n\t\t\tnum = num.length;\r\n\t\t} else if (num && typeof num.size === 'number') {\r\n\t\t\tnum = num.size;\r\n\t\t} else {\r\n\t\t\tnum = Number(num);\r\n\t\t}\r\n\t\treturn (num !== 1 ? pluralSuffix : singular);\r\n\t}\r\n\r\n\t/**\r\n\t * Counts the thing passed.\r\n\t *\r\n\t * Chat.count(2, \"days\") === \"2 days\"\r\n\t * Chat.count(1, \"days\") === \"1 day\"\r\n\t * Chat.count([\"foo\"], \"things are\") === \"1 thing is\"\r\n\t *\r\n\t */\r\n\tcount(num: any, pluralSuffix: string, singular = \"\") {\r\n\t\tif (num && typeof num.length === 'number') {\r\n\t\t\tnum = num.length;\r\n\t\t} else if (num && typeof num.size === 'number') {\r\n\t\t\tnum = num.size;\r\n\t\t} else {\r\n\t\t\tnum = Number(num);\r\n\t\t}\r\n\t\tif (!singular) {\r\n\t\t\tif (pluralSuffix.endsWith(\"s\")) {\r\n\t\t\t\tsingular = pluralSuffix.slice(0, -1);\r\n\t\t\t} else if (pluralSuffix.endsWith(\"s have\")) {\r\n\t\t\t\tsingular = pluralSuffix.slice(0, -6) + \" has\";\r\n\t\t\t} else if (pluralSuffix.endsWith(\"s were\")) {\r\n\t\t\t\tsingular = pluralSuffix.slice(0, -6) + \" was\";\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst space = singular.startsWith('<') ? '' : ' ';\r\n\t\treturn `${num}${space}${num > 1 ? pluralSuffix : singular}`;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a timestamp in the form {yyyy}-{MM}-{dd} {hh}:{mm}:{ss}.\r\n\t *\r\n\t * options.human = true will reports hours human-readable\r\n\t */\r\n\ttoTimestamp(date: Date, options: {human?: boolean} = {}) {\r\n\t\tconst human = options.human;\r\n\t\tlet parts: any[] = [\r\n\t\t\tdate.getFullYear(),\tdate.getMonth() + 1, date.getDate(),\r\n\t\t\tdate.getHours(), date.getMinutes(),\tdate.getSeconds(),\r\n\t\t];\r\n\t\tif (human) {\r\n\t\t\tparts.push(parts[3] >= 12 ? 'pm' : 'am');\r\n\t\t\tparts[3] = parts[3] % 12 || 12;\r\n\t\t}\r\n\t\tparts = parts.map(val => val < 10 ? '0' + val : '' + val);\r\n\t\treturn parts.slice(0, 3).join(\"-\") + \" \" + parts.slice(3, human ? 5 : 6).join(\":\") + (human ? \"\" + parts[6] : \"\");\r\n\t}\r\n\r\n\t/**\r\n\t * Takes a number of milliseconds, and reports the duration in English: hours, minutes, etc.\r\n\t *\r\n\t * options.hhmmss = true will instead report the duration in 00:00:00 format\r\n\t *\r\n\t */\r\n\ttoDurationString(val: number, options: {hhmmss?: boolean, precision?: number} = {}) {\r\n\t\t// TODO: replace by Intl.DurationFormat or equivalent when it becomes available (ECMA-402)\r\n\t\t// https://github.com/tc39/ecma402/issues/47\r\n\t\tconst date = new Date(+val);\r\n\t\tif (isNaN(date.getTime())) return 'forever';\r\n\r\n\t\tconst parts = [\r\n\t\t\tdate.getUTCFullYear() - 1970, date.getUTCMonth(), date.getUTCDate() - 1,\r\n\t\t\tdate.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(),\r\n\t\t];\r\n\t\tconst roundingBoundaries = [6, 15, 12, 30, 30];\r\n\t\tconst unitNames = [\"second\", \"minute\", \"hour\", \"day\", \"month\", \"year\"];\r\n\t\tconst positiveIndex = parts.findIndex(elem => elem > 0);\r\n\t\tlet precision = (options?.precision ? options.precision : 3);\r\n\t\tif (options?.hhmmss) {\r\n\t\t\tconst str = parts.slice(positiveIndex).map(value => value < 10 ? \"0\" + value : \"\" + value).join(\":\");\r\n\t\t\treturn str.length === 2 ? \"00:\" + str : str;\r\n\t\t}\r\n\r\n\t\t// round least significant displayed unit\r\n\t\tif (positiveIndex + precision < parts.length && precision > 0 && positiveIndex >= 0) {\r\n\t\t\tif (parts[positiveIndex + precision] >= roundingBoundaries[positiveIndex + precision - 1]) {\r\n\t\t\t\tparts[positiveIndex + precision - 1]++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// don't display trailing 0's if the number is exact\r\n\t\tlet precisionIndex = 5;\r\n\t\twhile (precisionIndex > positiveIndex && !parts[precisionIndex]) {\r\n\t\t\tprecisionIndex--;\r\n\t\t}\r\n\t\tprecision = Math.min(precision, precisionIndex - positiveIndex + 1);\r\n\r\n\t\treturn parts\r\n\t\t\t.slice(positiveIndex)\r\n\t\t\t.reverse()\r\n\t\t\t.map((value, index) => `${value} ${unitNames[index]}${value !== 1 ? \"s\" : \"\"}`)\r\n\t\t\t.reverse()\r\n\t\t\t.slice(0, precision)\r\n\t\t\t.join(\" \")\r\n\t\t\t.trim();\r\n\t}\r\n\r\n\t/**\r\n\t * Takes an array and turns it into a sentence string by adding commas and the word \"and\"\r\n\t */\r\n\ttoListString(arr: string[], conjunction = \"and\") {\r\n\t\tif (!arr.length) return '';\r\n\t\tif (arr.length === 1) return arr[0];\r\n\t\tif (arr.length === 2) return `${arr[0]} ${conjunction.trim()} ${arr[1]}`;\r\n\t\treturn `${arr.slice(0, -1).join(\", \")}, ${conjunction.trim()} ${arr.slice(-1)[0]}`;\r\n\t}\r\n\r\n\t/**\r\n\t * Takes an array and turns it into a sentence string by adding commas and the word \"or\"\r\n\t */\r\n\ttoOrList(arr: string[]) {\r\n\t\tif (!arr.length) return '';\r\n\t\tif (arr.length === 1) return arr[0];\r\n\t\tif (arr.length === 2) return `${arr[0]} or ${arr[1]}`;\r\n\t\treturn `${arr.slice(0, -1).join(\", \")}, or ${arr.slice(-1)[0]}`;\r\n\t}\r\n\r\n\t/**\r\n\t * Convert multiline HTML into a single line without losing whitespace (so\r\n\t *
 blocks still render correctly). Linebreaks inside <> are replaced\r\n\t * with ` `, and linebreaks outside <> are replaced with `
`.\r\n\t *\r\n\t * PS's protocol often requires sending a block of HTML in a single line,\r\n\t * so this ensures any block of HTML ends up as a single line.\r\n\t */\r\n\tcollapseLineBreaksHTML(htmlContent: string) {\r\n\t\thtmlContent = htmlContent.replace(/<[^>]*>/g, tag => tag.replace(/\\n/g, ' '));\r\n\t\thtmlContent = htmlContent.replace(/\\n/g, '
');\r\n\t\treturn htmlContent;\r\n\t}\r\n\t/**\r\n\t * Takes a string of text and transforms it into a block of html using the details tag.\r\n\t * If it has a newline, will make the 3 lines the preview, and fill the rest in.\r\n\t * @param str string to block\r\n\t */\r\n\tgetReadmoreBlock(str: string, isCode?: boolean, cutoff = 3) {\r\n\t\tconst params = str.slice(+str.startsWith('\\n')).split('\\n');\r\n\t\tconst output: string[] = [];\r\n\t\tfor (const [i, param] of params.entries()) {\r\n\t\t\tif (output.length < cutoff && param.length > 80 && cutoff > 2) cutoff--;\r\n\t\t\tif (param.length > cutoff * 160 && i < cutoff) cutoff = i;\r\n\t\t\toutput.push(Utils[isCode ? 'escapeHTMLForceWrap' : 'escapeHTML'](param));\r\n\t\t}\r\n\r\n\t\tif (output.length > cutoff) {\r\n\t\t\treturn `
${\r\n\t\t\t\toutput.slice(0, cutoff).join('
')\r\n\t\t\t}
${\r\n\t\t\t\toutput.slice(cutoff).join('
')\r\n\t\t\t}
`;\r\n\t\t} else {\r\n\t\t\tconst tag = isCode ? `code` : `div`;\r\n\t\t\treturn `<${tag} style=\"white-space: pre-wrap; display: table; tab-size: 3\">${\r\n\t\t\t\toutput.join('
')\r\n\t\t\t}`;\r\n\t\t}\r\n\t}\r\n\r\n\tgetReadmoreCodeBlock(str: string, cutoff?: number) {\r\n\t\treturn Chat.getReadmoreBlock(str, true, cutoff);\r\n\t}\r\n\r\n\tgetDataPokemonHTML(species: Species, gen = 8, tier = '') {\r\n\t\tlet buf = '
  • ';\r\n\t\tbuf += '' + (tier || species.tier) + ' ';\r\n\t\tbuf += ` `;\r\n\t\tbuf += `${species.name} `;\r\n\t\tbuf += '';\r\n\t\tif (species.types) {\r\n\t\t\tfor (const type of species.types) {\r\n\t\t\t\tbuf += `\"${type}\"`;\r\n\t\t\t}\r\n\t\t}\r\n\t\tbuf += ' ';\r\n\t\tif (gen >= 3) {\r\n\t\t\tbuf += '';\r\n\t\t\tif (species.abilities['1'] && (gen >= 4 || Dex.abilities.get(species.abilities['1']).gen === 3)) {\r\n\t\t\t\tbuf += '' + species.abilities['0'] + '
    ' + species.abilities['1'] + '
    ';\r\n\t\t\t} else {\r\n\t\t\t\tbuf += '' + species.abilities['0'] + '';\r\n\t\t\t}\r\n\t\t\tif (species.abilities['H'] && species.abilities['S']) {\r\n\t\t\t\tbuf += '' + species.abilities['H'] + '
    (' + species.abilities['S'] + ')
    ';\r\n\t\t\t} else if (species.abilities['H']) {\r\n\t\t\t\tbuf += '' + species.abilities['H'] + '';\r\n\t\t\t} else if (species.abilities['S']) {\r\n\t\t\t\t// special case for Zygarde\r\n\t\t\t\tbuf += '(' + species.abilities['S'] + ')';\r\n\t\t\t} else {\r\n\t\t\t\tbuf += '';\r\n\t\t\t}\r\n\t\t\tbuf += '
    ';\r\n\t\t}\r\n\t\tbuf += '';\r\n\t\tbuf += 'HP
    ' + species.baseStats.hp + '
    ';\r\n\t\tbuf += 'Atk
    ' + species.baseStats.atk + '
    ';\r\n\t\tbuf += 'Def
    ' + species.baseStats.def + '
    ';\r\n\t\tif (gen <= 1) {\r\n\t\t\tbuf += 'Spc
    ' + species.baseStats.spa + '
    ';\r\n\t\t} else {\r\n\t\t\tbuf += 'SpA
    ' + species.baseStats.spa + '
    ';\r\n\t\t\tbuf += 'SpD
    ' + species.baseStats.spd + '
    ';\r\n\t\t}\r\n\t\tbuf += 'Spe
    ' + species.baseStats.spe + '
    ';\r\n\t\tbuf += 'BST
    ' + species.bst + '
    ';\r\n\t\tbuf += '
    ';\r\n\t\tbuf += '
  • ';\r\n\t\treturn `
      ${buf}
    `;\r\n\t}\r\n\tgetDataMoveHTML(move: Move) {\r\n\t\tlet buf = `
    • `;\r\n\t\tbuf += `${move.name} `;\r\n\t\t// encoding is important for the ??? type icon\r\n\t\tconst encodedMoveType = encodeURIComponent(move.type);\r\n\t\tbuf += `\"${move.type}\"`;\r\n\t\tbuf += `\"${move.category}\" `;\r\n\t\tif (move.basePower) {\r\n\t\t\tbuf += `Power
      ${typeof move.basePower === 'number' ? move.basePower : '\u2014'}
      `;\r\n\t\t}\r\n\t\tbuf += `Accuracy
      ${typeof move.accuracy === 'number' ? (move.accuracy + '%') : '\u2014'}
      `;\r\n\t\tconst basePP = move.pp || 1;\r\n\t\tconst pp = Math.floor(move.noPPBoosts ? basePP : basePP * 8 / 5);\r\n\t\tbuf += `PP
      ${pp}
      `;\r\n\t\tbuf += `${move.shortDesc || move.desc} `;\r\n\t\tbuf += `
    `;\r\n\t\treturn buf;\r\n\t}\r\n\tgetDataAbilityHTML(ability: Ability) {\r\n\t\tlet buf = `
    • `;\r\n\t\tbuf += `${ability.name} `;\r\n\t\tbuf += `${ability.shortDesc || ability.desc} `;\r\n\t\tbuf += `
    `;\r\n\t\treturn buf;\r\n\t}\r\n\tgetDataItemHTML(item: Item) {\r\n\t\tlet buf = `
    • `;\r\n\t\tbuf += ` ${item.name} `;\r\n\t\tbuf += `${item.shortDesc || item.desc} `;\r\n\t\tbuf += `
    `;\r\n\t\treturn buf;\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the dimension of the image at url. Returns 0x0 if the image isn't found, as well as the relevant error.\r\n\t */\r\n\tgetImageDimensions(url: string): Promise<{height: number, width: number}> {\r\n\t\treturn probe(url);\r\n\t}\r\n\r\n\tparseArguments(\r\n\t\tstr: string,\r\n\t\tdelim = ',',\r\n\t\topts: Partial<{paramDelim: string, useIDs: boolean, allowEmpty: boolean}> = {useIDs: true}\r\n\t) {\r\n\t\tconst result: Record = {};\r\n\t\tfor (const part of str.split(delim)) {\r\n\t\t\tlet [key, val] = Utils.splitFirst(part, opts.paramDelim ||= \"=\").map(f => f.trim());\r\n\t\t\tif (opts.useIDs) key = toID(key);\r\n\t\t\tif (!toID(key) || (!opts.allowEmpty && !toID(val))) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`Invalid option ${part}. Must be in [key]${opts.paramDelim}[value] format.`);\r\n\t\t\t}\r\n\t\t\tif (!result[key]) result[key] = [];\r\n\t\t\tresult[key].push(val);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\t/**\r\n\t * Normalize a message for the purposes of applying chat filters.\r\n\t *\r\n\t * Not used by PS itself, but feel free to use it in your own chat filters.\r\n\t */\r\n\tnormalize(message: string) {\r\n\t\tmessage = message.replace(/'/g, '').replace(/[^A-Za-z0-9]+/g, ' ').trim();\r\n\t\tif (!/[A-Za-z][A-Za-z]/.test(message)) {\r\n\t\t\tmessage = message.replace(/ */g, '');\r\n\t\t} else if (!message.includes(' ')) {\r\n\t\t\tmessage = message.replace(/([A-Z])/g, ' $1').trim();\r\n\t\t}\r\n\t\treturn ' ' + message.toLowerCase() + ' ';\r\n\t}\r\n\r\n\t/**\r\n\t * Generates dimensions to fit an image at url into a maximum size of maxWidth x maxHeight,\r\n\t * preserving aspect ratio.\r\n\t *\r\n\t * @return [width, height, resized]\r\n\t */\r\n\tasync fitImage(url: string, maxHeight = 300, maxWidth = 300): Promise<[number, number, boolean]> {\r\n\t\tconst {height, width} = await Chat.getImageDimensions(url);\r\n\r\n\t\tif (width <= maxWidth && height <= maxHeight) return [width, height, false];\r\n\r\n\t\tconst ratio = Math.min(maxHeight / height, maxWidth / width);\r\n\r\n\t\treturn [Math.round(width * ratio), Math.round(height * ratio), true];\r\n\t}\r\n\r\n\trefreshPageFor(\r\n\t\tpageid: string,\r\n\t\troomid: Room | RoomID,\r\n\t\tcheckPrefix = false,\r\n\t\tignoreUsers: ID[] | null = null\r\n\t) {\r\n\t\tconst room = Rooms.get(roomid);\r\n\t\tif (!room) return false;\r\n\t\tfor (const id in room.users) {\r\n\t\t\tif (ignoreUsers?.includes(id as ID)) continue;\r\n\t\t\tconst u = room.users[id];\r\n\t\t\tfor (const conn of u.connections) {\r\n\t\t\t\tif (conn.openPages) {\r\n\t\t\t\t\tfor (const page of conn.openPages) {\r\n\t\t\t\t\t\tif ((checkPrefix ? page.startsWith(pageid) : page === pageid)) {\r\n\t\t\t\t\t\t\tvoid this.parse(`/j view-${page}`, room, u, conn);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Notifies a targetUser that a user was blocked from reaching them due to a setting they have enabled.\r\n\t */\r\n\tmaybeNotifyBlocked(blocked: 'pm' | 'challenge' | 'invite', targetUser: User, user: User) {\r\n\t\tconst prefix = `|pm|&|${targetUser.getIdentity()}|/nonotify `;\r\n\t\tconst options = 'or change it in the menu in the upper right.';\r\n\t\tif (blocked === 'pm') {\r\n\t\t\tif (!targetUser.notified.blockPMs) {\r\n\t\t\t\ttargetUser.send(`${prefix}The user '${Utils.escapeHTML(user.name)}' attempted to PM you but was blocked. To enable PMs, use /unblockpms ${options}`);\r\n\t\t\t\ttargetUser.notified.blockPMs = true;\r\n\t\t\t}\r\n\t\t} else if (blocked === 'challenge') {\r\n\t\t\tif (!targetUser.notified.blockChallenges) {\r\n\t\t\t\ttargetUser.send(`${prefix}The user '${Utils.escapeHTML(user.name)}' attempted to challenge you to a battle but was blocked. To enable challenges, use /unblockchallenges ${options}`);\r\n\t\t\t\ttargetUser.notified.blockChallenges = true;\r\n\t\t\t}\r\n\t\t} else if (blocked === 'invite') {\r\n\t\t\tif (!targetUser.notified.blockInvites) {\r\n\t\t\t\ttargetUser.send(`${prefix}The user '${Utils.escapeHTML(user.name)}' attempted to invite you to a room but was blocked. To enable invites, use /unblockinvites.`);\r\n\t\t\t\ttargetUser.notified.blockInvites = true;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treadonly formatText = formatText;\r\n\treadonly linkRegex = linkRegex;\r\n\treadonly stripFormatting = stripFormatting;\r\n\r\n\t/** Helper function to ensure no state issues occur when regex testing for links. */\r\n\tisLink(possibleUrl: string) {\r\n\t\t// if we don't do this, it starts spitting out false every other time even if it's a valid link\r\n\t\t// since global regexes are stateful.\r\n\t\t// this took me so much pain to debug.\r\n\t\t// Yes, that is intended JS behavior. Yes, it fills me with unyielding rage.\r\n\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test\r\n\t\tthis.linkRegex.lastIndex = -1;\r\n\t\treturn this.linkRegex.test(possibleUrl);\r\n\t}\r\n\r\n\treadonly filterWords: {[k: string]: FilterWord[]} = {};\r\n\treadonly monitors: {[k: string]: Monitor} = {};\r\n\r\n\tregisterMonitor(id: string, entry: Monitor) {\r\n\t\tif (!Chat.filterWords[id]) Chat.filterWords[id] = [];\r\n\t\tChat.monitors[id] = entry;\r\n\t}\r\n\r\n\tresolvePage(pageid: string, user: User, connection: Connection) {\r\n\t\treturn (new PageContext({pageid, user, connection, language: user.language!})).resolve();\r\n\t}\r\n};\r\n\r\n// backwards compatibility; don't actually use these\r\n// they're just there so forks have time to slowly transition\r\n(Chat as any).escapeHTML = Utils.escapeHTML;\r\n(Chat as any).splitFirst = Utils.splitFirst;\r\n(CommandContext.prototype as any).can = CommandContext.prototype.checkCan;\r\n(CommandContext.prototype as any).canTalk = CommandContext.prototype.checkChat;\r\n(CommandContext.prototype as any).canBroadcast = CommandContext.prototype.checkBroadcast;\r\n(CommandContext.prototype as any).canHTML = CommandContext.prototype.checkHTML;\r\n(CommandContext.prototype as any).canEmbedURI = CommandContext.prototype.checkEmbedURI;\r\n(CommandContext.prototype as any).privatelyCan = CommandContext.prototype.privatelyCheckCan;\r\n(CommandContext.prototype as any).requiresRoom = CommandContext.prototype.requireRoom;\r\n(CommandContext.prototype as any).targetUserOrSelf = function (this: any, target: string, exactName: boolean) {\r\n\tconst user = this.getUserOrSelf(target, exactName);\r\n\tthis.targetUser = user;\r\n\tthis.inputUsername = target;\r\n\tthis.targetUsername = user?.name || target;\r\n\treturn user;\r\n};\r\n(CommandContext.prototype as any).splitTarget = function (this: any, target: string, exactName: boolean) {\r\n\tconst {targetUser, inputUsername, targetUsername, rest} = this.splitUser(target, exactName);\r\n\tthis.targetUser = targetUser;\r\n\tthis.inputUsername = inputUsername;\r\n\tthis.targetUsername = targetUsername;\r\n\treturn rest;\r\n};\r\n\r\n/**\r\n * Used by ChatMonitor.\r\n */\r\nexport interface FilterWord {\r\n\tregex: RegExp;\r\n\tword: string;\r\n\thits: number;\r\n\treason?: string;\r\n\tpublicReason?: string;\r\n\treplacement?: string;\r\n}\r\n\r\nexport type MonitorHandler = (\r\n\tthis: CommandContext,\r\n\tline: FilterWord,\r\n\troom: Room | null,\r\n\tuser: User,\r\n\tmessage: string,\r\n\tlcMessage: string,\r\n\tisStaff: boolean\r\n) => string | false | undefined;\r\nexport interface Monitor {\r\n\tlocation: string;\r\n\tpunishment: string;\r\n\tlabel: string;\r\n\tcondition?: string;\r\n\tmonitor?: MonitorHandler;\r\n}\r\n\r\n// explicitly check this so it doesn't happen in other child processes\r\nif (!process.send) {\r\n\tChat.database.spawn(Config.chatdbprocesses || 1);\r\n\tChat.databaseReadyPromise = Chat.prepareDatabase();\r\n\t// we need to make sure it is explicitly JUST the child of the original parent db process\r\n\t// no other child processes\r\n} else if (process.mainModule === module) {\r\n\tglobal.Monitor = {\r\n\t\tcrashlog(error: Error, source = 'A chat child process', details: AnyObject | null = null) {\r\n\t\t\tconst repr = JSON.stringify([error.name, error.message, source, details]);\r\n\t\t\tprocess.send!(`THROW\\n@!!@${repr}\\n${error.stack}`);\r\n\t\t},\r\n\t};\r\n\tprocess.on('uncaughtException', err => {\r\n\t\tMonitor.crashlog(err, 'A chat database process');\r\n\t});\r\n\tprocess.on('unhandledRejection', err => {\r\n\t\tMonitor.crashlog(err as Error, 'A chat database process');\r\n\t});\r\n\tglobal.Config = require('./config-loader').Config;\r\n\t// eslint-disable-next-line no-eval\r\n\tRepl.start('chat-db', cmd => eval(cmd));\r\n}\r\n"], "mappings": "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", "names": ["dex", "format", "game", "cmd"] }